Merge "Fix fastdeploy issues when testing Boat Attack Unity3D demo"
diff --git a/TEST_MAPPING b/TEST_MAPPING
index c47230f..f9c3b4a 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -2,6 +2,30 @@
"presubmit": [
{
"name": "adbd_test"
+ },
+ {
+ "name": "debuggerd_test"
+ },
+ {
+ "name": "init_tests"
+ },
+ {
+ "name": "libbase_test"
+ },
+ {
+ "name": "libprocinfo_test"
+ },
+ {
+ "name": "memunreachable_test"
+ },
+ {
+ "name": "memunreachable_binder_test"
+ },
+ {
+ "name": "propertyinfoserializer_tests"
+ },
+ {
+ "name": "ziparchive-tests"
}
]
}
diff --git a/adb/Android.bp b/adb/Android.bp
index 00e98fe..e994075 100644
--- a/adb/Android.bp
+++ b/adb/Android.bp
@@ -285,6 +285,15 @@
"deploypatchgenerator",
],
+ // Archive adb, adb.exe.
+ dist: {
+ targets: [
+ "dist_files",
+ "sdk",
+ "win_sdk",
+ ],
+ },
+
target: {
darwin: {
cflags: [
diff --git a/adb/Android.mk b/adb/Android.mk
deleted file mode 100644
index 8b2d558..0000000
--- a/adb/Android.mk
+++ /dev/null
@@ -1,8 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-
-# Archive adb, adb.exe.
-$(call dist-for-goals,dist_files sdk win_sdk,$(HOST_OUT_EXECUTABLES)/adb)
-
-ifdef HOST_CROSS_OS
-$(call dist-for-goals,dist_files sdk win_sdk,$(ALL_MODULES.host_cross_adb.BUILT))
-endif
diff --git a/adb/adb_auth.h b/adb/adb_auth.h
index 715e04f..2fc8478 100644
--- a/adb/adb_auth.h
+++ b/adb/adb_auth.h
@@ -36,6 +36,7 @@
void adb_auth_init();
int adb_auth_keygen(const char* filename);
+int adb_auth_pubkey(const char* filename);
std::string adb_auth_get_userkey();
std::deque<std::shared_ptr<RSA>> adb_auth_get_private_keys();
diff --git a/adb/client/auth.cpp b/adb/client/auth.cpp
index 71c19b8..bcb829b 100644
--- a/adb/client/auth.cpp
+++ b/adb/client/auth.cpp
@@ -43,6 +43,7 @@
#include "adb.h"
#include "adb_auth.h"
+#include "adb_io.h"
#include "adb_utils.h"
#include "sysdeps.h"
#include "transport.h"
@@ -52,30 +53,7 @@
*new std::map<std::string, std::shared_ptr<RSA>>;
static std::map<int, std::string>& g_monitored_paths = *new std::map<int, std::string>;
-static std::string get_user_info() {
- LOG(INFO) << "get_user_info...";
-
- std::string hostname;
- if (getenv("HOSTNAME")) hostname = getenv("HOSTNAME");
-#if !defined(_WIN32)
- char buf[64];
- if (hostname.empty() && gethostname(buf, sizeof(buf)) != -1) hostname = buf;
-#endif
- if (hostname.empty()) hostname = "unknown";
-
- std::string username;
- if (getenv("LOGNAME")) username = getenv("LOGNAME");
-#if !defined _WIN32 && !defined ADB_HOST_ON_TARGET
- if (username.empty() && getlogin()) username = getlogin();
-#endif
- if (username.empty()) hostname = "unknown";
-
- return " " + username + "@" + hostname;
-}
-
-static bool write_public_keyfile(RSA* private_key, const std::string& private_key_path) {
- LOG(INFO) << "write_public_keyfile...";
-
+static bool calculate_public_key(std::string* out, RSA* private_key) {
uint8_t binary_key_data[ANDROID_PUBKEY_ENCODED_SIZE];
if (!android_pubkey_encode(private_key, binary_key_data, sizeof(binary_key_data))) {
LOG(ERROR) << "Failed to convert to public key";
@@ -88,20 +66,10 @@
return false;
}
- std::string content;
- content.resize(expected_length);
- size_t actual_length = EVP_EncodeBlock(reinterpret_cast<uint8_t*>(&content[0]), binary_key_data,
+ out->resize(expected_length);
+ size_t actual_length = EVP_EncodeBlock(reinterpret_cast<uint8_t*>(out->data()), binary_key_data,
sizeof(binary_key_data));
- content.resize(actual_length);
-
- content += get_user_info();
-
- std::string path(private_key_path + ".pub");
- if (!android::base::WriteStringToFile(content, path)) {
- PLOG(ERROR) << "Failed to write public key to '" << path << "'";
- return false;
- }
-
+ out->resize(actual_length);
return true;
}
@@ -140,11 +108,6 @@
goto out;
}
- if (!write_public_keyfile(rsa, file)) {
- D("Failed to write public key");
- goto out;
- }
-
ret = 1;
out:
@@ -170,36 +133,41 @@
return result;
}
-static bool read_key_file(const std::string& file) {
- LOG(INFO) << "read_key_file '" << file << "'...";
-
+static std::shared_ptr<RSA> read_key_file(const std::string& file) {
std::unique_ptr<FILE, decltype(&fclose)> fp(fopen(file.c_str(), "r"), fclose);
if (!fp) {
PLOG(ERROR) << "Failed to open '" << file << "'";
- return false;
+ return nullptr;
}
RSA* key = RSA_new();
if (!PEM_read_RSAPrivateKey(fp.get(), &key, nullptr, nullptr)) {
LOG(ERROR) << "Failed to read key";
RSA_free(key);
+ return nullptr;
+ }
+
+ return std::shared_ptr<RSA>(key, RSA_free);
+}
+
+static bool load_key(const std::string& file) {
+ std::shared_ptr<RSA> key = read_key_file(file);
+ if (!key) {
return false;
}
std::lock_guard<std::mutex> lock(g_keys_mutex);
- std::string fingerprint = hash_key(key);
+ std::string fingerprint = hash_key(key.get());
if (g_keys.find(fingerprint) != g_keys.end()) {
LOG(INFO) << "ignoring already-loaded key: " << file;
- RSA_free(key);
} else {
- g_keys[fingerprint] = std::shared_ptr<RSA>(key, RSA_free);
+ g_keys[fingerprint] = std::move(key);
}
-
return true;
}
-static bool read_keys(const std::string& path, bool allow_dir = true) {
- LOG(INFO) << "read_keys '" << path << "'...";
+static bool load_keys(const std::string& path, bool allow_dir = true) {
+ LOG(INFO) << "load_keys '" << path << "'...";
struct stat st;
if (stat(path.c_str(), &st) != 0) {
@@ -208,7 +176,7 @@
}
if (S_ISREG(st.st_mode)) {
- return read_key_file(path);
+ return load_key(path);
} else if (S_ISDIR(st.st_mode)) {
if (!allow_dir) {
// inotify isn't recursive. It would break expectations to load keys in nested
@@ -237,7 +205,7 @@
continue;
}
- result |= read_key_file((path + OS_PATH_SEPARATOR + name));
+ result |= load_key((path + OS_PATH_SEPARATOR + name));
}
return result;
}
@@ -250,7 +218,7 @@
return adb_get_android_dir_path() + OS_PATH_SEPARATOR + "adbkey";
}
-static bool get_user_key() {
+static bool generate_userkey() {
std::string path = get_user_key_path();
if (path.empty()) {
PLOG(ERROR) << "Error getting user key filename";
@@ -266,7 +234,7 @@
}
}
- return read_key_file(path);
+ return load_key(path);
}
static std::set<std::string> get_vendor_keys() {
@@ -320,26 +288,42 @@
return result;
}
+static bool pubkey_from_privkey(std::string* out, const std::string& path) {
+ std::shared_ptr<RSA> privkey = read_key_file(path);
+ if (!privkey) {
+ return false;
+ }
+ return calculate_public_key(out, privkey.get());
+}
+
std::string adb_auth_get_userkey() {
std::string path = get_user_key_path();
if (path.empty()) {
PLOG(ERROR) << "Error getting user key filename";
return "";
}
- path += ".pub";
- std::string content;
- if (!android::base::ReadFileToString(path, &content)) {
- PLOG(ERROR) << "Can't load '" << path << "'";
+ std::string result;
+ if (!pubkey_from_privkey(&result, path)) {
return "";
}
- return content;
+ return result;
}
int adb_auth_keygen(const char* filename) {
return (generate_key(filename) == 0);
}
+int adb_auth_pubkey(const char* filename) {
+ std::string pubkey;
+ if (!pubkey_from_privkey(&pubkey, filename)) {
+ return 1;
+ }
+ pubkey.push_back('\n');
+
+ return WriteFdExactly(STDOUT_FILENO, pubkey.data(), pubkey.size()) ? 0 : 1;
+}
+
#if defined(__linux__)
static void adb_auth_inotify_update(int fd, unsigned fd_event, void*) {
LOG(INFO) << "adb_auth_inotify_update called";
@@ -380,7 +364,7 @@
LOG(INFO) << "ignoring new directory at '" << path << "'";
} else {
LOG(INFO) << "observed new file at '" << path << "'";
- read_keys(path, false);
+ load_keys(path, false);
}
} else {
LOG(WARNING) << "unmonitored event for " << path << ": 0x" << std::hex
@@ -420,8 +404,8 @@
void adb_auth_init() {
LOG(INFO) << "adb_auth_init...";
- if (!get_user_key()) {
- LOG(ERROR) << "Failed to get user key";
+ if (!generate_userkey()) {
+ LOG(ERROR) << "Failed to generate user key";
return;
}
@@ -432,7 +416,7 @@
#endif
for (const std::string& path : key_paths) {
- read_keys(path.c_str());
+ load_keys(path.c_str());
}
}
diff --git a/adb/client/commandline.cpp b/adb/client/commandline.cpp
index b5bed28..c11052d 100644
--- a/adb/client/commandline.cpp
+++ b/adb/client/commandline.cpp
@@ -185,7 +185,6 @@
" enable-verity re-enable dm-verity checking on userdebug builds\n"
" keygen FILE\n"
" generate adb public/private key; private key stored in FILE,\n"
- " public key stored in FILE.pub (existing files overwritten)\n"
"\n"
"scripting:\n"
" wait-for[-TRANSPORT]-STATE\n"
@@ -1756,14 +1755,14 @@
// Always print key generation information for keygen command.
adb_trace_enable(AUTH);
return adb_auth_keygen(argv[1]);
- }
- else if (!strcmp(argv[0], "jdwp")) {
+ } else if (!strcmp(argv[0], "pubkey")) {
+ if (argc != 2) error_exit("pubkey requires an argument");
+ return adb_auth_pubkey(argv[1]);
+ } else if (!strcmp(argv[0], "jdwp")) {
return adb_connect_command("jdwp");
- }
- else if (!strcmp(argv[0], "track-jdwp")) {
+ } else if (!strcmp(argv[0], "track-jdwp")) {
return adb_connect_command("track-jdwp");
- }
- else if (!strcmp(argv[0], "track-devices")) {
+ } else if (!strcmp(argv[0], "track-devices")) {
return adb_connect_command("host:track-devices");
} else if (!strcmp(argv[0], "raw")) {
if (argc != 2) {
@@ -1772,13 +1771,11 @@
return adb_connect_command(argv[1]);
}
-
/* "adb /?" is a common idiom under Windows */
else if (!strcmp(argv[0], "--help") || !strcmp(argv[0], "help") || !strcmp(argv[0], "/?")) {
help();
return 0;
- }
- else if (!strcmp(argv[0], "--version") || !strcmp(argv[0], "version")) {
+ } else if (!strcmp(argv[0], "--version") || !strcmp(argv[0], "version")) {
fprintf(stdout, "%s", adb_version().c_str());
return 0;
} else if (!strcmp(argv[0], "features")) {
diff --git a/adb/fastdeploy/OWNERS b/adb/fastdeploy/OWNERS
new file mode 100644
index 0000000..d145834
--- /dev/null
+++ b/adb/fastdeploy/OWNERS
@@ -0,0 +1 @@
+idries@google.com
diff --git a/cpio/Android.bp b/cpio/Android.bp
index 847e0f1..baa0319 100644
--- a/cpio/Android.bp
+++ b/cpio/Android.bp
@@ -5,4 +5,7 @@
srcs: ["mkbootfs.c"],
cflags: ["-Werror"],
shared_libs: ["libcutils"],
+ dist: {
+ targets: ["dist_files"],
+ },
}
diff --git a/cpio/Android.mk b/cpio/Android.mk
deleted file mode 100644
index fc3551b..0000000
--- a/cpio/Android.mk
+++ /dev/null
@@ -1,3 +0,0 @@
-# Copyright 2005 The Android Open Source Project
-
-$(call dist-for-goals,dist_files,$(ALL_MODULES.mkbootfs.BUILT))
diff --git a/debuggerd/crash_dump.cpp b/debuggerd/crash_dump.cpp
index 577e336..d79d20b 100644
--- a/debuggerd/crash_dump.cpp
+++ b/debuggerd/crash_dump.cpp
@@ -348,8 +348,16 @@
return vm_pid;
}
+static void InstallSigPipeHandler() {
+ struct sigaction action = {};
+ action.sa_handler = SIG_IGN;
+ action.sa_flags = SA_RESTART;
+ sigaction(SIGPIPE, &action, nullptr);
+}
+
int main(int argc, char** argv) {
DefuseSignalHandlers();
+ InstallSigPipeHandler();
atrace_begin(ATRACE_TAG, "before reparent");
pid_t target_process = getppid();
diff --git a/debuggerd/libdebuggerd/tombstone.cpp b/debuggerd/libdebuggerd/tombstone.cpp
index 0b8a936..1179263 100644
--- a/debuggerd/libdebuggerd/tombstone.cpp
+++ b/debuggerd/libdebuggerd/tombstone.cpp
@@ -78,7 +78,7 @@
_LOG(log, logtype::HEADER, "ABI: '%s'\n", ABI_STRING);
}
-static void dump_probable_cause(log_t* log, const siginfo_t* si) {
+static void dump_probable_cause(log_t* log, const siginfo_t* si, BacktraceMap* map) {
std::string cause;
if (si->si_signo == SIGSEGV && si->si_code == SEGV_MAPERR) {
if (si->si_addr < reinterpret_cast<void*>(4096)) {
@@ -94,6 +94,14 @@
} else if (si->si_addr == reinterpret_cast<void*>(0xffff0f60)) {
cause = "call to kuser_cmpxchg64";
}
+ } else if (si->si_signo == SIGSEGV && si->si_code == SEGV_ACCERR) {
+ for (auto it = map->begin(); it != map->end(); ++it) {
+ const backtrace_map_t* entry = *it;
+ if (si->si_addr >= reinterpret_cast<void*>(entry->start) &&
+ si->si_addr < reinterpret_cast<void*>(entry->end) && entry->flags == PROT_EXEC) {
+ cause = "execute-only (no-read) memory access error; likely due to data in .text.";
+ }
+ }
} else if (si->si_signo == SIGSYS && si->si_code == SYS_SECCOMP) {
cause = StringPrintf("seccomp prevented call to disallowed %s system call %d", ABI_STRING,
si->si_syscall);
@@ -125,8 +133,6 @@
_LOG(log, logtype::HEADER, "signal %d (%s), code %d (%s%s), fault addr %s\n",
thread_info.siginfo->si_signo, get_signame(thread_info.siginfo),
thread_info.siginfo->si_code, get_sigcode(thread_info.siginfo), sender_desc, addr_desc);
-
- dump_probable_cause(log, thread_info.siginfo);
}
static void dump_thread_info(log_t* log, const ThreadInfo& thread_info) {
@@ -426,6 +432,7 @@
if (thread_info.siginfo) {
dump_signal_info(log, thread_info, process_memory);
+ dump_probable_cause(log, thread_info.siginfo, map);
}
if (primary_thread) {
diff --git a/fastboot/Android.bp b/fastboot/Android.bp
index faed376..8006c41 100644
--- a/fastboot/Android.bp
+++ b/fastboot/Android.bp
@@ -260,6 +260,13 @@
"mke2fs",
"make_f2fs",
],
+ dist: {
+ targets: [
+ "dist_files",
+ "sdk",
+ "win_sdk",
+ ],
+ },
target: {
not_windows: {
diff --git a/fastboot/Android.mk b/fastboot/Android.mk
index e4c1317..17ec392 100644
--- a/fastboot/Android.mk
+++ b/fastboot/Android.mk
@@ -18,13 +18,9 @@
# Package fastboot-related executables.
#
-my_dist_files := $(HOST_OUT_EXECUTABLES)/fastboot
-my_dist_files += $(HOST_OUT_EXECUTABLES)/mke2fs
+my_dist_files := $(HOST_OUT_EXECUTABLES)/mke2fs
my_dist_files += $(HOST_OUT_EXECUTABLES)/e2fsdroid
my_dist_files += $(HOST_OUT_EXECUTABLES)/make_f2fs
my_dist_files += $(HOST_OUT_EXECUTABLES)/sload_f2fs
$(call dist-for-goals,dist_files sdk win_sdk,$(my_dist_files))
-ifdef HOST_CROSS_OS
-$(call dist-for-goals,dist_files sdk win_sdk,$(ALL_MODULES.host_cross_fastboot.BUILT))
-endif
my_dist_files :=
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index e066bff..fee0857 100644
--- a/fastboot/fastboot.cpp
+++ b/fastboot/fastboot.cpp
@@ -46,6 +46,7 @@
#include <chrono>
#include <functional>
#include <regex>
+#include <string>
#include <thread>
#include <utility>
#include <vector>
@@ -78,6 +79,7 @@
using android::base::Split;
using android::base::Trim;
using android::base::unique_fd;
+using namespace std::string_literals;
static const char* serial = nullptr;
@@ -162,9 +164,17 @@
// clang-format on
};
-static std::string find_item_given_name(const std::string& img_name) {
+static char* get_android_product_out() {
char* dir = getenv("ANDROID_PRODUCT_OUT");
if (dir == nullptr || dir[0] == '\0') {
+ return nullptr;
+ }
+ return dir;
+}
+
+static std::string find_item_given_name(const std::string& img_name) {
+ char* dir = get_android_product_out();
+ if (!dir) {
die("ANDROID_PRODUCT_OUT not set");
}
return std::string(dir) + "/" + img_name;
@@ -1098,6 +1108,14 @@
return fb->GetVar("is-logical:" + partition, &value) == fastboot::SUCCESS && value == "yes";
}
+static bool is_retrofit_device() {
+ std::string value;
+ if (fb->GetVar("super-partition-name", &value) != fastboot::SUCCESS) {
+ return false;
+ }
+ return android::base::StartsWith(value, "system_");
+}
+
static void do_flash(const char* pname, const char* fname) {
struct fastboot_buffer buf;
@@ -1311,6 +1329,19 @@
command += ":wipe";
}
fb->RawCommand(command, "Updating super partition");
+
+ // Retrofit devices have two super partitions, named super_a and super_b.
+ // On these devices, secondary slots must be flashed as physical
+ // partitions (otherwise they would not mount on first boot). To enforce
+ // this, we delete any logical partitions for the "other" slot.
+ if (is_retrofit_device()) {
+ for (const auto& [image, slot] : os_images_) {
+ std::string partition_name = image->part_name + "_"s + slot;
+ if (image->IsSecondary() && is_logical(partition_name)) {
+ fb->DeletePartition(partition_name);
+ }
+ }
+ }
}
class ZipImageSource final : public ImageSource {
@@ -1466,15 +1497,13 @@
fprintf(stderr, "File system type %s not supported.\n", partition_type.c_str());
return;
}
- fprintf(stderr, "Formatting is not supported for file system with type '%s'.\n",
- partition_type.c_str());
- return;
+ die("Formatting is not supported for file system with type '%s'.",
+ partition_type.c_str());
}
int64_t size;
if (!android::base::ParseInt(partition_size, &size)) {
- fprintf(stderr, "Couldn't parse partition size '%s'.\n", partition_size.c_str());
- return;
+ die("Couldn't parse partition size '%s'.", partition_size.c_str());
}
unsigned eraseBlkSize, logicalBlkSize;
@@ -1484,17 +1513,14 @@
if (fs_generator_generate(gen, output.path, size, initial_dir,
eraseBlkSize, logicalBlkSize)) {
die("Cannot generate image for %s", partition.c_str());
- return;
}
fd.reset(open(output.path, O_RDONLY));
if (fd == -1) {
- fprintf(stderr, "Cannot open generated image: %s\n", strerror(errno));
- return;
+ die("Cannot open generated image: %s", strerror(errno));
}
if (!load_buf_fd(fd.release(), &buf)) {
- fprintf(stderr, "Cannot read image: %s\n", strerror(errno));
- return;
+ die("Cannot read image: %s", strerror(errno));
}
flash_buf(partition, &buf);
return;
@@ -1505,9 +1531,15 @@
if (errMsg) fprintf(stderr, "%s", errMsg);
}
fprintf(stderr, "FAILED (%s)\n", fb->Error().c_str());
+ if (!skip_if_not_supported) {
+ die("Command failed");
+ }
}
static bool should_flash_in_userspace(const std::string& partition_name) {
+ if (!get_android_product_out()) {
+ return false;
+ }
auto path = find_item_given_name("super_empty.img");
if (path.empty()) {
return false;
diff --git a/fastboot/fs.cpp b/fastboot/fs.cpp
index fc6a16b..8c0aa6b 100644
--- a/fastboot/fs.cpp
+++ b/fastboot/fs.cpp
@@ -172,13 +172,8 @@
mkf2fs_args.push_back("-S");
std::string size_str = std::to_string(partSize);
mkf2fs_args.push_back(size_str.c_str());
- mkf2fs_args.push_back("-f");
- mkf2fs_args.push_back("-O");
- mkf2fs_args.push_back("encrypt");
- mkf2fs_args.push_back("-O");
- mkf2fs_args.push_back("quota");
- mkf2fs_args.push_back("-O");
- mkf2fs_args.push_back("verity");
+ mkf2fs_args.push_back("-g");
+ mkf2fs_args.push_back("android");
mkf2fs_args.push_back(fileName);
mkf2fs_args.push_back(nullptr);
diff --git a/fs_mgr/Android.bp b/fs_mgr/Android.bp
index 6c8a943..f150af3 100644
--- a/fs_mgr/Android.bp
+++ b/fs_mgr/Android.bp
@@ -42,8 +42,6 @@
"fs_mgr.cpp",
"fs_mgr_format.cpp",
"fs_mgr_verity.cpp",
- "fs_mgr_avb.cpp",
- "fs_mgr_avb_ops.cpp",
"fs_mgr_dm_linear.cpp",
"fs_mgr_overlayfs.cpp",
"fs_mgr_vendor_overlay.cpp",
@@ -61,10 +59,12 @@
],
static_libs: [
"libavb",
+ "libfs_avb",
"libfstab",
"libdm",
],
export_static_lib_headers: [
+ "libfs_avb",
"libfstab",
"libdm",
],
@@ -104,3 +104,28 @@
export_include_dirs: ["include_fstab"],
header_libs: ["libbase_headers"],
}
+
+cc_library_static {
+ name: "libfs_avb",
+ defaults: ["fs_mgr_defaults"],
+ recovery_available: true,
+ export_include_dirs: ["libfs_avb/include"],
+ srcs: [
+ "libfs_avb/avb_ops.cpp",
+ "libfs_avb/fs_avb.cpp",
+ ],
+ static_libs: [
+ "libavb",
+ "libfstab",
+ "libdm",
+ ],
+ export_static_lib_headers: [
+ "libfstab",
+ ],
+ shared_libs: [
+ "libcrypto",
+ ],
+ header_libs: [
+ "libbase_headers",
+ ],
+}
diff --git a/fs_mgr/README.overlayfs.md b/fs_mgr/README.overlayfs.md
new file mode 100644
index 0000000..d715d7b
--- /dev/null
+++ b/fs_mgr/README.overlayfs.md
@@ -0,0 +1,92 @@
+Android Overlayfs integration with adb remount
+==============================================
+
+Introduction
+------------
+
+Users working with userdebug or eng builds expect to be able to
+remount the system partition as read-write and then add or modify
+any number of files without reflashing the system image, which is
+understandably efficient for a development cycle.
+Limited memory systems that chose to use readonly filesystems like
+*squashfs*, or *Logical Resizable Android Partitions* which land
+system partition images right-sized, and with filesystem that have
+been deduped on the block level to compress the content; means that
+either a remount is not possible directly, or when done offers
+little or no utility because of remaining space limitations or
+support logistics.
+
+*Overlayfs* comes to the rescue for these debug scenarios, and logic
+will _automatically_ setup backing storage for a writable filesystem
+as an upper reference, and mount overtop the lower. These actions
+will be performed in the **adb disable-verity** and **adb remount**
+requests.
+
+Operations
+----------
+
+### Cookbook
+
+The typical action to utilize the remount facility is:
+
+ $ adb root
+ $ adb disable-verity
+ $ adb reboot
+ $ adb wait-for-device
+ $ adb root
+ $ adb remount
+
+Followed by one of the following:
+
+ $ adb stop
+ $ adb sync
+ $ adb start
+ $ adb reboot
+
+*or*
+
+ $ adb push <source> <destination>
+ $ adb reboot
+
+Note that the sequence above:
+
+ $ adb disable-verity
+ $ adb reboot
+
+can be replaced with:
+
+ $ adb reboot -R
+
+which will not reboot if everything is already prepared and ready
+to go.
+
+None of this changes if *overlayfs* needs to be engaged.
+The decisions whether to use traditional direct filesystem remount,
+or one wrapped by *overlayfs* is automatically determined based on
+a probe of the filesystem types and space remaining.
+
+### Backing Storage
+
+When *overlayfs* logic is feasible, it will use either the
+**/cache/overlay/** directory for non-A/B devices, or the
+**/mnt/scratch/overlay** directory for A/B devices that have
+access to *Logical Resizeable Android Partitions*.
+The backing store is used as soon as possible in the boot
+process and can occur at first stage init, or at the
+mount_all init rc commands.
+
+This early as possible attachment of *overlayfs* means that
+*sepolicy* or *init* itself can also be pushed and used after
+the exec phases that accompany each stage.
+
+Caveats
+-------
+
+- Space used in the backing storage is on a file by file basis
+ and will require more space than if updated in place.
+- Kernel must have CONFIG_OVERLAY_FS=y and will need to be patched
+ with "*overlayfs: override_creds=off option bypass creator_cred*"
+ if higher than 4.6.
+- *adb enable-verity* will free up overlayfs and as a bonus the
+ device will be reverted pristine to before any content was updated.
+- File bugs or submit fixes for review.
diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp
index 8e57e1e..1ba956d 100644
--- a/fs_mgr/fs_mgr.cpp
+++ b/fs_mgr/fs_mgr.cpp
@@ -34,6 +34,7 @@
#include <unistd.h>
#include <functional>
+#include <map>
#include <memory>
#include <string>
#include <thread>
@@ -53,6 +54,7 @@
#include <ext4_utils/ext4_sb.h>
#include <ext4_utils/ext4_utils.h>
#include <ext4_utils/wipe.h>
+#include <fs_avb/fs_avb.h>
#include <fs_mgr_overlayfs.h>
#include <libdm/dm.h>
#include <liblp/metadata_format.h>
@@ -62,7 +64,6 @@
#include <log/log_properties.h>
#include <logwrap/logwrap.h>
-#include "fs_mgr_avb.h"
#include "fs_mgr_priv.h"
#define KEY_LOC_PROP "ro.crypto.keyfile.userdata"
@@ -82,6 +83,9 @@
using android::dm::DeviceMapper;
using android::dm::DmDeviceState;
+using android::fs_mgr::AvbHandle;
+using android::fs_mgr::AvbHashtreeResult;
+using android::fs_mgr::AvbUniquePtr;
// record fs stat
enum FsStatFlags {
@@ -973,7 +977,7 @@
int mount_errno = 0;
int attempted_idx = -1;
CheckpointManager checkpoint_manager;
- FsManagerAvbUniquePtr avb_handle(nullptr);
+ AvbUniquePtr avb_handle(nullptr);
if (!fstab) {
return FS_MGR_MNTALL_FAIL;
@@ -1031,14 +1035,14 @@
if (fstab->recs[i].fs_mgr_flags & MF_AVB) {
if (!avb_handle) {
- avb_handle = FsManagerAvbHandle::Open();
+ avb_handle = AvbHandle::Open();
if (!avb_handle) {
- LERROR << "Failed to open FsManagerAvbHandle";
+ LERROR << "Failed to open AvbHandle";
return FS_MGR_MNTALL_FAIL;
}
}
if (avb_handle->SetUpAvbHashtree(&fstab->recs[i], true /* wait_for_verity_dev */) ==
- SetUpAvbHashtreeResult::kFail) {
+ AvbHashtreeResult::kFail) {
LERROR << "Failed to set up AVB on partition: "
<< fstab->recs[i].mount_point << ", skipping!";
/* Skips mounting the device. */
@@ -1232,7 +1236,7 @@
int first_mount_errno = 0;
char* mount_point;
CheckpointManager checkpoint_manager(needs_checkpoint);
- FsManagerAvbUniquePtr avb_handle(nullptr);
+ AvbUniquePtr avb_handle(nullptr);
if (!fstab) {
return FS_MGR_DOMNT_FAILED;
@@ -1275,14 +1279,14 @@
if (fstab->recs[i].fs_mgr_flags & MF_AVB) {
if (!avb_handle) {
- avb_handle = FsManagerAvbHandle::Open();
+ avb_handle = AvbHandle::Open();
if (!avb_handle) {
- LERROR << "Failed to open FsManagerAvbHandle";
+ LERROR << "Failed to open AvbHandle";
return FS_MGR_DOMNT_FAILED;
}
}
if (avb_handle->SetUpAvbHashtree(&fstab->recs[i], true /* wait_for_verity_dev */) ==
- SetUpAvbHashtreeResult::kFail) {
+ AvbHashtreeResult::kFail) {
LERROR << "Failed to set up AVB on partition: "
<< fstab->recs[i].mount_point << ", skipping!";
/* Skips mounting the device. */
@@ -1603,9 +1607,6 @@
} else if (slot == -1) {
suffix = fs_mgr_get_slot_suffix();
}
- if (suffix.empty()) {
- LFATAL << "Super partition name can only be overridden on A/B devices.";
- }
return super_partition + suffix;
}
return LP_METADATA_DEFAULT_PARTITION_NAME;
diff --git a/fs_mgr/fs_mgr_format.cpp b/fs_mgr/fs_mgr_format.cpp
index 845cca9..0983663 100644
--- a/fs_mgr/fs_mgr_format.cpp
+++ b/fs_mgr/fs_mgr_format.cpp
@@ -117,12 +117,7 @@
// clang-format off
const char* const args[] = {
"/system/bin/make_f2fs",
- "-d1",
- "-f",
- "-O", "encrypt",
- "-O", "quota",
- "-O", "verity",
- "-w", "4096",
+ "-g", "android",
fs_blkdev,
size_str.c_str(),
nullptr
diff --git a/fs_mgr/fs_mgr_overlayfs.cpp b/fs_mgr/fs_mgr_overlayfs.cpp
index a1de005..bef46e1 100644
--- a/fs_mgr/fs_mgr_overlayfs.cpp
+++ b/fs_mgr/fs_mgr_overlayfs.cpp
@@ -432,7 +432,7 @@
if (change) *change = true;
if (!DestroyLogicalPartition(partition_name, 0s)) return false;
} else {
- PERROR << "delete partition " << overlay;
+ LERROR << "delete partition " << overlay;
return false;
}
errno = save_errno;
@@ -647,49 +647,65 @@
if (fs_mgr_overlayfs_already_mounted(kScratchMountPoint, false)) return true;
auto mnt_type = fs_mgr_overlayfs_scratch_mount_type();
auto scratch_device = fs_mgr_overlayfs_scratch_device();
- auto partition_exists = fs_mgr_rw_access(scratch_device);
+ auto partition_create = !fs_mgr_rw_access(scratch_device);
+ auto slot_number = fs_mgr_overlayfs_slot_number();
+ auto super_device = fs_mgr_overlayfs_super_device(slot_number);
+ if (!fs_mgr_rw_access(super_device)) return false;
+ if (!fs_mgr_overlayfs_has_logical(fstab)) return false;
+ auto builder = MetadataBuilder::New(super_device, slot_number);
+ if (!builder) {
+ LERROR << "open " << super_device << " metadata";
+ return false;
+ }
+ const auto partition_name = android::base::Basename(kScratchMountPoint);
+ auto partition = builder->FindPartition(partition_name);
+ auto partition_exists = partition != nullptr;
+ auto changed = false;
if (!partition_exists) {
- auto slot_number = fs_mgr_overlayfs_slot_number();
- auto super_device = fs_mgr_overlayfs_super_device(slot_number);
- if (!fs_mgr_rw_access(super_device)) return false;
- if (!fs_mgr_overlayfs_has_logical(fstab)) return false;
- auto builder = MetadataBuilder::New(super_device, slot_number);
- if (!builder) {
- PERROR << "open " << super_device << " metadata";
+ partition = builder->AddPartition(partition_name, LP_PARTITION_ATTR_NONE);
+ if (!partition) {
+ LERROR << "create " << partition_name;
return false;
}
- const auto partition_name = android::base::Basename(kScratchMountPoint);
- partition_exists = builder->FindPartition(partition_name) != nullptr;
- if (!partition_exists) {
- auto partition = builder->AddPartition(partition_name, LP_PARTITION_ATTR_NONE);
- if (!partition) {
- PERROR << "create " << partition_name;
- return false;
+ changed = true;
+ }
+ // Take half of free space, minimum 512MB or free space - 256KB margin.
+ static constexpr auto kMinimumSize = uint64_t(512 * 1024 * 1024);
+ static constexpr auto kMarginSize = uint64_t(256 * 1024);
+ if (partition->size() < kMinimumSize) {
+ auto partition_size =
+ builder->AllocatableSpace() - builder->UsedSpace() + partition->size();
+ if ((partition_size > kMinimumSize) || !partition->size()) {
+ partition_size = std::max(std::min(kMinimumSize, partition_size - kMarginSize),
+ partition_size / 2);
+ if (partition_size > partition->size()) {
+ if (!builder->ResizePartition(partition, partition_size)) {
+ LERROR << "resize " << partition_name;
+ return false;
+ }
+ if (!partition_create) DestroyLogicalPartition(partition_name, 10s);
+ changed = true;
+ partition_exists = false;
}
- auto partition_size = builder->AllocatableSpace() - builder->UsedSpace();
- // 512MB or half the remaining available space, whichever is greater.
- partition_size = std::max(uint64_t(512 * 1024 * 1024), partition_size / 2);
- if (!builder->ResizePartition(partition, partition_size)) {
- PERROR << "resize " << partition_name;
- return false;
- }
-
- auto metadata = builder->Export();
- if (!metadata) {
- LERROR << "generate new metadata " << partition_name;
- return false;
- }
- if (!UpdatePartitionTable(super_device, *metadata.get(), slot_number)) {
- LERROR << "update " << partition_name;
- return false;
- }
-
- if (change) *change = true;
+ }
+ }
+ // land the update back on to the partition
+ if (changed) {
+ auto metadata = builder->Export();
+ if (!metadata || !UpdatePartitionTable(super_device, *metadata.get(), slot_number)) {
+ LERROR << "add partition " << partition_name;
+ return false;
}
+ if (change) *change = true;
+ }
+
+ if (changed || partition_create) {
if (!CreateLogicalPartition(super_device, slot_number, partition_name, true, 0s,
&scratch_device))
return false;
+
+ if (change) *change = true;
}
if (partition_exists) {
@@ -709,6 +725,7 @@
} else if (mnt_type == "ext4") {
command = kMkExt4 + " -b 4096 -t ext4 -m 0 -O has_journal -M " + kScratchMountPoint;
} else {
+ errno = ESRCH;
LERROR << mnt_type << " has no mkfs cookbook";
return false;
}
@@ -773,6 +790,8 @@
}
std::vector<std::string> fs_mgr_overlayfs_required_devices(fstab* fstab) {
+ if (fs_mgr_overlayfs_valid() == OverlayfsValidResult::kNotSupported) return {};
+
if (fs_mgr_get_entry_for_mount_point(const_cast<struct fstab*>(fstab), kScratchMountPoint)) {
return {};
}
diff --git a/fs_mgr/fs_mgr_priv.h b/fs_mgr/fs_mgr_priv.h
index 23a92d3..87c971a 100644
--- a/fs_mgr/fs_mgr_priv.h
+++ b/fs_mgr/fs_mgr_priv.h
@@ -21,8 +21,8 @@
#include <string>
#include <android-base/logging.h>
+#include <fs_mgr.h>
-#include "fs_mgr.h"
#include "fs_mgr_priv_boot_config.h"
/* The CHECK() in logging.h will use program invocation name as the tag.
diff --git a/fs_mgr/fs_mgr_vendor_overlay.cpp b/fs_mgr/fs_mgr_vendor_overlay.cpp
index e1815ff..830f0dd 100644
--- a/fs_mgr/fs_mgr_vendor_overlay.cpp
+++ b/fs_mgr/fs_mgr_vendor_overlay.cpp
@@ -35,43 +35,42 @@
namespace {
-const auto kVendorOverlaySourceDir = "/system/vendor_overlay/"s;
+// The order of the list means the priority to show the files in the directory.
+// The last one has the highest priority.
+const std::vector<const std::string> kVendorOverlaySourceDirs = {
+ "/system/vendor_overlay/",
+ "/product/vendor_overlay/",
+};
const auto kVndkVersionPropertyName = "ro.vndk.version"s;
const auto kVendorTopDir = "/vendor/"s;
const auto kLowerdirOption = "lowerdir="s;
-std::string fs_mgr_get_vendor_overlay_top_dir() {
- // VNDK version is provided by the /vendor/default.prop
- // To read the property, it must be called at the second init stage after the default
- // properties are loaded.
- std::string vndk_version = android::base::GetProperty(kVndkVersionPropertyName, "");
- if (vndk_version.empty()) {
- return "";
- }
- return kVendorOverlaySourceDir + vndk_version;
-}
+std::vector<std::pair<std::string, std::string>> fs_mgr_get_vendor_overlay_dirs(
+ const std::string& vndk_version) {
+ std::vector<std::pair<std::string, std::string>> vendor_overlay_dirs;
+ for (const auto& vendor_overlay_source : kVendorOverlaySourceDirs) {
+ const auto overlay_top = vendor_overlay_source + vndk_version;
+ std::unique_ptr<DIR, decltype(&closedir)> vendor_overlay_top(opendir(overlay_top.c_str()),
+ closedir);
+ if (!vendor_overlay_top) continue;
-std::vector<std::string> fs_mgr_get_vendor_overlay_dirs(const std::string& overlay_top) {
- std::vector<std::string> vendor_overlay_dirs;
- std::unique_ptr<DIR, decltype(&closedir)> vendor_overlay_top(opendir(overlay_top.c_str()),
- closedir);
- if (!vendor_overlay_top) return vendor_overlay_dirs;
+ // Vendor overlay root for current vendor version found!
+ LINFO << "vendor overlay root: " << overlay_top;
- // Vendor overlay root for current vendor version found!
- LINFO << "vendor overlay root: " << overlay_top;
- struct dirent* dp;
- while ((dp = readdir(vendor_overlay_top.get())) != nullptr) {
- if (dp->d_type != DT_DIR || dp->d_name[0] == '.') {
- continue;
+ struct dirent* dp;
+ while ((dp = readdir(vendor_overlay_top.get())) != nullptr) {
+ if (dp->d_type != DT_DIR || dp->d_name[0] == '.') {
+ continue;
+ }
+ vendor_overlay_dirs.emplace_back(overlay_top, dp->d_name);
}
- vendor_overlay_dirs.push_back(dp->d_name);
}
-
return vendor_overlay_dirs;
}
-bool fs_mgr_vendor_overlay_mount(const std::string& overlay_top, const std::string& mount_point) {
- const auto vendor_mount_point = kVendorTopDir + mount_point;
+bool fs_mgr_vendor_overlay_mount(const std::pair<std::string, std::string>& mount_point) {
+ const auto [overlay_top, mount_dir] = mount_point;
+ const auto vendor_mount_point = kVendorTopDir + mount_dir;
LINFO << "vendor overlay mount on " << vendor_mount_point;
const auto target_context = fs_mgr_get_context(vendor_mount_point);
@@ -79,7 +78,7 @@
PERROR << " failed: cannot find the target vendor mount point";
return false;
}
- const auto source_directory = overlay_top + "/" + mount_point;
+ const auto source_directory = overlay_top + "/" + mount_dir;
const auto source_context = fs_mgr_get_context(source_directory);
if (target_context != source_context) {
LERROR << " failed: source and target contexts do not match (source:" << source_context
@@ -112,22 +111,25 @@
// To read the properties, vendor overlay must be mounted at the second stage, right
// after "property_load_boot_defaults()" is called.
bool fs_mgr_vendor_overlay_mount_all() {
- const auto overlay_top = fs_mgr_get_vendor_overlay_top_dir();
- if (overlay_top.empty()) {
+ // To read the property, it must be called at the second init stage after the default
+ // properties are loaded.
+ static const auto vndk_version = android::base::GetProperty(kVndkVersionPropertyName, "");
+ if (vndk_version.empty()) {
LINFO << "vendor overlay: vndk version not defined";
return false;
}
- const auto vendor_overlay_dirs = fs_mgr_get_vendor_overlay_dirs(overlay_top);
+
+ const auto vendor_overlay_dirs = fs_mgr_get_vendor_overlay_dirs(vndk_version);
if (vendor_overlay_dirs.empty()) return true;
if (fs_mgr_overlayfs_valid() == OverlayfsValidResult::kNotSupported) {
LINFO << "vendor overlay: kernel does not support overlayfs";
return false;
}
- // Mount each directory in /system/vendor_overlay/<ver> on /vendor
+ // Mount each directory in /(system|product)/vendor_overlay/<ver> on /vendor
auto ret = true;
for (const auto& vendor_overlay_dir : vendor_overlay_dirs) {
- if (!fs_mgr_vendor_overlay_mount(overlay_top, vendor_overlay_dir)) {
+ if (!fs_mgr_vendor_overlay_mount(vendor_overlay_dir)) {
ret = false;
}
}
diff --git a/fs_mgr/fs_mgr_avb_ops.cpp b/fs_mgr/libfs_avb/avb_ops.cpp
similarity index 93%
rename from fs_mgr/fs_mgr_avb_ops.cpp
rename to fs_mgr/libfs_avb/avb_ops.cpp
index 18efa22..f56a517 100644
--- a/fs_mgr/fs_mgr_avb_ops.cpp
+++ b/fs_mgr/libfs_avb/avb_ops.cpp
@@ -22,7 +22,7 @@
* SOFTWARE.
*/
-#include "fs_mgr_priv_avb_ops.h"
+#include "avb_ops.h"
#include <errno.h>
#include <fcntl.h>
@@ -37,15 +37,17 @@
#include <libavb/libavb.h>
#include <utils/Compat.h>
-#include "fs_mgr.h"
#include "fs_mgr_priv.h"
using namespace std::literals;
+namespace android {
+namespace fs_mgr {
+
static AvbIOResult read_from_partition(AvbOps* ops, const char* partition, int64_t offset,
size_t num_bytes, void* buffer, size_t* out_num_read) {
return FsManagerAvbOps::GetInstanceFromAvbOps(ops)->ReadFromPartition(
- partition, offset, num_bytes, buffer, out_num_read);
+ partition, offset, num_bytes, buffer, out_num_read);
}
static AvbIOResult dummy_read_rollback_index(AvbOps* ops ATTRIBUTE_UNUSED,
@@ -58,9 +60,10 @@
}
static AvbIOResult dummy_validate_vbmeta_public_key(
- AvbOps* ops ATTRIBUTE_UNUSED, const uint8_t* public_key_data ATTRIBUTE_UNUSED,
- size_t public_key_length ATTRIBUTE_UNUSED, const uint8_t* public_key_metadata ATTRIBUTE_UNUSED,
- size_t public_key_metadata_length ATTRIBUTE_UNUSED, bool* out_is_trusted) {
+ AvbOps* ops ATTRIBUTE_UNUSED, const uint8_t* public_key_data ATTRIBUTE_UNUSED,
+ size_t public_key_length ATTRIBUTE_UNUSED,
+ const uint8_t* public_key_metadata ATTRIBUTE_UNUSED,
+ size_t public_key_metadata_length ATTRIBUTE_UNUSED, bool* out_is_trusted) {
// vbmeta public key has been checked in bootloader phase.
// In user-space, returns true to pass the check.
//
@@ -178,3 +181,6 @@
return avb_slot_verify(&avb_ops_, requested_partitions, ab_suffix.c_str(), flags,
AVB_HASHTREE_ERROR_MODE_RESTART_AND_INVALIDATE, out_data);
}
+
+} // namespace fs_mgr
+} // namespace android
diff --git a/fs_mgr/fs_mgr_priv_avb_ops.h b/fs_mgr/libfs_avb/avb_ops.h
similarity index 89%
rename from fs_mgr/fs_mgr_priv_avb_ops.h
rename to fs_mgr/libfs_avb/avb_ops.h
index 44eb1da..e6b33c2 100644
--- a/fs_mgr/fs_mgr_priv_avb_ops.h
+++ b/fs_mgr/libfs_avb/avb_ops.h
@@ -22,15 +22,14 @@
* SOFTWARE.
*/
-#ifndef __CORE_FS_MGR_PRIV_AVB_OPS_H
-#define __CORE_FS_MGR_PRIV_AVB_OPS_H
+#pragma once
-#include <map>
#include <string>
#include <libavb/libavb.h>
-#include "fs_mgr.h"
+namespace android {
+namespace fs_mgr {
// This class provides C++ bindings to interact with libavb, a small
// self-contained piece of code that's intended to be used in bootloaders.
@@ -42,7 +41,7 @@
// read and verify the metadata and store it into the out_data parameter.
// The caller MUST check the integrity of metadata against the
// androidboot.vbmeta.{hash_alg, size, digest} values from /proc/cmdline.
-// e.g., see class FsManagerAvbVerifier for more details.
+// e.g., see class AvbVerifier for more details.
//
class FsManagerAvbOps {
public:
@@ -60,6 +59,7 @@
private:
AvbOps avb_ops_;
- std::map<std::string, std::string> by_name_symlink_map_;
};
-#endif /* __CORE_FS_MGR_PRIV_AVB_OPS_H */
+
+} // namespace fs_mgr
+} // namespace android
diff --git a/fs_mgr/fs_mgr_avb.cpp b/fs_mgr/libfs_avb/fs_avb.cpp
similarity index 86%
rename from fs_mgr/fs_mgr_avb.cpp
rename to fs_mgr/libfs_avb/fs_avb.cpp
index 6f94d45..c4accad 100644
--- a/fs_mgr/fs_mgr_avb.cpp
+++ b/fs_mgr/libfs_avb/fs_avb.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#include "fs_mgr_avb.h"
+#include "fs_avb/fs_avb.h"
#include <fcntl.h>
#include <libgen.h>
@@ -35,10 +35,12 @@
#include <libavb/libavb.h>
#include <libdm/dm.h>
-#include "fs_mgr.h"
+#include "avb_ops.h"
#include "fs_mgr_priv.h"
-#include "fs_mgr_priv_avb_ops.h"
-#include "fs_mgr_priv_sha.h"
+#include "sha.h"
+
+namespace android {
+namespace fs_mgr {
static inline bool nibble_value(const char& c, uint8_t* value) {
FS_MGR_CHECK(value != nullptr);
@@ -117,14 +119,14 @@
// - androidboot.vbmeta.hash_alg
// - androidboot.vbmeta.size
// - androidboot.vbmeta.digest
-class FsManagerAvbVerifier {
+class AvbVerifier {
public:
- // The factory method to return a unique_ptr<FsManagerAvbVerifier>
- static std::unique_ptr<FsManagerAvbVerifier> Create();
+ // The factory method to return a unique_ptr<AvbVerifier>
+ static std::unique_ptr<AvbVerifier> Create();
bool VerifyVbmetaImages(const AvbSlotVerifyData& verify_data);
protected:
- FsManagerAvbVerifier() = default;
+ AvbVerifier() = default;
private:
enum HashAlgorithm {
@@ -138,10 +140,10 @@
size_t vbmeta_size_;
};
-std::unique_ptr<FsManagerAvbVerifier> FsManagerAvbVerifier::Create() {
- std::unique_ptr<FsManagerAvbVerifier> avb_verifier(new FsManagerAvbVerifier());
+std::unique_ptr<AvbVerifier> AvbVerifier::Create() {
+ std::unique_ptr<AvbVerifier> avb_verifier(new AvbVerifier());
if (!avb_verifier) {
- LERROR << "Failed to create unique_ptr<FsManagerAvbVerifier>";
+ LERROR << "Failed to create unique_ptr<AvbVerifier>";
return nullptr;
}
@@ -184,7 +186,7 @@
return avb_verifier;
}
-bool FsManagerAvbVerifier::VerifyVbmetaImages(const AvbSlotVerifyData& verify_data) {
+bool AvbVerifier::VerifyVbmetaImages(const AvbSlotVerifyData& verify_data) {
if (verify_data.num_vbmeta_images == 0) {
LERROR << "No vbmeta images";
return false;
@@ -195,10 +197,10 @@
if (hash_alg_ == kSHA256) {
std::tie(total_size, digest_matched) =
- verify_vbmeta_digest<SHA256Hasher>(verify_data, digest_);
+ verify_vbmeta_digest<SHA256Hasher>(verify_data, digest_);
} else if (hash_alg_ == kSHA512) {
std::tie(total_size, digest_matched) =
- verify_vbmeta_digest<SHA512Hasher>(verify_data, digest_);
+ verify_vbmeta_digest<SHA512Hasher>(verify_data, digest_);
}
if (total_size != vbmeta_size_) {
@@ -268,7 +270,8 @@
const std::string& salt, const std::string& root_digest,
bool wait_for_verity_dev) {
android::dm::DmTable table;
- if (!construct_verity_table(hashtree_desc, salt, root_digest, fstab_entry->blk_device, &table) ||
+ if (!construct_verity_table(hashtree_desc, salt, root_digest, fstab_entry->blk_device,
+ &table) ||
!table.valid()) {
LERROR << "Failed to construct verity table.";
return false;
@@ -314,9 +317,9 @@
// Get descriptors from vbmeta_images[i].
size_t num_descriptors;
std::unique_ptr<const AvbDescriptor* [], decltype(&avb_free)> descriptors(
- avb_descriptor_get_all(verify_data.vbmeta_images[i].vbmeta_data,
- verify_data.vbmeta_images[i].vbmeta_size, &num_descriptors),
- avb_free);
+ avb_descriptor_get_all(verify_data.vbmeta_images[i].vbmeta_data,
+ verify_data.vbmeta_images[i].vbmeta_size, &num_descriptors),
+ avb_free);
if (!descriptors || num_descriptors < 1) {
continue;
@@ -329,9 +332,10 @@
continue;
}
if (desc.tag == AVB_DESCRIPTOR_TAG_HASHTREE) {
- desc_partition_name = (const uint8_t*)descriptors[j] + sizeof(AvbHashtreeDescriptor);
+ desc_partition_name =
+ (const uint8_t*)descriptors[j] + sizeof(AvbHashtreeDescriptor);
if (!avb_hashtree_descriptor_validate_and_byteswap(
- (AvbHashtreeDescriptor*)descriptors[j], out_hashtree_desc)) {
+ (AvbHashtreeDescriptor*)descriptors[j], out_hashtree_desc)) {
continue;
}
if (out_hashtree_desc->partition_name_len != partition_name.length()) {
@@ -361,12 +365,12 @@
return true;
}
-FsManagerAvbUniquePtr FsManagerAvbHandle::Open() {
+AvbUniquePtr AvbHandle::Open() {
bool is_device_unlocked = fs_mgr_is_device_unlocked();
- FsManagerAvbUniquePtr avb_handle(new FsManagerAvbHandle());
+ AvbUniquePtr avb_handle(new AvbHandle());
if (!avb_handle) {
- LERROR << "Failed to allocate FsManagerAvbHandle";
+ LERROR << "Failed to allocate AvbHandle";
return nullptr;
}
@@ -406,7 +410,7 @@
// Sets the MAJOR.MINOR for init to set it into "ro.boot.avb_version".
avb_handle->avb_version_ =
- android::base::StringPrintf("%d.%d", AVB_VERSION_MAJOR, AVB_VERSION_MINOR);
+ android::base::StringPrintf("%d.%d", AVB_VERSION_MAJOR, AVB_VERSION_MINOR);
// Checks whether FLAGS_VERIFICATION_DISABLED is set:
// - Only the top-level vbmeta struct is read.
@@ -414,18 +418,18 @@
// and AVB HASHTREE descriptor(s).
AvbVBMetaImageHeader vbmeta_header;
avb_vbmeta_image_header_to_host_byte_order(
- (AvbVBMetaImageHeader*)avb_handle->avb_slot_data_->vbmeta_images[0].vbmeta_data,
- &vbmeta_header);
- bool verification_disabled =
- ((AvbVBMetaImageFlags)vbmeta_header.flags & AVB_VBMETA_IMAGE_FLAGS_VERIFICATION_DISABLED);
+ (AvbVBMetaImageHeader*)avb_handle->avb_slot_data_->vbmeta_images[0].vbmeta_data,
+ &vbmeta_header);
+ bool verification_disabled = ((AvbVBMetaImageFlags)vbmeta_header.flags &
+ AVB_VBMETA_IMAGE_FLAGS_VERIFICATION_DISABLED);
if (verification_disabled) {
avb_handle->status_ = kAvbHandleVerificationDisabled;
} else {
// Verifies vbmeta structs against the digest passed from bootloader in kernel cmdline.
- std::unique_ptr<FsManagerAvbVerifier> avb_verifier = FsManagerAvbVerifier::Create();
+ std::unique_ptr<AvbVerifier> avb_verifier = AvbVerifier::Create();
if (!avb_verifier) {
- LERROR << "Failed to create FsManagerAvbVerifier";
+ LERROR << "Failed to create AvbVerifier";
return nullptr;
}
if (!avb_verifier->VerifyVbmetaImages(*avb_handle->avb_slot_data_)) {
@@ -434,8 +438,8 @@
}
// Checks whether FLAGS_HASHTREE_DISABLED is set.
- bool hashtree_disabled =
- ((AvbVBMetaImageFlags)vbmeta_header.flags & AVB_VBMETA_IMAGE_FLAGS_HASHTREE_DISABLED);
+ bool hashtree_disabled = ((AvbVBMetaImageFlags)vbmeta_header.flags &
+ AVB_VBMETA_IMAGE_FLAGS_HASHTREE_DISABLED);
if (hashtree_disabled) {
avb_handle->status_ = kAvbHandleHashtreeDisabled;
}
@@ -445,16 +449,16 @@
return avb_handle;
}
-SetUpAvbHashtreeResult FsManagerAvbHandle::SetUpAvbHashtree(struct fstab_rec* fstab_entry,
- bool wait_for_verity_dev) {
+AvbHashtreeResult AvbHandle::SetUpAvbHashtree(struct fstab_rec* fstab_entry,
+ bool wait_for_verity_dev) {
if (!fstab_entry || status_ == kAvbHandleUninitialized || !avb_slot_data_ ||
avb_slot_data_->num_vbmeta_images < 1) {
- return SetUpAvbHashtreeResult::kFail;
+ return AvbHashtreeResult::kFail;
}
if (status_ == kAvbHandleHashtreeDisabled || status_ == kAvbHandleVerificationDisabled) {
LINFO << "AVB HASHTREE disabled on: " << fstab_entry->mount_point;
- return SetUpAvbHashtreeResult::kDisabled;
+ return AvbHashtreeResult::kDisabled;
}
// Derives partition_name from blk_device to query the corresponding AVB HASHTREE descriptor
@@ -478,14 +482,17 @@
std::string root_digest;
if (!get_hashtree_descriptor(partition_name, *avb_slot_data_, &hashtree_descriptor, &salt,
&root_digest)) {
- return SetUpAvbHashtreeResult::kFail;
+ return AvbHashtreeResult::kFail;
}
// Converts HASHTREE descriptor to verity_table_params.
if (!hashtree_dm_verity_setup(fstab_entry, hashtree_descriptor, salt, root_digest,
wait_for_verity_dev)) {
- return SetUpAvbHashtreeResult::kFail;
+ return AvbHashtreeResult::kFail;
}
- return SetUpAvbHashtreeResult::kSuccess;
+ return AvbHashtreeResult::kSuccess;
}
+
+} // namespace fs_mgr
+} // namespace android
diff --git a/fs_mgr/include/fs_mgr_avb.h b/fs_mgr/libfs_avb/include/fs_avb/fs_avb.h
similarity index 75%
rename from fs_mgr/include/fs_mgr_avb.h
rename to fs_mgr/libfs_avb/include/fs_avb/fs_avb.h
index bb55a14..9adab3d 100644
--- a/fs_mgr/include/fs_mgr_avb.h
+++ b/fs_mgr/libfs_avb/include/fs_avb/fs_avb.h
@@ -14,18 +14,18 @@
* limitations under the License.
*/
-#ifndef __CORE_FS_MGR_AVB_H
-#define __CORE_FS_MGR_AVB_H
+#pragma once
-#include <map>
#include <memory>
#include <string>
+#include <fstab/fstab.h>
#include <libavb/libavb.h>
-#include "fs_mgr.h"
+namespace android {
+namespace fs_mgr {
-enum class SetUpAvbHashtreeResult {
+enum class AvbHashtreeResult {
kSuccess = 0,
kFail,
kDisabled,
@@ -33,17 +33,15 @@
class FsManagerAvbOps;
-class FsManagerAvbHandle;
-using FsManagerAvbUniquePtr = std::unique_ptr<FsManagerAvbHandle>;
-
-using ByNameSymlinkMap = std::map<std::string, std::string>;
+class AvbHandle;
+using AvbUniquePtr = std::unique_ptr<AvbHandle>;
// Provides a factory method to return a unique_ptr pointing to itself and the
// SetUpAvbHashtree() function to extract dm-verity parameters from AVB HASHTREE
// descriptors to load verity table into kernel through ioctl.
-class FsManagerAvbHandle {
+class AvbHandle {
public:
- // The factory method to return a FsManagerAvbUniquePtr that holds
+ // The factory method to return a AvbUniquePtr that holds
// the verified AVB (external/avb) metadata of all verified partitions
// in avb_slot_data_.vbmeta_images[].
//
@@ -51,7 +49,7 @@
// - androidboot.vbmeta.{hash_alg, size, digest}.
//
// A typical usage will be:
- // - FsManagerAvbUniquePtr handle = FsManagerAvbHandle::Open();
+ // - AvbUniquePtr handle = AvbHandle::Open();
//
// Possible return values:
// - nullptr: any error when reading and verifying the metadata,
@@ -75,7 +73,7 @@
// - a valid unique_ptr with status kAvbHandleSuccess: the metadata
// is verified and can be trusted.
//
- static FsManagerAvbUniquePtr Open();
+ static AvbUniquePtr Open();
// Sets up dm-verity on the given fstab entry.
// The 'wait_for_verity_dev' parameter makes this function wait for the
@@ -87,17 +85,17 @@
// failed to get the HASHTREE descriptor, runtime error when set up
// device-mapper, etc.
// - kDisabled: hashtree is disabled.
- SetUpAvbHashtreeResult SetUpAvbHashtree(fstab_rec* fstab_entry, bool wait_for_verity_dev);
+ AvbHashtreeResult SetUpAvbHashtree(fstab_rec* fstab_entry, bool wait_for_verity_dev);
const std::string& avb_version() const { return avb_version_; }
- FsManagerAvbHandle(const FsManagerAvbHandle&) = delete; // no copy
- FsManagerAvbHandle& operator=(const FsManagerAvbHandle&) = delete; // no assignment
+ AvbHandle(const AvbHandle&) = delete; // no copy
+ AvbHandle& operator=(const AvbHandle&) = delete; // no assignment
- FsManagerAvbHandle(FsManagerAvbHandle&&) noexcept = delete; // no move
- FsManagerAvbHandle& operator=(FsManagerAvbHandle&&) noexcept = delete; // no move assignment
+ AvbHandle(AvbHandle&&) noexcept = delete; // no move
+ AvbHandle& operator=(AvbHandle&&) noexcept = delete; // no move assignment
- ~FsManagerAvbHandle() {
+ ~AvbHandle() {
if (avb_slot_data_) {
avb_slot_verify_data_free(avb_slot_data_);
}
@@ -112,11 +110,12 @@
kAvbHandleVerificationError,
};
- FsManagerAvbHandle() : avb_slot_data_(nullptr), status_(kAvbHandleUninitialized) {}
+ AvbHandle() : avb_slot_data_(nullptr), status_(kAvbHandleUninitialized) {}
AvbSlotVerifyData* avb_slot_data_;
AvbHandleStatus status_;
std::string avb_version_;
};
-#endif /* __CORE_FS_MGR_AVB_H */
+} // namespace fs_mgr
+} // namespace android
diff --git a/fs_mgr/fs_mgr_priv_sha.h b/fs_mgr/libfs_avb/sha.h
similarity index 92%
rename from fs_mgr/fs_mgr_priv_sha.h
rename to fs_mgr/libfs_avb/sha.h
index 5b53eea..2d3ca6d 100644
--- a/fs_mgr/fs_mgr_priv_sha.h
+++ b/fs_mgr/libfs_avb/sha.h
@@ -14,11 +14,13 @@
* limitations under the License.
*/
-#ifndef __CORE_FS_MGR_PRIV_SHA_H
-#define __CORE_FS_MGR_PRIV_SHA_H
+#pragma once
#include <openssl/sha.h>
+namespace android {
+namespace fs_mgr {
+
class SHA256Hasher {
private:
SHA256_CTX sha256_ctx;
@@ -59,4 +61,5 @@
}
};
-#endif /* __CORE_FS_MGR_PRIV_SHA_H */
+} // namespace fs_mgr
+} // namespace android
diff --git a/fs_mgr/tests/adb-remount-test.sh b/fs_mgr/tests/adb-remount-test.sh
index 7a00194..d9e017c 100755
--- a/fs_mgr/tests/adb-remount-test.sh
+++ b/fs_mgr/tests/adb-remount-test.sh
@@ -63,6 +63,7 @@
Returns: the logcat output" ]
adb_logcat() {
+ echo "${RED}[ INFO ]${NORMAL} logcat ${@}" >&2 &&
adb logcat "${@}" </dev/null |
grep -v 'logd : logdr: UID=' |
sed -e '${/------- beginning of kernel/d}' -e 's/^[0-1][0-9]-[0-3][0-9] //'
@@ -106,12 +107,13 @@
Returns: true if the reboot command succeeded" ]
adb_reboot() {
- adb reboot remount-test
+ adb reboot remount-test &&
+ sleep 2
}
[ "USAGE: adb_wait [timeout]
-Returns: waits until the device has returned or the optional timeout" ]
+Returns: waits until the device has returned for adb or optional timeout" ]
adb_wait() {
if [ -n "${1}" ]; then
timeout --preserve-status --signal=KILL ${1} adb wait-for-device
@@ -120,14 +122,49 @@
fi
}
+[ "USAGE: fastboot_wait [timeout]
+
+Returns: waits until the device has returned for fastboot or optional timeout" ]
+fastboot_wait() {
+ # fastboot has no wait-for-device, but it does an automatic
+ # wait and requires (even a nonsensical) command to do so.
+ if [ -n "${1}" ]; then
+ timeout --preserve-status --signal=KILL ${1} fastboot wait-for-device
+ else
+ fastboot wait-for-device >/dev/null
+ fi >/dev/null 2>/dev/null ||
+ inFastboot
+}
+
[ "USAGE: adb_root
Returns: true if device in root state" ]
adb_root() {
- adb root >/dev/null </dev/null 2>/dev/null &&
- sleep 1 &&
- adb_wait &&
- sleep 1
+ adb root >/dev/null </dev/null 2>/dev/null
+ sleep 2
+ adb_wait 2m &&
+ [ `adb_sh echo '${USER}'` = root ]
+}
+
+[ "USAGE: fastboot_getvar var expected
+
+Returns: true if var output matches expected" ]
+fastboot_getvar() {
+ O=`fastboot getvar ${1} 2>&1`
+ err=${?}
+ O="${O#< waiting for * >?}"
+ O="${O%%?Finished. Total time: *}"
+ if [ 0 -ne ${err} ]; then
+ echo ${O} >&2
+ false
+ return
+ fi
+ if [ -n "${2}" -a "${1}: ${2}" != "${O}" ]; then
+ echo "${2} != ${O}" >&2
+ false
+ return
+ fi
+ echo ${O} >&2
}
[ "USAGE: die [-t <epoch>] [message] >/dev/stderr
@@ -233,8 +270,7 @@
adb_su ls /sys/module/overlay/parameters/override_creds </dev/null >/dev/null &&
echo "${GREEN}[ OK ]${NORMAL} overlay module supports override_creds" >&2 ||
die "overlay module can not be used on ANDROID"
-adb_root &&
- adb_wait ||
+adb_root ||
die "initial setup"
reboot=false
OVERLAYFS_BACKING="cache mnt/scratch"
@@ -250,8 +286,7 @@
echo "${ORANGE}[ WARNING ]${NORMAL} rebooting before test" >&2
adb_reboot &&
adb_wait 2m &&
- adb_root &&
- adb_wait ||
+ adb_root ||
die "reboot after wipe"
fi
D=`adb_sh df -k </dev/null` &&
@@ -288,7 +323,6 @@
T=`adb_date`
adb_root &&
- adb_wait &&
adb remount &&
D=`adb_sh df -k </dev/null` ||
die -t ${T} "can not collect filesystem data"
@@ -340,19 +374,31 @@
die "re-read vendor hello after reboot w/o root"
check_eq "cat: /vendor/hello: Permission denied" "${B}" vendor after reboot w/o root
adb_root &&
- adb_wait &&
B="`adb_cat /vendor/hello`" ||
die "re-read vendor hello after reboot"
check_eq "${A}" "${B}" vendor after reboot
adb reboot-fastboot &&
- fastboot flash vendor &&
- fastboot reboot ||
+ fastboot_wait 2m &&
+ fastboot flash vendor ||
die "fastbootd flash vendor"
+# check scratch via fastboot
+fastboot_getvar partition-type:scratch raw &&
+ fastboot_getvar has-slot:scratch no &&
+ fastboot_getvar is-logical:scratch yes ||
+ die "fastboot can not see scratch parameters"
+echo "${ORANGE}[ INFO ]${NORMAL} expect fastboot erase scratch to fail" >&2
+fastboot erase scratch &&
+ die "fastbootd can erase scratch"
+echo "${ORANGE}[ INFO ]${NORMAL} expect fastboot format scratch to fail" >&2
+fastboot format scratch &&
+ die "fastbootd can format scratch"
+fastboot reboot ||
+ die "can not reboot out of fastbootd"
+echo "${ORANGE}[ WARNING ]${NORMAL} adb after fastboot ... waiting 2 minutes"
adb_wait 2m ||
die "did not reboot after flash"
adb_root &&
- adb_wait &&
D=`adb_sh df -k </dev/null` &&
H=`echo "${D}" | head -1` &&
D=`echo "${D}" | grep "^overlay "` &&
@@ -365,8 +411,7 @@
B="`adb_cat /system/hello`" ||
die "re-read system hello after flash vendor"
check_eq "${A}" "${B}" system after flash vendor
-adb_root &&
- adb_wait ||
+adb_root ||
die "adb root"
B="`adb_cat /vendor/hello`" &&
die "re-read vendor hello after flash vendor"
@@ -384,4 +429,27 @@
die "re-read vendor hello after rm"
check_eq "cat: /vendor/hello: No such file or directory" "${B}" after flash rm
+adb reboot-fastboot &&
+ dd if=/dev/zero of=adb-remount-test.img bs=4096 count=16 &&
+ fastboot_wait 2m ||
+ die "reboot into fastbootd"
+fastboot flash scratch adb-remount-test.img
+err=${?}
+rm adb-remount-test.img
+[ 0 -eq ${err} ] ||
+ die "fastbootd flash scratch"
+fastboot reboot ||
+ die "can not reboot out of fastbootd"
+adb_wait 2m &&
+ adb_root ||
+ die "did not reboot after flash"
+T=`adb_date`
+D=`adb disable-verity 2>&1`
+err=${?}
+echo "${D}"
+[ ${err} = 0 ] &&
+ [ X"${D}" = X"${D##*setup failed}" ] &&
+ [ X"${D}" != X"${D##*using overlayfs}" ] ||
+ die -t ${T} "setup for overlayfs"
+
echo "${GREEN}[ PASSED ]${NORMAL} adb remount" >&2
diff --git a/init/Android.bp b/init/Android.bp
index ff3b61f..ea66ac6 100644
--- a/init/Android.bp
+++ b/init/Android.bp
@@ -71,6 +71,7 @@
"libbinder",
"libbootloader_message",
"libcutils",
+ "libcrypto",
"libdl",
"libext4_utils",
"libfs_mgr",
@@ -79,6 +80,7 @@
"libkeyutils",
"liblog",
"liblogwrap",
+ "liblp",
"libselinux",
"libutils",
],
@@ -92,6 +94,7 @@
"action.cpp",
"action_manager.cpp",
"action_parser.cpp",
+ "boringssl_self_test.cpp",
"bootchart.cpp",
"builtins.cpp",
"capabilities.cpp",
@@ -99,6 +102,7 @@
"devices.cpp",
"epoll.cpp",
"firmware_handler.cpp",
+ "first_stage_init.cpp",
"first_stage_mount.cpp",
"import_parser.cpp",
"init.cpp",
@@ -117,6 +121,7 @@
"sigchld_handler.cpp",
"subcontext.cpp",
"subcontext.proto",
+ "switch_root.cpp",
"rlimit_parser.cpp",
"tokenizer.cpp",
"uevent_listener.cpp",
diff --git a/init/Android.mk b/init/Android.mk
index dc46d21..69f1d87 100644
--- a/init/Android.mk
+++ b/init/Android.mk
@@ -39,12 +39,15 @@
# --
+# Do not build this even with mmma if we're system-as-root, otherwise it will overwrite the symlink.
+ifneq ($(BOARD_BUILD_SYSTEM_ROOT_IMAGE),true)
include $(CLEAR_VARS)
LOCAL_CPPFLAGS := $(init_cflags)
LOCAL_SRC_FILES := \
devices.cpp \
+ first_stage_init.cpp \
+ first_stage_main.cpp \
first_stage_mount.cpp \
- init_first_stage.cpp \
reboot_utils.cpp \
selinux.cpp \
switch_root.cpp \
@@ -67,6 +70,7 @@
$(TARGET_RAMDISK_OUT)/sys \
LOCAL_STATIC_LIBRARIES := \
+ libfs_avb \
libfs_mgr \
libfec \
libfec_rs \
@@ -93,20 +97,15 @@
# First stage init is weird: it may start without stdout/stderr, and no /proc.
LOCAL_NOSANITIZE := hwaddress
include $(BUILD_EXECUTABLE)
+endif
include $(CLEAR_VARS)
LOCAL_MODULE := init_system
-ifeq ($(BOARD_BUILD_SYSTEM_ROOT_IMAGE),true)
-LOCAL_REQUIRED_MODULES := \
- init_first_stage \
- init_second_stage \
-
-else
LOCAL_REQUIRED_MODULES := \
init_second_stage \
-endif
+LOCAL_POST_INSTALL_CMD := ln -sf /system/bin/init $(TARGET_ROOT_OUT)/init
include $(BUILD_PHONY_PACKAGE)
include $(CLEAR_VARS)
@@ -118,5 +117,3 @@
endif
include $(BUILD_PHONY_PACKAGE)
-
-
diff --git a/init/boringssl_self_test.cpp b/init/boringssl_self_test.cpp
new file mode 100644
index 0000000..0408d30
--- /dev/null
+++ b/init/boringssl_self_test.cpp
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "boringssl_self_test.h"
+
+#include <android-base/logging.h>
+#include <cutils/android_reboot.h>
+#include <openssl/crypto.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+namespace android {
+namespace init {
+
+Result<Success> StartBoringSslSelfTest(const BuiltinArguments&) {
+ pid_t id = fork();
+
+ if (id == 0) {
+ if (BORINGSSL_self_test() != 1) {
+ LOG(INFO) << "BoringSSL crypto self tests failed";
+
+ // This check has failed, so the device should refuse
+ // to boot. Rebooting to bootloader to wait for
+ // further action from the user.
+
+ int result = android_reboot(ANDROID_RB_RESTART2, 0,
+ "bootloader,boringssl-self-check-failed");
+ if (result != 0) {
+ LOG(ERROR) << "Failed to reboot into bootloader";
+ }
+ }
+
+ _exit(0);
+ } else if (id == -1) {
+ // Failed to fork, so cannot run the test. Refuse to continue.
+ PLOG(FATAL) << "Failed to fork for BoringSSL self test";
+ }
+
+ return Success();
+}
+
+} // namespace init
+} // namespace android
diff --git a/init/boringssl_self_test.h b/init/boringssl_self_test.h
new file mode 100644
index 0000000..b21fc78
--- /dev/null
+++ b/init/boringssl_self_test.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "builtin_arguments.h"
+#include "result.h"
+
+namespace android {
+namespace init {
+
+Result<Success> StartBoringSslSelfTest(const BuiltinArguments&);
+
+} // namespace init
+} // namespace android
diff --git a/init/init_first_stage.cpp b/init/first_stage_init.cpp
similarity index 97%
rename from init/init_first_stage.cpp
rename to init/first_stage_init.cpp
index c2c6868..e11d897 100644
--- a/init/init_first_stage.cpp
+++ b/init/first_stage_init.cpp
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#include "first_stage_init.h"
+
#include <dirent.h>
#include <fcntl.h>
#include <paths.h>
@@ -94,7 +96,7 @@
} // namespace
-int main(int argc, char** argv) {
+int FirstStageMain(int argc, char** argv) {
if (REBOOT_BOOTLOADER_ON_PANIC) {
InstallRebootSignalHandlers();
}
@@ -214,7 +216,7 @@
setenv("INIT_STARTED_AT", std::to_string(start_ms).c_str(), 1);
const char* path = "/system/bin/init";
- const char* args[] = {path, nullptr};
+ const char* args[] = {path, "selinux_setup", nullptr};
execv(path, const_cast<char**>(args));
// execv() only returns if an error happened, in which case we
@@ -226,7 +228,3 @@
} // namespace init
} // namespace android
-
-int main(int argc, char** argv) {
- return android::init::main(argc, argv);
-}
diff --git a/init/first_stage_init.h b/init/first_stage_init.h
new file mode 100644
index 0000000..0476e44
--- /dev/null
+++ b/init/first_stage_init.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+namespace android {
+namespace init {
+
+int FirstStageMain(int argc, char** argv);
+
+} // namespace init
+} // namespace android
diff --git a/init/first_stage_main.cpp b/init/first_stage_main.cpp
new file mode 100644
index 0000000..7bae84c
--- /dev/null
+++ b/init/first_stage_main.cpp
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "first_stage_init.h"
+
+int main(int argc, char** argv) {
+ return android::init::FirstStageMain(argc, argv);
+}
diff --git a/init/first_stage_mount.cpp b/init/first_stage_mount.cpp
index 43b2ebf..8644dae 100644
--- a/init/first_stage_mount.cpp
+++ b/init/first_stage_mount.cpp
@@ -30,8 +30,8 @@
#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/strings.h>
+#include <fs_avb/fs_avb.h>
#include <fs_mgr.h>
-#include <fs_mgr_avb.h>
#include <fs_mgr_dm_linear.h>
#include <fs_mgr_overlayfs.h>
#include <liblp/liblp.h>
@@ -43,6 +43,9 @@
#include "util.h"
using android::base::Timer;
+using android::fs_mgr::AvbHandle;
+using android::fs_mgr::AvbHashtreeResult;
+using android::fs_mgr::AvbUniquePtr;
using namespace std::literals;
@@ -113,7 +116,7 @@
bool InitAvbHandle();
std::string device_tree_vbmeta_parts_;
- FsManagerAvbUniquePtr avb_handle_;
+ AvbUniquePtr avb_handle_;
};
// Static Functions
@@ -449,7 +452,9 @@
// Includes the partition names of fstab records and verity_loc_device (if any).
// Notes that fstab_rec->blk_device has A/B suffix updated by fs_mgr when A/B is used.
for (auto fstab_rec : mount_fstab_recs_) {
- required_devices_partition_names_.emplace(basename(fstab_rec->blk_device));
+ if (!fs_mgr_is_logical(fstab_rec)) {
+ required_devices_partition_names_.emplace(basename(fstab_rec->blk_device));
+ }
}
if (!verity_loc_device.empty()) {
@@ -545,12 +550,12 @@
bool FirstStageMountVBootV2::SetUpDmVerity(fstab_rec* fstab_rec) {
if (fs_mgr_is_avb(fstab_rec)) {
if (!InitAvbHandle()) return false;
- SetUpAvbHashtreeResult hashtree_result =
+ AvbHashtreeResult hashtree_result =
avb_handle_->SetUpAvbHashtree(fstab_rec, false /* wait_for_verity_dev */);
switch (hashtree_result) {
- case SetUpAvbHashtreeResult::kDisabled:
+ case AvbHashtreeResult::kDisabled:
return true; // Returns true to mount the partition.
- case SetUpAvbHashtreeResult::kSuccess:
+ case AvbHashtreeResult::kSuccess:
// The exact block device name (fstab_rec->blk_device) is changed to
// "/dev/block/dm-XX". Needs to create it because ueventd isn't started in init
// first stage.
@@ -565,10 +570,10 @@
bool FirstStageMountVBootV2::InitAvbHandle() {
if (avb_handle_) return true; // Returns true if the handle is already initialized.
- avb_handle_ = FsManagerAvbHandle::Open();
+ avb_handle_ = AvbHandle::Open();
if (!avb_handle_) {
- PLOG(ERROR) << "Failed to open FsManagerAvbHandle";
+ PLOG(ERROR) << "Failed to open AvbHandle";
return false;
}
// Sets INIT_AVB_VERSION here for init to set ro.boot.avb_version in the second stage.
@@ -605,7 +610,7 @@
return;
}
- // Initializes required devices for the subsequent FsManagerAvbHandle::Open()
+ // Initializes required devices for the subsequent AvbHandle::Open()
// to verify AVB metadata on all partitions in the verified chain.
// We only set INIT_AVB_VERSION when the AVB verification succeeds, i.e., the
// Open() function returns a valid handle.
@@ -616,9 +621,9 @@
return;
}
- FsManagerAvbUniquePtr avb_handle = FsManagerAvbHandle::Open();
+ AvbUniquePtr avb_handle = AvbHandle::Open();
if (!avb_handle) {
- PLOG(ERROR) << "Failed to open FsManagerAvbHandle for INIT_AVB_VERSION";
+ PLOG(ERROR) << "Failed to open AvbHandle for INIT_AVB_VERSION";
return;
}
setenv("INIT_AVB_VERSION", avb_handle->avb_version().c_str(), 1);
diff --git a/init/init.cpp b/init/init.cpp
index e7dbc11..dc46a82 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -49,6 +49,7 @@
#endif
#include "action_parser.h"
+#include "boringssl_self_test.h"
#include "epoll.h"
#include "first_stage_mount.h"
#include "import_parser.h"
@@ -59,13 +60,8 @@
#include "security.h"
#include "selinux.h"
#include "sigchld_handler.h"
-#include "ueventd.h"
#include "util.h"
-#if __has_feature(address_sanitizer)
-#include <sanitizer/asan_interface.h>
-#endif
-
using namespace std::chrono_literals;
using namespace std::string_literals;
@@ -79,25 +75,6 @@
namespace android {
namespace init {
-#if __has_feature(address_sanitizer)
-// Load asan.options if it exists since these are not yet in the environment.
-// Always ensure detect_container_overflow=0 as there are false positives with this check.
-// Always ensure abort_on_error=1 to ensure we reboot to bootloader for development builds.
-extern "C" const char* __asan_default_options() {
- return "include_if_exists=/system/asan.options:detect_container_overflow=0:abort_on_error=1";
-}
-
-__attribute__((no_sanitize("address", "memory", "thread", "undefined"))) extern "C" void
-__sanitizer_report_error_summary(const char* summary) {
- LOG(ERROR) << "Main stage (error summary): " << summary;
-}
-
-__attribute__((no_sanitize("address", "memory", "thread", "undefined"))) static void
-AsanReportCallback(const char* str) {
- LOG(ERROR) << "Main stage: " << str;
-}
-#endif
-
static int property_triggers_enabled = 0;
static char qemu[32];
@@ -622,57 +599,11 @@
});
}
-static void SetupSelinux(char** argv) {
- android::base::InitLogging(argv, &android::base::KernelLogger, [](const char*) {
- RebootSystem(ANDROID_RB_RESTART2, "bootloader");
- });
-
- // Set up SELinux, loading the SELinux policy.
- SelinuxSetupKernelLogging();
- SelinuxInitialize();
-
- // We're in the kernel domain and want to transition to the init domain. File systems that
- // store SELabels in their xattrs, such as ext4 do not need an explicit restorecon here,
- // but other file systems do. In particular, this is needed for ramdisks such as the
- // recovery image for A/B devices.
- if (selinux_android_restorecon("/system/bin/init", 0) == -1) {
- PLOG(FATAL) << "restorecon failed of /system/bin/init failed";
- }
-
- setenv("SELINUX_INITIALIZED", "true", 1);
-
- const char* path = "/system/bin/init";
- const char* args[] = {path, nullptr};
- execv(path, const_cast<char**>(args));
-
- // execv() only returns if an error happened, in which case we
- // panic and never return from this function.
- PLOG(FATAL) << "execv(\"" << path << "\") failed";
-}
-
-int main(int argc, char** argv) {
-#if __has_feature(address_sanitizer)
- __asan_set_error_report_callback(AsanReportCallback);
-#endif
-
- if (!strcmp(basename(argv[0]), "ueventd")) {
- return ueventd_main(argc, argv);
- }
-
- if (argc > 1 && !strcmp(argv[1], "subcontext")) {
- android::base::InitLogging(argv, &android::base::KernelLogger);
- const BuiltinFunctionMap function_map;
- return SubcontextMain(argc, argv, &function_map);
- }
-
+int SecondStageMain(int argc, char** argv) {
if (REBOOT_BOOTLOADER_ON_PANIC) {
InstallRebootSignalHandlers();
}
- if (getenv("SELINUX_INITIALIZED") == nullptr) {
- SetupSelinux(argv);
- }
-
// We need to set up stdin/stdout/stderr again now that we're running in init's context.
InitKernelLogging(argv, InitAborter);
LOG(INFO) << "init second stage started!";
@@ -708,7 +639,6 @@
if (avb_version) property_set("ro.boot.avb_version", avb_version);
// Clean up our environment.
- unsetenv("SELINUX_INITIALIZED");
unsetenv("INIT_STARTED_AT");
unsetenv("INIT_SELINUX_TOOK");
unsetenv("INIT_AVB_VERSION");
@@ -768,6 +698,9 @@
// Trigger all the boot actions to get us started.
am.QueueEventTrigger("init");
+ // Starting the BoringSSL self test, for NIAP certification compliance.
+ am.QueueBuiltinAction(StartBoringSslSelfTest, "StartBoringSslSelfTest");
+
// Repeat mix_hwrng_into_linux_rng in case /dev/hw_random or /dev/random
// wasn't ready immediately after wait_for_coldboot_done
am.QueueBuiltinAction(MixHwrngIntoLinuxRngAction, "MixHwrngIntoLinuxRng");
diff --git a/init/init.h b/init/init.h
index 65405aa..a76da20 100644
--- a/init/init.h
+++ b/init/init.h
@@ -50,7 +50,7 @@
void ResetWaitForProp();
-int main(int argc, char** argv);
+int SecondStageMain(int argc, char** argv);
} // namespace init
} // namespace android
diff --git a/init/main.cpp b/init/main.cpp
index 9ed451b..868c409 100644
--- a/init/main.cpp
+++ b/init/main.cpp
@@ -14,8 +14,70 @@
* limitations under the License.
*/
+#include "builtins.h"
+#include "first_stage_init.h"
#include "init.h"
+#include "selinux.h"
+#include "subcontext.h"
+#include "ueventd.h"
+
+#include <android-base/logging.h>
+
+#if __has_feature(address_sanitizer)
+#include <sanitizer/asan_interface.h>
+#endif
+
+#if __has_feature(address_sanitizer)
+// Load asan.options if it exists since these are not yet in the environment.
+// Always ensure detect_container_overflow=0 as there are false positives with this check.
+// Always ensure abort_on_error=1 to ensure we reboot to bootloader for development builds.
+extern "C" const char* __asan_default_options() {
+ return "include_if_exists=/system/asan.options:detect_container_overflow=0:abort_on_error=1";
+}
+
+__attribute__((no_sanitize("address", "memory", "thread", "undefined"))) extern "C" void
+__sanitizer_report_error_summary(const char* summary) {
+ LOG(ERROR) << "Init (error summary): " << summary;
+}
+
+__attribute__((no_sanitize("address", "memory", "thread", "undefined"))) static void
+AsanReportCallback(const char* str) {
+ LOG(ERROR) << "Init: " << str;
+}
+#endif
+
+using namespace android::init;
int main(int argc, char** argv) {
- android::init::main(argc, argv);
+#if __has_feature(address_sanitizer)
+ __asan_set_error_report_callback(AsanReportCallback);
+#endif
+
+ if (!strcmp(basename(argv[0]), "ueventd")) {
+ return ueventd_main(argc, argv);
+ }
+
+ if (argc < 2) {
+ return FirstStageMain(argc, argv);
+ }
+
+ if (!strcmp(argv[1], "subcontext")) {
+ android::base::InitLogging(argv, &android::base::KernelLogger);
+ const BuiltinFunctionMap function_map;
+
+ return SubcontextMain(argc, argv, &function_map);
+ }
+
+ if (!strcmp(argv[1], "selinux_setup")) {
+ return SetupSelinux(argv);
+ }
+
+ if (!strcmp(argv[1], "second_stage")) {
+ return SecondStageMain(argc, argv);
+ }
+
+ android::base::InitLogging(argv, &android::base::KernelLogger);
+
+ LOG(ERROR) << "Unknown argument passed to init '" << argv[1] << "'";
+ return 1;
}
diff --git a/init/selinux.cpp b/init/selinux.cpp
index fd7e86f..3a09096 100644
--- a/init/selinux.cpp
+++ b/init/selinux.cpp
@@ -18,8 +18,8 @@
// for SELinux operation for init.
// When the system boots, there is no SEPolicy present and init is running in the kernel domain.
-// Init loads the SEPolicy from the file system, restores the context of /init based on this
-// SEPolicy, and finally exec()'s itself to run in the proper domain.
+// Init loads the SEPolicy from the file system, restores the context of /system/bin/init based on
+// this SEPolicy, and finally exec()'s itself to run in the proper domain.
// The SEPolicy on Android comes in two variants: monolithic and split.
@@ -58,8 +58,10 @@
#include <android-base/logging.h>
#include <android-base/parseint.h>
#include <android-base/unique_fd.h>
+#include <cutils/android_reboot.h>
#include <selinux/android.h>
+#include "reboot_utils.h"
#include "util.h"
using android::base::ParseInt;
@@ -379,8 +381,6 @@
return IsSplitPolicyDevice() ? LoadSplitPolicy() : LoadMonolithicPolicy();
}
-} // namespace
-
void SelinuxInitialize() {
Timer t;
@@ -405,6 +405,8 @@
setenv("INIT_SELINUX_TOOK", std::to_string(t.duration().count()).c_str(), 1);
}
+} // namespace
+
// The files and directories that were created before initial sepolicy load or
// files on ramdisk need to have their security context restored to the proper
// value. This must happen before /dev is populated by ueventd.
@@ -496,6 +498,39 @@
return major_version;
}
+// This function initializes SELinux then execs init to run in the init SELinux context.
+int SetupSelinux(char** argv) {
+ android::base::InitLogging(argv, &android::base::KernelLogger, [](const char*) {
+ RebootSystem(ANDROID_RB_RESTART2, "bootloader");
+ });
+
+ if (REBOOT_BOOTLOADER_ON_PANIC) {
+ InstallRebootSignalHandlers();
+ }
+
+ // Set up SELinux, loading the SELinux policy.
+ SelinuxSetupKernelLogging();
+ SelinuxInitialize();
+
+ // We're in the kernel domain and want to transition to the init domain. File systems that
+ // store SELabels in their xattrs, such as ext4 do not need an explicit restorecon here,
+ // but other file systems do. In particular, this is needed for ramdisks such as the
+ // recovery image for A/B devices.
+ if (selinux_android_restorecon("/system/bin/init", 0) == -1) {
+ PLOG(FATAL) << "restorecon failed of /system/bin/init failed";
+ }
+
+ const char* path = "/system/bin/init";
+ const char* args[] = {path, "second_stage", nullptr};
+ execv(path, const_cast<char**>(args));
+
+ // execv() only returns if an error happened, in which case we
+ // panic and never return from this function.
+ PLOG(FATAL) << "execv(\"" << path << "\") failed";
+
+ return 1;
+}
+
// selinux_android_file_context_handle() takes on the order of 10+ms to run, so we want to cache
// its value. selinux_android_restorecon() also needs an sehandle for file context look up. It
// will create and store its own copy, but selinux_android_set_sehandle() can be used to provide
diff --git a/init/selinux.h b/init/selinux.h
index c41d7f0..3aa9406 100644
--- a/init/selinux.h
+++ b/init/selinux.h
@@ -23,7 +23,7 @@
namespace android {
namespace init {
-void SelinuxInitialize();
+int SetupSelinux(char** argv);
void SelinuxRestoreContext();
void SelinuxSetupKernelLogging();
diff --git a/libmemunreachable/HeapWalker.cpp b/libmemunreachable/HeapWalker.cpp
index 2403ad0..89837f7 100644
--- a/libmemunreachable/HeapWalker.cpp
+++ b/libmemunreachable/HeapWalker.cpp
@@ -35,6 +35,13 @@
end = begin + 1;
}
Range range{begin, end};
+ if (valid_mappings_range_.end != 0 &&
+ (begin < valid_mappings_range_.begin || end > valid_mappings_range_.end)) {
+ MEM_LOG_ALWAYS_FATAL("allocation %p-%p is outside mapping range %p-%p",
+ reinterpret_cast<void*>(begin), reinterpret_cast<void*>(end),
+ reinterpret_cast<void*>(valid_mappings_range_.begin),
+ reinterpret_cast<void*>(valid_mappings_range_.end));
+ }
auto inserted = allocations_.insert(std::pair<Range, AllocationInfo>(range, AllocationInfo{}));
if (inserted.second) {
valid_allocations_range_.begin = std::min(valid_allocations_range_.begin, begin);
@@ -76,15 +83,22 @@
Range range = to_do.back();
to_do.pop_back();
+ walking_range_ = range;
ForEachPtrInRange(range, [&](Range& ref_range, AllocationInfo* ref_info) {
if (!ref_info->referenced_from_root) {
ref_info->referenced_from_root = true;
to_do.push_back(ref_range);
}
});
+ walking_range_ = Range{0, 0};
}
}
+void HeapWalker::Mapping(uintptr_t begin, uintptr_t end) {
+ valid_mappings_range_.begin = std::min(valid_mappings_range_.begin, begin);
+ valid_mappings_range_.end = std::max(valid_mappings_range_.end, end);
+}
+
void HeapWalker::Root(uintptr_t begin, uintptr_t end) {
roots_.push_back(Range{begin, end});
}
@@ -113,6 +127,10 @@
RecurseRoot(vals);
+ if (segv_page_count_ > 0) {
+ MEM_ALOGE("%zu pages skipped due to segfaults", segv_page_count_);
+ }
+
return true;
}
@@ -168,7 +186,15 @@
handler.reset();
return;
}
- MEM_ALOGW("failed to read page at %p, signal %d", si->si_addr, signal);
+ if (!segv_logged_) {
+ MEM_ALOGW("failed to read page at %p, signal %d", si->si_addr, signal);
+ if (walking_range_.begin != 0U) {
+ MEM_ALOGW("while walking range %p-%p", reinterpret_cast<void*>(walking_range_.begin),
+ reinterpret_cast<void*>(walking_range_.end));
+ }
+ segv_logged_ = true;
+ }
+ segv_page_count_++;
if (!MapOverPage(si->si_addr)) {
handler.reset();
}
diff --git a/libmemunreachable/HeapWalker.h b/libmemunreachable/HeapWalker.h
index 92a8325..9e3db08 100644
--- a/libmemunreachable/HeapWalker.h
+++ b/libmemunreachable/HeapWalker.h
@@ -53,9 +53,14 @@
roots_(allocator),
root_vals_(allocator),
segv_handler_(),
- walking_ptr_(0) {
+ walking_ptr_(0),
+ walking_range_{0, 0},
+ segv_logged_(false),
+ segv_page_count_(0) {
valid_allocations_range_.end = 0;
valid_allocations_range_.begin = ~valid_allocations_range_.end;
+ valid_mappings_range_.end = 0;
+ valid_mappings_range_.begin = ~valid_allocations_range_.end;
segv_handler_.install(
SIGSEGV, [=](ScopedSignalHandler& handler, int signal, siginfo_t* siginfo, void* uctx) {
@@ -65,6 +70,7 @@
~HeapWalker() {}
bool Allocation(uintptr_t begin, uintptr_t end);
+ void Mapping(uintptr_t begin, uintptr_t end);
void Root(uintptr_t begin, uintptr_t end);
void Root(const allocator::vector<uintptr_t>& vals);
@@ -95,12 +101,16 @@
AllocationMap allocations_;
size_t allocation_bytes_;
Range valid_allocations_range_;
+ Range valid_mappings_range_;
allocator::vector<Range> roots_;
allocator::vector<uintptr_t> root_vals_;
ScopedSignalHandler segv_handler_;
- uintptr_t walking_ptr_;
+ volatile uintptr_t walking_ptr_;
+ Range walking_range_;
+ bool segv_logged_;
+ size_t segv_page_count_;
};
template <class F>
diff --git a/libmemunreachable/MemUnreachable.cpp b/libmemunreachable/MemUnreachable.cpp
index b160de9..3d7b8a8 100644
--- a/libmemunreachable/MemUnreachable.cpp
+++ b/libmemunreachable/MemUnreachable.cpp
@@ -87,6 +87,11 @@
const allocator::vector<Mapping>& mappings,
const allocator::vector<uintptr_t>& refs) {
MEM_ALOGI("searching process %d for allocations", pid_);
+
+ for (auto it = mappings.begin(); it != mappings.end(); it++) {
+ heap_walker_.Mapping(it->begin, it->end);
+ }
+
allocator::vector<Mapping> heap_mappings{mappings};
allocator::vector<Mapping> anon_mappings{mappings};
allocator::vector<Mapping> globals_mappings{mappings};
diff --git a/libmemunreachable/tests/HeapWalker_test.cpp b/libmemunreachable/tests/HeapWalker_test.cpp
index 84a0ec6..9610cd6 100644
--- a/libmemunreachable/tests/HeapWalker_test.cpp
+++ b/libmemunreachable/tests/HeapWalker_test.cpp
@@ -73,6 +73,24 @@
ASSERT_FALSE(heap_walker.Allocation(2, 3));
}
+TEST_F(HeapWalkerTest, mapping) {
+ HeapWalker heap_walker(heap_);
+ heap_walker.Mapping(2, 3);
+ heap_walker.Mapping(4, 5);
+ ASSERT_TRUE(heap_walker.Allocation(2, 3));
+ ASSERT_TRUE(heap_walker.Allocation(4, 5));
+ // space between mappings is not checked, but could be in the future
+ ASSERT_TRUE(heap_walker.Allocation(3, 4));
+
+ // re-enable malloc, ASSERT_DEATH may allocate
+ disable_malloc_.Enable();
+ ASSERT_DEATH({ heap_walker.Allocation(1, 2); }, "0x1-0x2.*outside.*0x2-0x5");
+ ASSERT_DEATH({ heap_walker.Allocation(1, 3); }, "0x1-0x3.*outside.*0x2-0x5");
+ ASSERT_DEATH({ heap_walker.Allocation(4, 6); }, "0x4-0x6.*outside.*0x2-0x5");
+ ASSERT_DEATH({ heap_walker.Allocation(5, 6); }, "0x5-0x6.*outside.*0x2-0x5");
+ ASSERT_DEATH({ heap_walker.Allocation(1, 6); }, "0x1-0x6.*outside.*0x2-0x5");
+}
+
#define buffer_begin(buffer) reinterpret_cast<uintptr_t>(buffer)
#define buffer_end(buffer) (reinterpret_cast<uintptr_t>(buffer) + sizeof(buffer))
diff --git a/libunwindstack/Android.bp b/libunwindstack/Android.bp
index 14f82c7..a5e0dc9 100644
--- a/libunwindstack/Android.bp
+++ b/libunwindstack/Android.bp
@@ -184,6 +184,7 @@
"tests/MapInfoGetLoadBiasTest.cpp",
"tests/MapsTest.cpp",
"tests/MemoryBufferTest.cpp",
+ "tests/MemoryCacheTest.cpp",
"tests/MemoryFake.cpp",
"tests/MemoryFileTest.cpp",
"tests/MemoryLocalTest.cpp",
@@ -310,6 +311,28 @@
],
}
+//-------------------------------------------------------------------------
+// Benchmarks
+//-------------------------------------------------------------------------
+cc_benchmark {
+ name: "unwind_benchmarks",
+ host_supported: true,
+ defaults: ["libunwindstack_flags"],
+
+ // Disable optimizations so that all of the calls are not optimized away.
+ cflags: [
+ "-O0",
+ ],
+
+ srcs: [
+ "benchmarks/unwind_benchmarks.cpp",
+ ],
+
+ shared_libs: [
+ "libunwindstack",
+ ],
+}
+
// Generates the elf data for use in the tests for .gnu_debugdata frames.
// Once these files are generated, use the xz command to compress the data.
cc_binary_host {
diff --git a/libunwindstack/Memory.cpp b/libunwindstack/Memory.cpp
index cfa8c6d..a30d65e 100644
--- a/libunwindstack/Memory.cpp
+++ b/libunwindstack/Memory.cpp
@@ -174,6 +174,13 @@
return std::shared_ptr<Memory>(new MemoryRemote(pid));
}
+std::shared_ptr<Memory> Memory::CreateProcessMemoryCached(pid_t pid) {
+ if (pid == getpid()) {
+ return std::shared_ptr<Memory>(new MemoryCache(new MemoryLocal()));
+ }
+ return std::shared_ptr<Memory>(new MemoryCache(new MemoryRemote(pid)));
+}
+
size_t MemoryBuffer::Read(uint64_t addr, void* dst, size_t size) {
if (addr >= raw_.size()) {
return 0;
@@ -398,4 +405,50 @@
return 0;
}
+size_t MemoryCache::Read(uint64_t addr, void* dst, size_t size) {
+ // Only bother caching and looking at the cache if this is a small read for now.
+ if (size > 64) {
+ return impl_->Read(addr, dst, size);
+ }
+
+ uint64_t addr_page = addr >> kCacheBits;
+ auto entry = cache_.find(addr_page);
+ uint8_t* cache_dst;
+ if (entry != cache_.end()) {
+ cache_dst = entry->second;
+ } else {
+ cache_dst = cache_[addr_page];
+ if (!impl_->ReadFully(addr_page << kCacheBits, cache_dst, kCacheSize)) {
+ // Erase the entry.
+ cache_.erase(addr_page);
+ return impl_->Read(addr, dst, size);
+ }
+ }
+ size_t max_read = ((addr_page + 1) << kCacheBits) - addr;
+ if (size <= max_read) {
+ memcpy(dst, &cache_dst[addr & kCacheMask], size);
+ return size;
+ }
+
+ // The read crossed into another cached entry, since a read can only cross
+ // into one extra cached page, duplicate the code rather than looping.
+ memcpy(dst, &cache_dst[addr & kCacheMask], max_read);
+ dst = &reinterpret_cast<uint8_t*>(dst)[max_read];
+ addr_page++;
+
+ entry = cache_.find(addr_page);
+ if (entry != cache_.end()) {
+ cache_dst = entry->second;
+ } else {
+ cache_dst = cache_[addr_page];
+ if (!impl_->ReadFully(addr_page << kCacheBits, cache_dst, kCacheSize)) {
+ // Erase the entry.
+ cache_.erase(addr_page);
+ return impl_->Read(addr_page << kCacheBits, dst, size - max_read) + max_read;
+ }
+ }
+ memcpy(dst, cache_dst, size - max_read);
+ return size;
+}
+
} // namespace unwindstack
diff --git a/libunwindstack/benchmarks/unwind_benchmarks.cpp b/libunwindstack/benchmarks/unwind_benchmarks.cpp
new file mode 100644
index 0000000..db0fb54
--- /dev/null
+++ b/libunwindstack/benchmarks/unwind_benchmarks.cpp
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdint.h>
+
+#include <memory>
+
+#include <benchmark/benchmark.h>
+
+#include <unwindstack/Maps.h>
+#include <unwindstack/Memory.h>
+#include <unwindstack/Regs.h>
+#include <unwindstack/RegsGetLocal.h>
+#include <unwindstack/Unwinder.h>
+
+size_t Call6(std::shared_ptr<unwindstack::Memory>& process_memory, unwindstack::Maps* maps) {
+ std::unique_ptr<unwindstack::Regs> regs(unwindstack::Regs::CreateFromLocal());
+ unwindstack::RegsGetLocal(regs.get());
+ unwindstack::Unwinder unwinder(32, maps, regs.get(), process_memory);
+ unwinder.Unwind();
+ return unwinder.NumFrames();
+}
+
+size_t Call5(std::shared_ptr<unwindstack::Memory>& process_memory, unwindstack::Maps* maps) {
+ return Call6(process_memory, maps);
+}
+
+size_t Call4(std::shared_ptr<unwindstack::Memory>& process_memory, unwindstack::Maps* maps) {
+ return Call5(process_memory, maps);
+}
+
+size_t Call3(std::shared_ptr<unwindstack::Memory>& process_memory, unwindstack::Maps* maps) {
+ return Call4(process_memory, maps);
+}
+
+size_t Call2(std::shared_ptr<unwindstack::Memory>& process_memory, unwindstack::Maps* maps) {
+ return Call3(process_memory, maps);
+}
+
+size_t Call1(std::shared_ptr<unwindstack::Memory>& process_memory, unwindstack::Maps* maps) {
+ return Call2(process_memory, maps);
+}
+
+static void BM_uncached_unwind(benchmark::State& state) {
+ auto process_memory = unwindstack::Memory::CreateProcessMemory(getpid());
+ unwindstack::LocalMaps maps;
+ if (!maps.Parse()) {
+ state.SkipWithError("Failed to parse local maps.");
+ }
+
+ for (auto _ : state) {
+ benchmark::DoNotOptimize(Call1(process_memory, &maps));
+ }
+}
+BENCHMARK(BM_uncached_unwind);
+
+static void BM_cached_unwind(benchmark::State& state) {
+ auto process_memory = unwindstack::Memory::CreateProcessMemoryCached(getpid());
+ unwindstack::LocalMaps maps;
+ if (!maps.Parse()) {
+ state.SkipWithError("Failed to parse local maps.");
+ }
+
+ for (auto _ : state) {
+ benchmark::DoNotOptimize(Call1(process_memory, &maps));
+ }
+}
+BENCHMARK(BM_cached_unwind);
+
+BENCHMARK_MAIN();
diff --git a/libunwindstack/include/unwindstack/Memory.h b/libunwindstack/include/unwindstack/Memory.h
index 9c425cb..dba41d1 100644
--- a/libunwindstack/include/unwindstack/Memory.h
+++ b/libunwindstack/include/unwindstack/Memory.h
@@ -25,6 +25,7 @@
#include <map>
#include <memory>
#include <string>
+#include <unordered_map>
#include <vector>
namespace unwindstack {
@@ -35,9 +36,12 @@
virtual ~Memory() = default;
static std::shared_ptr<Memory> CreateProcessMemory(pid_t pid);
+ static std::shared_ptr<Memory> CreateProcessMemoryCached(pid_t pid);
virtual bool ReadString(uint64_t addr, std::string* string, uint64_t max_read = UINT64_MAX);
+ virtual void Clear() {}
+
virtual size_t Read(uint64_t addr, void* dst, size_t size) = 0;
bool ReadFully(uint64_t addr, void* dst, size_t size);
@@ -51,6 +55,24 @@
}
};
+class MemoryCache : public Memory {
+ public:
+ MemoryCache(Memory* memory) : impl_(memory) {}
+ virtual ~MemoryCache() = default;
+
+ size_t Read(uint64_t addr, void* dst, size_t size) override;
+
+ void Clear() override { cache_.clear(); }
+
+ private:
+ constexpr static size_t kCacheBits = 12;
+ constexpr static size_t kCacheMask = (1 << kCacheBits) - 1;
+ constexpr static size_t kCacheSize = 1 << kCacheBits;
+ std::unordered_map<uint64_t, uint8_t[kCacheSize]> cache_;
+
+ std::unique_ptr<Memory> impl_;
+};
+
class MemoryBuffer : public Memory {
public:
MemoryBuffer() = default;
diff --git a/libunwindstack/tests/MemoryCacheTest.cpp b/libunwindstack/tests/MemoryCacheTest.cpp
new file mode 100644
index 0000000..a3def20
--- /dev/null
+++ b/libunwindstack/tests/MemoryCacheTest.cpp
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdint.h>
+
+#include <vector>
+
+#include <gtest/gtest.h>
+
+#include <unwindstack/Memory.h>
+
+#include "MemoryFake.h"
+
+namespace unwindstack {
+
+class MemoryCacheTest : public ::testing::Test {
+ protected:
+ void SetUp() override {
+ memory_ = new MemoryFake;
+ memory_cache_.reset(new MemoryCache(memory_));
+
+ memory_->SetMemoryBlock(0x8000, 4096, 0xab);
+ memory_->SetMemoryBlock(0x9000, 4096, 0xde);
+ memory_->SetMemoryBlock(0xa000, 3000, 0x50);
+ }
+
+ MemoryFake* memory_;
+ std::unique_ptr<MemoryCache> memory_cache_;
+
+ constexpr static size_t kMaxCachedSize = 64;
+};
+
+TEST_F(MemoryCacheTest, cached_read) {
+ for (size_t i = 1; i <= kMaxCachedSize; i++) {
+ std::vector<uint8_t> buffer(i);
+ ASSERT_TRUE(memory_cache_->ReadFully(0x8000 + i, buffer.data(), i))
+ << "Read failed at size " << i;
+ ASSERT_EQ(std::vector<uint8_t>(i, 0xab), buffer) << "Failed at size " << i;
+ }
+
+ // Verify the cached data is used.
+ memory_->SetMemoryBlock(0x8000, 4096, 0xff);
+ for (size_t i = 1; i <= kMaxCachedSize; i++) {
+ std::vector<uint8_t> buffer(i);
+ ASSERT_TRUE(memory_cache_->ReadFully(0x8000 + i, buffer.data(), i))
+ << "Read failed at size " << i;
+ ASSERT_EQ(std::vector<uint8_t>(i, 0xab), buffer) << "Failed at size " << i;
+ }
+}
+
+TEST_F(MemoryCacheTest, no_cached_read_after_clear) {
+ for (size_t i = 1; i <= kMaxCachedSize; i++) {
+ std::vector<uint8_t> buffer(i);
+ ASSERT_TRUE(memory_cache_->ReadFully(0x8000 + i, buffer.data(), i))
+ << "Read failed at size " << i;
+ ASSERT_EQ(std::vector<uint8_t>(i, 0xab), buffer) << "Failed at size " << i;
+ }
+
+ // Verify the cached data is not used after a reset.
+ memory_cache_->Clear();
+ memory_->SetMemoryBlock(0x8000, 4096, 0xff);
+ for (size_t i = 1; i <= kMaxCachedSize; i++) {
+ std::vector<uint8_t> buffer(i);
+ ASSERT_TRUE(memory_cache_->ReadFully(0x8000 + i, buffer.data(), i))
+ << "Read failed at size " << i;
+ ASSERT_EQ(std::vector<uint8_t>(i, 0xff), buffer) << "Failed at size " << i;
+ }
+}
+
+TEST_F(MemoryCacheTest, cached_read_across_caches) {
+ std::vector<uint8_t> expect(16, 0xab);
+ expect.resize(32, 0xde);
+
+ std::vector<uint8_t> buffer(32);
+ ASSERT_TRUE(memory_cache_->ReadFully(0x8ff0, buffer.data(), 32));
+ ASSERT_EQ(expect, buffer);
+
+ // Verify the cached data is used.
+ memory_->SetMemoryBlock(0x8000, 4096, 0xff);
+ memory_->SetMemoryBlock(0x9000, 4096, 0xff);
+ ASSERT_TRUE(memory_cache_->ReadFully(0x8ff0, buffer.data(), 32));
+ ASSERT_EQ(expect, buffer);
+}
+
+TEST_F(MemoryCacheTest, no_cache_read) {
+ for (size_t i = kMaxCachedSize + 1; i < 2 * kMaxCachedSize; i++) {
+ std::vector<uint8_t> buffer(i);
+ ASSERT_TRUE(memory_cache_->ReadFully(0x8000 + i, buffer.data(), i))
+ << "Read failed at size " << i;
+ ASSERT_EQ(std::vector<uint8_t>(i, 0xab), buffer) << "Failed at size " << i;
+ }
+
+ // Verify the cached data is not used.
+ memory_->SetMemoryBlock(0x8000, 4096, 0xff);
+ for (size_t i = kMaxCachedSize + 1; i < 2 * kMaxCachedSize; i++) {
+ std::vector<uint8_t> buffer(i);
+ ASSERT_TRUE(memory_cache_->ReadFully(0x8000 + i, buffer.data(), i))
+ << "Read failed at size " << i;
+ ASSERT_EQ(std::vector<uint8_t>(i, 0xff), buffer) << "Failed at size " << i;
+ }
+}
+
+TEST_F(MemoryCacheTest, read_for_cache_fail) {
+ std::vector<uint8_t> buffer(kMaxCachedSize);
+ ASSERT_TRUE(memory_cache_->ReadFully(0xa010, buffer.data(), kMaxCachedSize));
+ ASSERT_EQ(std::vector<uint8_t>(kMaxCachedSize, 0x50), buffer);
+
+ // Verify the cached data is not used.
+ memory_->SetMemoryBlock(0xa000, 3000, 0xff);
+ ASSERT_TRUE(memory_cache_->ReadFully(0xa010, buffer.data(), kMaxCachedSize));
+ ASSERT_EQ(std::vector<uint8_t>(kMaxCachedSize, 0xff), buffer);
+}
+
+TEST_F(MemoryCacheTest, read_for_cache_fail_cross) {
+ std::vector<uint8_t> expect(16, 0xde);
+ expect.resize(32, 0x50);
+
+ std::vector<uint8_t> buffer(32);
+ ASSERT_TRUE(memory_cache_->ReadFully(0x9ff0, buffer.data(), 32));
+ ASSERT_EQ(expect, buffer);
+
+ // Verify the cached data is not used for the second half but for the first.
+ memory_->SetMemoryBlock(0xa000, 3000, 0xff);
+ ASSERT_TRUE(memory_cache_->ReadFully(0x9ff0, buffer.data(), 32));
+ expect.resize(16);
+ expect.resize(32, 0xff);
+ ASSERT_EQ(expect, buffer);
+}
+
+} // namespace unwindstack
diff --git a/libziparchive/Android.bp b/libziparchive/Android.bp
index 2095189..9538bba 100644
--- a/libziparchive/Android.bp
+++ b/libziparchive/Android.bp
@@ -125,6 +125,7 @@
enabled: true,
},
},
+ test_suites: ["device-tests"],
}
// Performance benchmarks.
diff --git a/logd/LogAudit.cpp b/logd/LogAudit.cpp
index fc8c960..18d5287 100644
--- a/logd/LogAudit.cpp
+++ b/logd/LogAudit.cpp
@@ -165,9 +165,14 @@
bug_num->assign("");
}
+ // Ensure the uid name is not null before passing it to the bug string.
if (uid >= AID_APP_START && uid <= AID_APP_END) {
- bug_num->append(" app=");
- bug_num->append(android::uidToName(uid));
+ char* uidname = android::uidToName(uid);
+ if (uidname) {
+ bug_num->append(" app=");
+ bug_num->append(uidname);
+ free(uidname);
+ }
}
}
diff --git a/rootdir/etc/ld.config.legacy.txt b/rootdir/etc/ld.config.legacy.txt
index ca6aafe..461184a 100644
--- a/rootdir/etc/ld.config.legacy.txt
+++ b/rootdir/etc/ld.config.legacy.txt
@@ -6,35 +6,40 @@
# All binaries gets the same configuration 'legacy'
dir.legacy = /system
+dir.legacy = /product
dir.legacy = /vendor
dir.legacy = /odm
dir.legacy = /sbin
-# Except for /postinstall, where only /system is searched
+# Except for /postinstall, where only /system and /product are searched
dir.postinstall = /postinstall
[legacy]
namespace.default.isolated = false
namespace.default.search.paths = /system/${LIB}
+namespace.default.search.paths += /product/${LIB}
namespace.default.search.paths += /vendor/${LIB}
namespace.default.search.paths += /odm/${LIB}
namespace.default.asan.search.paths = /data/asan/system/${LIB}
namespace.default.asan.search.paths += /system/${LIB}
-namespace.default.asan.search.paths += /data/asan/odm/${LIB}
-namespace.default.asan.search.paths += /odm/${LIB}
+namespace.default.asan.search.paths += /data/asan/product/${LIB}
+namespace.default.asan.search.paths += /product/${LIB}
namespace.default.asan.search.paths += /data/asan/vendor/${LIB}
namespace.default.asan.search.paths += /vendor/${LIB}
+namespace.default.asan.search.paths += /data/asan/odm/${LIB}
+namespace.default.asan.search.paths += /odm/${LIB}
###############################################################################
# Namespace config for binaries under /postinstall.
# Only one default namespace is defined and it has no directories other than
-# /system/lib in the search paths. This is because linker calls realpath on the
-# search paths and this causes selinux denial if the paths (/vendor, /odm) are
-# not allowed to the poinstall binaries. There is no reason to allow the
-# binaries to access the paths.
+# /system/lib and /product/lib in the search paths. This is because linker
+# calls realpath on the search paths and this causes selinux denial if the
+# paths (/vendor, /odm) are not allowed to the poinstall binaries.
+# There is no reason to allow the binaries to access the paths.
###############################################################################
[postinstall]
namespace.default.isolated = false
-namespace.default.search.paths = /system/${LIB}
+namespace.default.search.paths = /system/${LIB}
+namespace.default.search.paths += /product/${LIB}
diff --git a/rootdir/ueventd.rc b/rootdir/ueventd.rc
index 2f85dec..d47506c 100644
--- a/rootdir/ueventd.rc
+++ b/rootdir/ueventd.rc
@@ -72,7 +72,7 @@
/dev/diag_arm9 0660 radio radio
/dev/ttyMSM0 0600 bluetooth bluetooth
/dev/uhid 0660 uhid uhid
-/dev/uinput 0660 system bluetooth
+/dev/uinput 0660 uhid uhid
/dev/alarm 0664 system radio
/dev/rtc0 0640 system system
/dev/tty0 0660 root system