summaryrefslogtreecommitdiffstats
path: root/uncrypt
diff options
context:
space:
mode:
Diffstat (limited to 'uncrypt')
-rw-r--r--uncrypt/uncrypt.cpp363
1 files changed, 174 insertions, 189 deletions
diff --git a/uncrypt/uncrypt.cpp b/uncrypt/uncrypt.cpp
index 95f40c71f..f1f4f69f0 100644
--- a/uncrypt/uncrypt.cpp
+++ b/uncrypt/uncrypt.cpp
@@ -89,7 +89,6 @@
#include <errno.h>
#include <fcntl.h>
#include <inttypes.h>
-#include <libgen.h>
#include <linux/fs.h>
#include <stdarg.h>
#include <stdio.h>
@@ -103,6 +102,7 @@
#include <algorithm>
#include <memory>
+#include <string>
#include <vector>
#include <android-base/file.h>
@@ -115,9 +115,13 @@
#include <cutils/android_reboot.h>
#include <cutils/sockets.h>
#include <fs_mgr.h>
+#include <fstab/fstab.h>
#include "otautil/error_code.h"
+using android::fs_mgr::Fstab;
+using android::fs_mgr::ReadDefaultFstab;
+
static constexpr int WINDOW_SIZE = 5;
static constexpr int FIBMAP_RETRY_LIMIT = 3;
@@ -136,7 +140,7 @@ static const std::string UNCRYPT_PATH_FILE = "/cache/recovery/uncrypt_file";
static const std::string UNCRYPT_STATUS = "/cache/recovery/uncrypt_status";
static const std::string UNCRYPT_SOCKET = "uncrypt";
-static struct fstab* fstab = nullptr;
+static Fstab fstab;
static int write_at_offset(unsigned char* buffer, size_t size, int wfd, off64_t offset) {
if (TEMP_FAILURE_RETRY(lseek64(wfd, offset, SEEK_SET)) == -1) {
@@ -162,49 +166,34 @@ static void add_block_to_ranges(std::vector<int>& ranges, int new_block) {
}
}
-static struct fstab* read_fstab() {
- fstab = fs_mgr_read_fstab_default();
- if (!fstab) {
- LOG(ERROR) << "failed to read default fstab";
- return NULL;
- }
-
- return fstab;
-}
-
-static const char* find_block_device(const char* path, bool* encryptable,
- bool* encrypted, bool* f2fs_fs) {
- // Look for a volume whose mount point is the prefix of path and
- // return its block device. Set encrypted if it's currently
- // encrypted.
-
- // ensure f2fs_fs is set to false first.
- *f2fs_fs = false;
-
- for (int i = 0; i < fstab->num_entries; ++i) {
- struct fstab_rec* v = &fstab->recs[i];
- if (!v->mount_point) {
- continue;
- }
- int len = strlen(v->mount_point);
- if (strncmp(path, v->mount_point, len) == 0 &&
- (path[len] == '/' || path[len] == 0)) {
- *encrypted = false;
- *encryptable = false;
- if (fs_mgr_is_encryptable(v) || fs_mgr_is_file_encrypted(v)) {
- *encryptable = true;
- if (android::base::GetProperty("ro.crypto.state", "") == "encrypted") {
- *encrypted = true;
- }
- }
- if (strcmp(v->fs_type, "f2fs") == 0) {
- *f2fs_fs = true;
- }
- return v->blk_device;
+// Looks for a volume whose mount point is the prefix of path and returns its block device or an
+// empty string. Sets encryption flags accordingly.
+static std::string FindBlockDevice(const std::string& path, bool* encryptable, bool* encrypted,
+ bool* f2fs_fs) {
+ // Ensure f2fs_fs is set to false first.
+ *f2fs_fs = false;
+
+ for (const auto& entry : fstab) {
+ if (entry.mount_point.empty()) {
+ continue;
+ }
+ if (android::base::StartsWith(path, entry.mount_point + "/")) {
+ *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 NULL;
+ return "";
}
static bool write_status_to_socket(int status, int socket) {
@@ -217,103 +206,102 @@ static bool write_status_to_socket(int status, int socket) {
return android::base::WriteFully(socket, &status_out, sizeof(int));
}
-// Parse uncrypt_file to find the update package name.
-static bool find_uncrypt_package(const std::string& uncrypt_path_file, std::string* package_name) {
- CHECK(package_name != nullptr);
- std::string uncrypt_path;
- if (!android::base::ReadFileToString(uncrypt_path_file, &uncrypt_path)) {
- PLOG(ERROR) << "failed to open \"" << uncrypt_path_file << "\"";
- return false;
- }
-
- // Remove the trailing '\n' if present.
- *package_name = android::base::Trim(uncrypt_path);
- return true;
-}
-
-static int retry_fibmap(const int fd, const char* name, int* block, const int head_block) {
- CHECK(block != nullptr);
- for (size_t i = 0; i < FIBMAP_RETRY_LIMIT; i++) {
- if (fsync(fd) == -1) {
- PLOG(ERROR) << "failed to fsync \"" << name << "\"";
- 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";
- return kUncryptIoctlError;
+// Parses the given path file to find the update package name.
+static bool FindUncryptPackage(const std::string& uncrypt_path_file, std::string* package_name) {
+ CHECK(package_name != nullptr);
+ std::string uncrypt_path;
+ if (!android::base::ReadFileToString(uncrypt_path_file, &uncrypt_path)) {
+ PLOG(ERROR) << "failed to open \"" << uncrypt_path_file << "\"";
+ return false;
+ }
+
+ // Remove the trailing '\n' if present.
+ *package_name = android::base::Trim(uncrypt_path);
+ return true;
}
-static int produce_block_map(const char* path, const char* map_file, const char* blk_dev,
- bool encrypted, bool f2fs_fs, int socket) {
- std::string err;
- if (!android::base::RemoveFileIfExists(map_file, &err)) {
- LOG(ERROR) << "failed to remove the existing map file " << map_file << ": " << err;
- return kUncryptFileRemoveError;
- }
- std::string tmp_map_file = std::string(map_file) + ".tmp";
- android::base::unique_fd mapfd(open(tmp_map_file.c_str(),
- O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR));
- if (mapfd == -1) {
- PLOG(ERROR) << "failed to open " << tmp_map_file;
- return kUncryptFileOpenError;
+static int RetryFibmap(int fd, const std::string& name, int* block, const int head_block) {
+ CHECK(block != nullptr);
+ for (size_t i = 0; i < FIBMAP_RETRY_LIMIT; i++) {
+ if (fsync(fd) == -1) {
+ PLOG(ERROR) << "failed to fsync \"" << name << "\"";
+ return kUncryptFileSyncError;
}
-
- // Make sure we can write to the socket.
- if (!write_status_to_socket(0, socket)) {
- LOG(ERROR) << "failed to write to socket " << socket;
- return kUncryptSocketWriteError;
+ if (ioctl(fd, FIBMAP, block) != 0) {
+ PLOG(ERROR) << "failed to find block " << head_block;
+ return kUncryptIoctlError;
}
-
- struct stat sb;
- if (stat(path, &sb) != 0) {
- LOG(ERROR) << "failed to stat " << path;
- return kUncryptFileStatError;
+ if (*block != 0) {
+ return kUncryptNoError;
}
+ sleep(1);
+ }
+ LOG(ERROR) << "fibmap of " << head_block << " always returns 0";
+ return kUncryptIoctlError;
+}
- LOG(INFO) << " block size: " << sb.st_blksize << " bytes";
-
- int blocks = ((sb.st_size-1) / sb.st_blksize) + 1;
- LOG(INFO) << " file size: " << sb.st_size << " bytes, " << blocks << " blocks";
-
- std::vector<int> ranges;
-
- std::string s = android::base::StringPrintf("%s\n%" PRId64 " %" PRId64 "\n",
- blk_dev, static_cast<int64_t>(sb.st_size),
- static_cast<int64_t>(sb.st_blksize));
- if (!android::base::WriteStringToFd(s, mapfd)) {
- PLOG(ERROR) << "failed to write " << tmp_map_file;
- return kUncryptWriteError;
- }
-
- std::vector<std::vector<unsigned char>> buffers;
- if (encrypted) {
- buffers.resize(WINDOW_SIZE, std::vector<unsigned char>(sb.st_blksize));
- }
- int head_block = 0;
- int head = 0, tail = 0;
-
- android::base::unique_fd fd(open(path, O_RDONLY));
- if (fd == -1) {
- PLOG(ERROR) << "failed to open " << path << " for reading";
- return kUncryptFileOpenError;
- }
-
- android::base::unique_fd wfd;
- if (encrypted) {
- wfd.reset(open(blk_dev, O_WRONLY));
- if (wfd == -1) {
- PLOG(ERROR) << "failed to open " << blk_dev << " for writing";
- return kUncryptBlockOpenError;
- }
- }
+static int ProductBlockMap(const std::string& path, const std::string& map_file,
+ const std::string& blk_dev, bool encrypted, bool f2fs_fs, int socket) {
+ std::string err;
+ if (!android::base::RemoveFileIfExists(map_file, &err)) {
+ LOG(ERROR) << "failed to remove the existing map file " << map_file << ": " << err;
+ return kUncryptFileRemoveError;
+ }
+ std::string tmp_map_file = map_file + ".tmp";
+ android::base::unique_fd mapfd(open(tmp_map_file.c_str(), O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR));
+ if (mapfd == -1) {
+ PLOG(ERROR) << "failed to open " << tmp_map_file;
+ return kUncryptFileOpenError;
+ }
+
+ // Make sure we can write to the socket.
+ if (!write_status_to_socket(0, socket)) {
+ LOG(ERROR) << "failed to write to socket " << socket;
+ return kUncryptSocketWriteError;
+ }
+
+ struct stat sb;
+ if (stat(path.c_str(), &sb) != 0) {
+ PLOG(ERROR) << "failed to stat " << path;
+ return kUncryptFileStatError;
+ }
+
+ LOG(INFO) << " block size: " << sb.st_blksize << " bytes";
+
+ int blocks = ((sb.st_size - 1) / sb.st_blksize) + 1;
+ LOG(INFO) << " file size: " << sb.st_size << " bytes, " << blocks << " blocks";
+
+ std::vector<int> ranges;
+
+ std::string s = android::base::StringPrintf("%s\n%" PRId64 " %" PRId64 "\n", blk_dev.c_str(),
+ static_cast<int64_t>(sb.st_size),
+ static_cast<int64_t>(sb.st_blksize));
+ if (!android::base::WriteStringToFd(s, mapfd)) {
+ PLOG(ERROR) << "failed to write " << tmp_map_file;
+ return kUncryptWriteError;
+ }
+
+ std::vector<std::vector<unsigned char>> buffers;
+ if (encrypted) {
+ buffers.resize(WINDOW_SIZE, std::vector<unsigned char>(sb.st_blksize));
+ }
+ int head_block = 0;
+ int head = 0, tail = 0;
+
+ android::base::unique_fd fd(open(path.c_str(), O_RDWR));
+ if (fd == -1) {
+ PLOG(ERROR) << "failed to open " << path << " for reading";
+ return kUncryptFileOpenError;
+ }
+
+ android::base::unique_fd wfd;
+ if (encrypted) {
+ wfd.reset(open(blk_dev.c_str(), O_WRONLY));
+ if (wfd == -1) {
+ PLOG(ERROR) << "failed to open " << blk_dev << " for writing";
+ return kUncryptBlockOpenError;
+ }
+ }
// F2FS-specific ioctl
// It requires the below kernel commit merged in v4.16-rc1.
@@ -329,7 +317,7 @@ static int produce_block_map(const char* path, const char* map_file, const char*
#define F2FS_IOCTL_MAGIC 0xf5
#endif
#define F2FS_IOC_SET_PIN_FILE _IOW(F2FS_IOCTL_MAGIC, 13, __u32)
-#define F2FS_IOC_GET_PIN_FILE _IOW(F2FS_IOCTL_MAGIC, 14, __u32)
+#define F2FS_IOC_GET_PIN_FILE _IOR(F2FS_IOCTL_MAGIC, 14, __u32)
#endif
if (f2fs_fs) {
__u32 set = 1;
@@ -361,7 +349,7 @@ static int produce_block_map(const char* path, const char* map_file, const char*
if (block == 0) {
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) {
return error;
}
@@ -406,7 +394,7 @@ static int produce_block_map(const char* path, const char* map_file, const char*
if (block == 0) {
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) {
return error;
}
@@ -456,13 +444,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) {
- PLOG(ERROR) << "failed to rename " << tmp_map_file << " to " << map_file;
- return kUncryptFileRenameError;
+ if (rename(tmp_map_file.c_str(), map_file.c_str()) == -1) {
+ PLOG(ERROR) << "failed to rename " << tmp_map_file << " to " << map_file;
+ return kUncryptFileRenameError;
}
// Sync dir to make rename() result written to disk.
- std::string file_name = map_file;
- std::string dir_name = dirname(&file_name[0]);
+ std::string dir_name = android::base::Dirname(map_file);
android::base::unique_fd dfd(open(dir_name.c_str(), O_RDONLY | O_DIRECTORY));
if (dfd == -1) {
PLOG(ERROR) << "failed to open dir " << dir_name;
@@ -479,45 +466,42 @@ static int produce_block_map(const char* path, const char* map_file, const char*
return 0;
}
-static int uncrypt(const char* input_path, const char* map_file, const int socket) {
- 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
- // what filesystem it's on.
- char path[PATH_MAX+1];
- if (realpath(input_path, path) == nullptr) {
- PLOG(ERROR) << "failed to convert \"" << input_path << "\" to absolute path";
- return kUncryptRealpathFindError;
- }
-
- bool encryptable;
- bool encrypted;
- bool f2fs_fs;
- const char* blk_dev = find_block_device(path, &encryptable, &encrypted, &f2fs_fs);
- if (blk_dev == nullptr) {
- LOG(ERROR) << "failed to find block device for " << path;
- return kUncryptBlockDeviceFindError;
- }
-
- // If the filesystem it's on isn't encrypted, we only produce the
- // block map, we don't rewrite the file contents (it would be
- // pointless to do so).
- LOG(INFO) << "encryptable: " << (encryptable ? "yes" : "no");
- LOG(INFO) << " encrypted: " << (encrypted ? "yes" : "no");
-
- // Recovery supports installing packages from 3 paths: /cache,
- // /data, and /sdcard. (On a particular device, other locations
- // 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 mounting the partition. On /cache
- // and /sdcard we leave the file alone.
- if (strncmp(path, "/data/", 6) == 0) {
- LOG(INFO) << "writing block map " << map_file;
- return produce_block_map(path, map_file, blk_dev, encrypted, f2fs_fs, socket);
- }
-
- return 0;
+static int Uncrypt(const std::string& input_path, const std::string& map_file, int socket) {
+ 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 what
+ // filesystem it's on.
+ std::string path;
+ if (!android::base::Realpath(input_path, &path)) {
+ PLOG(ERROR) << "Failed to convert \"" << input_path << "\" to absolute path";
+ return kUncryptRealpathFindError;
+ }
+
+ bool encryptable;
+ bool encrypted;
+ bool f2fs_fs;
+ const std::string blk_dev = FindBlockDevice(path, &encryptable, &encrypted, &f2fs_fs);
+ if (blk_dev.empty()) {
+ LOG(ERROR) << "Failed to find block device for " << path;
+ return kUncryptBlockDeviceFindError;
+ }
+
+ // If the filesystem it's on isn't encrypted, we only produce the block map, we don't rewrite the
+ // file contents (it would be pointless to do so).
+ LOG(INFO) << "encryptable: " << (encryptable ? "yes" : "no");
+ LOG(INFO) << " encrypted: " << (encrypted ? "yes" : "no");
+
+ // Recovery supports installing packages from 3 paths: /cache, /data, and /sdcard. (On a
+ // particular device, other locations 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
+ // mounting the partition. On /cache and /sdcard we leave the file alone.
+ if (android::base::StartsWith(path, "/data/")) {
+ LOG(INFO) << "writing block map " << map_file;
+ return ProductBlockMap(path, map_file, blk_dev, encrypted, f2fs_fs, socket);
+ }
+
+ return 0;
}
static void log_uncrypt_error_code(UncryptErrorCode error_code) {
@@ -533,18 +517,18 @@ static bool uncrypt_wrapper(const char* input_path, const char* map_file, const
std::string package;
if (input_path == nullptr) {
- if (!find_uncrypt_package(UNCRYPT_PATH_FILE, &package)) {
- write_status_to_socket(-1, socket);
- // Overwrite the error message.
- log_uncrypt_error_code(kUncryptPackageMissingError);
- return false;
- }
- input_path = package.c_str();
+ if (!FindUncryptPackage(UNCRYPT_PATH_FILE, &package)) {
+ write_status_to_socket(-1, socket);
+ // Overwrite the error message.
+ log_uncrypt_error_code(kUncryptPackageMissingError);
+ return false;
+ }
+ input_path = package.c_str();
}
CHECK(map_file != nullptr);
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;
int count = static_cast<int>(duration.count());
@@ -654,7 +638,8 @@ int main(int argc, char** argv) {
return 2;
}
- if ((fstab = read_fstab()) == nullptr) {
+ if (!ReadDefaultFstab(&fstab)) {
+ LOG(ERROR) << "failed to read default fstab";
log_uncrypt_error_code(kUncryptFstabReadError);
return 1;
}