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:
Tao Bao 2018-12-05 09:23:40 -08:00
parent 62040c53e0
commit d1670a064d

View file

@ -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());