uncrypt: Replace a few C-strings with std::string.
Also use android::base::{Dirname,Realpath,StartsWith}. Test: Run uncrypt on device (`uncrypt package block.map`). Change-Id: Ifacd01d6b35d85ea4afcb93a0dbc0235bb765a75
This commit is contained in:
parent
62040c53e0
commit
d1670a064d
1 changed files with 162 additions and 169 deletions
|
@ -89,7 +89,6 @@
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#include <libgen.h>
|
|
||||||
#include <linux/fs.h>
|
#include <linux/fs.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
@ -103,6 +102,7 @@
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include <android-base/file.h>
|
#include <android-base/file.h>
|
||||||
|
@ -163,38 +163,36 @@ static void add_block_to_ranges(std::vector<int>& ranges, int new_block) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::string find_block_device(const char* path, bool* encryptable, bool* encrypted,
|
// Looks for a volume whose mount point is the prefix of path and returns its block device or an
|
||||||
bool* f2fs_fs) {
|
// empty string. Sets encryption flags accordingly.
|
||||||
// Look for a volume whose mount point is the prefix of path and
|
static std::string FindBlockDevice(const std::string& path, bool* encryptable, bool* encrypted,
|
||||||
// return its block device. Set encrypted if it's currently
|
bool* f2fs_fs) {
|
||||||
// encrypted.
|
// Ensure f2fs_fs is set to false first.
|
||||||
|
*f2fs_fs = false;
|
||||||
|
|
||||||
// ensure f2fs_fs is set to false first.
|
for (const auto& entry : fstab) {
|
||||||
*f2fs_fs = false;
|
if (entry.mount_point.empty()) {
|
||||||
|
continue;
|
||||||
for (const auto& entry : fstab) {
|
|
||||||
if (entry.mount_point.empty()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
auto len = entry.mount_point.size();
|
|
||||||
if (android::base::StartsWith(path, entry.mount_point) &&
|
|
||||||
(path[len] == '/' || path[len] == 0)) {
|
|
||||||
*encrypted = false;
|
|
||||||
*encryptable = false;
|
|
||||||
if (entry.is_encryptable() || entry.fs_mgr_flags.file_encryption) {
|
|
||||||
*encryptable = true;
|
|
||||||
if (android::base::GetProperty("ro.crypto.state", "") == "encrypted") {
|
|
||||||
*encrypted = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (entry.fs_type == "f2fs") {
|
|
||||||
*f2fs_fs = true;
|
|
||||||
}
|
|
||||||
return entry.blk_device;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
auto len = entry.mount_point.size();
|
||||||
|
if (android::base::StartsWith(path, entry.mount_point) &&
|
||||||
|
(path[len] == '/' || path[len] == 0)) {
|
||||||
|
*encrypted = false;
|
||||||
|
*encryptable = false;
|
||||||
|
if (entry.is_encryptable() || entry.fs_mgr_flags.file_encryption) {
|
||||||
|
*encryptable = true;
|
||||||
|
if (android::base::GetProperty("ro.crypto.state", "") == "encrypted") {
|
||||||
|
*encrypted = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (entry.fs_type == "f2fs") {
|
||||||
|
*f2fs_fs = true;
|
||||||
|
}
|
||||||
|
return entry.blk_device;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool write_status_to_socket(int status, int socket) {
|
static bool write_status_to_socket(int status, int socket) {
|
||||||
|
@ -207,103 +205,102 @@ static bool write_status_to_socket(int status, int socket) {
|
||||||
return android::base::WriteFully(socket, &status_out, sizeof(int));
|
return android::base::WriteFully(socket, &status_out, sizeof(int));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse uncrypt_file to find the update package name.
|
// Parses the given path file to find the update package name.
|
||||||
static bool find_uncrypt_package(const std::string& uncrypt_path_file, std::string* package_name) {
|
static bool FindUncryptPackage(const std::string& uncrypt_path_file, std::string* package_name) {
|
||||||
CHECK(package_name != nullptr);
|
CHECK(package_name != nullptr);
|
||||||
std::string uncrypt_path;
|
std::string uncrypt_path;
|
||||||
if (!android::base::ReadFileToString(uncrypt_path_file, &uncrypt_path)) {
|
if (!android::base::ReadFileToString(uncrypt_path_file, &uncrypt_path)) {
|
||||||
PLOG(ERROR) << "failed to open \"" << uncrypt_path_file << "\"";
|
PLOG(ERROR) << "failed to open \"" << uncrypt_path_file << "\"";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove the trailing '\n' if present.
|
// Remove the trailing '\n' if present.
|
||||||
*package_name = android::base::Trim(uncrypt_path);
|
*package_name = android::base::Trim(uncrypt_path);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int retry_fibmap(const int fd, const char* name, int* block, const int head_block) {
|
static int RetryFibmap(int fd, const std::string& name, int* block, const int head_block) {
|
||||||
CHECK(block != nullptr);
|
CHECK(block != nullptr);
|
||||||
for (size_t i = 0; i < FIBMAP_RETRY_LIMIT; i++) {
|
for (size_t i = 0; i < FIBMAP_RETRY_LIMIT; i++) {
|
||||||
if (fsync(fd) == -1) {
|
if (fsync(fd) == -1) {
|
||||||
PLOG(ERROR) << "failed to fsync \"" << name << "\"";
|
PLOG(ERROR) << "failed to fsync \"" << name << "\"";
|
||||||
return kUncryptFileSyncError;
|
return kUncryptFileSyncError;
|
||||||
}
|
|
||||||
if (ioctl(fd, FIBMAP, block) != 0) {
|
|
||||||
PLOG(ERROR) << "failed to find block " << head_block;
|
|
||||||
return kUncryptIoctlError;
|
|
||||||
}
|
|
||||||
if (*block != 0) {
|
|
||||||
return kUncryptNoError;
|
|
||||||
}
|
|
||||||
sleep(1);
|
|
||||||
}
|
}
|
||||||
LOG(ERROR) << "fibmap of " << head_block << "always returns 0";
|
if (ioctl(fd, FIBMAP, block) != 0) {
|
||||||
return kUncryptIoctlError;
|
PLOG(ERROR) << "failed to find block " << head_block;
|
||||||
|
return kUncryptIoctlError;
|
||||||
|
}
|
||||||
|
if (*block != 0) {
|
||||||
|
return kUncryptNoError;
|
||||||
|
}
|
||||||
|
sleep(1);
|
||||||
|
}
|
||||||
|
LOG(ERROR) << "fibmap of " << head_block << " always returns 0";
|
||||||
|
return kUncryptIoctlError;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int produce_block_map(const char* path, const char* map_file, const char* blk_dev,
|
static int ProductBlockMap(const std::string& path, const std::string& map_file,
|
||||||
bool encrypted, bool f2fs_fs, int socket) {
|
const std::string& blk_dev, bool encrypted, bool f2fs_fs, int socket) {
|
||||||
std::string err;
|
std::string err;
|
||||||
if (!android::base::RemoveFileIfExists(map_file, &err)) {
|
if (!android::base::RemoveFileIfExists(map_file, &err)) {
|
||||||
LOG(ERROR) << "failed to remove the existing map file " << map_file << ": " << err;
|
LOG(ERROR) << "failed to remove the existing map file " << map_file << ": " << err;
|
||||||
return kUncryptFileRemoveError;
|
return kUncryptFileRemoveError;
|
||||||
}
|
}
|
||||||
std::string tmp_map_file = std::string(map_file) + ".tmp";
|
std::string tmp_map_file = map_file + ".tmp";
|
||||||
android::base::unique_fd mapfd(open(tmp_map_file.c_str(),
|
android::base::unique_fd mapfd(open(tmp_map_file.c_str(), O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR));
|
||||||
O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR));
|
if (mapfd == -1) {
|
||||||
if (mapfd == -1) {
|
PLOG(ERROR) << "failed to open " << tmp_map_file;
|
||||||
PLOG(ERROR) << "failed to open " << tmp_map_file;
|
return kUncryptFileOpenError;
|
||||||
return kUncryptFileOpenError;
|
}
|
||||||
}
|
|
||||||
|
// Make sure we can write to the socket.
|
||||||
// Make sure we can write to the socket.
|
if (!write_status_to_socket(0, socket)) {
|
||||||
if (!write_status_to_socket(0, socket)) {
|
LOG(ERROR) << "failed to write to socket " << socket;
|
||||||
LOG(ERROR) << "failed to write to socket " << socket;
|
return kUncryptSocketWriteError;
|
||||||
return kUncryptSocketWriteError;
|
}
|
||||||
}
|
|
||||||
|
struct stat sb;
|
||||||
struct stat sb;
|
if (stat(path.c_str(), &sb) != 0) {
|
||||||
if (stat(path, &sb) != 0) {
|
PLOG(ERROR) << "failed to stat " << path;
|
||||||
LOG(ERROR) << "failed to stat " << path;
|
return kUncryptFileStatError;
|
||||||
return kUncryptFileStatError;
|
}
|
||||||
}
|
|
||||||
|
LOG(INFO) << " block size: " << sb.st_blksize << " bytes";
|
||||||
LOG(INFO) << " block size: " << sb.st_blksize << " bytes";
|
|
||||||
|
int blocks = ((sb.st_size - 1) / sb.st_blksize) + 1;
|
||||||
int blocks = ((sb.st_size-1) / sb.st_blksize) + 1;
|
LOG(INFO) << " file size: " << sb.st_size << " bytes, " << blocks << " blocks";
|
||||||
LOG(INFO) << " file size: " << sb.st_size << " bytes, " << blocks << " blocks";
|
|
||||||
|
std::vector<int> ranges;
|
||||||
std::vector<int> ranges;
|
|
||||||
|
std::string s = android::base::StringPrintf("%s\n%" PRId64 " %" PRId64 "\n", blk_dev.c_str(),
|
||||||
std::string s = android::base::StringPrintf("%s\n%" PRId64 " %" PRId64 "\n",
|
static_cast<int64_t>(sb.st_size),
|
||||||
blk_dev, static_cast<int64_t>(sb.st_size),
|
static_cast<int64_t>(sb.st_blksize));
|
||||||
static_cast<int64_t>(sb.st_blksize));
|
if (!android::base::WriteStringToFd(s, mapfd)) {
|
||||||
if (!android::base::WriteStringToFd(s, mapfd)) {
|
PLOG(ERROR) << "failed to write " << tmp_map_file;
|
||||||
PLOG(ERROR) << "failed to write " << tmp_map_file;
|
return kUncryptWriteError;
|
||||||
return kUncryptWriteError;
|
}
|
||||||
}
|
|
||||||
|
std::vector<std::vector<unsigned char>> buffers;
|
||||||
std::vector<std::vector<unsigned char>> buffers;
|
if (encrypted) {
|
||||||
if (encrypted) {
|
buffers.resize(WINDOW_SIZE, std::vector<unsigned char>(sb.st_blksize));
|
||||||
buffers.resize(WINDOW_SIZE, std::vector<unsigned char>(sb.st_blksize));
|
}
|
||||||
}
|
int head_block = 0;
|
||||||
int head_block = 0;
|
int head = 0, tail = 0;
|
||||||
int head = 0, tail = 0;
|
|
||||||
|
android::base::unique_fd fd(open(path.c_str(), O_RDWR));
|
||||||
android::base::unique_fd fd(open(path, O_RDWR));
|
if (fd == -1) {
|
||||||
if (fd == -1) {
|
PLOG(ERROR) << "failed to open " << path << " for reading";
|
||||||
PLOG(ERROR) << "failed to open " << path << " for reading";
|
return kUncryptFileOpenError;
|
||||||
return kUncryptFileOpenError;
|
}
|
||||||
}
|
|
||||||
|
android::base::unique_fd wfd;
|
||||||
android::base::unique_fd wfd;
|
if (encrypted) {
|
||||||
if (encrypted) {
|
wfd.reset(open(blk_dev.c_str(), O_WRONLY));
|
||||||
wfd.reset(open(blk_dev, O_WRONLY));
|
if (wfd == -1) {
|
||||||
if (wfd == -1) {
|
PLOG(ERROR) << "failed to open " << blk_dev << " for writing";
|
||||||
PLOG(ERROR) << "failed to open " << blk_dev << " for writing";
|
return kUncryptBlockOpenError;
|
||||||
return kUncryptBlockOpenError;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// F2FS-specific ioctl
|
// F2FS-specific ioctl
|
||||||
// It requires the below kernel commit merged in v4.16-rc1.
|
// It requires the below kernel commit merged in v4.16-rc1.
|
||||||
|
@ -351,7 +348,7 @@ static int produce_block_map(const char* path, const char* map_file, const char*
|
||||||
|
|
||||||
if (block == 0) {
|
if (block == 0) {
|
||||||
LOG(ERROR) << "failed to find block " << head_block << ", retrying";
|
LOG(ERROR) << "failed to find block " << head_block << ", retrying";
|
||||||
int error = retry_fibmap(fd, path, &block, head_block);
|
int error = RetryFibmap(fd, path, &block, head_block);
|
||||||
if (error != kUncryptNoError) {
|
if (error != kUncryptNoError) {
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
@ -396,7 +393,7 @@ static int produce_block_map(const char* path, const char* map_file, const char*
|
||||||
|
|
||||||
if (block == 0) {
|
if (block == 0) {
|
||||||
LOG(ERROR) << "failed to find block " << head_block << ", retrying";
|
LOG(ERROR) << "failed to find block " << head_block << ", retrying";
|
||||||
int error = retry_fibmap(fd, path, &block, head_block);
|
int error = RetryFibmap(fd, path, &block, head_block);
|
||||||
if (error != kUncryptNoError) {
|
if (error != kUncryptNoError) {
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
@ -446,13 +443,12 @@ static int produce_block_map(const char* path, const char* map_file, const char*
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rename(tmp_map_file.c_str(), map_file) == -1) {
|
if (rename(tmp_map_file.c_str(), map_file.c_str()) == -1) {
|
||||||
PLOG(ERROR) << "failed to rename " << tmp_map_file << " to " << map_file;
|
PLOG(ERROR) << "failed to rename " << tmp_map_file << " to " << map_file;
|
||||||
return kUncryptFileRenameError;
|
return kUncryptFileRenameError;
|
||||||
}
|
}
|
||||||
// Sync dir to make rename() result written to disk.
|
// Sync dir to make rename() result written to disk.
|
||||||
std::string file_name = map_file;
|
std::string dir_name = android::base::Dirname(map_file);
|
||||||
std::string dir_name = dirname(&file_name[0]);
|
|
||||||
android::base::unique_fd dfd(open(dir_name.c_str(), O_RDONLY | O_DIRECTORY));
|
android::base::unique_fd dfd(open(dir_name.c_str(), O_RDONLY | O_DIRECTORY));
|
||||||
if (dfd == -1) {
|
if (dfd == -1) {
|
||||||
PLOG(ERROR) << "failed to open dir " << dir_name;
|
PLOG(ERROR) << "failed to open dir " << dir_name;
|
||||||
|
@ -469,45 +465,42 @@ static int produce_block_map(const char* path, const char* map_file, const char*
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int uncrypt(const char* input_path, const char* map_file, const int socket) {
|
static int Uncrypt(const std::string& input_path, const std::string& map_file, int socket) {
|
||||||
LOG(INFO) << "update package is \"" << input_path << "\"";
|
LOG(INFO) << "update package is \"" << input_path << "\"";
|
||||||
|
|
||||||
// Turn the name of the file we're supposed to convert into an absolute path, so we can find
|
// Turn the name of the file we're supposed to convert into an absolute path, so we can find what
|
||||||
// what filesystem it's on.
|
// filesystem it's on.
|
||||||
char path[PATH_MAX+1];
|
std::string path;
|
||||||
if (realpath(input_path, path) == nullptr) {
|
if (!android::base::Realpath(input_path, &path)) {
|
||||||
PLOG(ERROR) << "failed to convert \"" << input_path << "\" to absolute path";
|
PLOG(ERROR) << "Failed to convert \"" << input_path << "\" to absolute path";
|
||||||
return kUncryptRealpathFindError;
|
return kUncryptRealpathFindError;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool encryptable;
|
bool encryptable;
|
||||||
bool encrypted;
|
bool encrypted;
|
||||||
bool f2fs_fs;
|
bool f2fs_fs;
|
||||||
const std::string blk_dev = find_block_device(path, &encryptable, &encrypted, &f2fs_fs);
|
const std::string blk_dev = FindBlockDevice(path, &encryptable, &encrypted, &f2fs_fs);
|
||||||
if (blk_dev.empty()) {
|
if (blk_dev.empty()) {
|
||||||
LOG(ERROR) << "failed to find block device for " << path;
|
LOG(ERROR) << "Failed to find block device for " << path;
|
||||||
return kUncryptBlockDeviceFindError;
|
return kUncryptBlockDeviceFindError;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the filesystem it's on isn't encrypted, we only produce the
|
// If the filesystem it's on isn't encrypted, we only produce the block map, we don't rewrite the
|
||||||
// block map, we don't rewrite the file contents (it would be
|
// file contents (it would be pointless to do so).
|
||||||
// pointless to do so).
|
LOG(INFO) << "encryptable: " << (encryptable ? "yes" : "no");
|
||||||
LOG(INFO) << "encryptable: " << (encryptable ? "yes" : "no");
|
LOG(INFO) << " encrypted: " << (encrypted ? "yes" : "no");
|
||||||
LOG(INFO) << " encrypted: " << (encrypted ? "yes" : "no");
|
|
||||||
|
|
||||||
// Recovery supports installing packages from 3 paths: /cache,
|
// Recovery supports installing packages from 3 paths: /cache, /data, and /sdcard. (On a
|
||||||
// /data, and /sdcard. (On a particular device, other locations
|
// particular device, other locations may work, but those are three we actually expect.)
|
||||||
// may work, but those are three we actually expect.)
|
//
|
||||||
//
|
// On /data we want to convert the file to a block map so that we can read the package without
|
||||||
// On /data we want to convert the file to a block map so that we
|
// mounting the partition. On /cache and /sdcard we leave the file alone.
|
||||||
// can read the package without mounting the partition. On /cache
|
if (android::base::StartsWith(path, "/data/")) {
|
||||||
// and /sdcard we leave the file alone.
|
LOG(INFO) << "writing block map " << map_file;
|
||||||
if (strncmp(path, "/data/", 6) == 0) {
|
return ProductBlockMap(path, map_file, blk_dev, encrypted, f2fs_fs, socket);
|
||||||
LOG(INFO) << "writing block map " << map_file;
|
}
|
||||||
return produce_block_map(path, map_file, blk_dev.c_str(), encrypted, f2fs_fs, socket);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void log_uncrypt_error_code(UncryptErrorCode error_code) {
|
static void log_uncrypt_error_code(UncryptErrorCode error_code) {
|
||||||
|
@ -523,18 +516,18 @@ static bool uncrypt_wrapper(const char* input_path, const char* map_file, const
|
||||||
|
|
||||||
std::string package;
|
std::string package;
|
||||||
if (input_path == nullptr) {
|
if (input_path == nullptr) {
|
||||||
if (!find_uncrypt_package(UNCRYPT_PATH_FILE, &package)) {
|
if (!FindUncryptPackage(UNCRYPT_PATH_FILE, &package)) {
|
||||||
write_status_to_socket(-1, socket);
|
write_status_to_socket(-1, socket);
|
||||||
// Overwrite the error message.
|
// Overwrite the error message.
|
||||||
log_uncrypt_error_code(kUncryptPackageMissingError);
|
log_uncrypt_error_code(kUncryptPackageMissingError);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
input_path = package.c_str();
|
input_path = package.c_str();
|
||||||
}
|
}
|
||||||
CHECK(map_file != nullptr);
|
CHECK(map_file != nullptr);
|
||||||
|
|
||||||
auto start = std::chrono::system_clock::now();
|
auto start = std::chrono::system_clock::now();
|
||||||
int status = uncrypt(input_path, map_file, socket);
|
int status = Uncrypt(input_path, map_file, socket);
|
||||||
std::chrono::duration<double> duration = std::chrono::system_clock::now() - start;
|
std::chrono::duration<double> duration = std::chrono::system_clock::now() - start;
|
||||||
int count = static_cast<int>(duration.count());
|
int count = static_cast<int>(duration.count());
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue