Merge "Modify the mmc data structure."
diff --git a/code_coverage/Android.bp b/code_coverage/Android.bp
index 2cb1617..d18e7a8 100644
--- a/code_coverage/Android.bp
+++ b/code_coverage/Android.bp
@@ -24,6 +24,14 @@
},
},
},
+ riscv64: {
+ src: "empty_policy/code_coverage.riscv64.policy",
+ product_variables: {
+ native_coverage: {
+ src: "seccomp_policy/code_coverage.riscv64.policy",
+ },
+ },
+ },
x86: {
src: "empty_policy/code_coverage.x86.policy",
product_variables: {
@@ -67,6 +75,10 @@
},
},
},
+ riscv64: {
+ // riscv64 doesn't have a secondary architecture.
+ enabled: false,
+ },
x86: {
src: "empty_policy/code_coverage.x86_64.policy",
product_variables: {
diff --git a/code_coverage/empty_policy/code_coverage.riscv64.policy b/code_coverage/empty_policy/code_coverage.riscv64.policy
new file mode 100644
index 0000000..9456932
--- /dev/null
+++ b/code_coverage/empty_policy/code_coverage.riscv64.policy
@@ -0,0 +1,2 @@
+# empty unless code_coverage is enabled.
+# code_coverage.riscv64.policy
diff --git a/code_coverage/seccomp_policy/code_coverage.riscv64.policy b/code_coverage/seccomp_policy/code_coverage.riscv64.policy
new file mode 100644
index 0000000..fdb4d1e
--- /dev/null
+++ b/code_coverage/seccomp_policy/code_coverage.riscv64.policy
@@ -0,0 +1,15 @@
+close: 1
+fchmod: 1
+mkdirat: 1
+msync: 1
+munmap: 1
+openat: 1
+write: 1
+fcntl: 1
+fstat: 1
+ftruncate: 1
+geteuid: 1
+lseek: 1
+mmap: 1
+rt_sigreturn: 1
+prctl: 1
diff --git a/debuggerd/Android.bp b/debuggerd/Android.bp
index 1c89472..7afbbe7 100644
--- a/debuggerd/Android.bp
+++ b/debuggerd/Android.bp
@@ -426,8 +426,8 @@
local_include_dirs: ["include"],
}
-cc_binary {
- name: "tombstoned",
+cc_defaults {
+ name: "tombstoned_defaults",
srcs: [
"util.cpp",
"tombstoned/intercept_manager.cpp",
@@ -446,10 +446,20 @@
"libevent",
"liblog",
],
+}
+cc_binary {
+ name: "tombstoned",
+ defaults: ["tombstoned_defaults"],
init_rc: ["tombstoned/tombstoned.rc"],
}
+cc_binary {
+ name: "tombstoned.microdroid",
+ defaults: ["tombstoned_defaults"],
+ init_rc: ["tombstoned/tombstoned.microdroid.rc"],
+}
+
prebuilt_etc {
name: "crash_dump.policy",
sub_dir: "seccomp_policy",
@@ -461,6 +471,9 @@
arm64: {
src: "seccomp_policy/crash_dump.arm64.policy",
},
+ riscv64: {
+ src: "seccomp_policy/crash_dump.riscv64.policy",
+ },
x86: {
src: "seccomp_policy/crash_dump.x86.policy",
},
diff --git a/debuggerd/crasher/Android.bp b/debuggerd/crasher/Android.bp
index 799163e..3af806b 100644
--- a/debuggerd/crasher/Android.bp
+++ b/debuggerd/crasher/Android.bp
@@ -19,14 +19,13 @@
arch: {
arm: {
srcs: ["arm/crashglue.S"],
-
- neon: {
- asflags: ["-DHAS_VFP_D32"],
- },
},
arm64: {
srcs: ["arm64/crashglue.S"],
},
+ riscv64: {
+ srcs: ["riscv64/crashglue.S"],
+ },
x86: {
srcs: ["x86/crashglue.S"],
},
diff --git a/debuggerd/crasher/arm/crashglue.S b/debuggerd/crasher/arm/crashglue.S
index 4fbfd6e..8649056 100644
--- a/debuggerd/crasher/arm/crashglue.S
+++ b/debuggerd/crasher/arm/crashglue.S
@@ -32,7 +32,6 @@
fconstd d13, #13
fconstd d14, #14
fconstd d15, #15
-#if defined(HAS_VFP_D32)
fconstd d16, #16
fconstd d17, #17
fconstd d18, #18
@@ -49,7 +48,6 @@
fconstd d29, #29
fconstd d30, #30
fconstd d31, #31
-#endif
mov lr, #0
ldr lr, [lr]
diff --git a/debuggerd/crasher/crasher.cpp b/debuggerd/crasher/crasher.cpp
index 55490b5..4eb7382 100644
--- a/debuggerd/crasher/crasher.cpp
+++ b/debuggerd/crasher/crasher.cpp
@@ -303,6 +303,8 @@
__asm__ volatile(".word 0xe7f0def0\n");
#elif defined(__i386__) || defined(__x86_64__)
__asm__ volatile("ud2\n");
+#elif defined(__riscv)
+ __asm__ volatile("unimp\n");
#else
#error
#endif
diff --git a/debuggerd/crasher/riscv64/crashglue.S b/debuggerd/crasher/riscv64/crashglue.S
new file mode 100644
index 0000000..47dd93b
--- /dev/null
+++ b/debuggerd/crasher/riscv64/crashglue.S
@@ -0,0 +1,45 @@
+
+ .globl crash1
+ .globl crashnostack
+
+crash1:
+ li x0,0xdead0000+0
+ li x1,0xdead0000+1
+ li x2,0xdead0000+2
+ li x3,0xdead0000+3
+ li x4,0xdead0000+4
+ li x5,0xdead0000+5
+ li x6,0xdead0000+6
+ li x7,0xdead0000+7
+ li x8,0xdead0000+8
+ li x9,0xdead0000+9
+ li x10,0xdead0000+10
+ li x11,0xdead0000+11
+ li x12,0xdead0000+12
+ li x13,0xdead0000+13
+ li x14,0xdead0000+14
+ li x15,0xdead0000+15
+ li x16,0xdead0000+16
+ li x17,0xdead0000+17
+ li x18,0xdead0000+18
+ li x19,0xdead0000+19
+ li x20,0xdead0000+20
+ li x21,0xdead0000+21
+ li x22,0xdead0000+22
+ li x23,0xdead0000+23
+ li x24,0xdead0000+24
+ li x25,0xdead0000+25
+ li x26,0xdead0000+26
+ li x27,0xdead0000+27
+ li x28,0xdead0000+28
+ # don't trash the stack otherwise the signal handler won't run
+ #li $29,0xdead0000+29
+ li x30,0xdead0000+30
+ li x31,0xdead0000+31
+
+ j .
+
+
+crashnostack:
+ li sp, 0
+ j .
diff --git a/debuggerd/debuggerd_test.cpp b/debuggerd/debuggerd_test.cpp
index aca476f..9c1b136 100644
--- a/debuggerd/debuggerd_test.cpp
+++ b/debuggerd/debuggerd_test.cpp
@@ -406,10 +406,10 @@
result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x[01]00000000000dead)");
}
-// Marked as weak to prevent the compiler from removing the malloc in the caller. In theory, the
-// compiler could still clobber the argument register before trapping, but that's unlikely.
-__attribute__((weak)) void CrasherTest::Trap(void* ptr ATTRIBUTE_UNUSED) {
- __builtin_trap();
+void CrasherTest::Trap(void* ptr) {
+ void (*volatile f)(void*) = nullptr;
+ __asm__ __volatile__("" : : "r"(f) : "memory");
+ f(ptr);
}
TEST_F(CrasherTest, heap_addr_in_register) {
@@ -445,6 +445,8 @@
ASSERT_MATCH(result, "memory near x0 \\(\\[anon:");
#elif defined(__arm__)
ASSERT_MATCH(result, "memory near r0 \\(\\[anon:");
+#elif defined(__riscv)
+ ASSERT_MATCH(result, "memory near a0 \\(\\[anon:");
#elif defined(__x86_64__)
ASSERT_MATCH(result, "memory near rdi \\(\\[anon:");
#else
@@ -828,7 +830,7 @@
StartIntercept(&output_fd);
FinishCrasher();
- AssertDeath(SIGTRAP);
+ AssertDeath(SIGSEGV);
FinishIntercept(&intercept_result);
ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
diff --git a/debuggerd/libdebuggerd/tombstone.cpp b/debuggerd/libdebuggerd/tombstone.cpp
index e5b4d74..375ed8a 100644
--- a/debuggerd/libdebuggerd/tombstone.cpp
+++ b/debuggerd/libdebuggerd/tombstone.cpp
@@ -77,9 +77,9 @@
.registers = std::move(regs), .uid = uid, .tid = target_tid,
.thread_name = std::move(thread_name), .pid = pid, .command_line = std::move(command_line),
.selinux_label = std::move(selinux_label), .siginfo = siginfo,
-#if defined(__aarch64__)
// Only supported on aarch64 for now.
- .tagged_addr_ctrl = prctl(PR_GET_TAGGED_ADDR_CTRL, 0, 0, 0, 0),
+#if defined(__aarch64__)
+ .tagged_addr_ctrl = prctl(PR_GET_TAGGED_ADDR_CTRL, 0, 0, 0, 0),
.pac_enabled_keys = prctl(PR_PAC_GET_ENABLED_KEYS, 0, 0, 0, 0),
#endif
};
@@ -88,7 +88,6 @@
if (target_tid == tid) {
return;
}
- async_safe_format_log(ANDROID_LOG_ERROR, LOG_TAG, "Adding thread %d", tid);
threads[tid] = ThreadInfo{
.uid = thread.uid,
.tid = tid,
diff --git a/debuggerd/libdebuggerd/tombstone_proto.cpp b/debuggerd/libdebuggerd/tombstone_proto.cpp
index 159ebc8..9a565de 100644
--- a/debuggerd/libdebuggerd/tombstone_proto.cpp
+++ b/debuggerd/libdebuggerd/tombstone_proto.cpp
@@ -82,6 +82,8 @@
return Architecture::X86;
#elif defined(__x86_64__)
return Architecture::X86_64;
+#elif defined(__riscv) && (__riscv_xlen == 64)
+ return Architecture::RISCV64;
#else
#error Unknown architecture!
#endif
diff --git a/debuggerd/libdebuggerd/tombstone_proto_to_text.cpp b/debuggerd/libdebuggerd/tombstone_proto_to_text.cpp
index 0265641..28154a7 100644
--- a/debuggerd/libdebuggerd/tombstone_proto_to_text.cpp
+++ b/debuggerd/libdebuggerd/tombstone_proto_to_text.cpp
@@ -47,6 +47,8 @@
return "arm";
case Architecture::ARM64:
return "arm64";
+ case Architecture::RISCV64:
+ return "riscv64";
case Architecture::X86:
return "x86";
case Architecture::X86_64:
@@ -62,6 +64,8 @@
return 4;
case Architecture::ARM64:
return 8;
+ case Architecture::RISCV64:
+ return 8;
case Architecture::X86:
return 4;
case Architecture::X86_64:
@@ -119,6 +123,10 @@
special_registers = {"ip", "lr", "sp", "pc", "pst"};
break;
+ case Architecture::RISCV64:
+ special_registers = {"ra", "sp", "pc"};
+ break;
+
case Architecture::X86:
special_registers = {"ebp", "esp", "eip"};
break;
diff --git a/debuggerd/proto/tombstone.proto b/debuggerd/proto/tombstone.proto
index f0d3d3f..49865a2 100644
--- a/debuggerd/proto/tombstone.proto
+++ b/debuggerd/proto/tombstone.proto
@@ -48,8 +48,9 @@
ARM64 = 1;
X86 = 2;
X86_64 = 3;
+ RISCV64 = 4;
- reserved 4 to 999;
+ reserved 5 to 999;
}
message Signal {
diff --git a/debuggerd/seccomp_policy/crash_dump.riscv64.policy b/debuggerd/seccomp_policy/crash_dump.riscv64.policy
new file mode 100644
index 0000000..21887ab
--- /dev/null
+++ b/debuggerd/seccomp_policy/crash_dump.riscv64.policy
@@ -0,0 +1,37 @@
+read: 1
+write: 1
+exit: 1
+rt_sigreturn: 1
+exit_group: 1
+clock_gettime: 1
+gettimeofday: 1
+futex: 1
+getrandom: 1
+getpid: 1
+gettid: 1
+ppoll: 1
+pipe2: 1
+openat: 1
+dup: 1
+close: 1
+lseek: 1
+getdents64: 1
+faccessat: 1
+recvmsg: 1
+recvfrom: 1
+process_vm_readv: 1
+tgkill: 1
+rt_sigprocmask: 1
+rt_sigaction: 1
+rt_tgsigqueueinfo: 1
+prctl: arg0 == PR_GET_NO_NEW_PRIVS || arg0 == 0x53564d41 || arg0 == PR_PAC_RESET_KEYS
+madvise: 1
+mprotect: arg2 in 0x1|0x2
+munmap: 1
+getuid: 1
+fstat: 1
+mmap: arg2 in 0x1|0x2
+geteuid: 1
+getgid: 1
+getegid: 1
+getgroups: 1
diff --git a/debuggerd/seccomp_policy/generate.sh b/debuggerd/seccomp_policy/generate.sh
index 8c58b05..c467d9e 100755
--- a/debuggerd/seccomp_policy/generate.sh
+++ b/debuggerd/seccomp_policy/generate.sh
@@ -6,5 +6,6 @@
CPP='cpp -undef -E -P crash_dump.policy.def'
$CPP -D__arm__ -o crash_dump.arm.policy
$CPP -D__aarch64__ -D__LP64__ -o crash_dump.arm64.policy
+$CPP -D__riscv -D__LP64__ -o crash_dump.riscv64.policy
$CPP -D__i386__ -o crash_dump.x86.policy
$CPP -D__x86_64__ -D__LP64__ -o crash_dump.x86_64.policy
diff --git a/debuggerd/tombstoned/tombstoned.microdroid.rc b/debuggerd/tombstoned/tombstoned.microdroid.rc
new file mode 100644
index 0000000..7f5c542
--- /dev/null
+++ b/debuggerd/tombstoned/tombstoned.microdroid.rc
@@ -0,0 +1,7 @@
+service tombstoned /system/bin/tombstoned.microdroid
+ user tombstoned
+ group system
+
+ socket tombstoned_crash seqpacket 0666 system system
+ socket tombstoned_intercept seqpacket 0666 system system
+ socket tombstoned_java_trace seqpacket 0666 system system
diff --git a/fastboot/Android.bp b/fastboot/Android.bp
index b478e6e..eed49fa 100644
--- a/fastboot/Android.bp
+++ b/fastboot/Android.bp
@@ -342,6 +342,8 @@
targets: [
"dist_files",
"sdk",
+ "sdk-repo-platform-tools",
+ "sdk_repo",
"win_sdk",
],
},
diff --git a/fs_mgr/Android.bp b/fs_mgr/Android.bp
index 45cd3c0..bebf19e 100644
--- a/fs_mgr/Android.bp
+++ b/fs_mgr/Android.bp
@@ -223,7 +223,6 @@
"libcutils",
"libcrypto",
"libext4_utils",
- "libfec",
"libfs_mgr_binder",
"liblog",
"liblp",
diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp
index 27137a2..1c1ab48 100644
--- a/fs_mgr/fs_mgr.cpp
+++ b/fs_mgr/fs_mgr.cpp
@@ -2191,36 +2191,22 @@
std::vector<std::string> tokens = android::base::Split(target.data, " \t\r\n");
if (tokens[0] != "0" && tokens[0] != "1") {
LOG(WARNING) << "Unrecognized device mapper version in " << target.data;
- return {};
}
// Hashtree algorithm & root digest are the 8th & 9th token in the output.
- return HashtreeInfo{.algorithm = android::base::Trim(tokens[7]),
- .root_digest = android::base::Trim(tokens[8])};
+ return HashtreeInfo{
+ .algorithm = android::base::Trim(tokens[7]),
+ .root_digest = android::base::Trim(tokens[8]),
+ .check_at_most_once = target.data.find("check_at_most_once") != std::string::npos};
}
return {};
}
bool fs_mgr_verity_is_check_at_most_once(const android::fs_mgr::FstabEntry& entry) {
- if (!entry.fs_mgr_flags.avb) {
- return false;
- }
-
- DeviceMapper& dm = DeviceMapper::Instance();
- std::string device = GetVerityDeviceName(entry);
-
- std::vector<DeviceMapper::TargetInfo> table;
- if (dm.GetState(device) == DmDeviceState::INVALID || !dm.GetTableInfo(device, &table)) {
- return false;
- }
- for (const auto& target : table) {
- if (strcmp(target.spec.target_type, "verity") == 0 &&
- target.data.find("check_at_most_once") != std::string::npos) {
- return true;
- }
- }
- return false;
+ auto hashtree_info = fs_mgr_get_hashtree_info(entry);
+ if (!hashtree_info) return false;
+ return hashtree_info->check_at_most_once;
}
std::string fs_mgr_get_super_partition_name(int slot) {
diff --git a/fs_mgr/fs_mgr_fstab.cpp b/fs_mgr/fs_mgr_fstab.cpp
index 76ef9e4..7189a71 100644
--- a/fs_mgr/fs_mgr_fstab.cpp
+++ b/fs_mgr/fs_mgr_fstab.cpp
@@ -754,10 +754,11 @@
}
#ifdef NO_SKIP_MOUNT
-bool SkipMountingPartitions(Fstab*, bool) {
- return true;
-}
+static constexpr bool kNoSkipMount = true;
#else
+static constexpr bool kNoSkipMount = false;
+#endif
+
// For GSI to skip mounting /product and /system_ext, until there are well-defined interfaces
// between them and /system. Otherwise, the GSI flashed on /system might not be able to work with
// device-specific /product and /system_ext. skip_mount.cfg belongs to system_ext partition because
@@ -765,17 +766,24 @@
// /system/system_ext because GSI is a single system.img that includes the contents of system_ext
// partition and product partition under /system/system_ext and /system/product, respectively.
bool SkipMountingPartitions(Fstab* fstab, bool verbose) {
- static constexpr char kSkipMountConfig[] = "/system/system_ext/etc/init/config/skip_mount.cfg";
-
- std::string skip_config;
- auto save_errno = errno;
- if (!ReadFileToString(kSkipMountConfig, &skip_config)) {
- errno = save_errno; // missing file is expected
+ if (kNoSkipMount) {
return true;
}
+ static constexpr char kSkipMountConfig[] = "/system/system_ext/etc/init/config/skip_mount.cfg";
+
+ std::string skip_mount_config;
+ auto save_errno = errno;
+ if (!ReadFileToString(kSkipMountConfig, &skip_mount_config)) {
+ errno = save_errno; // missing file is expected
+ return true;
+ }
+ return SkipMountWithConfig(skip_mount_config, fstab, verbose);
+}
+
+bool SkipMountWithConfig(const std::string& skip_mount_config, Fstab* fstab, bool verbose) {
std::vector<std::string> skip_mount_patterns;
- for (const auto& line : Split(skip_config, "\n")) {
+ for (const auto& line : Split(skip_mount_config, "\n")) {
if (line.empty() || StartsWith(line, "#")) {
continue;
}
@@ -801,7 +809,6 @@
fstab->erase(remove_from, fstab->end());
return true;
}
-#endif
// Loads the fstab file and combines with fstab entries passed in from device tree.
bool ReadDefaultFstab(Fstab* fstab) {
diff --git a/fs_mgr/fs_mgr_overlayfs.cpp b/fs_mgr/fs_mgr_overlayfs.cpp
index df26d85..5468fb8e 100644
--- a/fs_mgr/fs_mgr_overlayfs.cpp
+++ b/fs_mgr/fs_mgr_overlayfs.cpp
@@ -68,6 +68,8 @@
namespace {
+constexpr char kDataScratchSizeMbProp[] = "fs_mgr.overlayfs.data_scratch_size_mb";
+
bool fs_mgr_access(const std::string& path) {
return access(path.c_str(), F_OK) == 0;
}
@@ -120,13 +122,9 @@
return !stat(path.c_str(), &st) && S_ISDIR(st.st_mode);
}
-// Similar test as overlayfs workdir= validation in the kernel for read-write
-// validation, except we use fs_mgr_work. Covers space and storage issues.
-bool fs_mgr_dir_is_writable(const std::string& path) {
- auto test_directory = path + "/fs_mgr_work";
- rmdir(test_directory.c_str());
- auto ret = !mkdir(test_directory.c_str(), 0700);
- return ret | !rmdir(test_directory.c_str());
+bool fs_mgr_rw_access(const std::string& path) {
+ if (path.empty()) return false;
+ return access(path.c_str(), R_OK | W_OK) == 0;
}
// At less than 1% or 8MB of free space return value of false,
@@ -204,6 +202,24 @@
return (info.feat_ro_compat & EXT4_FEATURE_RO_COMPAT_SHARED_BLOCKS) != 0;
}
+#define F2FS_SUPER_OFFSET 1024
+#define F2FS_FEATURE_OFFSET 2180
+#define F2FS_FEATURE_RO 0x4000
+bool fs_mgr_is_read_only_f2fs(const std::string& dev) {
+ if (!fs_mgr_is_f2fs(dev)) return false;
+
+ android::base::unique_fd fd(open(dev.c_str(), O_RDONLY | O_CLOEXEC));
+ if (fd < 0) return false;
+
+ __le32 feat;
+ if ((TEMP_FAILURE_RETRY(lseek64(fd, F2FS_SUPER_OFFSET + F2FS_FEATURE_OFFSET, SEEK_SET)) < 0) ||
+ (TEMP_FAILURE_RETRY(read(fd, &feat, sizeof(feat))) < 0)) {
+ return false;
+ }
+
+ return (feat & cpu_to_le32(F2FS_FEATURE_RO)) != 0;
+}
+
bool fs_mgr_overlayfs_enabled(FstabEntry* entry) {
// readonly filesystem, can not be mount -o remount,rw
// for squashfs, erofs or if free space is (near) zero making such a remount
@@ -218,6 +234,11 @@
return true;
}
+ // f2fs read-only mode doesn't support remount,rw
+ if (fs_mgr_is_read_only_f2fs(entry->blk_device)) {
+ return true;
+ }
+
// check if ext4 de-dupe
auto has_shared_blocks = fs_mgr_has_shared_blocks(entry->mount_point, entry->blk_device);
if (!has_shared_blocks && (entry->mount_point == "/system")) {
@@ -280,7 +301,7 @@
if (!fs_mgr_is_dir(upper)) continue;
auto work = dir + kWorkName;
if (!fs_mgr_is_dir(work)) continue;
- if (!fs_mgr_dir_is_writable(work)) continue;
+ if (!fs_mgr_rw_access(work)) continue;
return dir;
}
return "";
@@ -317,11 +338,6 @@
return "/system";
}
-bool fs_mgr_rw_access(const std::string& path) {
- if (path.empty()) return false;
- return access(path.c_str(), R_OK | W_OK) == 0;
-}
-
constexpr char kOverlayfsFileContext[] = "u:object_r:overlayfs_file:s0";
class AutoSetFsCreateCon final {
@@ -446,6 +462,28 @@
return true;
}
+OverlayfsTeardownResult TeardownDataScratch(IImageManager* images,
+ const std::string& partition_name, bool was_mounted) {
+ if (!images) {
+ return OverlayfsTeardownResult::Error;
+ }
+ if (!images->DisableImage(partition_name)) {
+ return OverlayfsTeardownResult::Error;
+ }
+ if (was_mounted) {
+ // If overlayfs was mounted, don't bother trying to unmap since
+ // it'll fail and create error spam.
+ return OverlayfsTeardownResult::Busy;
+ }
+ if (!images->UnmapImageIfExists(partition_name)) {
+ return OverlayfsTeardownResult::Busy;
+ }
+ if (!images->DeleteBackingImage(partition_name)) {
+ return OverlayfsTeardownResult::Busy;
+ }
+ return OverlayfsTeardownResult::Ok;
+}
+
OverlayfsTeardownResult fs_mgr_overlayfs_teardown_scratch(const std::string& overlay,
bool* change) {
// umount and delete kScratchMountPoint storage if we have logical partitions
@@ -468,24 +506,9 @@
auto images = IImageManager::Open("remount", 10s);
if (images && images->BackingImageExists(partition_name)) {
- if (!images->DisableImage(partition_name)) {
- return OverlayfsTeardownResult::Error;
- }
- if (was_mounted) {
- // If overlayfs was mounted, don't bother trying to unmap since
- // it'll fail and create error spam.
- return OverlayfsTeardownResult::Busy;
- }
- if (!images->UnmapImageIfExists(partition_name)) {
- return OverlayfsTeardownResult::Busy;
- }
- if (!images->DeleteBackingImage(partition_name)) {
- return OverlayfsTeardownResult::Busy;
- }
-
// No need to check super partition, if we knew we had a scratch device
// in /data.
- return OverlayfsTeardownResult::Ok;
+ return TeardownDataScratch(images.get(), partition_name, was_mounted);
}
auto slot_number = fs_mgr_overlayfs_slot_number();
@@ -785,8 +808,7 @@
}
// Mount kScratchMountPoint
-bool fs_mgr_overlayfs_mount_scratch(const std::string& device_path, const std::string mnt_type,
- bool readonly = false) {
+bool MountScratch(const std::string& device_path, bool readonly = false) {
if (readonly) {
if (!fs_mgr_access(device_path)) {
LOG(ERROR) << "Path does not exist: " << device_path;
@@ -797,9 +819,12 @@
return false;
}
- auto f2fs = fs_mgr_is_f2fs(device_path);
- auto ext4 = fs_mgr_is_ext4(device_path);
- if (!f2fs && !ext4) {
+ std::vector<const char*> filesystem_candidates;
+ if (fs_mgr_is_f2fs(device_path)) {
+ filesystem_candidates = {"f2fs", "ext4"};
+ } else if (fs_mgr_is_ext4(device_path)) {
+ filesystem_candidates = {"ext4", "f2fs"};
+ } else {
LOG(ERROR) << "Scratch partition is not f2fs or ext4";
return false;
}
@@ -816,11 +841,7 @@
FstabEntry entry;
entry.blk_device = device_path;
entry.mount_point = kScratchMountPoint;
- entry.fs_type = mnt_type;
- if ((mnt_type == "f2fs") && !f2fs) entry.fs_type = "ext4";
- if ((mnt_type == "ext4") && !ext4) entry.fs_type = "f2fs";
entry.flags = MS_NOATIME | MS_RDONLY;
- auto mounted = true;
if (!readonly) {
entry.flags &= ~MS_RDONLY;
entry.flags |= MS_SYNCHRONOUS;
@@ -831,14 +852,12 @@
if (fs_mgr_overlayfs_already_mounted("/data", false)) {
entry.fs_mgr_flags.check = true;
}
- if (mounted) mounted = fs_mgr_do_mount_one(entry) == 0;
- if (!mounted) {
- if ((entry.fs_type == "f2fs") && ext4) {
- entry.fs_type = "ext4";
- mounted = fs_mgr_do_mount_one(entry) == 0;
- } else if ((entry.fs_type == "ext4") && f2fs) {
- entry.fs_type = "f2fs";
- mounted = fs_mgr_do_mount_one(entry) == 0;
+ bool mounted = false;
+ for (auto fs_type : filesystem_candidates) {
+ entry.fs_type = fs_type;
+ if (fs_mgr_do_mount_one(entry) == 0) {
+ mounted = true;
+ break;
}
}
if (!createcon.Restore()) {
@@ -854,39 +873,6 @@
const std::string kMkF2fs("/system/bin/make_f2fs");
const std::string kMkExt4("/system/bin/mke2fs");
-// Only a suggestion for _first_ try during mounting
-std::string fs_mgr_overlayfs_scratch_mount_type() {
- if (!access(kMkF2fs.c_str(), X_OK) && fs_mgr_filesystem_available("f2fs")) {
- return "f2fs";
- }
- if (!access(kMkExt4.c_str(), X_OK) && fs_mgr_filesystem_available("ext4")) {
- return "ext4";
- }
- return "auto";
-}
-
-// Note: we do not check access() here except for the super partition, since
-// in first-stage init we wouldn't have registed by-name symlinks for "other"
-// partitions that won't be mounted.
-static std::string GetPhysicalScratchDevice() {
- auto slot_number = fs_mgr_overlayfs_slot_number();
- auto super_device = fs_mgr_overlayfs_super_device(slot_number);
- auto path = fs_mgr_overlayfs_super_device(slot_number == 0);
- if (super_device != path) {
- return path;
- }
- if (fs_mgr_access(super_device)) {
- // Do not try to use system_other on a DAP device.
- return "";
- }
-
- auto other_slot = fs_mgr_get_other_slot_suffix();
- if (!other_slot.empty()) {
- return kPhysicalDevice + "system" + other_slot;
- }
- return "";
-}
-
// Note: The scratch partition of DSU is managed by gsid, and should be initialized during
// first-stage-mount. Just check if the DM device for DSU scratch partition is created or not.
static std::string GetDsuScratchDevice() {
@@ -923,27 +909,30 @@
return device;
}
- // There is no dynamic scratch, so try and find a physical one.
- return GetPhysicalScratchDevice();
+ return "";
}
-bool fs_mgr_overlayfs_make_scratch(const std::string& scratch_device, const std::string& mnt_type) {
+bool MakeScratchFilesystem(const std::string& scratch_device) {
// Force mkfs by design for overlay support of adb remount, simplify and
// thus do not rely on fsck to correct problems that could creep in.
+ auto fs_type = ""s;
auto command = ""s;
- if (mnt_type == "f2fs") {
+ if (!access(kMkF2fs.c_str(), X_OK) && fs_mgr_filesystem_available("f2fs")) {
+ fs_type = "f2fs";
command = kMkF2fs + " -w 4096 -f -d1 -l" + android::base::Basename(kScratchMountPoint);
- } else if (mnt_type == "ext4") {
+ } else if (!access(kMkExt4.c_str(), X_OK) && fs_mgr_filesystem_available("ext4")) {
+ fs_type = "ext4";
command = kMkExt4 + " -F -b 4096 -t ext4 -m 0 -O has_journal -M " + kScratchMountPoint;
} else {
- LERROR << mnt_type << " has no mkfs cookbook";
+ LERROR << "No supported mkfs command or filesystem driver available, supported filesystems "
+ "are: f2fs, ext4";
return false;
}
command += " " + scratch_device + " >/dev/null 2>/dev/null </dev/null";
fs_mgr_set_blk_ro(scratch_device, false);
auto ret = system(command.c_str());
if (ret) {
- LERROR << "make " << mnt_type << " filesystem on " << scratch_device << " return=" << ret;
+ LERROR << "make " << fs_type << " filesystem on " << scratch_device << " return=" << ret;
return false;
}
return true;
@@ -1104,7 +1093,10 @@
return false;
}
if (!images->BackingImageExists(partition_name)) {
- uint64_t size = GetIdealDataScratchSize();
+ auto size = android::base::GetUintProperty<uint64_t>(kDataScratchSizeMbProp, 0) * 1_MiB;
+ if (!size) {
+ size = GetIdealDataScratchSize();
+ }
if (!size) {
size = 2_GiB;
}
@@ -1118,12 +1110,14 @@
}
if (!images->MapImageDevice(partition_name, 10s, scratch_device)) {
LERROR << "could not map scratch image";
+ // If we cannot use this image, then remove it.
+ TeardownDataScratch(images.get(), partition_name, false /* was_mounted */);
return false;
}
return true;
}
-static bool CanUseSuperPartition(const Fstab& fstab, bool* is_virtual_ab) {
+static bool CanUseSuperPartition(const Fstab& fstab) {
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) || !fs_mgr_overlayfs_has_logical(fstab)) {
@@ -1133,7 +1127,6 @@
if (!metadata) {
return false;
}
- *is_virtual_ab = !!(metadata->header.flags & LP_HEADER_FLAG_VIRTUAL_AB_DEVICE);
return true;
}
@@ -1146,23 +1139,18 @@
return *partition_exists;
}
- // Try a physical partition first.
- *scratch_device = GetPhysicalScratchDevice();
- if (!scratch_device->empty() && fs_mgr_rw_access(*scratch_device)) {
- *partition_exists = true;
- return true;
- }
-
- // If that fails, see if we can land on super.
- bool is_virtual_ab;
- if (CanUseSuperPartition(fstab, &is_virtual_ab)) {
- bool can_use_data = false;
- if (is_virtual_ab && FilesystemHasReliablePinning("/data", &can_use_data) && can_use_data) {
- return CreateScratchOnData(scratch_device, partition_exists);
+ // Try ImageManager on /data first.
+ bool can_use_data = false;
+ if (FilesystemHasReliablePinning("/data", &can_use_data) && can_use_data) {
+ if (CreateScratchOnData(scratch_device, partition_exists)) {
+ return true;
}
+ LOG(WARNING) << "Failed to allocate scratch on /data, fallback to use free space on super";
+ }
+ // If that fails, see if we can land on super.
+ if (CanUseSuperPartition(fstab)) {
return CreateDynamicScratch(scratch_device, partition_exists);
}
-
return false;
}
@@ -1180,9 +1168,8 @@
}
// If the partition exists, assume first that it can be mounted.
- auto mnt_type = fs_mgr_overlayfs_scratch_mount_type();
if (partition_exists) {
- if (fs_mgr_overlayfs_mount_scratch(scratch_device, mnt_type)) {
+ if (MountScratch(scratch_device)) {
if (fs_mgr_access(kScratchMountPoint + kOverlayTopDir) ||
fs_mgr_filesystem_has_space(kScratchMountPoint)) {
return true;
@@ -1195,12 +1182,12 @@
}
}
- if (!fs_mgr_overlayfs_make_scratch(scratch_device, mnt_type)) {
+ if (!MakeScratchFilesystem(scratch_device)) {
LOG(ERROR) << "Failed to format scratch partition";
return false;
}
- return fs_mgr_overlayfs_mount_scratch(scratch_device, mnt_type);
+ return MountScratch(scratch_device);
}
#if ALLOW_ADBD_DISABLE_VERITY
@@ -1319,14 +1306,13 @@
if (!WaitForFile(scratch_device, 10s)) {
return;
}
- const auto mount_type = fs_mgr_overlayfs_scratch_mount_type();
- if (!fs_mgr_overlayfs_mount_scratch(scratch_device, mount_type, true /* readonly */)) {
+ if (!MountScratch(scratch_device, true /* readonly */)) {
return;
}
auto has_overlayfs_dir = fs_mgr_access(kScratchMountPoint + kOverlayTopDir);
fs_mgr_overlayfs_umount_scratch();
if (has_overlayfs_dir) {
- fs_mgr_overlayfs_mount_scratch(scratch_device, mount_type);
+ MountScratch(scratch_device);
}
}
@@ -1565,8 +1551,7 @@
if ((mount_point != nullptr) && !fs_mgr_overlayfs_already_mounted(kScratchMountPoint, false)) {
std::string scratch_device = GetBootScratchDevice();
if (!scratch_device.empty()) {
- mount_scratch = fs_mgr_overlayfs_mount_scratch(scratch_device,
- fs_mgr_overlayfs_scratch_mount_type());
+ mount_scratch = MountScratch(scratch_device);
}
}
@@ -1687,7 +1672,7 @@
if (auto info = EnsureScratchMapped(); info.has_value()) {
// Map scratch device, mount kScratchMountPoint and teardown kScratchMountPoint.
fs_mgr_overlayfs_umount_scratch();
- if (fs_mgr_overlayfs_mount_scratch(info->device, fs_mgr_overlayfs_scratch_mount_type())) {
+ if (MountScratch(info->device)) {
bool should_destroy_scratch = false;
fs_mgr_overlayfs_teardown_one(kScratchMountPoint, teardown_dir, ignore_change,
&should_destroy_scratch);
@@ -1702,7 +1687,7 @@
std::string scratch_device;
if (MapDsuScratchDevice(&scratch_device)) {
fs_mgr_overlayfs_umount_scratch();
- if (fs_mgr_overlayfs_mount_scratch(scratch_device, fs_mgr_overlayfs_scratch_mount_type())) {
+ if (MountScratch(scratch_device)) {
fs_mgr_overlayfs_teardown_one(kScratchMountPoint, teardown_dir, ignore_change);
fs_mgr_overlayfs_umount_scratch();
}
diff --git a/fs_mgr/fs_mgr_remount.cpp b/fs_mgr/fs_mgr_remount.cpp
index 54c1c2c..2edaaad 100644
--- a/fs_mgr/fs_mgr_remount.cpp
+++ b/fs_mgr/fs_mgr_remount.cpp
@@ -35,7 +35,6 @@
#include <binder/IServiceManager.h>
#include <bootloader_message/bootloader_message.h>
#include <cutils/android_reboot.h>
-#include <fec/io.h>
#include <fs_mgr_overlayfs.h>
#include <fs_mgr_priv.h>
#include <fstab/fstab.h>
@@ -50,7 +49,7 @@
namespace {
-[[noreturn]] void usage(int exit_status) {
+void usage() {
LOG(INFO) << getprogname()
<< " [-h] [-R] [-T fstab_file] [partition]...\n"
"\t-h --help\tthis help\n"
@@ -62,8 +61,6 @@
"-R notwithstanding, verity must be disabled on partition(s).\n"
"-R within a DSU guest system reboots into the DSU instead of the host system,\n"
"this command would enable DSU (one-shot) if not already enabled.";
-
- ::exit(exit_status);
}
const std::string system_mount_point(const android::fs_mgr::FstabEntry& entry) {
@@ -116,15 +113,9 @@
} // namespace
-using namespace std::chrono_literals;
-
enum RemountStatus {
REMOUNT_SUCCESS = 0,
- NOT_USERDEBUG,
- BADARG,
- NOT_ROOT,
- NO_FSTAB,
- UNKNOWN_PARTITION,
+ UNKNOWN_PARTITION = 5,
INVALID_PARTITION,
VERITY_PARTITION,
BAD_OVERLAY,
@@ -281,23 +272,13 @@
if (!fs_mgr_is_verity_enabled(entry)) {
return REMOUNT_SUCCESS;
}
- if (android::base::GetProperty("ro.boot.vbmeta.device_state", "") == "locked") {
- return VERITY_PARTITION;
- }
-
- bool ok = false;
std::unique_ptr<AvbOps, decltype(&::avb_ops_user_free)> ops(avb_ops_user_new(),
&::avb_ops_user_free);
- if (ops) {
- auto suffix = android::base::GetProperty("ro.boot.slot_suffix", "");
- ok = avb_user_verity_set(ops.get(), suffix.c_str(), false);
+ if (!ops) {
+ return VERITY_PARTITION;
}
- if (!ok && fs_mgr_set_blk_ro(entry.blk_device, false)) {
- fec::io fh(entry.blk_device.c_str(), O_RDWR);
- ok = fh && fh.set_verity_status(false);
- }
- if (!ok) {
+ if (!avb_user_verity_set(ops.get(), fs_mgr_get_slot_suffix().c_str(), false)) {
return VERITY_PARTITION;
}
result->disabled_verity = true;
@@ -489,15 +470,20 @@
// Make sure we are root.
if (::getuid() != 0) {
LOG(ERROR) << "Not running as root. Try \"adb root\" first.";
- return NOT_ROOT;
+ return 1;
}
// If somehow this executable is delivered on a "user" build, it can
// not function, so providing a clear message to the caller rather than
// letting if fall through and provide a lot of confusing failure messages.
- if (!ALLOW_ADBD_DISABLE_VERITY || (android::base::GetProperty("ro.debuggable", "0") != "1")) {
- LOG(ERROR) << "only functions on userdebug or eng builds";
- return NOT_USERDEBUG;
+ if (!ALLOW_ADBD_DISABLE_VERITY || !android::base::GetBoolProperty("ro.debuggable", false)) {
+ LOG(ERROR) << "Device must be userdebug build";
+ return 1;
+ }
+
+ if (android::base::GetProperty("ro.boot.vbmeta.device_state", "") == "locked") {
+ LOG(ERROR) << "Device must be bootloader unlocked";
+ return 1;
}
const char* fstab_file = nullptr;
@@ -514,15 +500,16 @@
for (int opt; (opt = ::getopt_long(argc, argv, "hRT:v", longopts, nullptr)) != -1;) {
switch (opt) {
case 'h':
- usage(SUCCESS);
- break;
+ usage();
+ return 0;
case 'R':
auto_reboot = true;
break;
case 'T':
if (fstab_file) {
LOG(ERROR) << "Cannot supply two fstabs: -T " << fstab_file << " -T" << optarg;
- usage(BADARG);
+ usage();
+ return 1;
}
fstab_file = optarg;
break;
@@ -531,8 +518,8 @@
break;
default:
LOG(ERROR) << "Bad Argument -" << char(opt);
- usage(BADARG);
- break;
+ usage();
+ return 1;
}
}
@@ -549,7 +536,7 @@
Fstab fstab;
if (!ReadFstab(fstab_file, &fstab) || fstab.empty()) {
PLOG(ERROR) << "Failed to read fstab";
- return NO_FSTAB;
+ return 1;
}
RemountCheckResult check_result;
diff --git a/fs_mgr/fuzz/fs_mgr_fstab_fuzzer.cpp b/fs_mgr/fuzz/fs_mgr_fstab_fuzzer.cpp
index 6a8a191..b5fdad4 100644
--- a/fs_mgr/fuzz/fs_mgr_fstab_fuzzer.cpp
+++ b/fs_mgr/fuzz/fs_mgr_fstab_fuzzer.cpp
@@ -14,13 +14,27 @@
// limitations under the License.
//
-#include <cstdio>
+#include <string>
+#include <vector>
#include <fstab/fstab.h>
+#include <fuzzer/FuzzedDataProvider.h>
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
- std::string make_fstab_str(reinterpret_cast<const char*>(data), size);
+ FuzzedDataProvider fdp(data, size);
+
+ std::string make_fstab_str = fdp.ConsumeRandomLengthString();
+ std::string dsu_slot = fdp.ConsumeRandomLengthString(30);
+ std::vector<std::string> dsu_partitions = {
+ fdp.ConsumeRandomLengthString(30),
+ fdp.ConsumeRandomLengthString(30),
+ };
+ std::string skip_mount_config = fdp.ConsumeRemainingBytesAsString();
+
android::fs_mgr::Fstab fstab;
android::fs_mgr::ParseFstabFromString(make_fstab_str, /* proc_mounts = */ false, &fstab);
+ android::fs_mgr::TransformFstabForDsu(&fstab, dsu_slot, dsu_partitions);
+ android::fs_mgr::SkipMountWithConfig(skip_mount_config, &fstab, /* verbose = */ false);
+
return 0;
}
diff --git a/fs_mgr/include/fs_mgr.h b/fs_mgr/include/fs_mgr.h
index 29a5e60..43de6d8 100644
--- a/fs_mgr/include/fs_mgr.h
+++ b/fs_mgr/include/fs_mgr.h
@@ -71,6 +71,8 @@
std::string algorithm;
// The root digest of the merkle tree.
std::string root_digest;
+ // If check_at_most_once is enabled.
+ bool check_at_most_once;
};
// fs_mgr_mount_all() updates fstab entries that reference device-mapper.
diff --git a/fs_mgr/include_fstab/fstab/fstab.h b/fs_mgr/include_fstab/fstab/fstab.h
index 689d18b..124f070 100644
--- a/fs_mgr/include_fstab/fstab/fstab.h
+++ b/fs_mgr/include_fstab/fstab/fstab.h
@@ -97,6 +97,8 @@
bool ParseFstabFromString(const std::string& fstab_str, bool proc_mounts, Fstab* fstab_out);
// Exported for testability. Regular users should use ReadDefaultFstab().
std::string GetFstabPath();
+// Exported for testability.
+bool SkipMountWithConfig(const std::string& skip_config, Fstab* fstab, bool verbose);
bool ReadFstabFromFile(const std::string& path, Fstab* fstab);
bool ReadFstabFromDt(Fstab* fstab, bool verbose = true);
diff --git a/fs_mgr/libsnapshot/Android.bp b/fs_mgr/libsnapshot/Android.bp
index d5e85e6..8e4b556 100644
--- a/fs_mgr/libsnapshot/Android.bp
+++ b/fs_mgr/libsnapshot/Android.bp
@@ -173,10 +173,11 @@
"libsnapshot_cow_defaults",
],
srcs: [
- "cow_decompress.cpp",
- "cow_reader.cpp",
- "cow_writer.cpp",
- "cow_format.cpp",
+ "libsnapshot_cow/cow_decompress.cpp",
+ "libsnapshot_cow/cow_reader.cpp",
+ "libsnapshot_cow/cow_writer.cpp",
+ "libsnapshot_cow/cow_format.cpp",
+ "libsnapshot_cow/cow_compress.cpp",
],
host_supported: true,
recovery_available: true,
@@ -323,6 +324,22 @@
"libstatslog",
"libutils",
],
+ header_libs: [
+ "libstorage_literals_headers",
+ ],
+ product_variables: {
+ debuggable: {
+ cppflags: [
+ "-DSNAPSHOTCTL_USERDEBUG_OR_ENG",
+ ],
+ shared_libs: [
+ "android.hardware.boot@1.0",
+ "android.hardware.boot@1.1",
+ "android.hardware.boot-V1-ndk",
+ "libboot_control_client",
+ ],
+ },
+ },
}
cc_test {
@@ -424,7 +441,7 @@
"libsnapshot_cow_defaults",
],
srcs: [
- "cow_api_test.cpp",
+ "libsnapshot_cow/cow_api_test.cpp",
],
cflags: [
"-D_FILE_OFFSET_BITS=64",
@@ -546,7 +563,7 @@
shared_libs: [
],
srcs: [
- "inspect_cow.cpp",
+ "libsnapshot_cow/inspect_cow.cpp",
],
}
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/cow_writer.h b/fs_mgr/libsnapshot/include/libsnapshot/cow_writer.h
index e7a2f02..b93fd32 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/cow_writer.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/cow_writer.h
@@ -52,8 +52,9 @@
virtual ~ICowWriter() {}
// Encode an operation that copies the contents of |old_block| to the
- // location of |new_block|.
- bool AddCopy(uint64_t new_block, uint64_t old_block);
+ // location of |new_block|. 'num_blocks' is the number of contiguous
+ // COPY operations from |old_block| to |new_block|.
+ bool AddCopy(uint64_t new_block, uint64_t old_block, uint64_t num_blocks = 1);
// Encode a sequence of raw blocks. |size| must be a multiple of the block size.
bool AddRawBlocks(uint64_t new_block_start, const void* data, size_t size);
@@ -84,7 +85,7 @@
const CowOptions& options() { return options_; }
protected:
- virtual bool EmitCopy(uint64_t new_block, uint64_t old_block) = 0;
+ virtual bool EmitCopy(uint64_t new_block, uint64_t old_block, uint64_t num_blocks = 1) = 0;
virtual bool EmitRawBlocks(uint64_t new_block_start, const void* data, size_t size) = 0;
virtual bool EmitXorBlocks(uint32_t new_block_start, const void* data, size_t size,
uint32_t old_block, uint16_t offset) = 0;
@@ -122,7 +123,7 @@
uint32_t GetCowVersion() { return header_.major_version; }
protected:
- virtual bool EmitCopy(uint64_t new_block, uint64_t old_block) override;
+ virtual bool EmitCopy(uint64_t new_block, uint64_t old_block, uint64_t num_blocks = 1) override;
virtual bool EmitRawBlocks(uint64_t new_block_start, const void* data, size_t size) override;
virtual bool EmitXorBlocks(uint32_t new_block_start, const void* data, size_t size,
uint32_t old_block, uint16_t offset) override;
@@ -164,10 +165,6 @@
bool is_dev_null_ = false;
bool merge_in_progress_ = false;
bool is_block_device_ = false;
-
- // :TODO: this is not efficient, but stringstream ubsan aborts because some
- // bytes overflow a signed char.
- std::basic_string<uint8_t> ops_;
};
} // namespace snapshot
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/mock_snapshot_writer.h b/fs_mgr/libsnapshot/include/libsnapshot/mock_snapshot_writer.h
index b0be5a5..29828bc 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/mock_snapshot_writer.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/mock_snapshot_writer.h
@@ -34,7 +34,7 @@
// Returns true if AddCopy() operations are supported.
MOCK_METHOD(bool, SupportsCopyOperation, (), (const override));
- MOCK_METHOD(bool, EmitCopy, (uint64_t, uint64_t), (override));
+ MOCK_METHOD(bool, EmitCopy, (uint64_t, uint64_t, uint64_t), (override));
MOCK_METHOD(bool, EmitRawBlocks, (uint64_t, const void*, size_t), (override));
MOCK_METHOD(bool, EmitXorBlocks, (uint32_t, const void*, size_t, uint32_t, uint16_t),
(override));
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
index 34c7baf..cdff06e 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
@@ -332,10 +332,13 @@
// Helper function for second stage init to restorecon on the rollback indicator.
static std::string GetGlobalRollbackIndicatorPath();
- // Detach dm-user devices from the current snapuserd, and populate
- // |snapuserd_argv| with the necessary arguments to restart snapuserd
- // and reattach them.
- bool DetachSnapuserdForSelinux(std::vector<std::string>* snapuserd_argv);
+ // Populate |snapuserd_argv| with the necessary arguments to restart snapuserd
+ // after loading selinux policy.
+ bool PrepareSnapuserdArgsForSelinux(std::vector<std::string>* snapuserd_argv);
+
+ // Detach dm-user devices from the first stage snapuserd. Load
+ // new dm-user tables after loading selinux policy.
+ bool DetachFirstStageSnapuserdForSelinux();
// Perform the transition from the selinux stage of snapuserd into the
// second-stage of snapuserd. This process involves re-creating the dm-user
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapshot_writer.h b/fs_mgr/libsnapshot/include/libsnapshot/snapshot_writer.h
index 545f117..0e3b1db 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/snapshot_writer.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/snapshot_writer.h
@@ -74,7 +74,7 @@
bool VerifyMergeOps() const noexcept;
protected:
- bool EmitCopy(uint64_t new_block, uint64_t old_block) override;
+ bool EmitCopy(uint64_t new_block, uint64_t old_block, uint64_t num_blocks = 1) override;
bool EmitRawBlocks(uint64_t new_block_start, const void* data, size_t size) override;
bool EmitXorBlocks(uint32_t new_block_start, const void* data, size_t size, uint32_t old_block,
uint16_t offset) override;
@@ -113,7 +113,7 @@
bool EmitZeroBlocks(uint64_t new_block_start, uint64_t num_blocks) override;
bool EmitXorBlocks(uint32_t new_block_start, const void* data, size_t size, uint32_t old_block,
uint16_t offset) override;
- bool EmitCopy(uint64_t new_block, uint64_t old_block) override;
+ bool EmitCopy(uint64_t new_block, uint64_t old_block, uint64_t num_blocks = 1) override;
bool EmitLabel(uint64_t label) override;
bool EmitSequenceData(size_t num_ops, const uint32_t* data) override;
diff --git a/fs_mgr/libsnapshot/cow_api_test.cpp b/fs_mgr/libsnapshot/libsnapshot_cow/cow_api_test.cpp
similarity index 96%
rename from fs_mgr/libsnapshot/cow_api_test.cpp
rename to fs_mgr/libsnapshot/libsnapshot_cow/cow_api_test.cpp
index ba4044f..2c1187f 100644
--- a/fs_mgr/libsnapshot/cow_api_test.cpp
+++ b/fs_mgr/libsnapshot/libsnapshot_cow/cow_api_test.cpp
@@ -62,6 +62,48 @@
std::string stream_;
};
+TEST_F(CowTest, CopyContiguous) {
+ CowOptions options;
+ options.cluster_ops = 0;
+ CowWriter writer(options);
+
+ ASSERT_TRUE(writer.Initialize(cow_->fd));
+
+ ASSERT_TRUE(writer.AddCopy(10, 1000, 100));
+ ASSERT_TRUE(writer.Finalize());
+ ASSERT_EQ(lseek(cow_->fd, 0, SEEK_SET), 0);
+
+ CowReader reader;
+ CowHeader header;
+ CowFooter footer;
+ ASSERT_TRUE(reader.Parse(cow_->fd));
+ ASSERT_TRUE(reader.GetHeader(&header));
+ ASSERT_TRUE(reader.GetFooter(&footer));
+ ASSERT_EQ(header.magic, kCowMagicNumber);
+ ASSERT_EQ(header.major_version, kCowVersionMajor);
+ ASSERT_EQ(header.minor_version, kCowVersionMinor);
+ ASSERT_EQ(header.block_size, options.block_size);
+ ASSERT_EQ(footer.op.num_ops, 100);
+
+ auto iter = reader.GetOpIter();
+ ASSERT_NE(iter, nullptr);
+ ASSERT_FALSE(iter->Done());
+
+ size_t i = 0;
+ while (!iter->Done()) {
+ auto op = &iter->Get();
+ ASSERT_EQ(op->type, kCowCopyOp);
+ ASSERT_EQ(op->compression, kCowCompressNone);
+ ASSERT_EQ(op->data_length, 0);
+ ASSERT_EQ(op->new_block, 10 + i);
+ ASSERT_EQ(op->source, 1000 + i);
+ iter->Next();
+ i += 1;
+ }
+
+ ASSERT_EQ(i, 100);
+}
+
TEST_F(CowTest, ReadWrite) {
CowOptions options;
options.cluster_ops = 0;
diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/cow_compress.cpp b/fs_mgr/libsnapshot/libsnapshot_cow/cow_compress.cpp
new file mode 100644
index 0000000..e58f45a
--- /dev/null
+++ b/fs_mgr/libsnapshot/libsnapshot_cow/cow_compress.cpp
@@ -0,0 +1,98 @@
+//
+// Copyright (C) 2020 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 <sys/types.h>
+#include <unistd.h>
+
+#include <limits>
+#include <queue>
+
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <android-base/unique_fd.h>
+#include <brotli/encode.h>
+#include <libsnapshot/cow_format.h>
+#include <libsnapshot/cow_reader.h>
+#include <libsnapshot/cow_writer.h>
+#include <lz4.h>
+#include <zlib.h>
+
+namespace android {
+namespace snapshot {
+
+std::basic_string<uint8_t> CowWriter::Compress(const void* data, size_t length) {
+ switch (compression_) {
+ case kCowCompressGz: {
+ const auto bound = compressBound(length);
+ std::basic_string<uint8_t> buffer(bound, '\0');
+
+ uLongf dest_len = bound;
+ auto rv = compress2(buffer.data(), &dest_len, reinterpret_cast<const Bytef*>(data),
+ length, Z_BEST_COMPRESSION);
+ if (rv != Z_OK) {
+ LOG(ERROR) << "compress2 returned: " << rv;
+ return {};
+ }
+ buffer.resize(dest_len);
+ return buffer;
+ }
+ case kCowCompressBrotli: {
+ const auto bound = BrotliEncoderMaxCompressedSize(length);
+ if (!bound) {
+ LOG(ERROR) << "BrotliEncoderMaxCompressedSize returned 0";
+ return {};
+ }
+ std::basic_string<uint8_t> buffer(bound, '\0');
+
+ size_t encoded_size = bound;
+ auto rv = BrotliEncoderCompress(
+ BROTLI_DEFAULT_QUALITY, BROTLI_DEFAULT_WINDOW, BROTLI_DEFAULT_MODE, length,
+ reinterpret_cast<const uint8_t*>(data), &encoded_size, buffer.data());
+ if (!rv) {
+ LOG(ERROR) << "BrotliEncoderCompress failed";
+ return {};
+ }
+ buffer.resize(encoded_size);
+ return buffer;
+ }
+ case kCowCompressLz4: {
+ const auto bound = LZ4_compressBound(length);
+ if (!bound) {
+ LOG(ERROR) << "LZ4_compressBound returned 0";
+ return {};
+ }
+ std::basic_string<uint8_t> buffer(bound, '\0');
+
+ const auto compressed_size = LZ4_compress_default(
+ static_cast<const char*>(data), reinterpret_cast<char*>(buffer.data()), length,
+ buffer.size());
+ if (compressed_size <= 0) {
+ LOG(ERROR) << "LZ4_compress_default failed, input size: " << length
+ << ", compression bound: " << bound << ", ret: " << compressed_size;
+ return {};
+ }
+ buffer.resize(compressed_size);
+ return buffer;
+ }
+ default:
+ LOG(ERROR) << "unhandled compression type: " << compression_;
+ break;
+ }
+ return {};
+}
+
+} // namespace snapshot
+} // namespace android
diff --git a/fs_mgr/libsnapshot/cow_decompress.cpp b/fs_mgr/libsnapshot/libsnapshot_cow/cow_decompress.cpp
similarity index 100%
rename from fs_mgr/libsnapshot/cow_decompress.cpp
rename to fs_mgr/libsnapshot/libsnapshot_cow/cow_decompress.cpp
diff --git a/fs_mgr/libsnapshot/cow_decompress.h b/fs_mgr/libsnapshot/libsnapshot_cow/cow_decompress.h
similarity index 100%
rename from fs_mgr/libsnapshot/cow_decompress.h
rename to fs_mgr/libsnapshot/libsnapshot_cow/cow_decompress.h
diff --git a/fs_mgr/libsnapshot/cow_format.cpp b/fs_mgr/libsnapshot/libsnapshot_cow/cow_format.cpp
similarity index 100%
rename from fs_mgr/libsnapshot/cow_format.cpp
rename to fs_mgr/libsnapshot/libsnapshot_cow/cow_format.cpp
diff --git a/fs_mgr/libsnapshot/cow_reader.cpp b/fs_mgr/libsnapshot/libsnapshot_cow/cow_reader.cpp
similarity index 100%
rename from fs_mgr/libsnapshot/cow_reader.cpp
rename to fs_mgr/libsnapshot/libsnapshot_cow/cow_reader.cpp
diff --git a/fs_mgr/libsnapshot/cow_writer.cpp b/fs_mgr/libsnapshot/libsnapshot_cow/cow_writer.cpp
similarity index 84%
rename from fs_mgr/libsnapshot/cow_writer.cpp
rename to fs_mgr/libsnapshot/libsnapshot_cow/cow_writer.cpp
index 7281fc2..5f5d1fb 100644
--- a/fs_mgr/libsnapshot/cow_writer.cpp
+++ b/fs_mgr/libsnapshot/libsnapshot_cow/cow_writer.cpp
@@ -38,11 +38,16 @@
using android::base::borrowed_fd;
using android::base::unique_fd;
-bool ICowWriter::AddCopy(uint64_t new_block, uint64_t old_block) {
- if (!ValidateNewBlock(new_block)) {
- return false;
+bool ICowWriter::AddCopy(uint64_t new_block, uint64_t old_block, uint64_t num_blocks) {
+ CHECK(num_blocks != 0);
+
+ for (size_t i = 0; i < num_blocks; i++) {
+ if (!ValidateNewBlock(new_block + i)) {
+ return false;
+ }
}
- return EmitCopy(new_block, old_block);
+
+ return EmitCopy(new_block, old_block, num_blocks);
}
bool ICowWriter::AddRawBlocks(uint64_t new_block_start, const void* data, size_t size) {
@@ -202,7 +207,6 @@
} else {
next_data_pos_ = next_op_pos_ + sizeof(CowOperation);
}
- ops_.clear();
current_cluster_size_ = 0;
current_data_size_ = 0;
}
@@ -286,13 +290,20 @@
return EmitClusterIfNeeded();
}
-bool CowWriter::EmitCopy(uint64_t new_block, uint64_t old_block) {
+bool CowWriter::EmitCopy(uint64_t new_block, uint64_t old_block, uint64_t num_blocks) {
CHECK(!merge_in_progress_);
- CowOperation op = {};
- op.type = kCowCopyOp;
- op.new_block = new_block;
- op.source = old_block;
- return WriteOperation(op);
+
+ for (size_t i = 0; i < num_blocks; i++) {
+ CowOperation op = {};
+ op.type = kCowCopyOp;
+ op.new_block = new_block + i;
+ op.source = old_block + i;
+ if (!WriteOperation(op)) {
+ return false;
+ }
+ }
+
+ return true;
}
bool CowWriter::EmitRawBlocks(uint64_t new_block_start, const void* data, size_t size) {
@@ -404,67 +415,6 @@
return true;
}
-std::basic_string<uint8_t> CowWriter::Compress(const void* data, size_t length) {
- switch (compression_) {
- case kCowCompressGz: {
- const auto bound = compressBound(length);
- std::basic_string<uint8_t> buffer(bound, '\0');
-
- uLongf dest_len = bound;
- auto rv = compress2(buffer.data(), &dest_len, reinterpret_cast<const Bytef*>(data),
- length, Z_BEST_COMPRESSION);
- if (rv != Z_OK) {
- LOG(ERROR) << "compress2 returned: " << rv;
- return {};
- }
- buffer.resize(dest_len);
- return buffer;
- }
- case kCowCompressBrotli: {
- const auto bound = BrotliEncoderMaxCompressedSize(length);
- if (!bound) {
- LOG(ERROR) << "BrotliEncoderMaxCompressedSize returned 0";
- return {};
- }
- std::basic_string<uint8_t> buffer(bound, '\0');
-
- size_t encoded_size = bound;
- auto rv = BrotliEncoderCompress(
- BROTLI_DEFAULT_QUALITY, BROTLI_DEFAULT_WINDOW, BROTLI_DEFAULT_MODE, length,
- reinterpret_cast<const uint8_t*>(data), &encoded_size, buffer.data());
- if (!rv) {
- LOG(ERROR) << "BrotliEncoderCompress failed";
- return {};
- }
- buffer.resize(encoded_size);
- return buffer;
- }
- case kCowCompressLz4: {
- const auto bound = LZ4_compressBound(length);
- if (!bound) {
- LOG(ERROR) << "LZ4_compressBound returned 0";
- return {};
- }
- std::basic_string<uint8_t> buffer(bound, '\0');
-
- const auto compressed_size = LZ4_compress_default(
- static_cast<const char*>(data), reinterpret_cast<char*>(buffer.data()), length,
- buffer.size());
- if (compressed_size <= 0) {
- LOG(ERROR) << "LZ4_compress_default failed, input size: " << length
- << ", compression bound: " << bound << ", ret: " << compressed_size;
- return {};
- }
- buffer.resize(compressed_size);
- return buffer;
- }
- default:
- LOG(ERROR) << "unhandled compression type: " << compression_;
- break;
- }
- return {};
-}
-
// TODO: Fix compilation issues when linking libcrypto library
// when snapuserd is compiled as part of ramdisk.
static void SHA256(const void*, size_t, uint8_t[]) {
@@ -481,7 +431,6 @@
auto continue_data_size = current_data_size_;
auto continue_data_pos = next_data_pos_;
auto continue_op_pos = next_op_pos_;
- auto continue_size = ops_.size();
auto continue_num_ops = footer_.op.num_ops;
bool extra_cluster = false;
@@ -507,7 +456,7 @@
extra_cluster = true;
}
- footer_.op.ops_size = ops_.size();
+ footer_.op.ops_size = footer_.op.num_ops * sizeof(CowOperation);
if (lseek(fd_.get(), next_op_pos_, SEEK_SET) < 0) {
PLOG(ERROR) << "Failed to seek to footer position.";
return false;
@@ -515,7 +464,6 @@
memset(&footer_.data.ops_checksum, 0, sizeof(uint8_t) * 32);
memset(&footer_.data.footer_checksum, 0, sizeof(uint8_t) * 32);
- SHA256(ops_.data(), ops_.size(), footer_.data.ops_checksum);
SHA256(&footer_.op, sizeof(footer_.op), footer_.data.footer_checksum);
// Write out footer at end of file
if (!android::base::WriteFully(fd_, reinterpret_cast<const uint8_t*>(&footer_),
@@ -542,7 +490,6 @@
next_data_pos_ = continue_data_pos;
next_op_pos_ = continue_op_pos;
footer_.op.num_ops = continue_num_ops;
- ops_.resize(continue_size);
}
return Sync();
}
@@ -593,7 +540,6 @@
next_data_pos_ += op.data_length + GetNextDataOffset(op, header_.cluster_ops);
next_op_pos_ += sizeof(CowOperation) + GetNextOpOffset(op, header_.cluster_ops);
- ops_.insert(ops_.size(), reinterpret_cast<const uint8_t*>(&op), sizeof(op));
}
bool CowWriter::WriteRawData(const void* data, size_t size) {
diff --git a/fs_mgr/libsnapshot/inspect_cow.cpp b/fs_mgr/libsnapshot/libsnapshot_cow/inspect_cow.cpp
similarity index 100%
rename from fs_mgr/libsnapshot/inspect_cow.cpp
rename to fs_mgr/libsnapshot/libsnapshot_cow/inspect_cow.cpp
diff --git a/fs_mgr/libsnapshot/snapshot.cpp b/fs_mgr/libsnapshot/snapshot.cpp
index 59abd6f..6fed09c 100644
--- a/fs_mgr/libsnapshot/snapshot.cpp
+++ b/fs_mgr/libsnapshot/snapshot.cpp
@@ -1746,13 +1746,6 @@
auto misc_name = user_cow_name;
- DmTable table;
- table.Emplace<DmTargetUser>(0, target.spec.length, misc_name);
- if (!dm_.LoadTableAndActivate(user_cow_name, table)) {
- LOG(ERROR) << "Unable to swap tables for " << misc_name;
- continue;
- }
-
std::string source_device_name;
if (snapshot_status.old_partition_size() > 0) {
source_device_name = GetSourceDeviceName(snapshot);
@@ -1780,13 +1773,6 @@
continue;
}
- // Wait for ueventd to acknowledge and create the control device node.
- std::string control_device = "/dev/dm-user/" + misc_name;
- if (!WaitForDevice(control_device, 10s)) {
- LOG(ERROR) << "dm-user control device no found: " << misc_name;
- continue;
- }
-
if (transition == InitTransition::SELINUX_DETACH) {
if (!UpdateUsesUserSnapshots(lock.get())) {
auto message = misc_name + "," + cow_image_device + "," + source_device;
@@ -1804,6 +1790,20 @@
continue;
}
+ DmTable table;
+ table.Emplace<DmTargetUser>(0, target.spec.length, misc_name);
+ if (!dm_.LoadTableAndActivate(user_cow_name, table)) {
+ LOG(ERROR) << "Unable to swap tables for " << misc_name;
+ continue;
+ }
+
+ // Wait for ueventd to acknowledge and create the control device node.
+ std::string control_device = "/dev/dm-user/" + misc_name;
+ if (!WaitForDevice(control_device, 10s)) {
+ LOG(ERROR) << "dm-user control device no found: " << misc_name;
+ continue;
+ }
+
uint64_t base_sectors;
if (!UpdateUsesUserSnapshots(lock.get())) {
base_sectors =
@@ -4136,10 +4136,71 @@
return status.state() != UpdateState::None && status.using_snapuserd();
}
-bool SnapshotManager::DetachSnapuserdForSelinux(std::vector<std::string>* snapuserd_argv) {
+bool SnapshotManager::PrepareSnapuserdArgsForSelinux(std::vector<std::string>* snapuserd_argv) {
return PerformInitTransition(InitTransition::SELINUX_DETACH, snapuserd_argv);
}
+bool SnapshotManager::DetachFirstStageSnapuserdForSelinux() {
+ LOG(INFO) << "Detaching first stage snapuserd";
+
+ auto lock = LockExclusive();
+ if (!lock) return false;
+
+ std::vector<std::string> snapshots;
+ if (!ListSnapshots(lock.get(), &snapshots)) {
+ LOG(ERROR) << "Failed to list snapshots.";
+ return false;
+ }
+
+ size_t num_cows = 0;
+ size_t ok_cows = 0;
+ for (const auto& snapshot : snapshots) {
+ std::string user_cow_name = GetDmUserCowName(snapshot, GetSnapshotDriver(lock.get()));
+
+ if (dm_.GetState(user_cow_name) == DmDeviceState::INVALID) {
+ continue;
+ }
+
+ DeviceMapper::TargetInfo target;
+ if (!GetSingleTarget(user_cow_name, TableQuery::Table, &target)) {
+ continue;
+ }
+
+ auto target_type = DeviceMapper::GetTargetType(target.spec);
+ if (target_type != "user") {
+ LOG(ERROR) << "Unexpected target type for " << user_cow_name << ": " << target_type;
+ continue;
+ }
+
+ num_cows++;
+ auto misc_name = user_cow_name;
+
+ DmTable table;
+ table.Emplace<DmTargetUser>(0, target.spec.length, misc_name);
+ if (!dm_.LoadTableAndActivate(user_cow_name, table)) {
+ LOG(ERROR) << "Unable to swap tables for " << misc_name;
+ continue;
+ }
+
+ // Wait for ueventd to acknowledge and create the control device node.
+ std::string control_device = "/dev/dm-user/" + misc_name;
+ if (!WaitForDevice(control_device, 10s)) {
+ LOG(ERROR) << "dm-user control device no found: " << misc_name;
+ continue;
+ }
+
+ ok_cows++;
+ LOG(INFO) << "control device is ready: " << control_device;
+ }
+
+ if (ok_cows != num_cows) {
+ LOG(ERROR) << "Could not transition all snapuserd consumers.";
+ return false;
+ }
+
+ return true;
+}
+
bool SnapshotManager::PerformSecondStageInitTransition() {
return PerformInitTransition(InitTransition::SECOND_STAGE);
}
diff --git a/fs_mgr/libsnapshot/snapshot_writer.cpp b/fs_mgr/libsnapshot/snapshot_writer.cpp
index 48b7d80..6aad3d1 100644
--- a/fs_mgr/libsnapshot/snapshot_writer.cpp
+++ b/fs_mgr/libsnapshot/snapshot_writer.cpp
@@ -111,8 +111,9 @@
return reader;
}
-bool CompressedSnapshotWriter::EmitCopy(uint64_t new_block, uint64_t old_block) {
- return cow_->AddCopy(new_block, old_block);
+bool CompressedSnapshotWriter::EmitCopy(uint64_t new_block, uint64_t old_block,
+ uint64_t num_blocks) {
+ return cow_->AddCopy(new_block, old_block, num_blocks);
}
bool CompressedSnapshotWriter::EmitRawBlocks(uint64_t new_block_start, const void* data,
@@ -191,19 +192,29 @@
return true;
}
-bool OnlineKernelSnapshotWriter::EmitCopy(uint64_t new_block, uint64_t old_block) {
+bool OnlineKernelSnapshotWriter::EmitCopy(uint64_t new_block, uint64_t old_block,
+ uint64_t num_blocks) {
auto source_fd = GetSourceFd();
if (source_fd < 0) {
return false;
}
- std::string buffer(options_.block_size, 0);
- uint64_t offset = old_block * options_.block_size;
- if (!android::base::ReadFullyAtOffset(source_fd, buffer.data(), buffer.size(), offset)) {
- PLOG(ERROR) << "EmitCopy read";
- return false;
+ CHECK(num_blocks != 0);
+
+ for (size_t i = 0; i < num_blocks; i++) {
+ std::string buffer(options_.block_size, 0);
+ uint64_t offset = (old_block + i) * options_.block_size;
+ if (!android::base::ReadFullyAtOffset(source_fd, buffer.data(), buffer.size(), offset)) {
+ PLOG(ERROR) << "EmitCopy read";
+ return false;
+ }
+ if (!EmitRawBlocks(new_block + i, buffer.data(), buffer.size())) {
+ PLOG(ERROR) << "EmitRawBlocks failed";
+ return false;
+ }
}
- return EmitRawBlocks(new_block, buffer.data(), buffer.size());
+
+ return true;
}
bool OnlineKernelSnapshotWriter::EmitLabel(uint64_t) {
diff --git a/fs_mgr/libsnapshot/snapshotctl.cpp b/fs_mgr/libsnapshot/snapshotctl.cpp
index 67189d4..ad3f83c 100644
--- a/fs_mgr/libsnapshot/snapshotctl.cpp
+++ b/fs_mgr/libsnapshot/snapshotctl.cpp
@@ -25,9 +25,27 @@
#include <android-base/logging.h>
#include <android-base/unique_fd.h>
+#include <fs_mgr.h>
+#include <fs_mgr_dm_linear.h>
+#include <fstab/fstab.h>
+#include <liblp/builder.h>
+#include <libsnapshot/cow_format.h>
#include <libsnapshot/snapshot.h>
+#include <storage_literals/storage_literals.h>
+#ifdef SNAPSHOTCTL_USERDEBUG_OR_ENG
+#include <BootControlClient.h>
+#endif
+
+using namespace std::chrono_literals;
using namespace std::string_literals;
+using namespace android::storage_literals;
+using android::fs_mgr::CreateLogicalPartitionParams;
+using android::fs_mgr::FindPartition;
+using android::fs_mgr::GetPartitionSize;
+using android::fs_mgr::PartitionOpener;
+using android::fs_mgr::ReadMetadata;
+using android::fs_mgr::SlotNumberForSlotSuffix;
int Usage() {
std::cerr << "snapshotctl: Control snapshots.\n"
@@ -67,11 +85,136 @@
return false;
}
+#ifdef SNAPSHOTCTL_USERDEBUG_OR_ENG
+bool CreateTestUpdate(SnapshotManager* sm) {
+ chromeos_update_engine::DeltaArchiveManifest manifest;
+
+ // We only copy system, to simplify things.
+ manifest.set_partial_update(true);
+
+ auto dap = manifest.mutable_dynamic_partition_metadata();
+ dap->set_snapshot_enabled(true);
+ dap->set_vabc_enabled(true);
+ dap->set_vabc_compression_param("none");
+ dap->set_cow_version(kCowVersionMajor);
+
+ auto source_slot = fs_mgr_get_slot_suffix();
+ auto source_slot_number = SlotNumberForSlotSuffix(source_slot);
+ auto target_slot = fs_mgr_get_other_slot_suffix();
+ auto target_slot_number = SlotNumberForSlotSuffix(target_slot);
+ auto super_source = fs_mgr_get_super_partition_name(source_slot_number);
+
+ // Get current partition information.
+ PartitionOpener opener;
+ auto source_metadata = ReadMetadata(opener, super_source, source_slot_number);
+ if (!source_metadata) {
+ std::cerr << "Could not read source partition metadata.\n";
+ return false;
+ }
+
+ auto system_source_name = "system" + source_slot;
+ auto system_source = FindPartition(*source_metadata.get(), system_source_name);
+ if (!system_source) {
+ std::cerr << "Could not find system partition: " << system_source_name << ".\n";
+ return false;
+ }
+ auto system_source_size = GetPartitionSize(*source_metadata.get(), *system_source);
+
+ // Since we only add copy operations, 64MB should be enough.
+ auto system_update = manifest.mutable_partitions()->Add();
+ system_update->set_partition_name("system");
+ system_update->set_estimate_cow_size(64_MiB);
+ system_update->mutable_new_partition_info()->set_size(system_source_size);
+
+ if (!sm->CreateUpdateSnapshots(manifest)) {
+ std::cerr << "Could not create update snapshots.\n";
+ return false;
+ }
+
+ // Write the "new" system partition.
+ auto system_target_name = "system" + target_slot;
+ auto source_device = "/dev/block/mapper/" + system_source_name;
+ CreateLogicalPartitionParams clpp = {
+ .block_device = fs_mgr_get_super_partition_name(target_slot_number),
+ .metadata_slot = {target_slot_number},
+ .partition_name = system_target_name,
+ .partition_opener = &opener,
+ .timeout_ms = 10s,
+ };
+ auto writer = sm->OpenSnapshotWriter(clpp, {source_device});
+ if (!writer) {
+ std::cerr << "Could not open snapshot writer.\n";
+ return false;
+ }
+ if (!writer->Initialize()) {
+ std::cerr << "Could not initialize snapshot for writing.\n";
+ return false;
+ }
+
+ for (uint64_t block = 0; block < system_source_size / 4096; block++) {
+ if (!writer->AddCopy(block, block)) {
+ std::cerr << "Unable to add copy operation for block " << block << ".\n";
+ return false;
+ }
+ }
+ if (!writer->Finalize()) {
+ std::cerr << "Could not finalize COW for " << system_target_name << ".\n";
+ return false;
+ }
+ writer = nullptr;
+
+ // Finished writing this partition, unmap.
+ if (!sm->UnmapUpdateSnapshot(system_target_name)) {
+ std::cerr << "Could not unmap snapshot for " << system_target_name << ".\n";
+ return false;
+ }
+
+ // All snapshots have been written.
+ if (!sm->FinishedSnapshotWrites(false /* wipe */)) {
+ std::cerr << "Could not finalize snapshot writes.\n";
+ return false;
+ }
+
+ auto hal = hal::BootControlClient::WaitForService();
+ if (!hal) {
+ std::cerr << "Could not find IBootControl HAL.\n";
+ return false;
+ }
+ auto cr = hal->SetActiveBootSlot(target_slot_number);
+ if (!cr.IsOk()) {
+ std::cerr << "Could not set active boot slot: " << cr.errMsg;
+ return false;
+ }
+
+ std::cerr << "It is now safe to reboot your device. If using a physical device, make\n"
+ << "sure that all physical partitions are flashed to both A and B slots.\n";
+ return true;
+}
+
+bool TestOtaHandler(int /* argc */, char** /* argv */) {
+ auto sm = SnapshotManager::New();
+
+ if (!sm->BeginUpdate()) {
+ std::cerr << "Error starting update.\n";
+ return false;
+ }
+
+ if (!CreateTestUpdate(sm.get())) {
+ sm->CancelUpdate();
+ return false;
+ }
+ return true;
+}
+#endif
+
static std::map<std::string, std::function<bool(int, char**)>> kCmdMap = {
// clang-format off
{"dump", DumpCmdHandler},
{"merge", MergeCmdHandler},
{"map", MapCmdHandler},
+#ifdef SNAPSHOTCTL_USERDEBUG_OR_ENG
+ {"test-blank-ota", TestOtaHandler},
+#endif
{"unmap", UnmapCmdHandler},
// clang-format on
};
diff --git a/fs_mgr/libsnapshot/utility.cpp b/fs_mgr/libsnapshot/utility.cpp
index 0a1be0d..cadd24d 100644
--- a/fs_mgr/libsnapshot/utility.cpp
+++ b/fs_mgr/libsnapshot/utility.cpp
@@ -153,9 +153,23 @@
}
bool WriteStringToFileAtomic(const std::string& content, const std::string& path) {
- std::string tmp_path = path + ".tmp";
- if (!android::base::WriteStringToFile(content, tmp_path)) {
- return false;
+ const std::string tmp_path = path + ".tmp";
+ {
+ const int flags = O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_BINARY;
+ android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(tmp_path.c_str(), flags, 0666)));
+ if (fd == -1) {
+ PLOG(ERROR) << "Failed to open " << path;
+ return false;
+ }
+ if (!android::base::WriteStringToFd(content, fd)) {
+ PLOG(ERROR) << "Failed to write to fd " << fd;
+ return false;
+ }
+ // rename() without fsync() is not safe. Data could still be living on page cache. To ensure
+ // atomiticity, call fsync()
+ if (fsync(fd) != 0) {
+ PLOG(ERROR) << "Failed to fsync " << tmp_path;
+ }
}
if (rename(tmp_path.c_str(), path.c_str()) == -1) {
PLOG(ERROR) << "rename failed from " << tmp_path << " to " << path;
diff --git a/fs_mgr/tests/adb-remount-test.sh b/fs_mgr/tests/adb-remount-test.sh
index a6bdd6c..68f8152 100755
--- a/fs_mgr/tests/adb-remount-test.sh
+++ b/fs_mgr/tests/adb-remount-test.sh
@@ -1241,40 +1241,45 @@
adb_sh grep -q " /vendor [^ ]* rw," /proc/mounts </dev/null ||
die -t "${T}" "/vendor is not RW"
+scratch_on_super=false
if ${overlayfs_needed}; then
- is_overlayfs_mounted || die -t "${T}" "expected overlay takeover"
-else
- is_overlayfs_mounted && die -t "${T}" "unexpected overlay takeover"
-fi
+ is_overlayfs_mounted /system ||
+ die -t "${T}" "expected overlay to takeover /system after remount"
-# If scratch_partition && uses_dynamic_scratch, then scratch is on super.
-# If scratch_partition && !uses_dynamic_scratch, then scratch is super_other, system_other.
-# If !scratch_partition, then scratch is on /data via image_manager.
-uses_dynamic_scratch=false
-scratch_partition=
-virtual_ab=$(get_property ro.virtual_ab.enabled)
-if ${overlayfs_needed}; then
+ # Collect information about the scratch device if we have one
M=$(adb_sh cat /proc/mounts </dev/null |
awk '$2 == "/mnt/scratch" { print $1, $3; exit }')
- [ -z "${M}" ] && die "cannot find any scratch device mounted on /mnt/scratch"
+ if [ -n "${M}" ]; then
+ scratch_device=$(echo "${M}" | awk '{ print $1 }')
+ scratch_filesystem=$(echo "${M}" | awk '{ print $2 }')
+ scratch_size=$(adb_sh df -k "${scratch_device}" </dev/null |
+ tail +2 | head -1 | awk '{ print $2 }')
+ [ -z "${scratch_size}" ] && die "cannot get size of scratch device (${scratch_device})"
- scratch_device=$(echo "${M}" | awk '{ print $1 }')
- scratch_filesystem=$(echo "${M}" | awk '{ print $2 }')
- scratch_size=$(adb_sh df -k "${scratch_device}" </dev/null |
- tail +2 | head -1 | awk '{ print $2 }')
- [ -z "${scratch_size}" ] && die "cannot get size of scratch device (${scratch_device})"
+ # Detect scratch partition backed by super?
+ for b in "/dev/block/by-name/super"{,_${ACTIVE_SLOT}}; do
+ if adb_test -e "${b}"; then
+ device=$(adb_su realpath "${b}")
+ D=$(adb_su stat -c '0x%t 0x%T' "${device}")
+ major=$(echo "${D}" | awk '{ print $1 }')
+ minor=$(echo "${D}" | awk '{ print $2 }')
+ super_devt=$(( major )):$(( minor ))
+ if adb_su dmctl table scratch | tail +2 | grep -q -w "${super_devt}"; then
+ scratch_on_super=true
+ fi
+ break
+ fi
+ done
- if [ -n "${virtual_ab}" ]; then
- LOG INFO "using dynamic scratch partition on /data (VAB device)"
- elif [[ "${scratch_device}" == /dev/block/by-name/* ]]; then
- scratch_partition="${scratch_device##/dev/block/by-name/}"
- LOG INFO "using physical scratch partition ${scratch_partition}"
+ if ${scratch_on_super}; then
+ LOG INFO "using dynamic scratch partition on super"
+ else
+ LOG INFO "using dynamic scratch partition on /data (VAB device)"
+ fi
+ LOG INFO "scratch device ${scratch_device} filesystem ${scratch_filesystem} size ${scratch_size}KiB"
else
- uses_dynamic_scratch=true
- scratch_partition=scratch
- LOG INFO "using dynamic scratch partition on super"
+ LOG INFO "cannot find any scratch device mounted on /mnt/scratch, using scratch on /cache"
fi
- LOG INFO "scratch device ${scratch_device} filesystem ${scratch_filesystem} size ${scratch_size}KiB"
for d in ${OVERLAYFS_BACKING}; do
if adb_test -d /${d}/overlay/system/upper; then
@@ -1283,8 +1288,6 @@
done
data_device=$(adb_sh awk '$2 == "/data" { print $1; exit }' /proc/mounts)
- is_overlayfs_mounted /system 2>/dev/null ||
- die -t "${T}" "expected overlay to takeover /system after remount"
# KISS (we do not support sub-mounts for system partitions currently)
adb_sh grep "^overlay " /proc/mounts </dev/null |
grep -vE "^overlay.* /(apex|system|vendor)/[^ ]" |
@@ -1312,6 +1315,8 @@
die "remount overlayfs missed a spot (rw)"
fi
done
+else
+ is_overlayfs_mounted && die -t "${T}" "unexpected overlay takeover"
fi
LOG OK "adb remount RW"
@@ -1418,7 +1423,7 @@
is_bootloader_fastboot=true
# cuttlefish?
-[[ "$(get_property ro.product.device)" == vsoc* ]] &&
+[[ "$(get_property ro.product.vendor.device)" == vsoc_* ]] &&
is_bootloader_fastboot=false
is_userspace_fastboot=false
@@ -1455,31 +1460,18 @@
fastboot_getvar is-userspace yes &&
is_userspace_fastboot=true
- # check ${scratch_partition} via fastboot
- if [ -n "${scratch_partition}" ]; then
- fastboot_getvar partition-type:${scratch_partition} raw ||
- ( fastboot reboot && false) ||
- die "fastboot can not see ${scratch_partition} parameters"
- if ${uses_dynamic_scratch}; then
- fastboot_getvar has-slot:${scratch_partition} no &&
- fastboot_getvar is-logical:${scratch_partition} yes ||
- ( fastboot reboot && false) ||
- die "fastboot can not see ${scratch_partition} parameters"
- LOG INFO "expect fastboot erase ${scratch_partition} to fail"
- fastboot erase ${scratch_partition} &&
- ( fastboot reboot || true) &&
- die "fastboot can erase ${scratch_partition}"
- else
- fastboot_getvar is-logical:${scratch_partition} no ||
- ( fastboot reboot && false) ||
- die "fastboot can not see ${scratch_partition} parameters"
- fastboot reboot-bootloader ||
- die "fastboot reboot bootloader"
- fi
- LOG INFO "expect fastboot format ${scratch_partition} to fail"
- fastboot format ${scratch_partition} &&
- ( fastboot reboot || true) &&
- die "fastboot can format ${scratch_partition}"
+
+ if ${scratch_on_super}; then
+ fastboot_getvar partition-type:scratch raw ||
+ die "fastboot cannot see parameter partition-type:scratch"
+ fastboot_getvar has-slot:scratch no ||
+ die "fastboot cannot see parameter has-slot:scratch"
+ fastboot_getvar is-logical:scratch yes ||
+ die "fastboot cannot see parameter is-logical:scratch"
+ LOG INFO "expect fastboot erase scratch to fail"
+ fastboot erase scratch && die "fastboot can erase scratch"
+ LOG INFO "expect fastboot format scratch to fail"
+ fastboot format scratch && die "fastboot can format scratch"
fi
fastboot reboot || die "cannot reboot out of fastboot"
@@ -1539,9 +1531,9 @@
done
################################################################################
-if ${is_bootloader_fastboot} && [ -n "${scratch_partition}" ]; then
+if ${is_bootloader_fastboot} && ${scratch_on_super}; then
- LOG RUN "test fastboot flash to ${scratch_partition} recovery"
+ LOG RUN "test fastboot flash to scratch recovery"
avc_check
adb reboot fastboot </dev/null ||
@@ -1550,15 +1542,15 @@
dd if=/dev/zero of=${img} bs=4096 count=16 2>/dev/null &&
fastboot_wait ${FASTBOOT_WAIT} ||
die "reboot into fastboot to flash scratch `usb_status`"
- fastboot flash --force ${scratch_partition} ${img}
+ fastboot flash --force scratch ${img}
err=${?}
fastboot reboot ||
die "can not reboot out of fastboot"
[ 0 -eq ${err} ] ||
- die "fastboot flash ${scratch_partition}"
+ die "fastboot flash scratch"
adb_wait ${ADB_WAIT} &&
adb_root ||
- die "did not reboot after flashing empty ${scratch_partition} `usb_status`"
+ die "did not reboot after flashing empty scratch $(usb_status)"
T=`adb_date`
D=`adb disable-verity 2>&1`
err=${?}
@@ -1578,7 +1570,7 @@
[ ${err} = 0 ] &&
[ X"${D}" = X"${D##*setup failed}" ] &&
[ X"${D}" != X"${D##*[Uu]sing overlayfs}" ] &&
- LOG OK "${scratch_partition} recreated" ||
+ LOG OK "recreated scratch" ||
die -t ${T} "setup for overlayfs"
adb remount >&2 ||
die -t ${T} "remount failed"
diff --git a/init/Android.bp b/init/Android.bp
index f0e362c..06f696e 100644
--- a/init/Android.bp
+++ b/init/Android.bp
@@ -39,6 +39,7 @@
"epoll.cpp",
"import_parser.cpp",
"interface_utils.cpp",
+ "interprocess_fifo.cpp",
"keychords.cpp",
"parser.cpp",
"property_type.cpp",
@@ -308,7 +309,7 @@
name: "init_first_stage_cc_defaults",
module_type: "cc_defaults",
config_namespace: "ANDROID",
- bool_variables: ["BOARD_BUILD_SYSTEM_ROOT_IMAGE", "BOARD_USES_RECOVERY_AS_BOOT"],
+ bool_variables: ["BOARD_USES_RECOVERY_AS_BOOT"],
properties: ["installable"],
}
@@ -317,9 +318,6 @@
init_first_stage_cc_defaults {
name: "init_first_stage_defaults",
soong_config_variables: {
- BOARD_BUILD_SYSTEM_ROOT_IMAGE: {
- installable: false,
- },
BOARD_USES_RECOVERY_AS_BOOT: {
installable: false,
},
@@ -470,6 +468,7 @@
"epoll_test.cpp",
"firmware_handler_test.cpp",
"init_test.cpp",
+ "interprocess_fifo_test.cpp",
"keychords_test.cpp",
"oneshot_on_test.cpp",
"persistent_properties_test.cpp",
@@ -484,7 +483,10 @@
"ueventd_test.cpp",
"util_test.cpp",
],
- static_libs: ["libinit"],
+ static_libs: [
+ "libgmock",
+ "libinit",
+ ],
test_suites: [
"cts",
diff --git a/init/Android.mk b/init/Android.mk
index c08fe03..4b85c15 100644
--- a/init/Android.mk
+++ b/init/Android.mk
@@ -8,11 +8,9 @@
LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
LOCAL_LICENSE_CONDITIONS := notice
LOCAL_NOTICE_FILE := $(LOCAL_PATH)/NOTICE
-ifneq ($(BOARD_BUILD_SYSTEM_ROOT_IMAGE),true)
ifneq ($(BOARD_USES_RECOVERY_AS_BOOT),true)
LOCAL_REQUIRED_MODULES := \
init_first_stage \
endif # BOARD_USES_RECOVERY_AS_BOOT
-endif # BOARD_BUILD_SYSTEM_ROOT_IMAGE
include $(BUILD_PHONY_PACKAGE)
diff --git a/init/README.md b/init/README.md
index 7b3d32a..6596528 100644
--- a/init/README.md
+++ b/init/README.md
@@ -368,8 +368,9 @@
given console.
`task_profiles <profile> [ <profile>\* ]`
-> Set task profiles for the process when it forks. This is designed to replace the use of
- writepid option for moving a process into a cgroup.
+> Set task profiles. Before Android U, the profiles are applied to the main thread of the service.
+ For Android U and later, the profiles are applied to the entire service process. This is designed
+ to replace the use of writepid option for moving a process into a cgroup.
`timeout_period <seconds>`
> Provide a timeout after which point the service will be killed. The oneshot keyword is respected
diff --git a/init/builtins.cpp b/init/builtins.cpp
index c8cb253..7cb8b11 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -879,6 +879,8 @@
SetProperty("partition." + partition + ".verified.hash_alg", hashtree_info->algorithm);
SetProperty("partition." + partition + ".verified.root_digest",
hashtree_info->root_digest);
+ SetProperty("partition." + partition + ".verified.check_at_most_once",
+ hashtree_info->check_at_most_once ? "1" : "0");
}
}
diff --git a/init/epoll.cpp b/init/epoll.cpp
index 0580f86..fd1af4f 100644
--- a/init/epoll.cpp
+++ b/init/epoll.cpp
@@ -45,18 +45,18 @@
return Error() << "Must specify events";
}
- Info info;
- info.events = events;
- info.handler = std::make_shared<decltype(handler)>(std::move(handler));
- auto [it, inserted] = epoll_handlers_.emplace(fd, std::move(info));
+ auto [it, inserted] = epoll_handlers_.emplace(
+ fd, Info{
+ .events = events,
+ .handler = std::move(handler),
+ });
if (!inserted) {
return Error() << "Cannot specify two epoll handlers for a given FD";
}
- epoll_event ev;
- ev.events = events;
- // std::map's iterators do not get invalidated until erased, so we use the
- // pointer to the std::function in the map directly for epoll_ctl.
- ev.data.ptr = reinterpret_cast<void*>(&it->second);
+ epoll_event ev = {
+ .events = events,
+ .data.fd = fd,
+ };
if (epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, fd, &ev) == -1) {
Result<void> result = ErrnoError() << "epoll_ctl failed to add fd";
epoll_handlers_.erase(fd);
@@ -69,14 +69,19 @@
if (epoll_ctl(epoll_fd_, EPOLL_CTL_DEL, fd, nullptr) == -1) {
return ErrnoError() << "epoll_ctl failed to remove fd";
}
- if (epoll_handlers_.erase(fd) != 1) {
+ auto it = epoll_handlers_.find(fd);
+ if (it == epoll_handlers_.end()) {
return Error() << "Attempting to remove epoll handler for FD without an existing handler";
}
+ to_remove_.insert(it->first);
return {};
}
-Result<std::vector<std::shared_ptr<Epoll::Handler>>> Epoll::Wait(
- std::optional<std::chrono::milliseconds> timeout) {
+void Epoll::SetFirstCallback(std::function<void()> first_callback) {
+ first_callback_ = std::move(first_callback);
+}
+
+Result<int> Epoll::Wait(std::optional<std::chrono::milliseconds> timeout) {
int timeout_ms = -1;
if (timeout && timeout->count() < INT_MAX) {
timeout_ms = timeout->count();
@@ -87,19 +92,28 @@
if (num_events == -1) {
return ErrnoError() << "epoll_wait failed";
}
- std::vector<std::shared_ptr<Handler>> pending_functions;
+ if (num_events > 0 && first_callback_) {
+ first_callback_();
+ }
for (int i = 0; i < num_events; ++i) {
- auto& info = *reinterpret_cast<Info*>(ev[i].data.ptr);
+ const auto it = epoll_handlers_.find(ev[i].data.fd);
+ if (it == epoll_handlers_.end()) {
+ continue;
+ }
+ const Info& info = it->second;
if ((info.events & (EPOLLIN | EPOLLPRI)) == (EPOLLIN | EPOLLPRI) &&
(ev[i].events & EPOLLIN) != ev[i].events) {
// This handler wants to know about exception events, and just got one.
// Log something informational.
LOG(ERROR) << "Received unexpected epoll event set: " << ev[i].events;
}
- pending_functions.emplace_back(info.handler);
+ info.handler();
+ for (auto fd : to_remove_) {
+ epoll_handlers_.erase(fd);
+ }
+ to_remove_.clear();
}
-
- return pending_functions;
+ return num_events;
}
} // namespace init
diff --git a/init/epoll.h b/init/epoll.h
index f58ae8d..1e71803 100644
--- a/init/epoll.h
+++ b/init/epoll.h
@@ -24,6 +24,7 @@
#include <map>
#include <memory>
#include <optional>
+#include <unordered_set>
#include <vector>
#include <android-base/unique_fd.h>
@@ -42,17 +43,19 @@
Result<void> Open();
Result<void> RegisterHandler(int fd, Handler handler, uint32_t events = EPOLLIN);
Result<void> UnregisterHandler(int fd);
- Result<std::vector<std::shared_ptr<Handler>>> Wait(
- std::optional<std::chrono::milliseconds> timeout);
+ void SetFirstCallback(std::function<void()> first_callback);
+ Result<int> Wait(std::optional<std::chrono::milliseconds> timeout);
private:
struct Info {
- std::shared_ptr<Handler> handler;
+ Handler handler;
uint32_t events;
};
android::base::unique_fd epoll_fd_;
std::map<int, Info> epoll_handlers_;
+ std::function<void()> first_callback_;
+ std::unordered_set<int> to_remove_;
};
} // namespace init
diff --git a/init/epoll_test.cpp b/init/epoll_test.cpp
index 9236cd5..7105a68 100644
--- a/init/epoll_test.cpp
+++ b/init/epoll_test.cpp
@@ -21,6 +21,7 @@
#include <unordered_set>
#include <android-base/file.h>
+#include <android-base/logging.h>
#include <gtest/gtest.h>
namespace android {
@@ -30,14 +31,10 @@
class CatchDtor final {
public:
- CatchDtor() { sValidObjects.emplace(this); }
- CatchDtor(const CatchDtor&) { sValidObjects.emplace(this); }
- ~CatchDtor() {
- auto iter = sValidObjects.find(this);
- if (iter != sValidObjects.end()) {
- sValidObjects.erase(iter);
- }
- }
+ CatchDtor() { CHECK(sValidObjects.emplace(this).second); }
+ CatchDtor(const CatchDtor&) { CHECK(sValidObjects.emplace(this).second); }
+ CatchDtor(const CatchDtor&&) { CHECK(sValidObjects.emplace(this).second); }
+ ~CatchDtor() { CHECK_EQ(sValidObjects.erase(this), size_t{1}); }
};
TEST(epoll, UnregisterHandler) {
@@ -48,11 +45,13 @@
ASSERT_EQ(pipe(fds), 0);
CatchDtor catch_dtor;
- bool handler_invoked;
+ bool handler_invoked = false;
auto handler = [&, catch_dtor]() -> void {
auto result = epoll.UnregisterHandler(fds[0]);
ASSERT_EQ(result.ok(), !handler_invoked);
handler_invoked = true;
+ // The assert statement below verifies that the UnregisterHandler() call
+ // above did not destroy the current std::function<> instance.
ASSERT_NE(sValidObjects.find((void*)&catch_dtor), sValidObjects.end());
};
@@ -61,14 +60,9 @@
uint8_t byte = 0xee;
ASSERT_TRUE(android::base::WriteFully(fds[1], &byte, sizeof(byte)));
- auto results = epoll.Wait({});
- ASSERT_RESULT_OK(results);
- ASSERT_EQ(results->size(), size_t(1));
-
- for (const auto& function : *results) {
- (*function)();
- (*function)();
- }
+ auto epoll_result = epoll.Wait({});
+ ASSERT_RESULT_OK(epoll_result);
+ ASSERT_EQ(*epoll_result, 1);
ASSERT_TRUE(handler_invoked);
}
diff --git a/init/fuzzer/Android.bp b/init/fuzzer/Android.bp
new file mode 100644
index 0000000..c21a196
--- /dev/null
+++ b/init/fuzzer/Android.bp
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+package {
+ default_applicable_licenses: ["system_core_init_license"],
+}
+
+cc_defaults {
+ name: "libinit_defaults",
+ static_libs: [
+ "libc++fs",
+ "liblmkd_utils",
+ "libmodprobe",
+ "libprotobuf-cpp-lite",
+ "libpropertyinfoparser",
+ "libsnapshot_init",
+ "libinit",
+ ],
+ shared_libs: [
+ "libbase",
+ "libfs_mgr",
+ "libhidl-gen-utils",
+ "libkeyutils",
+ "liblog",
+ "libprocessgroup",
+ "libselinux",
+ ],
+ header_libs: ["libinit_headers"],
+ fuzz_config: {
+ cc: [
+ "android-media-fuzzing-reports@google.com",
+ ],
+ componentid: 155276,
+ },
+}
+
+cc_fuzz {
+ name: "init_parser_fuzzer",
+ srcs: [
+ "init_parser_fuzzer.cpp",
+ ],
+ shared_libs: ["libhidlmetadata",],
+ defaults: [
+ "libinit_defaults",
+ ],
+}
+
+cc_fuzz {
+ name: "init_property_fuzzer",
+ srcs: [
+ "init_property_fuzzer.cpp",
+ ],
+ defaults: ["libinit_defaults"],
+}
+
+cc_fuzz {
+ name: "init_ueventHandler_fuzzer",
+ srcs: [
+ "init_ueventHandler_fuzzer.cpp",
+ ],
+ defaults: [
+ "libinit_defaults",
+ ],
+}
diff --git a/init/fuzzer/README.md b/init/fuzzer/README.md
new file mode 100644
index 0000000..fc9a6a6
--- /dev/null
+++ b/init/fuzzer/README.md
@@ -0,0 +1,98 @@
+# Fuzzers for libinit
+
+## Table of contents
++ [init_parser_fuzzer](#InitParser)
++ [init_property_fuzzer](#InitProperty)
++ [init_ueventHandler_fuzzer](#InitUeventHandler)
+
+# <a name="InitParser"></a> Fuzzer for InitParser
+
+InitParser supports the following parameters:
+1. ValidPathNames (parameter name: "kValidPaths")
+2. ValidParseInputs (parameter name: "kValidInputs")
+
+| Parameter| Valid Values| Configured Value|
+|------------- |-------------| ----- |
+|`kValidPaths`| 0.`/system/etc/init/hw/init.rc`,<br/> 1.`/system/etc/init` |Value obtained from FuzzedDataProvider|
+|`kValidInputs`| 0.`{"","cpu", "10", "10"}`,<br/> 1.`{"","RLIM_CPU", "10", "10"}`,<br/> 2.`{"","12", "unlimited", "10"}`,<br/> 3.`{"","13", "-1", "10"}`,<br/> 4.`{"","14", "10", "unlimited"}`,<br/> 5.`{"","15", "10", "-1"}` |Value obtained from FuzzedDataProvider|
+
+#### Steps to run
+1. Build the fuzzer
+```
+ $ mm -j$(nproc) init_parser_fuzzer
+```
+2. Run on device
+```
+ $ adb sync data
+ $ adb shell /data/fuzz/arm64/init_parser_fuzzer/init_parser_fuzzer
+```
+
+# <a name="InitProperty"></a> Fuzzer for InitProperty
+
+InitProperty supports the following parameters:
+ PropertyType (parameter name: "PropertyType")
+
+| Parameter| Valid Values |Configured Value|
+|-------------|----------|----- |
+|`PropertyType`| 0.`STRING`,<br/> 1.`BOOL`,<br/> 2.`INT`,<br/> 3.`UINT`,<br/> 4.`DOUBLE`,<br/> 5.`SIZE`,<br/>6.`ENUM`,<br/>7.`RANDOM`|Value obtained from FuzzedDataProvider|
+
+#### Steps to run
+1. Build the fuzzer
+```
+ $ mm -j$(nproc) init_property_fuzzer
+```
+2. Run on device
+```
+ $ adb sync data
+ $ adb shell /data/fuzz/arm64/init_property_fuzzer/init_property_fuzzer
+```
+
+# <a name="InitUeventHandler"></a> Fuzzer for InitUeventHandler
+
+##### Maximize code coverage
+The configuration parameters are not hardcoded, but instead selected based on
+incoming data. This ensures more code paths are reached by the fuzzer.
+
+InitUeventHandler supports the following parameters:
+1. Major (parameter name: `major`)
+2. Minor (parameter name: `minor`)
+3. PartitionNum (parameter name: `partition_num`)
+4. Uid (parameter name: `uid`)
+5. Gid (parameter name: `gid`)
+6. Action (parameter name: `action`)
+7. Path (parameter name: `path`)
+8. Subsystem (parameter name: `subsystem`)
+9. PartitionName (parameter name: `partition_name`)
+10. DeviceName (parameter name: `device_name`)
+11. Modalias (parameter name: `modalias`)
+12. DevPath (parameter name: `devPath`)
+13. HandlerPath (parameter name: `handlerPath`)
+
+| Parameter| Valid Values| Configured Value|
+|------------- |-------------| ----- |
+| `major` | `UINT32_MIN` to `UINT32_MAX` | Value obtained from FuzzedDataProvider|
+| `minor` | `UINT32_MIN` to `UINT32_MAX` | Value obtained from FuzzedDataProvider|
+| `partition_num ` | `UINT32_MIN` to `UINT32_MAX` | Value obtained from FuzzedDataProvider|
+| `uid` | `UINT32_MIN` to `UINT32_MAX` | Value obtained from FuzzedDataProvider|
+| `gid` | `UINT32_MIN` to `UINT32_MAX` | Value obtained from FuzzedDataProvider|
+| `action` | `String` | Value obtained from FuzzedDataProvider|
+| `path` | `String` | Value obtained from FuzzedDataProvider|
+| `subsystem` | `String` | Value obtained from FuzzedDataProvider|
+| `partition_name` | `String` | Value obtained from FuzzedDataProvider|
+| `device_name` | `String` | Value obtained from FuzzedDataProvider|
+| `modalias` | `String` | Value obtained from FuzzedDataProvider|
+| `devPath` | `String` | Value obtained from FuzzedDataProvider|
+| `handlerPath` | `String` | Value obtained from FuzzedDataProvider|
+
+This also ensures that the plugin is always deterministic for any given input.
+
+#### Steps to run
+1. Build the fuzzer
+```
+$ mm -j$(nproc) init_ueventHandler_fuzzer
+```
+2. Run on device
+```
+$ adb sync data
+$ adb shell /data/fuzz/arm64/init_ueventHandler_fuzzer/init_ueventHandler_fuzzer
+```
diff --git a/init/fuzzer/init_parser_fuzzer.cpp b/init/fuzzer/init_parser_fuzzer.cpp
new file mode 100644
index 0000000..e6a78a2
--- /dev/null
+++ b/init/fuzzer/init_parser_fuzzer.cpp
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2022 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 <fuzzer/FuzzedDataProvider.h>
+#include <hidl/metadata.h>
+#include <import_parser.h>
+#include <interface_utils.h>
+#include <rlimit_parser.h>
+
+using namespace android;
+using namespace android::init;
+
+const std::vector<std::string> kValidInputs[] = {
+ {"", "cpu", "10", "10"}, {"", "RLIM_CPU", "10", "10"}, {"", "12", "unlimited", "10"},
+ {"", "13", "-1", "10"}, {"", "14", "10", "unlimited"}, {"", "15", "10", "-1"},
+};
+
+const std::string kValidPaths[] = {
+ "/system/etc/init/hw/init.rc",
+ "/system/etc/init",
+};
+
+const int32_t kMaxBytes = 256;
+const std::string kValidInterfaces = "android.frameworks.vr.composer@2.0::IVrComposerClient";
+
+class InitParserFuzzer {
+ public:
+ InitParserFuzzer(const uint8_t* data, size_t size) : fdp_(data, size){};
+ void Process();
+
+ private:
+ void InvokeParser();
+ void InvokeLimitParser();
+ void InvokeInterfaceUtils();
+ InterfaceInheritanceHierarchyMap GenerateHierarchyMap();
+ std::vector<HidlInterfaceMetadata> GenerateInterfaceMetadata();
+
+ FuzzedDataProvider fdp_;
+};
+
+void InitParserFuzzer::InvokeLimitParser() {
+ if (fdp_.ConsumeBool()) {
+ std::vector<std::string> input;
+ input.push_back("");
+ input.push_back(fdp_.ConsumeRandomLengthString(kMaxBytes));
+ input.push_back(fdp_.ConsumeRandomLengthString(kMaxBytes));
+ input.push_back(fdp_.ConsumeRandomLengthString(kMaxBytes));
+ ParseRlimit(input);
+ } else {
+ ParseRlimit(fdp_.PickValueInArray(kValidInputs));
+ }
+}
+
+std::vector<HidlInterfaceMetadata> InitParserFuzzer::GenerateInterfaceMetadata() {
+ std::vector<HidlInterfaceMetadata> random_interface;
+ for (size_t idx = 0; idx < fdp_.ConsumeIntegral<size_t>(); ++idx) {
+ HidlInterfaceMetadata metadata;
+ metadata.name = fdp_.ConsumeRandomLengthString(kMaxBytes);
+ for (size_t idx1 = 0; idx1 < fdp_.ConsumeIntegral<size_t>(); ++idx1) {
+ metadata.inherited.push_back(fdp_.ConsumeRandomLengthString(kMaxBytes));
+ }
+ random_interface.push_back(metadata);
+ }
+ return random_interface;
+}
+
+InterfaceInheritanceHierarchyMap InitParserFuzzer::GenerateHierarchyMap() {
+ InterfaceInheritanceHierarchyMap result;
+ std::vector<HidlInterfaceMetadata> random_interface;
+ if (fdp_.ConsumeBool()) {
+ random_interface = GenerateInterfaceMetadata();
+ } else {
+ random_interface = HidlInterfaceMetadata::all();
+ }
+
+ for (const HidlInterfaceMetadata& iface : random_interface) {
+ std::set<FQName> inherited_interfaces;
+ for (const std::string& intf : iface.inherited) {
+ FQName fqname;
+ (void)fqname.setTo(intf);
+ inherited_interfaces.insert(fqname);
+ }
+ FQName fqname;
+ (void)fqname.setTo(iface.name);
+ result[fqname] = inherited_interfaces;
+ }
+ return result;
+}
+
+void InitParserFuzzer::InvokeInterfaceUtils() {
+ InterfaceInheritanceHierarchyMap hierarchy_map = GenerateHierarchyMap();
+ SetKnownInterfaces(hierarchy_map);
+ IsKnownInterface(fdp_.ConsumeRandomLengthString(kMaxBytes));
+ std::set<std::string> interface_set;
+ for (size_t idx = 0; idx < fdp_.ConsumeIntegral<size_t>(); ++idx) {
+ auto set_interface_values = fdp_.PickValueInArray<const std::function<void()>>({
+ [&]() {
+ interface_set.insert(("aidl/" + fdp_.ConsumeRandomLengthString(kMaxBytes)));
+ },
+ [&]() { interface_set.insert(fdp_.ConsumeRandomLengthString(kMaxBytes)); },
+ [&]() { interface_set.insert(kValidInterfaces); },
+ });
+ set_interface_values();
+ }
+ CheckInterfaceInheritanceHierarchy(interface_set, hierarchy_map);
+}
+
+void InitParserFuzzer::InvokeParser() {
+ Parser parser;
+ std::string name = fdp_.ConsumeBool() ? fdp_.ConsumeRandomLengthString(kMaxBytes) : "import";
+ parser.AddSectionParser(name, std::make_unique<ImportParser>(&parser));
+ std::string path = fdp_.ConsumeBool() ? fdp_.PickValueInArray(kValidPaths)
+ : fdp_.ConsumeRandomLengthString(kMaxBytes);
+ parser.ParseConfig(path);
+ parser.ParseConfigFileInsecure(path);
+}
+
+void InitParserFuzzer::Process() {
+ while (fdp_.remaining_bytes()) {
+ auto invoke_parser_fuzzer = fdp_.PickValueInArray<const std::function<void()>>({
+ [&]() { InvokeParser(); },
+ [&]() { InvokeInterfaceUtils(); },
+ [&]() { InvokeLimitParser(); },
+ });
+ invoke_parser_fuzzer();
+ }
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ InitParserFuzzer init_parser_fuzzer(data, size);
+ init_parser_fuzzer.Process();
+ return 0;
+}
diff --git a/init/fuzzer/init_property_fuzzer.cpp b/init/fuzzer/init_property_fuzzer.cpp
new file mode 100644
index 0000000..22df375
--- /dev/null
+++ b/init/fuzzer/init_property_fuzzer.cpp
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2022 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 <persistent_properties.h>
+#include <property_type.h>
+#include <sys/stat.h>
+#include <fstream>
+#include "fuzzer/FuzzedDataProvider.h"
+
+using namespace android;
+using namespace android::init;
+using android::init::persistent_property_filename;
+
+const std::string kTempDir = "/data/local/tmp/";
+const std::string kFuzzerPropertyFile = kTempDir + "persistent_properties";
+constexpr int32_t kMaxPropertyLength = 10;
+const std::string kPrefix = "persist.";
+const std::string kPropertyName = kPrefix + "sys.timezone";
+const std::string kPropertyValue = "America/Los_Angeles";
+const std::string kLegacyPropertyFile = "/data/property/persist.properties";
+const std::string kSizeSuffix[3] = {"g", "k", "m"};
+constexpr int32_t kMinNumStrings = 1;
+constexpr int32_t kMaxNumStrings = 10;
+
+enum PropertyType { STRING, BOOL, INT, UINT, DOUBLE, SIZE, ENUM, RANDOM, kMaxValue = RANDOM };
+
+class InitPropertyFuzzer {
+ public:
+ InitPropertyFuzzer(const uint8_t* data, size_t size) : fdp_(data, size){};
+ void process();
+
+ private:
+ void InvokeCheckType();
+ void InvokeWritePersistentProperty();
+ void RemoveFiles();
+ void CreateFuzzerPropertyFile(const std::string property_file);
+ FuzzedDataProvider fdp_;
+};
+
+void InitPropertyFuzzer::InvokeCheckType() {
+ std::string property_type;
+ std::string value;
+ int type = fdp_.ConsumeEnum<PropertyType>();
+ switch (type) {
+ case STRING:
+ value = fdp_.ConsumeRandomLengthString(kMaxPropertyLength);
+ property_type = "string";
+ break;
+ case BOOL:
+ value = fdp_.ConsumeBool();
+ property_type = "bool";
+ break;
+ case INT:
+ value = fdp_.ConsumeIntegral<int>();
+ property_type = "int";
+ break;
+ case UINT:
+ value = fdp_.ConsumeIntegral<uint_t>();
+ property_type = "uint";
+ break;
+ case DOUBLE:
+ value = fdp_.ConsumeFloatingPoint<double>();
+ property_type = "double";
+ break;
+ case SIZE:
+ value = fdp_.ConsumeIntegral<uint_t>();
+ value = value.append(fdp_.PickValueInArray(kSizeSuffix));
+ property_type = "size";
+ break;
+ case ENUM:
+ value = fdp_.ConsumeIntegral<uint_t>();
+ property_type = "enum";
+ break;
+ case RANDOM:
+ value = fdp_.ConsumeRandomLengthString(kMaxPropertyLength);
+ property_type = fdp_.ConsumeRandomLengthString(kMaxPropertyLength);
+ break;
+ }
+
+ CheckType(property_type, value);
+}
+
+void InitPropertyFuzzer::InvokeWritePersistentProperty() {
+ if (fdp_.ConsumeBool()) {
+ WritePersistentProperty(kPropertyName, kPropertyValue);
+ } else {
+ WritePersistentProperty((kPrefix + fdp_.ConsumeRandomLengthString(kMaxPropertyLength)),
+ fdp_.ConsumeRandomLengthString(kMaxPropertyLength));
+ }
+}
+
+void InitPropertyFuzzer::RemoveFiles() {
+ remove(kFuzzerPropertyFile.c_str());
+ remove(kLegacyPropertyFile.c_str());
+}
+
+void InitPropertyFuzzer::CreateFuzzerPropertyFile(const std::string property_file) {
+ std::ofstream out;
+ out.open(property_file, std::ios::binary | std::ofstream::trunc);
+ chmod(property_file.c_str(), S_IRWXU);
+ const int32_t numStrings = fdp_.ConsumeIntegralInRange(kMinNumStrings, kMaxNumStrings);
+ for (int32_t i = 0; i < numStrings; ++i) {
+ out << fdp_.ConsumeRandomLengthString(kMaxPropertyLength) << "\n";
+ }
+ out.close();
+}
+
+void InitPropertyFuzzer::process() {
+ persistent_property_filename = kFuzzerPropertyFile;
+ /* Property and legacy files are created using createFuzzerPropertyFile() and */
+ /* are used in the below APIs. Hence createFuzzerPropertyFile() is not a part */
+ /* of the lambda construct. */
+ CreateFuzzerPropertyFile(kFuzzerPropertyFile);
+ CreateFuzzerPropertyFile(kLegacyPropertyFile);
+ auto property_type = fdp_.PickValueInArray<const std::function<void()>>({
+ [&]() { InvokeCheckType(); },
+ [&]() { InvokeWritePersistentProperty(); },
+ [&]() { LoadPersistentProperties(); },
+ });
+ property_type();
+ RemoveFiles();
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ InitPropertyFuzzer initPropertyFuzzer(data, size);
+ initPropertyFuzzer.process();
+ return 0;
+}
diff --git a/init/fuzzer/init_ueventHandler_fuzzer.cpp b/init/fuzzer/init_ueventHandler_fuzzer.cpp
new file mode 100644
index 0000000..b6d5f8a
--- /dev/null
+++ b/init/fuzzer/init_ueventHandler_fuzzer.cpp
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2022 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 <devices.h>
+#include <firmware_handler.h>
+#include <fuzzer/FuzzedDataProvider.h>
+#include <modalias_handler.h>
+#include <sys/stat.h>
+#include <util.h>
+#include <fstream>
+
+using namespace android;
+using namespace android::init;
+constexpr int32_t kMaxBytes = 100;
+constexpr int32_t kMaxSize = 1000;
+constexpr int32_t kMinSize = 1;
+
+/*'HandleUevent' prefixes the path with '/sys' and hence this is required to point
+ * to'/data/local/tmp' dir.*/
+const std::string kPath = "/../data/local/tmp/";
+const std::string kPathPrefix = "/..";
+
+void MakeFile(FuzzedDataProvider* fdp, std::string s) {
+ std::ofstream out;
+ out.open(s, std::ios::binary | std::ofstream::trunc);
+ for (int32_t idx = 0; idx < fdp->ConsumeIntegralInRange(kMinSize, kMaxSize); ++idx) {
+ out << fdp->ConsumeRandomLengthString(kMaxBytes) << "\n";
+ }
+ out.close();
+}
+
+void CreateDir(std::string Directory, FuzzedDataProvider* fdp) {
+ std::string tmp = Directory.substr(kPathPrefix.length());
+ mkdir_recursive(android::base::Dirname(tmp.c_str()),
+ S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
+ MakeFile(fdp, tmp + "/data");
+ MakeFile(fdp, tmp + "/loading");
+}
+
+std::string SelectRandomString(FuzzedDataProvider* fdp, std::string s) {
+ if (fdp->ConsumeBool()) {
+ if (fdp->ConsumeBool()) {
+ return fdp->ConsumeRandomLengthString(kMaxBytes);
+ } else {
+ return s;
+ }
+ }
+ return "";
+}
+
+Uevent CreateUevent(FuzzedDataProvider* fdp) {
+ Uevent uevent;
+ uevent.action = SelectRandomString(fdp, "add");
+ uevent.subsystem = SelectRandomString(fdp, "firmware");
+ uevent.path = SelectRandomString(fdp, kPath + fdp->ConsumeRandomLengthString(kMaxBytes));
+ uevent.firmware = fdp->ConsumeBool() ? fdp->ConsumeRandomLengthString(kMaxBytes) : "";
+ uevent.partition_name = fdp->ConsumeBool() ? fdp->ConsumeRandomLengthString(kMaxBytes) : "";
+ uevent.device_name = fdp->ConsumeBool() ? fdp->ConsumeRandomLengthString(kMaxBytes) : "";
+ uevent.modalias = fdp->ConsumeBool() ? fdp->ConsumeRandomLengthString(kMaxBytes) : "";
+ uevent.partition_num = fdp->ConsumeIntegral<int32_t>();
+ uevent.major = fdp->ConsumeIntegral<int32_t>();
+ uevent.minor = fdp->ConsumeIntegral<int32_t>();
+ return uevent;
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ FuzzedDataProvider fdp(data, size);
+ while (fdp.remaining_bytes()) {
+ auto invoke_uevent_handler_fuzzer = fdp.PickValueInArray<const std::function<void()>>({
+ [&]() {
+ std::vector<std::string> modalias_vector;
+ for (size_t idx = 0;
+ idx < fdp.ConsumeIntegralInRange<size_t>(kMinSize, kMaxSize); ++idx) {
+ modalias_vector.push_back(fdp.ConsumeRandomLengthString(kMaxBytes));
+ }
+ ModaliasHandler modalias_handler = ModaliasHandler(modalias_vector);
+ modalias_handler.HandleUevent(CreateUevent(&fdp));
+ },
+ [&]() {
+ std::vector<ExternalFirmwareHandler> external_handlers;
+ std::vector<std::string> firmware_directories;
+ for (size_t idx = 0;
+ idx < fdp.ConsumeIntegralInRange<size_t>(kMinSize, kMaxSize); ++idx) {
+ std::string devPath = fdp.ConsumeRandomLengthString(kMaxBytes);
+ uid_t uid = fdp.ConsumeIntegral<uid_t>();
+ gid_t gid = fdp.ConsumeIntegral<gid_t>();
+ std::string handlerPath = fdp.ConsumeRandomLengthString(kMaxBytes);
+ ExternalFirmwareHandler externalFirmwareHandler =
+ ExternalFirmwareHandler(devPath, uid, gid, handlerPath);
+ external_handlers.push_back(externalFirmwareHandler);
+ firmware_directories.push_back(fdp.ConsumeRandomLengthString(kMaxBytes));
+ }
+ FirmwareHandler firmware_handler =
+ FirmwareHandler(firmware_directories, external_handlers);
+ Uevent uevent = CreateUevent(&fdp);
+ if (fdp.ConsumeBool() && uevent.path.size() != 0 &&
+ uevent.path.find(kPath) == 0) {
+ CreateDir(uevent.path, &fdp);
+ firmware_handler.HandleUevent(uevent);
+ std::string s = uevent.path.substr(kPathPrefix.length());
+ remove(s.c_str());
+ } else {
+ firmware_handler.HandleUevent(uevent);
+ }
+ },
+ });
+ invoke_uevent_handler_fuzzer();
+ }
+ return 0;
+}
diff --git a/init/host_init_stubs.h b/init/host_init_stubs.h
index 2a8bf6c..753ed6b 100644
--- a/init/host_init_stubs.h
+++ b/init/host_init_stubs.h
@@ -29,6 +29,9 @@
#define __ANDROID_API_P__ 28
#define __ANDROID_API_Q__ 29
#define __ANDROID_API_R__ 30
+#define __ANDROID_API_S__ 31
+#define __ANDROID_API_T__ 33
+#define __ANDROID_API_U__ 34
// sys/system_properties.h
#define PROP_VALUE_MAX 92
diff --git a/init/init.cpp b/init/init.cpp
index ce668d7..540e2ca 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -513,7 +513,7 @@
}
static Result<void> DoLoadApex(const std::string& apex_name) {
- if(auto result = ParseApexConfigs(apex_name); !result.ok()) {
+ if (auto result = ParseApexConfigs(apex_name); !result.ok()) {
return result.error();
}
@@ -662,6 +662,10 @@
}
static Result<void> SetupCgroupsAction(const BuiltinArguments&) {
+ if (!CgroupsAvailable()) {
+ LOG(INFO) << "Cgroups support in kernel is not enabled";
+ return {};
+ }
// Have to create <CGROUPS_RC_DIR> using make_dir function
// for appropriate sepolicy to be set for it
make_dir(android::base::Dirname(CGROUPS_RC_PATH), 0711);
@@ -743,6 +747,9 @@
do {
ssize_t bytes_read = TEMP_FAILURE_RETRY(read(signal_fd, &siginfo, sizeof(siginfo)));
if (bytes_read < 0 && errno == EAGAIN) {
+ if (one_off) {
+ return;
+ }
auto now = std::chrono::steady_clock::now();
std::chrono::duration<double> waited = now - started;
if (waited >= kDiagnosticTimeout) {
@@ -768,7 +775,7 @@
HandleSigtermSignal(siginfo);
break;
default:
- PLOG(ERROR) << "signal_fd: received unexpected signal " << siginfo.ssi_signo;
+ LOG(ERROR) << "signal_fd: received unexpected signal " << siginfo.ssi_signo;
break;
}
}
@@ -1061,6 +1068,11 @@
PLOG(FATAL) << result.error();
}
+ // We always reap children before responding to the other pending functions. This is to
+ // prevent a race where other daemons see that a service has exited and ask init to
+ // start it again via ctl.start before init has reaped it.
+ epoll.SetFirstCallback(ReapAnyOutstandingChildren);
+
InstallSignalFdHandler(&epoll);
InstallInitNotifier(&epoll);
StartPropertyService(&property_fd);
@@ -1143,7 +1155,7 @@
setpriority(PRIO_PROCESS, 0, 0);
while (true) {
// By default, sleep until something happens.
- auto epoll_timeout = std::optional<std::chrono::milliseconds>{kDiagnosticTimeout};
+ std::chrono::milliseconds epoll_timeout{kDiagnosticTimeout};
auto shutdown_command = shutdown_state.CheckShutdown();
if (shutdown_command) {
@@ -1163,7 +1175,7 @@
if (next_process_action_time) {
epoll_timeout = std::chrono::ceil<std::chrono::milliseconds>(
*next_process_action_time - boot_clock::now());
- if (*epoll_timeout < 0ms) epoll_timeout = 0ms;
+ if (epoll_timeout < 0ms) epoll_timeout = 0ms;
}
}
@@ -1172,18 +1184,10 @@
if (am.HasMoreCommands()) epoll_timeout = 0ms;
}
- auto pending_functions = epoll.Wait(epoll_timeout);
- if (!pending_functions.ok()) {
- LOG(ERROR) << pending_functions.error();
- } else if (!pending_functions->empty()) {
- // We always reap children before responding to the other pending functions. This is to
- // prevent a race where other daemons see that a service has exited and ask init to
- // start it again via ctl.start before init has reaped it.
- ReapAnyOutstandingChildren();
- for (const auto& function : *pending_functions) {
- (*function)();
- }
- } else if (Service::is_exec_service_running()) {
+ auto epoll_result = epoll.Wait(epoll_timeout);
+ if (!epoll_result.ok()) {
+ LOG(ERROR) << epoll_result.error();
+ } else if (*epoll_result <= 0 && Service::is_exec_service_running()) {
static bool dumped_diagnostics = false;
std::chrono::duration<double> waited =
std::chrono::steady_clock::now() - Service::exec_service_started();
diff --git a/init/interprocess_fifo.cpp b/init/interprocess_fifo.cpp
new file mode 100644
index 0000000..6e0d031
--- /dev/null
+++ b/init/interprocess_fifo.cpp
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2022 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 "interprocess_fifo.h"
+
+#include <android-base/logging.h>
+
+#include <unistd.h>
+
+using ::android::base::ErrnoError;
+using ::android::base::Error;
+using ::android::base::Result;
+
+namespace android {
+namespace init {
+
+InterprocessFifo::InterprocessFifo() noexcept : fds_({-1, -1}) {}
+
+InterprocessFifo::InterprocessFifo(InterprocessFifo&& orig) noexcept : fds_({-1, -1}) {
+ std::swap(fds_, orig.fds_);
+}
+
+InterprocessFifo::~InterprocessFifo() noexcept {
+ Close();
+}
+
+void InterprocessFifo::CloseFd(int& fd) noexcept {
+ if (fd >= 0) {
+ close(fd);
+ fd = -1;
+ }
+}
+
+void InterprocessFifo::CloseReadFd() noexcept {
+ CloseFd(fds_[0]);
+}
+
+void InterprocessFifo::CloseWriteFd() noexcept {
+ CloseFd(fds_[1]);
+}
+
+void InterprocessFifo::Close() noexcept {
+ CloseReadFd();
+ CloseWriteFd();
+}
+
+Result<void> InterprocessFifo::Initialize() noexcept {
+ if (fds_[0] >= 0) {
+ return Error() << "already initialized";
+ }
+ if (pipe(fds_.data()) < 0) { // NOLINT(android-cloexec-pipe)
+ return ErrnoError() << "pipe()";
+ }
+ return {};
+}
+
+Result<uint8_t> InterprocessFifo::Read() noexcept {
+ uint8_t byte;
+ ssize_t count = read(fds_[0], &byte, 1);
+ if (count < 0) {
+ return ErrnoError() << "read()";
+ }
+ if (count == 0) {
+ return Error() << "read() EOF";
+ }
+ DCHECK_EQ(count, 1);
+ return byte;
+}
+
+Result<void> InterprocessFifo::Write(uint8_t byte) noexcept {
+ ssize_t written = write(fds_[1], &byte, 1);
+ if (written < 0) {
+ return ErrnoError() << "write()";
+ }
+ if (written == 0) {
+ return Error() << "write() EOF";
+ }
+ DCHECK_EQ(written, 1);
+ return {};
+}
+
+} // namespace init
+} // namespace android
diff --git a/init/interprocess_fifo.h b/init/interprocess_fifo.h
new file mode 100644
index 0000000..cdaac86
--- /dev/null
+++ b/init/interprocess_fifo.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2022 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 <array>
+
+#include <android-base/result.h>
+
+namespace android {
+namespace init {
+
+// A FIFO for inter-process communication that uses a Unix pipe internally.
+class InterprocessFifo {
+ public:
+ template <typename T>
+ using Result = ::android::base::Result<T>;
+
+ InterprocessFifo() noexcept;
+ InterprocessFifo(const InterprocessFifo& orig) noexcept = delete;
+ InterprocessFifo(InterprocessFifo&& orig) noexcept;
+ InterprocessFifo& operator=(const InterprocessFifo& orig) noexcept = delete;
+ InterprocessFifo& operator=(InterprocessFifo&& orig) noexcept = delete;
+ ~InterprocessFifo() noexcept;
+ void CloseReadFd() noexcept;
+ void CloseWriteFd() noexcept;
+ void Close() noexcept;
+ Result<void> Initialize() noexcept;
+ Result<void> Write(uint8_t byte) noexcept;
+ Result<uint8_t> Read() noexcept;
+
+ private:
+ static void CloseFd(int& fd) noexcept;
+
+ std::array<int, 2> fds_;
+};
+
+} // namespace init
+} // namespace android
diff --git a/init/interprocess_fifo_test.cpp b/init/interprocess_fifo_test.cpp
new file mode 100644
index 0000000..81cfbac
--- /dev/null
+++ b/init/interprocess_fifo_test.cpp
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2022 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 "interprocess_fifo.h"
+
+#include <android-base/result-gmock.h>
+#include <gtest/gtest.h>
+
+#define ASSERT_OK(e) ASSERT_THAT(e, Ok())
+#define ASSERT_NOT_OK(e) ASSERT_THAT(e, Not(Ok()))
+
+using ::android::base::Result;
+using ::android::base::testing::Ok;
+using ::testing::Not;
+
+namespace android {
+namespace init {
+
+TEST(FifoTest, WriteAndRead) {
+ InterprocessFifo fifo;
+ ASSERT_OK(fifo.Initialize());
+ ASSERT_OK(fifo.Write('a'));
+ ASSERT_OK(fifo.Write('b'));
+ Result<uint8_t> result = fifo.Read();
+ ASSERT_OK(result);
+ EXPECT_EQ(*result, 'a');
+ result = fifo.Read();
+ ASSERT_OK(result);
+ EXPECT_EQ(*result, 'b');
+ InterprocessFifo fifo2 = std::move(fifo);
+ ASSERT_NOT_OK(fifo.Write('c'));
+ ASSERT_NOT_OK(fifo.Read());
+ ASSERT_OK(fifo2.Write('d'));
+ result = fifo2.Read();
+ ASSERT_OK(result);
+ EXPECT_EQ(*result, 'd');
+}
+
+} // namespace init
+} // namespace android
diff --git a/init/keychords_test.cpp b/init/keychords_test.cpp
index 8a333a2..5789bf5 100644
--- a/init/keychords_test.cpp
+++ b/init/keychords_test.cpp
@@ -212,11 +212,8 @@
}
void TestFrame::RelaxForMs(std::chrono::milliseconds wait) {
- auto pending_functions = epoll_.Wait(wait);
- ASSERT_RESULT_OK(pending_functions);
- for (const auto& function : *pending_functions) {
- (*function)();
- }
+ auto epoll_result = epoll_.Wait(wait);
+ ASSERT_RESULT_OK(epoll_result);
}
void TestFrame::SetChord(int key, bool value) {
diff --git a/init/property_service.cpp b/init/property_service.cpp
index c2ba8d5..f3550a1 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -1381,13 +1381,9 @@
}
while (true) {
- auto pending_functions = epoll.Wait(std::nullopt);
- if (!pending_functions.ok()) {
- LOG(ERROR) << pending_functions.error();
- } else {
- for (const auto& function : *pending_functions) {
- (*function)();
- }
+ auto epoll_result = epoll.Wait(std::nullopt);
+ if (!epoll_result.ok()) {
+ LOG(ERROR) << epoll_result.error();
}
}
}
diff --git a/init/reboot.cpp b/init/reboot.cpp
index 880674c..4c27a56 100644
--- a/init/reboot.cpp
+++ b/init/reboot.cpp
@@ -608,7 +608,7 @@
if (sem_init(&reboot_semaphore, false, 0) == -1) {
// These should never fail, but if they do, skip the graceful reboot and reboot immediately.
LOG(ERROR) << "sem_init() fail and RebootSystem() return!";
- RebootSystem(cmd, reboot_target);
+ RebootSystem(cmd, reboot_target, reason);
}
// Start a thread to monitor init shutdown process
@@ -636,7 +636,7 @@
// worry about unmounting it.
if (!IsDataMounted("*")) {
sync();
- RebootSystem(cmd, reboot_target);
+ RebootSystem(cmd, reboot_target, reason);
abort();
}
@@ -769,7 +769,7 @@
LOG(INFO) << "Shutdown /data";
}
}
- RebootSystem(cmd, reboot_target);
+ RebootSystem(cmd, reboot_target, reason);
abort();
}
diff --git a/init/reboot_utils.cpp b/init/reboot_utils.cpp
index f8e1de0..e6b868e 100644
--- a/init/reboot_utils.cpp
+++ b/init/reboot_utils.cpp
@@ -106,7 +106,8 @@
return value == CAP_SET;
}
-void __attribute__((noreturn)) RebootSystem(unsigned int cmd, const std::string& rebootTarget) {
+void __attribute__((noreturn))
+RebootSystem(unsigned int cmd, const std::string& rebootTarget, const std::string& reboot_reason) {
LOG(INFO) << "Reboot ending, jumping to kernel";
if (!IsRebootCapable()) {
@@ -127,10 +128,12 @@
case ANDROID_RB_THERMOFF:
if (android::base::GetBoolProperty("ro.thermal_warmreset", false)) {
+ std::string reason = "shutdown,thermal";
+ if (!reboot_reason.empty()) reason = reboot_reason;
+
LOG(INFO) << "Try to trigger a warm reset for thermal shutdown";
- static constexpr const char kThermalShutdownTarget[] = "shutdown,thermal";
syscall(__NR_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2,
- LINUX_REBOOT_CMD_RESTART2, kThermalShutdownTarget);
+ LINUX_REBOOT_CMD_RESTART2, reason.c_str());
} else {
reboot(RB_POWER_OFF);
}
diff --git a/init/reboot_utils.h b/init/reboot_utils.h
index a0023b9..09e87ef 100644
--- a/init/reboot_utils.h
+++ b/init/reboot_utils.h
@@ -29,7 +29,8 @@
// so if any of the attempts to determine this fail, it will still return true.
bool IsRebootCapable();
// This is a wrapper around the actual reboot calls.
-void __attribute__((noreturn)) RebootSystem(unsigned int cmd, const std::string& reboot_target);
+void __attribute__((noreturn)) RebootSystem(unsigned int cmd, const std::string& reboot_target,
+ const std::string& reboot_reason = "");
void __attribute__((noreturn)) InitFatalReboot(int signal_number);
void InstallRebootSignalHandlers();
diff --git a/init/security.cpp b/init/security.cpp
index 0e9f6c2..2ecf687 100644
--- a/init/security.cpp
+++ b/init/security.cpp
@@ -116,6 +116,13 @@
if (SetMmapRndBitsMin(33, 24, false) && (!Has32BitAbi() || SetMmapRndBitsMin(16, 16, true))) {
return {};
}
+#elif defined(__riscv)
+ // TODO: sv48 and sv57 were both added to the kernel this year, so we
+ // probably just need some kernel fixes to enable higher ASLR randomization,
+ // but for now 24 is the maximum that the kernel supports.
+ if (SetMmapRndBitsMin(24, 18, false)) {
+ return {};
+ }
#elif defined(__x86_64__)
// x86_64 supports 28 - 32 rnd bits, but Android wants to ensure that the
// theoretical maximum of 32 bits is always supported and used.
diff --git a/init/service.cpp b/init/service.cpp
index a633048..caa9095 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -38,6 +38,7 @@
#include <string>
+#include "interprocess_fifo.h"
#include "lmkd_service.h"
#include "service_list.h"
#include "util.h"
@@ -442,14 +443,6 @@
return {};
}
-static void ClosePipe(const std::array<int, 2>* pipe) {
- for (const auto fd : *pipe) {
- if (fd >= 0) {
- close(fd);
- }
- }
-}
-
Result<void> Service::CheckConsole() {
if (!(flags_ & SVC_CONSOLE)) {
return {};
@@ -514,7 +507,7 @@
// Enters namespaces, sets environment variables, writes PID files and runs the service executable.
void Service::RunService(const std::vector<Descriptor>& descriptors,
- std::unique_ptr<std::array<int, 2>, decltype(&ClosePipe)> pipefd) {
+ InterprocessFifo cgroups_activated, InterprocessFifo setsid_finished) {
if (auto result = EnterNamespaces(namespaces_, name_, mount_namespace_); !result.ok()) {
LOG(FATAL) << "Service '" << name_ << "' failed to set up namespaces: " << result.error();
}
@@ -536,24 +529,40 @@
// Wait until the cgroups have been created and until the cgroup controllers have been
// activated.
- char byte = 0;
- if (read((*pipefd)[0], &byte, 1) < 0) {
- PLOG(ERROR) << "failed to read from notification channel";
+ Result<uint8_t> byte = cgroups_activated.Read();
+ if (!byte.ok()) {
+ LOG(ERROR) << name_ << ": failed to read from notification channel: " << byte.error();
}
- pipefd.reset();
- if (!byte) {
+ cgroups_activated.Close();
+ if (!*byte) {
LOG(FATAL) << "Service '" << name_ << "' failed to start due to a fatal error";
_exit(EXIT_FAILURE);
}
- if (task_profiles_.size() > 0 && !SetTaskProfiles(getpid(), task_profiles_)) {
- LOG(ERROR) << "failed to set task profiles";
+ if (task_profiles_.size() > 0) {
+ bool succeeded = SelinuxGetVendorAndroidVersion() < __ANDROID_API_U__
+ ?
+ // Compatibility mode: apply the task profiles to the current
+ // thread.
+ SetTaskProfiles(getpid(), task_profiles_)
+ :
+ // Apply the task profiles to the current process.
+ SetProcessProfiles(getuid(), getpid(), task_profiles_);
+ if (!succeeded) {
+ LOG(ERROR) << "failed to set task profiles";
+ }
}
// As requested, set our gid, supplemental gids, uid, context, and
// priority. Aborts on failure.
SetProcessAttributesAndCaps();
+ // If SetProcessAttributes() called setsid(), report this to the parent.
+ if (!proc_attr_.console.empty()) {
+ setsid_finished.Write(2);
+ }
+ setsid_finished.Close();
+
if (!ExpandArgsAndExecv(args_, sigstop_)) {
PLOG(ERROR) << "cannot execv('" << args_[0]
<< "'). See the 'Debugging init' section of init's README.md for tips";
@@ -595,16 +604,23 @@
return {};
}
- std::unique_ptr<std::array<int, 2>, decltype(&ClosePipe)> pipefd(new std::array<int, 2>{-1, -1},
- ClosePipe);
- if (pipe(pipefd->data()) < 0) {
- return ErrnoError() << "pipe()";
+ InterprocessFifo cgroups_activated, setsid_finished;
+
+ if (Result<void> result = cgroups_activated.Initialize(); !result.ok()) {
+ return result;
}
if (Result<void> result = CheckConsole(); !result.ok()) {
return result;
}
+ // Only check proc_attr_.console after the CheckConsole() call.
+ if (!proc_attr_.console.empty()) {
+ if (Result<void> result = setsid_finished.Initialize(); !result.ok()) {
+ return result;
+ }
+ }
+
struct stat sb;
if (stat(args_[0].c_str(), &sb) == -1) {
flags_ |= SVC_DISABLED;
@@ -657,8 +673,13 @@
if (pid == 0) {
umask(077);
- RunService(descriptors, std::move(pipefd));
+ cgroups_activated.CloseWriteFd();
+ setsid_finished.CloseReadFd();
+ RunService(descriptors, std::move(cgroups_activated), std::move(setsid_finished));
_exit(127);
+ } else {
+ cgroups_activated.CloseReadFd();
+ setsid_finished.CloseWriteFd();
}
if (pid < 0) {
@@ -682,32 +703,54 @@
start_order_ = next_start_order_++;
process_cgroup_empty_ = false;
- bool use_memcg = swappiness_ != -1 || soft_limit_in_bytes_ != -1 || limit_in_bytes_ != -1 ||
- limit_percent_ != -1 || !limit_property_.empty();
- errno = -createProcessGroup(proc_attr_.uid, pid_, use_memcg);
- if (errno != 0) {
- if (char byte = 0; write((*pipefd)[1], &byte, 1) < 0) {
- return ErrnoError() << "sending notification failed";
+ if (CgroupsAvailable()) {
+ bool use_memcg = swappiness_ != -1 || soft_limit_in_bytes_ != -1 || limit_in_bytes_ != -1 ||
+ limit_percent_ != -1 || !limit_property_.empty();
+ errno = -createProcessGroup(proc_attr_.uid, pid_, use_memcg);
+ if (errno != 0) {
+ Result<void> result = cgroups_activated.Write(0);
+ if (!result.ok()) {
+ return Error() << "Sending notification failed: " << result.error();
+ }
+ return Error() << "createProcessGroup(" << proc_attr_.uid << ", " << pid_
+ << ") failed for service '" << name_ << "'";
}
- return Error() << "createProcessGroup(" << proc_attr_.uid << ", " << pid_
- << ") failed for service '" << name_ << "'";
- }
- // When the blkio controller is mounted in the v1 hierarchy, NormalIoPriority is
- // the default (/dev/blkio). When the blkio controller is mounted in the v2 hierarchy, the
- // NormalIoPriority profile has to be applied explicitly.
- SetProcessProfiles(proc_attr_.uid, pid_, {"NormalIoPriority"});
+ // When the blkio controller is mounted in the v1 hierarchy, NormalIoPriority is
+ // the default (/dev/blkio). When the blkio controller is mounted in the v2 hierarchy, the
+ // NormalIoPriority profile has to be applied explicitly.
+ SetProcessProfiles(proc_attr_.uid, pid_, {"NormalIoPriority"});
- if (use_memcg) {
- ConfigureMemcg();
+ if (use_memcg) {
+ ConfigureMemcg();
+ }
+ } else {
+ process_cgroup_empty_ = true;
}
if (oom_score_adjust_ != DEFAULT_OOM_SCORE_ADJUST) {
LmkdRegister(name_, proc_attr_.uid, pid_, oom_score_adjust_);
}
- if (char byte = 1; write((*pipefd)[1], &byte, 1) < 0) {
- return ErrnoError() << "sending notification failed";
+ if (Result<void> result = cgroups_activated.Write(1); !result.ok()) {
+ return Error() << "Sending cgroups activated notification failed: " << result.error();
+ }
+
+ // Call setpgid() from the parent process to make sure that this call has
+ // finished before the parent process calls kill(-pgid, ...).
+ if (proc_attr_.console.empty()) {
+ if (setpgid(pid, pid) == -1) {
+ return ErrnoError() << "setpgid failed";
+ }
+ } else {
+ // The Read() call below will return an error if the child is killed.
+ if (Result<uint8_t> result = setsid_finished.Read(); !result.ok() || *result != 2) {
+ if (!result.ok()) {
+ return Error() << "Waiting for setsid() failed: " << result.error();
+ } else {
+ return Error() << "Waiting for setsid() failed: " << *result << " <> 2";
+ }
+ }
}
NotifyStateChange("running");
diff --git a/init/service.h b/init/service.h
index ab19865..10a0790 100644
--- a/init/service.h
+++ b/init/service.h
@@ -31,6 +31,7 @@
#include "action.h"
#include "capabilities.h"
+#include "interprocess_fifo.h"
#include "keyword_map.h"
#include "mount_namespace.h"
#include "parser.h"
@@ -154,9 +155,8 @@
void ResetFlagsForStart();
Result<void> CheckConsole();
void ConfigureMemcg();
- void RunService(
- const std::vector<Descriptor>& descriptors,
- std::unique_ptr<std::array<int, 2>, void (*)(const std::array<int, 2>* pipe)> pipefd);
+ void RunService(const std::vector<Descriptor>& descriptors, InterprocessFifo cgroups_activated,
+ InterprocessFifo setsid_finished);
void SetMountNamespace();
static unsigned long next_start_order_;
static bool is_exec_service_running_;
diff --git a/init/service_utils.cpp b/init/service_utils.cpp
index d19f5ee..56a80b5 100644
--- a/init/service_utils.cpp
+++ b/init/service_utils.cpp
@@ -244,7 +244,11 @@
setsid();
OpenConsole(attr.console);
} else {
- if (setpgid(0, getpid()) == -1) {
+ // Without PID namespaces, this call duplicates the setpgid() call from
+ // the parent process. With PID namespaces, this setpgid() call sets the
+ // process group ID for a child of the init process in the PID
+ // namespace.
+ if (setpgid(0, 0) == -1) {
return ErrnoError() << "setpgid failed";
}
SetupStdio(attr.stdio_to_kmsg);
@@ -280,6 +284,15 @@
}
Result<void> WritePidToFiles(std::vector<std::string>* files) {
+ if (files->empty()) {
+ // No files to write pid to, exit early.
+ return {};
+ }
+
+ if (!CgroupsAvailable()) {
+ return Error() << "cgroups are not available";
+ }
+
// See if there were "writepid" instructions to write to files under cpuset path.
std::string cpuset_path;
if (CgroupGetControllerPath("cpuset", &cpuset_path)) {
diff --git a/init/sigchld_handler.cpp b/init/sigchld_handler.cpp
index 6fc64df..f8c501f 100644
--- a/init/sigchld_handler.cpp
+++ b/init/sigchld_handler.cpp
@@ -24,6 +24,7 @@
#include <unistd.h>
#include <android-base/chrono_utils.h>
+#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/scopeguard.h>
#include <android-base/stringprintf.h>
@@ -36,6 +37,7 @@
using android::base::boot_clock;
using android::base::make_scope_guard;
+using android::base::ReadFileToString;
using android::base::StringPrintf;
using android::base::Timer;
@@ -51,8 +53,13 @@
return 0;
}
- auto pid = siginfo.si_pid;
- if (pid == 0) return 0;
+ const pid_t pid = siginfo.si_pid;
+ if (pid == 0) {
+ DCHECK_EQ(siginfo.si_signo, 0);
+ return 0;
+ }
+
+ DCHECK_EQ(siginfo.si_signo, SIGCHLD);
// At this point we know we have a zombie pid, so we use this scopeguard to reap the pid
// whenever the function returns from this point forward.
@@ -132,6 +139,11 @@
}
LOG(INFO) << "Waiting for " << pids.size() << " pids to be reaped took " << t << " with "
<< alive_pids.size() << " of them still running";
+ for (pid_t pid : pids) {
+ std::string status = "(no-such-pid)";
+ ReadFileToString(StringPrintf("/proc/%d/status", pid), &status);
+ LOG(INFO) << "Still running: " << pid << ' ' << status;
+ }
}
} // namespace init
diff --git a/init/snapuserd_transition.cpp b/init/snapuserd_transition.cpp
index 5c821b0..6972f30 100644
--- a/init/snapuserd_transition.cpp
+++ b/init/snapuserd_transition.cpp
@@ -226,12 +226,9 @@
argv_.emplace_back("snapuserd");
argv_.emplace_back("-no_socket");
- if (!sm_->DetachSnapuserdForSelinux(&argv_)) {
+ if (!sm_->PrepareSnapuserdArgsForSelinux(&argv_)) {
LOG(FATAL) << "Could not perform selinux transition";
}
-
- // Make sure the process is gone so we don't have any selinux audits.
- KillFirstStageSnapuserd(old_pid_);
}
void SnapuserdSelinuxHelper::FinishTransition() {
@@ -301,6 +298,12 @@
}
void SnapuserdSelinuxHelper::RelaunchFirstStageSnapuserd() {
+ if (!sm_->DetachFirstStageSnapuserdForSelinux()) {
+ LOG(FATAL) << "Could not perform selinux transition";
+ }
+
+ KillFirstStageSnapuserd(old_pid_);
+
auto fd = GetRamdiskSnapuserdFd();
if (!fd) {
LOG(FATAL) << "Environment variable " << kSnapuserdFirstStageFdVar << " was not set!";
diff --git a/init/subcontext.h b/init/subcontext.h
index 8acc032..93ebace 100644
--- a/init/subcontext.h
+++ b/init/subcontext.h
@@ -36,8 +36,10 @@
class Subcontext {
public:
- Subcontext(std::vector<std::string> path_prefixes, std::string context, bool host = false)
- : path_prefixes_(std::move(path_prefixes)), context_(std::move(context)), pid_(0) {
+ Subcontext(std::vector<std::string> path_prefixes, std::string_view context, bool host = false)
+ : path_prefixes_(std::move(path_prefixes)),
+ context_(context.begin(), context.end()),
+ pid_(0) {
if (!host) {
Fork();
}
diff --git a/libcutils/Android.bp b/libcutils/Android.bp
index fde30ad..b135e57 100644
--- a/libcutils/Android.bp
+++ b/libcutils/Android.bp
@@ -193,6 +193,9 @@
],
},
android: {
+ sanitize: {
+ misc_undefined: ["integer"],
+ },
static_libs: [
"libasync_safe",
],
@@ -209,32 +212,6 @@
],
},
- android_arm: {
- sanitize: {
- misc_undefined: ["integer"],
- },
- },
- android_arm64: {
- sanitize: {
- misc_undefined: ["integer"],
- },
- },
-
- android_x86: {
- // TODO: This is to work around b/29412086.
- // Remove once __mulodi4 is available and move the "sanitize" block
- // to the android target.
- sanitize: {
- misc_undefined: [],
- },
- },
-
- android_x86_64: {
- sanitize: {
- misc_undefined: ["integer"],
- },
- },
-
// qtaguid.cpp loads libnetd_client.so with dlopen(). Since
// the interface of libnetd_client.so may vary between AOSP
// releases, exclude qtaguid.cpp from the VNDK-SP variant.
diff --git a/libprocessgroup/include/processgroup/processgroup.h b/libprocessgroup/include/processgroup/processgroup.h
index 45a723f..9b2d775 100644
--- a/libprocessgroup/include/processgroup/processgroup.h
+++ b/libprocessgroup/include/processgroup/processgroup.h
@@ -28,6 +28,7 @@
static constexpr const char* CGROUPV2_CONTROLLER_NAME = "cgroup2";
+bool CgroupsAvailable();
bool CgroupGetControllerPath(const std::string& cgroup_name, std::string* path);
bool CgroupGetControllerFromPath(const std::string& path, std::string* cgroup_name);
bool CgroupGetAttributePath(const std::string& attr_name, std::string* path);
diff --git a/libprocessgroup/processgroup.cpp b/libprocessgroup/processgroup.cpp
index bdda102..3fac373 100644
--- a/libprocessgroup/processgroup.cpp
+++ b/libprocessgroup/processgroup.cpp
@@ -55,6 +55,11 @@
#define PROCESSGROUP_CGROUP_PROCS_FILE "/cgroup.procs"
+bool CgroupsAvailable() {
+ static bool cgroups_available = access("/proc/cgroups", F_OK) == 0;
+ return cgroups_available;
+}
+
bool CgroupGetControllerPath(const std::string& cgroup_name, std::string* path) {
auto controller = CgroupMap::GetInstance().FindController(cgroup_name);
diff --git a/libprocessgroup/task_profiles.cpp b/libprocessgroup/task_profiles.cpp
index 744710f..35adf36 100644
--- a/libprocessgroup/task_profiles.cpp
+++ b/libprocessgroup/task_profiles.cpp
@@ -287,7 +287,7 @@
if (cache_type == ResourceCacheType::RCT_TASK &&
fd_[cache_type] == FdCacheHelper::FDS_APP_DEPENDENT) {
// application-dependent path can't be used with tid
- PLOG(ERROR) << "Application profile can't be applied to a thread";
+ LOG(ERROR) << Name() << ": application profile can't be applied to a thread";
return ProfileAction::FAIL;
}
@@ -304,7 +304,7 @@
std::string procs_path = controller()->GetProcsFilePath(path_, uid, pid);
unique_fd tmp_fd(TEMP_FAILURE_RETRY(open(procs_path.c_str(), O_WRONLY | O_CLOEXEC)));
if (tmp_fd < 0) {
- PLOG(WARNING) << "Failed to open " << procs_path;
+ PLOG(WARNING) << Name() << "::" << __func__ << ": failed to open " << procs_path;
return false;
}
if (!AddTidToCgroup(pid, tmp_fd, controller()->name())) {
@@ -325,7 +325,7 @@
std::string tasks_path = controller()->GetTasksFilePath(path_);
unique_fd tmp_fd(TEMP_FAILURE_RETRY(open(tasks_path.c_str(), O_WRONLY | O_CLOEXEC)));
if (tmp_fd < 0) {
- PLOG(WARNING) << "Failed to open " << tasks_path;
+ PLOG(WARNING) << Name() << "::" << __func__ << ": failed to open " << tasks_path;
return false;
}
if (!AddTidToCgroup(tid, tmp_fd, controller()->name())) {
@@ -394,7 +394,7 @@
unique_fd tmp_fd(TEMP_FAILURE_RETRY(open(path.c_str(), O_WRONLY | O_CLOEXEC)));
if (tmp_fd < 0) {
- if (logfailures) PLOG(WARNING) << "Failed to open " << path;
+ if (logfailures) PLOG(WARNING) << Name() << "::" << __func__ << ": failed to open " << path;
return false;
}
@@ -431,7 +431,7 @@
if (cache_type == ResourceCacheType::RCT_TASK &&
fd_[cache_type] == FdCacheHelper::FDS_APP_DEPENDENT) {
// application-dependent path can't be used with tid
- PLOG(ERROR) << "Application profile can't be applied to a thread";
+ LOG(ERROR) << Name() << ": application profile can't be applied to a thread";
return ProfileAction::FAIL;
}
return ProfileAction::UNUSED;
diff --git a/libstats/pull_rust/Android.bp b/libstats/pull_rust/Android.bp
index a3ef131..85a38f8 100644
--- a/libstats/pull_rust/Android.bp
+++ b/libstats/pull_rust/Android.bp
@@ -51,6 +51,7 @@
min_sdk_version: "apex_inherit",
apex_available: [
"//apex_available:platform",
+ "com.android.resolv",
"com.android.virt",
],
}
diff --git a/libutils/Android.bp b/libutils/Android.bp
index c744b53..26e1597 100644
--- a/libutils/Android.bp
+++ b/libutils/Android.bp
@@ -58,10 +58,6 @@
vendor_available: true,
product_available: true,
recovery_available: true,
- vndk: {
- enabled: true,
- support_system_process: true,
- },
host_supported: true,
cflags: [
@@ -126,8 +122,8 @@
},
}
-cc_library {
- name: "libutils",
+cc_defaults {
+ name: "libutils_impl_defaults",
defaults: ["libutils_defaults"],
native_bridge_supported: true,
@@ -181,11 +177,39 @@
}
cc_library {
+ name: "libutils",
+ defaults: ["libutils_impl_defaults"],
+
+ vndk: {
+ enabled: true,
+ support_system_process: true,
+ },
+}
+
+cc_library {
+ name: "libutils_test_compile",
+ defaults: ["libutils_impl_defaults"],
+
+ cflags: [
+ "-DCALLSTACKS=1",
+ "-DDEBUG_POLL_AND_WAKE=1",
+ "-DDEBUG_REFS=1",
+ "-DDEBUG_TOKENIZER=1",
+ ],
+
+ visibility: [":__subpackages__"],
+}
+
+cc_library {
name: "libutilscallstack",
defaults: ["libutils_defaults"],
// TODO(b/153609531): remove when no longer needed.
native_bridge_supported: true,
min_sdk_version: "29",
+ vndk: {
+ enabled: true,
+ support_system_process: true,
+ },
srcs: [
"CallStack.cpp",
diff --git a/libutils/Looper.cpp b/libutils/Looper.cpp
index 1a3f34b..402e43c 100644
--- a/libutils/Looper.cpp
+++ b/libutils/Looper.cpp
@@ -8,10 +8,14 @@
//#define LOG_NDEBUG 0
// Debugs poll and wake interactions.
+#ifndef DEBUG_POLL_AND_WAKE
#define DEBUG_POLL_AND_WAKE 0
+#endif
// Debugs callback registration and invocation.
+#ifndef DEBUG_CALLBACKS
#define DEBUG_CALLBACKS 0
+#endif
#include <utils/Looper.h>
diff --git a/libutils/RefBase.cpp b/libutils/RefBase.cpp
index ed5b2a9..ab122c7 100644
--- a/libutils/RefBase.cpp
+++ b/libutils/RefBase.cpp
@@ -21,9 +21,11 @@
#include <android-base/macros.h>
+#include <fcntl.h>
#include <log/log.h>
#include <utils/RefBase.h>
+#include <utils/String8.h>
#include <utils/Mutex.h>
@@ -32,7 +34,9 @@
#endif
// Compile with refcounting debugging enabled.
+#ifndef DEBUG_REFS
#define DEBUG_REFS 0
+#endif
// The following three are ignored unless DEBUG_REFS is set.
@@ -45,7 +49,11 @@
// folder where stack traces are saved when DEBUG_REFS is enabled
// this folder needs to exist and be writable
+#ifdef __ANDROID__
#define DEBUG_REFS_CALLSTACK_PATH "/data/debug"
+#else
+#define DEBUG_REFS_CALLSTACK_PATH "."
+#endif
// log all reference counting operations
#define PRINT_REFS 0
@@ -320,11 +328,11 @@
char name[100];
snprintf(name, sizeof(name), DEBUG_REFS_CALLSTACK_PATH "/%p.stack",
this);
- int rc = open(name, O_RDWR | O_CREAT | O_APPEND, 644);
+ int rc = open(name, O_RDWR | O_CREAT | O_APPEND, 0644);
if (rc >= 0) {
(void)write(rc, text.string(), text.length());
close(rc);
- ALOGD("STACK TRACE for %p saved in %s", this, name);
+ ALOGI("STACK TRACE for %p saved in %s", this, name);
}
else ALOGE("FAILED TO PRINT STACK TRACE for %p in %s: %s", this,
name, strerror(errno));
diff --git a/libutils/String8.cpp b/libutils/String8.cpp
index 3690389..82f5cb6 100644
--- a/libutils/String8.cpp
+++ b/libutils/String8.cpp
@@ -25,6 +25,7 @@
#include <ctype.h>
+#include <limits>
#include <string>
#include "SharedBuffer.h"
diff --git a/libutils/Tokenizer.cpp b/libutils/Tokenizer.cpp
index 98dd2fd..c3ec165 100644
--- a/libutils/Tokenizer.cpp
+++ b/libutils/Tokenizer.cpp
@@ -21,9 +21,10 @@
#include <sys/stat.h>
#include <utils/Log.h>
+#ifndef DEBUG_TOKENIZER
// Enables debug output for the tokenizer.
#define DEBUG_TOKENIZER 0
-
+#endif
namespace android {
diff --git a/rootdir/etc/public.libraries.wear.txt b/rootdir/etc/public.libraries.wear.txt
index 82196e4..ea1e234 100644
--- a/rootdir/etc/public.libraries.wear.txt
+++ b/rootdir/etc/public.libraries.wear.txt
@@ -10,6 +10,7 @@
libGLESv1_CM.so
libGLESv2.so
libGLESv3.so
+libicu.so
libicui18n.so
libicuuc.so
libjnigraphics.so
diff --git a/rootdir/init.rc b/rootdir/init.rc
index ec760d3..123148e 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -952,9 +952,10 @@
mkdir /data_mirror/data_de/null 0700 root root
# Bind mount CE and DE data directory to mirror's default volume directory.
- # The 'slave' option (MS_SLAVE) is needed to cause the later bind mount of
- # /data/data onto /data/user/0 to propagate to /data_mirror/data_ce/null/0.
- mount none /data/user /data_mirror/data_ce/null bind rec slave
+ # Note that because the /data mount has the "shared" propagation type, the
+ # later bind mount of /data/data onto /data/user/0 will automatically
+ # propagate to /data_mirror/data_ce/null/0 as well.
+ mount none /data/user /data_mirror/data_ce/null bind rec
mount none /data/user_de /data_mirror/data_de/null bind rec
# Create mirror directory for jit profiles
@@ -1037,6 +1038,9 @@
# Enable FUSE by default
setprop persist.sys.fuse true
+ # Update dm-verity state and set partition.*.verified properties.
+ verity_update_state
+
# It is recommended to put unnecessary data/ initialization from post-fs-data
# to start-zygote in device's init.rc to unblock zygote start.
on zygote-start && property:ro.crypto.state=unencrypted
@@ -1175,9 +1179,6 @@
# Define default initial receive window size in segments.
setprop net.tcp_def_init_rwnd 60
- # Update dm-verity state and set partition.*.verified properties.
- verity_update_state
-
# Start standard binderized HAL daemons
class_start hal
diff --git a/trusty/confirmationui/Android.bp b/trusty/confirmationui/Android.bp
index 0922415..c5c5012 100644
--- a/trusty/confirmationui/Android.bp
+++ b/trusty/confirmationui/Android.bp
@@ -24,21 +24,23 @@
}
cc_binary {
- name: "android.hardware.confirmationui@1.0-service.trusty",
+ name: "android.hardware.confirmationui-service.trusty",
relative_install_path: "hw",
vendor: true,
shared_libs: [
- "android.hardware.confirmationui@1.0",
+ "android.hardware.confirmationui-V1-ndk",
"android.hardware.confirmationui.not-so-secure-input",
- "android.hardware.confirmationui@1.0-lib.trusty",
+ "android.hardware.confirmationui-lib.trusty",
+ "libbinder_ndk",
+ "libteeui_hal_support",
"libbase",
"libhidlbase",
"libutils",
],
- init_rc: ["android.hardware.confirmationui@1.0-service.trusty.rc"],
+ init_rc: ["android.hardware.confirmationui-service.trusty.rc"],
- vintf_fragments: ["android.hardware.confirmationui@1.0-service.trusty.xml"],
+ vintf_fragments: ["android.hardware.confirmationui-service.trusty.xml"],
srcs: [
"service.cpp",
@@ -51,18 +53,39 @@
],
}
-cc_library {
- name: "android.hardware.confirmationui@1.0-lib.trusty",
+cc_fuzz {
+ name: "android.hardware.confirmationui-service.trusty_fuzzer",
+ defaults: ["service_fuzzer_defaults"],
vendor: true,
shared_libs: [
- "android.hardware.confirmationui@1.0",
- "android.hardware.keymaster@4.0",
+ "android.hardware.confirmationui-V1-ndk",
+ "android.hardware.confirmationui.not-so-secure-input",
+ "android.hardware.confirmationui-lib.trusty",
+ "liblog",
+ ],
+ srcs: ["fuzzer.cpp"],
+ fuzz_config: {
+ cc: [
+ "nyamagoud@google.com",
+ ],
+ },
+}
+
+cc_library {
+ name: "android.hardware.confirmationui-lib.trusty",
+ defaults: [
+ "keymint_use_latest_hal_aidl_ndk_shared",
+ ],
+ vendor: true,
+ shared_libs: [
+ "android.hardware.confirmationui-V1-ndk",
"libbase",
+ "libcutils",
"libdmabufheap",
- "libhidlbase",
"libteeui_hal_support",
"libtrusty",
"libutils",
+ "libbinder_ndk",
],
export_include_dirs: ["include"],
diff --git a/trusty/confirmationui/TrustyConfirmationUI.cpp b/trusty/confirmationui/TrustyConfirmationUI.cpp
index c6625e0..f01a4e1 100644
--- a/trusty/confirmationui/TrustyConfirmationUI.cpp
+++ b/trusty/confirmationui/TrustyConfirmationUI.cpp
@@ -18,8 +18,6 @@
#include "TrustyConfirmationUI.h"
#include <android-base/logging.h>
-#include <android/hardware/confirmationui/1.0/types.h>
-#include <android/hardware/keymaster/4.0/types.h>
#include <fcntl.h>
#include <linux/input.h>
#include <poll.h>
@@ -42,12 +40,7 @@
#include <tuple>
#include <vector>
-namespace android {
-namespace hardware {
-namespace confirmationui {
-namespace V1_0 {
-namespace implementation {
-
+namespace aidl::android::hardware::confirmationui {
using namespace secure_input;
using ::android::trusty::confirmationui::TrustyAppError;
@@ -64,8 +57,6 @@
using ::secure_input::createSecureInput;
-using ::android::hardware::keymaster::V4_0::HardwareAuthToken;
-
using ::std::tie;
using TeeuiRc = ::teeui::ResponseCode;
@@ -87,46 +78,47 @@
void release() { f_ = {}; }
};
-ResponseCode convertRc(TeeuiRc trc) {
+int convertRc(TeeuiRc trc) {
static_assert(
- uint32_t(TeeuiRc::OK) == uint32_t(ResponseCode::OK) &&
- uint32_t(TeeuiRc::Canceled) == uint32_t(ResponseCode::Canceled) &&
- uint32_t(TeeuiRc::Aborted) == uint32_t(ResponseCode::Aborted) &&
- uint32_t(TeeuiRc::OperationPending) == uint32_t(ResponseCode::OperationPending) &&
- uint32_t(TeeuiRc::Ignored) == uint32_t(ResponseCode::Ignored) &&
- uint32_t(TeeuiRc::SystemError) == uint32_t(ResponseCode::SystemError) &&
- uint32_t(TeeuiRc::Unimplemented) == uint32_t(ResponseCode::Unimplemented) &&
- uint32_t(TeeuiRc::Unexpected) == uint32_t(ResponseCode::Unexpected) &&
- uint32_t(TeeuiRc::UIError) == uint32_t(ResponseCode::UIError) &&
- uint32_t(TeeuiRc::UIErrorMissingGlyph) == uint32_t(ResponseCode::UIErrorMissingGlyph) &&
+ uint32_t(TeeuiRc::OK) == uint32_t(IConfirmationUI::OK) &&
+ uint32_t(TeeuiRc::Canceled) == uint32_t(IConfirmationUI::CANCELED) &&
+ uint32_t(TeeuiRc::Aborted) == uint32_t(IConfirmationUI::ABORTED) &&
+ uint32_t(TeeuiRc::OperationPending) == uint32_t(IConfirmationUI::OPERATION_PENDING) &&
+ uint32_t(TeeuiRc::Ignored) == uint32_t(IConfirmationUI::IGNORED) &&
+ uint32_t(TeeuiRc::SystemError) == uint32_t(IConfirmationUI::SYSTEM_ERROR) &&
+ uint32_t(TeeuiRc::Unimplemented) == uint32_t(IConfirmationUI::UNIMPLEMENTED) &&
+ uint32_t(TeeuiRc::Unexpected) == uint32_t(IConfirmationUI::UNEXPECTED) &&
+ uint32_t(TeeuiRc::UIError) == uint32_t(IConfirmationUI::UI_ERROR) &&
+ uint32_t(TeeuiRc::UIErrorMissingGlyph) ==
+ uint32_t(IConfirmationUI::UI_ERROR_MISSING_GLYPH) &&
uint32_t(TeeuiRc::UIErrorMessageTooLong) ==
- uint32_t(ResponseCode::UIErrorMessageTooLong) &&
+ uint32_t(IConfirmationUI::UI_ERROR_MESSAGE_TOO_LONG) &&
uint32_t(TeeuiRc::UIErrorMalformedUTF8Encoding) ==
- uint32_t(ResponseCode::UIErrorMalformedUTF8Encoding),
+ uint32_t(IConfirmationUI::UI_ERROR_MALFORMED_UTF8ENCODING),
"teeui::ResponseCode and "
"::android::hardware::confirmationui::V1_0::Responsecude are out of "
"sync");
- return ResponseCode(trc);
+ return static_cast<int>(trc);
}
teeui::UIOption convertUIOption(UIOption uio) {
- static_assert(uint32_t(UIOption::AccessibilityInverted) ==
+ static_assert(uint32_t(UIOption::ACCESSIBILITY_INVERTED) ==
uint32_t(teeui::UIOption::AccessibilityInverted) &&
- uint32_t(UIOption::AccessibilityMagnified) ==
+ uint32_t(UIOption::ACCESSIBILITY_MAGNIFIED) ==
uint32_t(teeui::UIOption::AccessibilityMagnified),
"teeui::UIOPtion and ::android::hardware::confirmationui::V1_0::UIOption "
- "anre out of sync");
+ "are out of sync");
return teeui::UIOption(uio);
}
-inline MsgString hidl2MsgString(const hidl_string& s) {
+inline MsgString stdString2MsgString(const string& s) {
return {s.c_str(), s.c_str() + s.size()};
}
-template <typename T> inline MsgVector<T> hidl2MsgVector(const hidl_vec<T>& v) {
+template <typename T> inline MsgVector<T> stdVector2MsgVector(const vector<T>& v) {
return {v};
}
-inline MsgVector<teeui::UIOption> hidl2MsgVector(const hidl_vec<UIOption>& v) {
+inline MsgVector<teeui::UIOption> stdVector2MsgVector(const vector<UIOption>& v) {
MsgVector<teeui::UIOption> result(v.size());
for (unsigned int i = 0; i < v.size(); ++i) {
result[i] = convertUIOption(v[i]);
@@ -137,7 +129,7 @@
} // namespace
TrustyConfirmationUI::TrustyConfirmationUI()
- : listener_state_(ListenerState::None), prompt_result_(ResponseCode::Ignored) {}
+ : listener_state_(ListenerState::None), prompt_result_(IConfirmationUI::IGNORED) {}
TrustyConfirmationUI::~TrustyConfirmationUI() {
ListenerState state = listener_state_;
@@ -385,15 +377,16 @@
// ############################## Start 4th Phase - cleanup ##################################
}
-// Methods from ::android::hardware::confirmationui::V1_0::IConfirmationUI
+// Methods from ::aidl::android::hardware::confirmationui::IConfirmationUI
// follow.
-Return<ResponseCode> TrustyConfirmationUI::promptUserConfirmation(
- const sp<IConfirmationResultCallback>& resultCB, const hidl_string& promptText,
- const hidl_vec<uint8_t>& extraData, const hidl_string& locale,
- const hidl_vec<UIOption>& uiOptions) {
+::ndk::ScopedAStatus TrustyConfirmationUI::promptUserConfirmation(
+ const shared_ptr<IConfirmationResultCallback>& resultCB, const vector<uint8_t>& promptTextBytes,
+ const vector<uint8_t>& extraData, const string& locale, const vector<UIOption>& uiOptions) {
std::unique_lock<std::mutex> stateLock(listener_state_lock_, std::defer_lock);
+ string promptText(promptTextBytes.begin(), promptTextBytes.end());
if (!stateLock.try_lock()) {
- return ResponseCode::OperationPending;
+ return ndk::ScopedAStatus(
+ AStatus_fromServiceSpecificError(IConfirmationUI::OPERATION_PENDING));
}
switch (listener_state_) {
case ListenerState::None:
@@ -401,23 +394,25 @@
case ListenerState::Starting:
case ListenerState::SetupDone:
case ListenerState::Interactive:
- return ResponseCode::OperationPending;
+ return ndk::ScopedAStatus(
+ AStatus_fromServiceSpecificError(IConfirmationUI::OPERATION_PENDING));
case ListenerState::Terminating:
callback_thread_.join();
listener_state_ = ListenerState::None;
break;
default:
- return ResponseCode::Unexpected;
+ return ndk::ScopedAStatus(AStatus_fromServiceSpecificError(IConfirmationUI::UNEXPECTED));
}
assert(listener_state_ == ListenerState::None);
callback_thread_ = std::thread(
- [this](sp<IConfirmationResultCallback> resultCB, hidl_string promptText,
- hidl_vec<uint8_t> extraData, hidl_string locale, hidl_vec<UIOption> uiOptions) {
- auto [trc, msg, token] =
- promptUserConfirmation_(hidl2MsgString(promptText), hidl2MsgVector(extraData),
- hidl2MsgString(locale), hidl2MsgVector(uiOptions));
+ [this](const shared_ptr<IConfirmationResultCallback>& resultCB, const string& promptText,
+ const vector<uint8_t>& extraData, const string& locale,
+ const vector<UIOption>& uiOptions) {
+ auto [trc, msg, token] = promptUserConfirmation_(
+ stdString2MsgString(promptText), stdVector2MsgVector(extraData),
+ stdString2MsgString(locale), stdVector2MsgVector(uiOptions));
bool do_callback = (listener_state_ == ListenerState::Interactive ||
listener_state_ == ListenerState::SetupDone) &&
resultCB;
@@ -426,7 +421,7 @@
if (do_callback) {
auto error = resultCB->result(prompt_result_, msg, token);
if (!error.isOk()) {
- LOG(ERROR) << "Result callback failed " << error.description();
+ LOG(ERROR) << "Result callback failed " << error.getDescription();
}
} else {
listener_state_condv_.notify_all();
@@ -442,14 +437,14 @@
if (listener_state_ == ListenerState::Terminating) {
callback_thread_.join();
listener_state_ = ListenerState::None;
- return prompt_result_;
+ return ndk::ScopedAStatus(AStatus_fromServiceSpecificError(prompt_result_));
}
- return ResponseCode::OK;
+ return ndk::ScopedAStatus::ok();
}
-Return<ResponseCode>
+::ndk::ScopedAStatus
TrustyConfirmationUI::deliverSecureInputEvent(const HardwareAuthToken& secureInputToken) {
- ResponseCode rc = ResponseCode::Ignored;
+ int rc = IConfirmationUI::IGNORED;
{
/*
* deliverSecureInputEvent is only used by the VTS test to mock human input. A correct
@@ -467,13 +462,17 @@
listener_state_condv_.wait(stateLock,
[this] { return listener_state_ != ListenerState::SetupDone; });
- if (listener_state_ != ListenerState::Interactive) return ResponseCode::Ignored;
+ if (listener_state_ != ListenerState::Interactive)
+ return ndk::ScopedAStatus(AStatus_fromServiceSpecificError(IConfirmationUI::IGNORED));
auto sapp = app_.lock();
- if (!sapp) return ResponseCode::Ignored;
+ if (!sapp)
+ return ndk::ScopedAStatus(AStatus_fromServiceSpecificError(IConfirmationUI::IGNORED));
auto [error, response] =
sapp->issueCmd<DeliverTestCommandMessage, DeliverTestCommandResponse>(
static_cast<teeui::TestModeCommands>(secureInputToken.challenge));
- if (error != TrustyAppError::OK) return ResponseCode::SystemError;
+ if (error != TrustyAppError::OK)
+ return ndk::ScopedAStatus(
+ AStatus_fromServiceSpecificError(IConfirmationUI::SYSTEM_ERROR));
auto& [trc] = response;
if (trc != TeeuiRc::Ignored) secureInputDelivered_ = true;
rc = convertRc(trc);
@@ -484,11 +483,14 @@
// Canceled into OK. Canceled is only returned if the delivered event canceled
// the operation, which means that the event was successfully delivered. Thus
// we return OK.
- if (rc == ResponseCode::Canceled) return ResponseCode::OK;
- return rc;
+ if (rc == IConfirmationUI::CANCELED) return ndk::ScopedAStatus::ok();
+ if (rc != IConfirmationUI::OK) {
+ return ndk::ScopedAStatus(AStatus_fromServiceSpecificError(rc));
+ }
+ return ndk::ScopedAStatus::ok();
}
-Return<void> TrustyConfirmationUI::abort() {
+::ndk::ScopedAStatus TrustyConfirmationUI::abort() {
{
std::unique_lock<std::mutex> stateLock(listener_state_lock_);
if (listener_state_ == ListenerState::SetupDone ||
@@ -499,15 +501,11 @@
}
}
listener_state_condv_.notify_all();
- return Void();
+ return ndk::ScopedAStatus::ok();
}
-android::sp<IConfirmationUI> createTrustyConfirmationUI() {
- return new TrustyConfirmationUI();
+std::shared_ptr<IConfirmationUI> createTrustyConfirmationUI() {
+ return ndk::SharedRefBase::make<TrustyConfirmationUI>();
}
-} // namespace implementation
-} // namespace V1_0
-} // namespace confirmationui
-} // namespace hardware
-} // namespace android
+} // namespace aidl::android::hardware::confirmationui
diff --git a/trusty/confirmationui/TrustyConfirmationUI.h b/trusty/confirmationui/TrustyConfirmationUI.h
index 0bd703c..6e85704 100644
--- a/trusty/confirmationui/TrustyConfirmationUI.h
+++ b/trusty/confirmationui/TrustyConfirmationUI.h
@@ -17,9 +17,11 @@
#ifndef ANDROID_HARDWARE_CONFIRMATIONUI_V1_0_TRUSTY_CONFIRMATIONUI_H
#define ANDROID_HARDWARE_CONFIRMATIONUI_V1_0_TRUSTY_CONFIRMATIONUI_H
-#include <android/hardware/confirmationui/1.0/IConfirmationUI.h>
-#include <android/hardware/keymaster/4.0/types.h>
-#include <hidl/Status.h>
+#include <aidl/android/hardware/confirmationui/BnConfirmationUI.h>
+#include <aidl/android/hardware/confirmationui/IConfirmationResultCallback.h>
+#include <aidl/android/hardware/confirmationui/UIOption.h>
+#include <aidl/android/hardware/security/keymint/HardwareAuthToken.h>
+#include <android/binder_manager.h>
#include <atomic>
#include <condition_variable>
@@ -30,35 +32,29 @@
#include "TrustyApp.h"
-namespace android {
-namespace hardware {
-namespace confirmationui {
-namespace V1_0 {
-namespace implementation {
+namespace aidl::android::hardware::confirmationui {
-using ::android::sp;
-using ::android::hardware::hidl_array;
-using ::android::hardware::hidl_string;
-using ::android::hardware::hidl_vec;
-using ::android::hardware::Return;
-using ::android::hardware::Void;
+using std::shared_ptr;
+using std::string;
+using std::vector;
+using ::aidl::android::hardware::security::keymint::HardwareAuthToken;
using ::android::trusty::confirmationui::TrustyApp;
-class TrustyConfirmationUI : public IConfirmationUI {
+class TrustyConfirmationUI : public BnConfirmationUI {
public:
TrustyConfirmationUI();
virtual ~TrustyConfirmationUI();
- // Methods from ::android::hardware::confirmationui::V1_0::IConfirmationUI
+ // Methods from ::aidl::android::hardware::confirmationui::IConfirmationUI
// follow.
- Return<ResponseCode> promptUserConfirmation(const sp<IConfirmationResultCallback>& resultCB,
- const hidl_string& promptText,
- const hidl_vec<uint8_t>& extraData,
- const hidl_string& locale,
- const hidl_vec<UIOption>& uiOptions) override;
- Return<ResponseCode> deliverSecureInputEvent(
- const ::android::hardware::keymaster::V4_0::HardwareAuthToken& secureInputToken) override;
- Return<void> abort() override;
+ ::ndk::ScopedAStatus
+ promptUserConfirmation(const shared_ptr<IConfirmationResultCallback>& resultCB,
+ const vector<uint8_t>& promptText, const vector<uint8_t>& extraData,
+ const string& locale, const vector<UIOption>& uiOptions) override;
+ ::ndk::ScopedAStatus
+ deliverSecureInputEvent(const HardwareAuthToken& secureInputToken) override;
+
+ ::ndk::ScopedAStatus abort() override;
private:
std::weak_ptr<TrustyApp> app_;
@@ -85,7 +81,7 @@
bool abort_called_;
std::mutex listener_state_lock_;
std::condition_variable listener_state_condv_;
- ResponseCode prompt_result_;
+ int prompt_result_;
bool secureInputDelivered_;
std::tuple<teeui::ResponseCode, teeui::MsgVector<uint8_t>, teeui::MsgVector<uint8_t>>
@@ -95,10 +91,6 @@
const teeui::MsgVector<teeui::UIOption>& uiOptions);
};
-} // namespace implementation
-} // namespace V1_0
-} // namespace confirmationui
-} // namespace hardware
-} // namespace android
+} // namespace aidl::android::hardware::confirmationui
#endif // ANDROID_HARDWARE_CONFIRMATIONUI_V1_0_TRUSTY_CONFIRMATIONUI_H
diff --git a/trusty/confirmationui/android.hardware.confirmationui-service.trusty.rc b/trusty/confirmationui/android.hardware.confirmationui-service.trusty.rc
new file mode 100644
index 0000000..b5c3159
--- /dev/null
+++ b/trusty/confirmationui/android.hardware.confirmationui-service.trusty.rc
@@ -0,0 +1,5 @@
+service vendor.confirmationui_default /vendor/bin/hw/android.hardware.confirmationui-service.trusty
+ interface aidl android.hardware.confirmationui.IConfirmationUI/default
+ class hal
+ user system
+ group drmrpc input system
diff --git a/trusty/confirmationui/android.hardware.confirmationui@1.0-service.trusty.xml b/trusty/confirmationui/android.hardware.confirmationui-service.trusty.xml
similarity index 71%
rename from trusty/confirmationui/android.hardware.confirmationui@1.0-service.trusty.xml
rename to trusty/confirmationui/android.hardware.confirmationui-service.trusty.xml
index 9008b87..afa2e8e 100644
--- a/trusty/confirmationui/android.hardware.confirmationui@1.0-service.trusty.xml
+++ b/trusty/confirmationui/android.hardware.confirmationui-service.trusty.xml
@@ -1,8 +1,7 @@
<manifest version="1.0" type="device">
- <hal format="hidl">
+ <hal format="aidl">
<name>android.hardware.confirmationui</name>
- <transport>hwbinder</transport>
- <version>1.0</version>
+ <version>1</version>
<interface>
<name>IConfirmationUI</name>
<instance>default</instance>
diff --git a/trusty/confirmationui/android.hardware.confirmationui@1.0-service.trusty.rc b/trusty/confirmationui/android.hardware.confirmationui@1.0-service.trusty.rc
deleted file mode 100644
index 3ba6fc0..0000000
--- a/trusty/confirmationui/android.hardware.confirmationui@1.0-service.trusty.rc
+++ /dev/null
@@ -1,4 +0,0 @@
-service confirmationui-1-0 /vendor/bin/hw/android.hardware.confirmationui@1.0-service.trusty
- class hal
- user system
- group drmrpc input system
diff --git a/trusty/confirmationui/fuzzer.cpp b/trusty/confirmationui/fuzzer.cpp
new file mode 100644
index 0000000..4446b79
--- /dev/null
+++ b/trusty/confirmationui/fuzzer.cpp
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2022 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 <TrustyConfirmationuiHal.h>
+#include <android-base/logging.h>
+#include <fuzzbinder/libbinder_ndk_driver.h>
+#include <fuzzer/FuzzedDataProvider.h>
+
+using aidl::android::hardware::confirmationui::createTrustyConfirmationUI;
+using aidl::android::hardware::confirmationui::IConfirmationUI;
+using android::fuzzService;
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ auto confirmationui = createTrustyConfirmationUI();
+
+ fuzzService(confirmationui->asBinder().get(), FuzzedDataProvider(data, size));
+
+ return 0;
+}
diff --git a/trusty/confirmationui/include/TrustyConfirmationuiHal.h b/trusty/confirmationui/include/TrustyConfirmationuiHal.h
index 2ab9389..8000ee2 100644
--- a/trusty/confirmationui/include/TrustyConfirmationuiHal.h
+++ b/trusty/confirmationui/include/TrustyConfirmationuiHal.h
@@ -16,18 +16,10 @@
#pragma once
-#include <android/hardware/confirmationui/1.0/IConfirmationUI.h>
+#include <aidl/android/hardware/confirmationui/IConfirmationUI.h>
-namespace android {
-namespace hardware {
-namespace confirmationui {
-namespace V1_0 {
-namespace implementation {
+namespace aidl::android::hardware::confirmationui {
-android::sp<IConfirmationUI> createTrustyConfirmationUI();
+std::shared_ptr<IConfirmationUI> createTrustyConfirmationUI();
-} // namespace implementation
-} // namespace V1_0
-} // namespace confirmationui
-} // namespace hardware
-} // namespace android
+} // namespace aidl::android::hardware::confirmationui
diff --git a/trusty/confirmationui/service.cpp b/trusty/confirmationui/service.cpp
index dd7e84b..44fa3a6 100644
--- a/trusty/confirmationui/service.cpp
+++ b/trusty/confirmationui/service.cpp
@@ -15,21 +15,24 @@
*/
#include <android-base/logging.h>
-#include <hidl/HidlTransportSupport.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
#include <TrustyConfirmationuiHal.h>
-using android::sp;
-using android::hardware::confirmationui::V1_0::implementation::createTrustyConfirmationUI;
+using ::aidl::android::hardware::confirmationui::createTrustyConfirmationUI;
+using ::aidl::android::hardware::confirmationui::IConfirmationUI;
int main() {
- ::android::hardware::configureRpcThreadpool(1, true /*willJoinThreadpool*/);
- auto service = createTrustyConfirmationUI();
- auto status = service->registerAsService();
- if (status != android::OK) {
- LOG(FATAL) << "Could not register service for ConfirmationUI 1.0 (" << status << ")";
- return -1;
- }
- ::android::hardware::joinRpcThreadpool();
- return -1;
+ ABinderProcess_setThreadPoolMaxThreadCount(0);
+
+ auto confirmationui = createTrustyConfirmationUI();
+
+ const auto instance = std::string(IConfirmationUI::descriptor) + "/default";
+ binder_status_t status =
+ AServiceManager_addService(confirmationui->asBinder().get(), instance.c_str());
+ CHECK_EQ(status, STATUS_OK) << "Could not register " << instance;
+
+ ABinderProcess_joinThreadPool();
+ return EXIT_FAILURE;
}
diff --git a/trusty/keymaster/TrustyKeymaster.cpp b/trusty/keymaster/TrustyKeymaster.cpp
index e77940a..ac98695 100644
--- a/trusty/keymaster/TrustyKeymaster.cpp
+++ b/trusty/keymaster/TrustyKeymaster.cpp
@@ -178,6 +178,11 @@
ForwardCommand(KM_GENERATE_CSR, request, response);
}
+void TrustyKeymaster::GenerateCsrV2(const GenerateCsrV2Request& request,
+ GenerateCsrV2Response* response) {
+ ForwardCommand(KM_GENERATE_CSR_V2, request, response);
+}
+
void TrustyKeymaster::GetKeyCharacteristics(const GetKeyCharacteristicsRequest& request,
GetKeyCharacteristicsResponse* response) {
ForwardCommand(KM_GET_KEY_CHARACTERISTICS, request, response);
@@ -285,4 +290,10 @@
return response;
}
+GetHwInfoResponse TrustyKeymaster::GetHwInfo() {
+ GetHwInfoResponse response(message_version());
+ ForwardCommand(KM_GET_HW_INFO, GetHwInfoRequest(message_version()), &response);
+ return response;
+}
+
} // namespace keymaster
diff --git a/trusty/keymaster/include/trusty_keymaster/TrustyKeymaster.h b/trusty/keymaster/include/trusty_keymaster/TrustyKeymaster.h
index 9f4f39b..60d3f87 100644
--- a/trusty/keymaster/include/trusty_keymaster/TrustyKeymaster.h
+++ b/trusty/keymaster/include/trusty_keymaster/TrustyKeymaster.h
@@ -44,6 +44,7 @@
void GenerateKey(const GenerateKeyRequest& request, GenerateKeyResponse* response);
void GenerateRkpKey(const GenerateRkpKeyRequest& request, GenerateRkpKeyResponse* response);
void GenerateCsr(const GenerateCsrRequest& request, GenerateCsrResponse* response);
+ void GenerateCsrV2(const GenerateCsrV2Request& request, GenerateCsrV2Response* response);
void GetKeyCharacteristics(const GetKeyCharacteristicsRequest& request,
GetKeyCharacteristicsResponse* response);
void ImportKey(const ImportKeyRequest& request, ImportKeyResponse* response);
@@ -67,6 +68,7 @@
ConfigureVendorPatchlevelResponse ConfigureVendorPatchlevel(
const ConfigureVendorPatchlevelRequest& request);
GetRootOfTrustResponse GetRootOfTrust(const GetRootOfTrustRequest& request);
+ GetHwInfoResponse GetHwInfo();
uint32_t message_version() const { return message_version_; }
diff --git a/trusty/keymaster/include/trusty_keymaster/TrustyRemotelyProvisionedComponentDevice.h b/trusty/keymaster/include/trusty_keymaster/TrustyRemotelyProvisionedComponentDevice.h
index d544b51..dbb7fff 100644
--- a/trusty/keymaster/include/trusty_keymaster/TrustyRemotelyProvisionedComponentDevice.h
+++ b/trusty/keymaster/include/trusty_keymaster/TrustyRemotelyProvisionedComponentDevice.h
@@ -46,6 +46,10 @@
DeviceInfo* deviceInfo, ProtectedData* protectedData,
std::vector<uint8_t>* keysToSignMac) override;
+ ScopedAStatus generateCertificateRequestV2(const std::vector<MacedPublicKey>& keysToSign,
+ const std::vector<uint8_t>& challenge,
+ std::vector<uint8_t>* csr) override;
+
private:
std::shared_ptr<::keymaster::TrustyKeymaster> impl_;
};
diff --git a/trusty/keymaster/include/trusty_keymaster/ipc/keymaster_ipc.h b/trusty/keymaster/include/trusty_keymaster/ipc/keymaster_ipc.h
index bf0cb70..f767d40 100644
--- a/trusty/keymaster/include/trusty_keymaster/ipc/keymaster_ipc.h
+++ b/trusty/keymaster/include/trusty_keymaster/ipc/keymaster_ipc.h
@@ -60,6 +60,8 @@
KM_GENERATE_CSR = (32 << KEYMASTER_REQ_SHIFT),
KM_CONFIGURE_VENDOR_PATCHLEVEL = (33 << KEYMASTER_REQ_SHIFT),
KM_GET_ROOT_OF_TRUST = (34 << KEYMASTER_REQ_SHIFT),
+ KM_GET_HW_INFO = (35 << KEYMASTER_REQ_SHIFT),
+ KM_GENERATE_CSR_V2 = (36 << KEYMASTER_REQ_SHIFT),
// Bootloader/provisioning calls.
KM_SET_BOOT_PARAMS = (0x1000 << KEYMASTER_REQ_SHIFT),
diff --git a/trusty/keymaster/keymint/TrustyRemotelyProvisionedComponentDevice.cpp b/trusty/keymaster/keymint/TrustyRemotelyProvisionedComponentDevice.cpp
index 099f189..c6800cd 100644
--- a/trusty/keymaster/keymint/TrustyRemotelyProvisionedComponentDevice.cpp
+++ b/trusty/keymaster/keymint/TrustyRemotelyProvisionedComponentDevice.cpp
@@ -28,9 +28,14 @@
using keymaster::GenerateCsrRequest;
using keymaster::GenerateCsrResponse;
+using keymaster::GenerateCsrV2Request;
+using keymaster::GenerateCsrV2Response;
using keymaster::GenerateRkpKeyRequest;
using keymaster::GenerateRkpKeyResponse;
+using keymaster::GetHwInfoRequest;
+using keymaster::GetHwInfoResponse;
using keymaster::KeymasterBlob;
+using km_utils::kmError2ScopedAStatus;
using ::std::string;
using ::std::unique_ptr;
using ::std::vector;
@@ -71,10 +76,15 @@
} // namespace
ScopedAStatus TrustyRemotelyProvisionedComponentDevice::getHardwareInfo(RpcHardwareInfo* info) {
- info->versionNumber = 2;
- info->rpcAuthorName = "Google";
- info->supportedEekCurve = RpcHardwareInfo::CURVE_25519;
- info->uniqueId = "Trusty: My password is ******";
+ GetHwInfoResponse response = impl_->GetHwInfo();
+ if (response.error != KM_ERROR_OK) {
+ return Status(-static_cast<int32_t>(response.error), "Failed to get hardware info.");
+ }
+
+ info->versionNumber = response.version;
+ info->rpcAuthorName = std::move(response.rpcAuthorName);
+ info->supportedEekCurve = response.supportedEekCurve;
+ info->uniqueId = std::move(response.uniqueId);
return ScopedAStatus::ok();
}
@@ -118,4 +128,25 @@
return ScopedAStatus::ok();
}
+ScopedAStatus TrustyRemotelyProvisionedComponentDevice::generateCertificateRequestV2(
+ const std::vector<MacedPublicKey>& keysToSign, const std::vector<uint8_t>& challenge,
+ std::vector<uint8_t>* csr) {
+ GenerateCsrV2Request request(impl_->message_version());
+ if (!request.InitKeysToSign(keysToSign.size())) {
+ return kmError2ScopedAStatus(static_cast<keymaster_error_t>(STATUS_FAILED));
+ }
+ for (size_t i = 0; i < keysToSign.size(); i++) {
+ request.SetKeyToSign(i, keysToSign[i].macedKey.data(), keysToSign[i].macedKey.size());
+ }
+ request.SetChallenge(challenge.data(), challenge.size());
+ GenerateCsrV2Response response(impl_->message_version());
+ impl_->GenerateCsrV2(request, &response);
+
+ if (response.error != KM_ERROR_OK) {
+ return Status(-static_cast<int32_t>(response.error), "Failure in CSR v2 generation.");
+ }
+ *csr = km_utils::kmBlob2vector(response.csr);
+ return ScopedAStatus::ok();
+}
+
} // namespace aidl::android::hardware::security::keymint::trusty
diff --git a/trusty/keymaster/keymint/android.hardware.security.keymint-service.trusty.xml b/trusty/keymaster/keymint/android.hardware.security.keymint-service.trusty.xml
index 0b995a2..77dc854 100644
--- a/trusty/keymaster/keymint/android.hardware.security.keymint-service.trusty.xml
+++ b/trusty/keymaster/keymint/android.hardware.security.keymint-service.trusty.xml
@@ -14,7 +14,7 @@
</hal>
<hal format="aidl">
<name>android.hardware.security.keymint</name>
- <version>2</version>
+ <version>3</version>
<fqname>IRemotelyProvisionedComponent/default</fqname>
</hal>
</manifest>
diff --git a/trusty/storage/interface/include/trusty/interface/storage.h b/trusty/storage/interface/include/trusty/interface/storage.h
index 255ade1..3291607 100644
--- a/trusty/storage/interface/include/trusty/interface/storage.h
+++ b/trusty/storage/interface/include/trusty/interface/storage.h
@@ -53,6 +53,8 @@
/* transaction support */
STORAGE_END_TRANSACTION = 9 << STORAGE_REQ_SHIFT,
+
+ STORAGE_FILE_GET_MAX_SIZE = 12 << STORAGE_REQ_SHIFT,
};
/**
@@ -184,6 +186,24 @@
};
/**
+ * struct storage_file_get_max_size_req - request format for
+ * STORAGE_FILE_GET_MAX_SIZE
+ * @handle: the handle for the file whose max size is requested
+ */
+struct storage_file_get_max_size_req {
+ uint32_t handle;
+};
+
+/**
+ * struct storage_file_get_max_size_resp - response format for
+ * STORAGE_FILE_GET_MAX_SIZE
+ * @max_size: the maximum size of the file
+ */
+struct storage_file_get_max_size_resp {
+ uint64_t max_size;
+};
+
+/**
* struct storage_file_read_req - request format for STORAGE_FILE_READ
* @handle: the handle for the file from which to read
* @size: the quantity of bytes to read from the file