Merge changes from topics 'adb_thread', 'adb_loopback'
* changes:
adb: statically link libbase into the tests.
adb: kill adb_thread_{create, join, detach, exit}.
adb: don't try to resolve 'localhost'
diff --git a/adb/commandline.cpp b/adb/commandline.cpp
index 730dc72..7702b0e 100644
--- a/adb/commandline.cpp
+++ b/adb/commandline.cpp
@@ -169,15 +169,7 @@
" '-k': keep the data and cache directories\n"
"\n"
"backup/restore:\n"
- " backup [-f FILE] [-apk|-noapk] [-obb|-noobb] [-shared|-noshared] [-all] [-system|-nosystem] [PACKAGE...]\n"
- " write an archive of the device's data to FILE [default=backup.adb]\n"
- " package list optional if -all/-shared are supplied\n"
- " -apk/-noapk: do/don't back up .apk files (default -noapk)\n"
- " -obb/-noobb: do/don't back up .obb files (default -noobb)\n"
- " -shared|-noshared: do/don't back up shared storage (default -noshared)\n"
- " -all: back up all installed applications\n"
- " -system|-nosystem: include system apps in -all (default -system)\n"
- " restore FILE restore device contents from FILE\n"
+ " to show usage run \"adb shell bu help\"\n"
"\n"
"debugging:\n"
" bugreport [PATH]\n"
diff --git a/base/Android.bp b/base/Android.bp
index 121da42..3af7686 100644
--- a/base/Android.bp
+++ b/base/Android.bp
@@ -98,6 +98,7 @@
"parseint_test.cpp",
"parsenetaddress_test.cpp",
"quick_exit_test.cpp",
+ "scopeguard_test.cpp",
"stringprintf_test.cpp",
"strings_test.cpp",
"test_main.cpp",
diff --git a/base/include/android-base/scopeguard.h b/base/include/android-base/scopeguard.h
new file mode 100644
index 0000000..abcf4bc
--- /dev/null
+++ b/base/include/android-base/scopeguard.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2014 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.
+ */
+
+#ifndef ANDROID_BASE_SCOPEGUARD_H
+#define ANDROID_BASE_SCOPEGUARD_H
+
+#include <utility> // for std::move
+
+namespace android {
+namespace base {
+
+template <typename F>
+class ScopeGuard {
+ public:
+ ScopeGuard(F f) : f_(f), active_(true) {}
+
+ ScopeGuard(ScopeGuard&& that) : f_(std::move(that.f_)), active_(that.active_) {
+ that.active_ = false;
+ }
+
+ ~ScopeGuard() {
+ if (active_) f_();
+ }
+
+ ScopeGuard() = delete;
+ ScopeGuard(const ScopeGuard&) = delete;
+ void operator=(const ScopeGuard&) = delete;
+ void operator=(ScopeGuard&& that) = delete;
+
+ void Disable() { active_ = false; }
+
+ bool active() const { return active_; }
+
+ private:
+ F f_;
+ bool active_;
+};
+
+template <typename T>
+ScopeGuard<T> make_scope_guard(T f) {
+ return ScopeGuard<T>(f);
+}
+
+} // namespace base
+} // namespace android
+
+#endif // ANDROID_BASE_SCOPEGUARD_H
diff --git a/base/scopeguard_test.cpp b/base/scopeguard_test.cpp
new file mode 100644
index 0000000..e11154a
--- /dev/null
+++ b/base/scopeguard_test.cpp
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2017 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 "android-base/scopeguard.h"
+
+#include <utility>
+
+#include <gtest/gtest.h>
+
+TEST(scopeguard, normal) {
+ bool guarded_var = true;
+ {
+ auto scopeguard = android::base::make_scope_guard([&guarded_var] { guarded_var = false; });
+ }
+ ASSERT_FALSE(guarded_var);
+}
+
+TEST(scopeguard, disabled) {
+ bool guarded_var = true;
+ {
+ auto scopeguard = android::base::make_scope_guard([&guarded_var] { guarded_var = false; });
+ scopeguard.Disable();
+ }
+ ASSERT_TRUE(guarded_var);
+}
+
+TEST(scopeguard, moved) {
+ int guarded_var = true;
+ auto scopeguard = android::base::make_scope_guard([&guarded_var] { guarded_var = false; });
+ { decltype(scopeguard) new_guard(std::move(scopeguard)); }
+ EXPECT_FALSE(scopeguard.active());
+ ASSERT_FALSE(guarded_var);
+}
diff --git a/debuggerd/client/debuggerd_client.cpp b/debuggerd/client/debuggerd_client.cpp
index 3b84853..2be13c6 100644
--- a/debuggerd/client/debuggerd_client.cpp
+++ b/debuggerd/client/debuggerd_client.cpp
@@ -140,7 +140,9 @@
}
bool backtrace = dump_type == kDebuggerdBacktrace;
- send_signal(pid, backtrace);
+ if (!send_signal(pid, backtrace)) {
+ return false;
+ }
rc = TEMP_FAILURE_RETRY(recv(set_timeout(sockfd.get()), &response, sizeof(response), MSG_TRUNC));
if (rc == 0) {
diff --git a/debuggerd/libdebuggerd/utility.cpp b/debuggerd/libdebuggerd/utility.cpp
index 22fde5e..7f450e6 100644
--- a/debuggerd/libdebuggerd/utility.cpp
+++ b/debuggerd/libdebuggerd/utility.cpp
@@ -22,16 +22,22 @@
#include <signal.h>
#include <string.h>
#include <sys/ptrace.h>
+#include <sys/uio.h>
#include <sys/wait.h>
#include <unistd.h>
#include <string>
+#include <android-base/logging.h>
+#include <android-base/properties.h>
#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
#include <android-base/unique_fd.h>
#include <backtrace/Backtrace.h>
#include <log/log.h>
+using android::base::unique_fd;
+
// Whitelist output desired in the logcat output.
bool is_allowed_in_logcat(enum logtype ltype) {
if ((ltype == HEADER)
@@ -42,6 +48,19 @@
return false;
}
+static bool should_write_to_kmsg() {
+ // Write to kmsg if tombstoned isn't up, and we're able to do so.
+ if (!android::base::GetBoolProperty("ro.debuggable", false)) {
+ return false;
+ }
+
+ if (android::base::GetProperty("init.svc.tombstoned", "") == "running") {
+ return false;
+ }
+
+ return true;
+}
+
__attribute__((__weak__, visibility("default")))
void _LOG(log_t* log, enum logtype ltype, const char* fmt, ...) {
bool write_to_tombstone = (log->tfd != -1);
@@ -49,6 +68,7 @@
&& log->crashed_tid != -1
&& log->current_tid != -1
&& (log->crashed_tid == log->current_tid);
+ static bool write_to_kmsg = should_write_to_kmsg();
char buf[512];
va_list ap;
@@ -70,6 +90,30 @@
if (log->amfd_data != nullptr) {
*log->amfd_data += buf;
}
+
+ if (write_to_kmsg) {
+ unique_fd kmsg_fd(open("/dev/kmsg_debug", O_WRONLY | O_APPEND | O_CLOEXEC));
+ if (kmsg_fd.get() >= 0) {
+ // Our output might contain newlines which would otherwise be handled by the android logger.
+ // Split the lines up ourselves before sending to the kernel logger.
+ if (buf[len - 1] == '\n') {
+ buf[len - 1] = '\0';
+ }
+
+ std::vector<std::string> fragments = android::base::Split(buf, "\n");
+ for (const std::string& fragment : fragments) {
+ static constexpr char prefix[] = "<3>DEBUG: ";
+ struct iovec iov[3];
+ iov[0].iov_base = const_cast<char*>(prefix);
+ iov[0].iov_len = strlen(prefix);
+ iov[1].iov_base = const_cast<char*>(fragment.c_str());
+ iov[1].iov_len = fragment.length();
+ iov[2].iov_base = const_cast<char*>("\n");
+ iov[2].iov_len = 1;
+ TEMP_FAILURE_RETRY(writev(kmsg_fd.get(), iov, 3));
+ }
+ }
+ }
}
}
@@ -205,7 +249,7 @@
}
void read_with_default(const char* path, char* buf, size_t len, const char* default_value) {
- android::base::unique_fd fd(open(path, O_RDONLY));
+ unique_fd fd(open(path, O_RDONLY | O_CLOEXEC));
if (fd != -1) {
int rc = TEMP_FAILURE_RETRY(read(fd.get(), buf, len - 1));
if (rc != -1) {
diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp
index 6636be2..ea9cb37 100644
--- a/fs_mgr/fs_mgr.cpp
+++ b/fs_mgr/fs_mgr.cpp
@@ -31,7 +31,10 @@
#include <time.h>
#include <unistd.h>
+#include <memory>
+
#include <android-base/file.h>
+#include <android-base/properties.h>
#include <android-base/stringprintf.h>
#include <android-base/unique_fd.h>
#include <cutils/android_reboot.h>
@@ -47,8 +50,10 @@
#include <logwrap/logwrap.h>
#include <private/android_logger.h> // for __android_log_is_debuggable()
+#include "fs_mgr.h"
+#include "fs_mgr_avb.h"
#include "fs_mgr_priv.h"
-#include "fs_mgr_priv_avb.h"
+#include "fs_mgr_priv_dm_ioctl.h"
#define KEY_LOC_PROP "ro.crypto.keyfile.userdata"
#define KEY_IN_FOOTER "footer"
@@ -283,7 +288,10 @@
return force_check;
}
*fs_stat |= FS_STAT_IS_EXT4;
- //TODO check if it is new version or not
+ LINFO << "superblock s_max_mnt_count:" << sb.s_max_mnt_count << "," << blk_device;
+ if (sb.s_max_mnt_count == 0xffff) { // -1 (int16) in ext2, but uint16 in ext4
+ *fs_stat |= FS_STAT_NEW_IMAGE_VERSION;
+ }
if ((sb.s_feature_incompat & EXT4_FEATURE_INCOMPAT_RECOVER) != 0 ||
(sb.s_state & EXT4_VALID_FS) == 0) {
LINFO << __FUNCTION__ << "(): was not clealy shutdown, state flag:"
@@ -704,6 +712,23 @@
}
}
+static std::string extract_by_name_prefix(struct fstab* fstab) {
+ // We assume that there's an entry for the /misc mount point in the
+ // fstab file and use that to get the device file by-name prefix.
+ // The device needs not to have an actual /misc partition.
+ // e.g.,
+ // - /dev/block/platform/soc.0/7824900.sdhci/by-name/misc ->
+ // - /dev/block/platform/soc.0/7824900.sdhci/by-name/
+ struct fstab_rec* fstab_entry = fs_mgr_get_entry_for_mount_point(fstab, "/misc");
+ if (fstab_entry == nullptr) {
+ LERROR << "/misc mount point not found in fstab";
+ return "";
+ }
+ std::string full_path(fstab_entry->blk_device);
+ size_t end_slash = full_path.find_last_of("/");
+ return full_path.substr(0, end_slash + 1);
+}
+
// TODO: add ueventd notifiers if they don't exist.
// This is just doing a wait_for_device for maximum of 1s
int fs_mgr_test_access(const char *device) {
@@ -747,17 +772,12 @@
int mret = -1;
int mount_errno = 0;
int attempted_idx = -1;
- int avb_ret = FS_MGR_SETUP_AVB_FAIL;
+ FsManagerAvbUniquePtr avb_handle(nullptr);
if (!fstab) {
return -1;
}
- if (fs_mgr_is_avb_used() &&
- (avb_ret = fs_mgr_load_vbmeta_images(fstab)) == FS_MGR_SETUP_AVB_FAIL) {
- return -1;
- }
-
for (i = 0; i < fstab->num_entries; i++) {
/* Don't mount entries that are managed by vold or not for the mount mode*/
if ((fstab->recs[i].fs_mgr_flags & (MF_VOLDMANAGED | MF_RECOVERYONLY)) ||
@@ -796,16 +816,15 @@
wait_for_file(fstab->recs[i].blk_device, WAIT_TIMEOUT);
}
- if (fs_mgr_is_avb_used() && (fstab->recs[i].fs_mgr_flags & MF_AVB)) {
- /* If HASHTREE_DISABLED is set (cf. 'adb disable-verity'), we
- * should set up the device without using dm-verity.
- * The actual mounting still take place in the following
- * mount_with_alternatives().
- */
- if (avb_ret == FS_MGR_SETUP_AVB_HASHTREE_DISABLED) {
- LINFO << "AVB HASHTREE disabled";
- } else if (fs_mgr_setup_avb(&fstab->recs[i]) !=
- FS_MGR_SETUP_AVB_SUCCESS) {
+ if (fstab->recs[i].fs_mgr_flags & MF_AVB) {
+ if (!avb_handle) {
+ avb_handle = FsManagerAvbHandle::Open(extract_by_name_prefix(fstab));
+ if (!avb_handle) {
+ LERROR << "Failed to open FsManagerAvbHandle";
+ return -1;
+ }
+ }
+ if (!avb_handle->SetUpAvb(&fstab->recs[i], true /* wait_for_verity_dev */)) {
LERROR << "Failed to set up AVB on partition: "
<< fstab->recs[i].mount_point << ", skipping!";
/* Skips mounting the device. */
@@ -931,10 +950,6 @@
}
}
- if (fs_mgr_is_avb_used()) {
- fs_mgr_unload_vbmeta_images();
- }
-
if (error_count) {
return -1;
} else {
@@ -973,17 +988,12 @@
int mount_errors = 0;
int first_mount_errno = 0;
char *m;
- int avb_ret = FS_MGR_SETUP_AVB_FAIL;
+ FsManagerAvbUniquePtr avb_handle(nullptr);
if (!fstab) {
return ret;
}
- if (fs_mgr_is_avb_used() &&
- (avb_ret = fs_mgr_load_vbmeta_images(fstab)) == FS_MGR_SETUP_AVB_FAIL) {
- return ret;
- }
-
for (i = 0; i < fstab->num_entries; i++) {
if (!fs_match(fstab->recs[i].mount_point, n_name)) {
continue;
@@ -1018,16 +1028,15 @@
do_reserved_size(n_blk_device, fstab->recs[i].fs_type, &fstab->recs[i], &fs_stat);
}
- if (fs_mgr_is_avb_used() && (fstab->recs[i].fs_mgr_flags & MF_AVB)) {
- /* If HASHTREE_DISABLED is set (cf. 'adb disable-verity'), we
- * should set up the device without using dm-verity.
- * The actual mounting still take place in the following
- * mount_with_alternatives().
- */
- if (avb_ret == FS_MGR_SETUP_AVB_HASHTREE_DISABLED) {
- LINFO << "AVB HASHTREE disabled";
- } else if (fs_mgr_setup_avb(&fstab->recs[i]) !=
- FS_MGR_SETUP_AVB_SUCCESS) {
+ if (fstab->recs[i].fs_mgr_flags & MF_AVB) {
+ if (!avb_handle) {
+ avb_handle = FsManagerAvbHandle::Open(extract_by_name_prefix(fstab));
+ if (!avb_handle) {
+ LERROR << "Failed to open FsManagerAvbHandle";
+ return -1;
+ }
+ }
+ if (!avb_handle->SetUpAvb(&fstab->recs[i], true /* wait_for_verity_dev */)) {
LERROR << "Failed to set up AVB on partition: "
<< fstab->recs[i].mount_point << ", skipping!";
/* Skips mounting the device. */
@@ -1076,9 +1085,6 @@
}
out:
- if (fs_mgr_is_avb_used()) {
- fs_mgr_unload_vbmeta_images();
- }
return ret;
}
@@ -1256,3 +1262,97 @@
return 0;
}
+
+bool fs_mgr_load_verity_state(int* mode) {
+ /* return the default mode, unless any of the verified partitions are in
+ * logging mode, in which case return that */
+ *mode = VERITY_MODE_DEFAULT;
+
+ std::unique_ptr<fstab, decltype(&fs_mgr_free_fstab)> fstab(fs_mgr_read_fstab_default(),
+ fs_mgr_free_fstab);
+ if (!fstab) {
+ LERROR << "Failed to read default fstab";
+ return false;
+ }
+
+ for (int i = 0; i < fstab->num_entries; i++) {
+ if (fs_mgr_is_avb(&fstab->recs[i])) {
+ *mode = VERITY_MODE_RESTART; // avb only supports restart mode.
+ break;
+ } else if (!fs_mgr_is_verified(&fstab->recs[i])) {
+ continue;
+ }
+
+ int current;
+ if (load_verity_state(&fstab->recs[i], ¤t) < 0) {
+ continue;
+ }
+ if (current != VERITY_MODE_DEFAULT) {
+ *mode = current;
+ break;
+ }
+ }
+
+ return true;
+}
+
+bool fs_mgr_update_verity_state(fs_mgr_verity_state_callback callback) {
+ if (!callback) {
+ return false;
+ }
+
+ int mode;
+ if (!fs_mgr_load_verity_state(&mode)) {
+ return false;
+ }
+
+ android::base::unique_fd fd(TEMP_FAILURE_RETRY(open("/dev/device-mapper", O_RDWR | O_CLOEXEC)));
+ if (fd == -1) {
+ PERROR << "Error opening device mapper";
+ return false;
+ }
+
+ std::unique_ptr<fstab, decltype(&fs_mgr_free_fstab)> fstab(fs_mgr_read_fstab_default(),
+ fs_mgr_free_fstab);
+ if (!fstab) {
+ LERROR << "Failed to read default fstab";
+ return false;
+ }
+
+ alignas(dm_ioctl) char buffer[DM_BUF_SIZE];
+ struct dm_ioctl* io = (struct dm_ioctl*)buffer;
+ bool system_root = android::base::GetProperty("ro.build.system_root_image", "") == "true";
+
+ for (int i = 0; i < fstab->num_entries; i++) {
+ if (!fs_mgr_is_verified(&fstab->recs[i]) && !fs_mgr_is_avb(&fstab->recs[i])) {
+ continue;
+ }
+
+ std::string mount_point;
+ if (system_root && !strcmp(fstab->recs[i].mount_point, "/")) {
+ mount_point = "system";
+ } else {
+ mount_point = basename(fstab->recs[i].mount_point);
+ }
+
+ fs_mgr_verity_ioctl_init(io, mount_point, 0);
+
+ const char* status;
+ if (ioctl(fd, DM_TABLE_STATUS, io)) {
+ if (fstab->recs[i].fs_mgr_flags & MF_VERIFYATBOOT) {
+ status = "V";
+ } else {
+ PERROR << "Failed to query DM_TABLE_STATUS for " << mount_point.c_str();
+ continue;
+ }
+ }
+
+ status = &buffer[io->data_start + sizeof(struct dm_target_spec)];
+
+ if (*status == 'C' || *status == 'V') {
+ callback(&fstab->recs[i], mount_point.c_str(), mode, *status);
+ }
+ }
+
+ return true;
+}
diff --git a/fs_mgr/fs_mgr_avb.cpp b/fs_mgr/fs_mgr_avb.cpp
index 7512eb9..7c82bb1 100644
--- a/fs_mgr/fs_mgr_avb.cpp
+++ b/fs_mgr/fs_mgr_avb.cpp
@@ -28,6 +28,7 @@
#include <android-base/file.h>
#include <android-base/parseint.h>
#include <android-base/properties.h>
+#include <android-base/stringprintf.h>
#include <android-base/strings.h>
#include <android-base/unique_fd.h>
#include <cutils/properties.h>
@@ -37,9 +38,9 @@
#include <utils/Compat.h>
#include "fs_mgr.h"
+#include "fs_mgr_avb.h"
#include "fs_mgr_avb_ops.h"
#include "fs_mgr_priv.h"
-#include "fs_mgr_priv_avb.h"
#include "fs_mgr_priv_dm_ioctl.h"
#include "fs_mgr_priv_sha.h"
@@ -85,24 +86,6 @@
hashtree_desc.fec_offset / hashtree_desc.data_block_size, /* fec_start */ \
VERITY_TABLE_OPT_IGNZERO, VERITY_TABLE_OPT_RESTART
-AvbSlotVerifyData* fs_mgr_avb_verify_data = nullptr;
-AvbOps* fs_mgr_avb_ops = nullptr;
-
-enum HashAlgorithm {
- kInvalid = 0,
- kSHA256 = 1,
- kSHA512 = 2,
-};
-
-struct androidboot_vbmeta {
- HashAlgorithm hash_alg;
- uint8_t digest[SHA512_DIGEST_LENGTH];
- size_t vbmeta_size;
- bool allow_verification_error;
-};
-
-androidboot_vbmeta fs_mgr_vbmeta_prop;
-
static inline bool nibble_value(const char& c, uint8_t* value) {
FS_MGR_CHECK(value != nullptr);
@@ -159,27 +142,78 @@
return hex;
}
-static bool load_vbmeta_prop(androidboot_vbmeta* vbmeta_prop) {
- FS_MGR_CHECK(vbmeta_prop != nullptr);
+template <typename Hasher>
+static std::pair<size_t, bool> verify_vbmeta_digest(const AvbSlotVerifyData& verify_data,
+ const uint8_t* expected_digest) {
+ size_t total_size = 0;
+ Hasher hasher;
+ for (size_t n = 0; n < verify_data.num_vbmeta_images; n++) {
+ hasher.update(verify_data.vbmeta_images[n].vbmeta_data,
+ verify_data.vbmeta_images[n].vbmeta_size);
+ total_size += verify_data.vbmeta_images[n].vbmeta_size;
+ }
+ bool matched = (memcmp(hasher.finalize(), expected_digest, Hasher::DIGEST_SIZE) == 0);
+
+ return std::make_pair(total_size, matched);
+}
+
+// Reads the following values from kernel cmdline and provides the
+// VerifyVbmetaImages() to verify AvbSlotVerifyData.
+// - androidboot.vbmeta.device_state
+// - androidboot.vbmeta.hash_alg
+// - androidboot.vbmeta.size
+// - androidboot.vbmeta.digest
+class FsManagerAvbVerifier {
+ public:
+ // The factory method to return a unique_ptr<FsManagerAvbVerifier>
+ static std::unique_ptr<FsManagerAvbVerifier> Create();
+ bool VerifyVbmetaImages(const AvbSlotVerifyData& verify_data);
+ bool IsDeviceUnlocked() { return is_device_unlocked_; }
+
+ protected:
+ FsManagerAvbVerifier() = default;
+
+ private:
+ enum HashAlgorithm {
+ kInvalid = 0,
+ kSHA256 = 1,
+ kSHA512 = 2,
+ };
+
+ HashAlgorithm hash_alg_;
+ uint8_t digest_[SHA512_DIGEST_LENGTH];
+ size_t vbmeta_size_;
+ bool is_device_unlocked_;
+};
+
+std::unique_ptr<FsManagerAvbVerifier> FsManagerAvbVerifier::Create() {
std::string cmdline;
- android::base::ReadFileToString("/proc/cmdline", &cmdline);
+ if (!android::base::ReadFileToString("/proc/cmdline", &cmdline)) {
+ LERROR << "Failed to read /proc/cmdline";
+ return nullptr;
+ }
- std::string hash_alg;
+ std::unique_ptr<FsManagerAvbVerifier> avb_verifier(new FsManagerAvbVerifier());
+ if (!avb_verifier) {
+ LERROR << "Failed to create unique_ptr<FsManagerAvbVerifier>";
+ return nullptr;
+ }
+
std::string digest;
-
+ std::string hash_alg;
for (const auto& entry : android::base::Split(android::base::Trim(cmdline), " ")) {
std::vector<std::string> pieces = android::base::Split(entry, "=");
const std::string& key = pieces[0];
const std::string& value = pieces[1];
if (key == "androidboot.vbmeta.device_state") {
- vbmeta_prop->allow_verification_error = (value == "unlocked");
+ avb_verifier->is_device_unlocked_ = (value == "unlocked");
} else if (key == "androidboot.vbmeta.hash_alg") {
hash_alg = value;
} else if (key == "androidboot.vbmeta.size") {
- if (!android::base::ParseUint(value.c_str(), &vbmeta_prop->vbmeta_size)) {
- return false;
+ if (!android::base::ParseUint(value.c_str(), &avb_verifier->vbmeta_size_)) {
+ return nullptr;
}
} else if (key == "androidboot.vbmeta.digest") {
digest = value;
@@ -190,48 +224,31 @@
size_t expected_digest_size = 0;
if (hash_alg == "sha256") {
expected_digest_size = SHA256_DIGEST_LENGTH * 2;
- vbmeta_prop->hash_alg = kSHA256;
+ avb_verifier->hash_alg_ = kSHA256;
} else if (hash_alg == "sha512") {
expected_digest_size = SHA512_DIGEST_LENGTH * 2;
- vbmeta_prop->hash_alg = kSHA512;
+ avb_verifier->hash_alg_ = kSHA512;
} else {
LERROR << "Unknown hash algorithm: " << hash_alg.c_str();
- return false;
+ return nullptr;
}
// Reads digest.
if (digest.size() != expected_digest_size) {
LERROR << "Unexpected digest size: " << digest.size()
<< " (expected: " << expected_digest_size << ")";
- return false;
+ return nullptr;
}
- if (!hex_to_bytes(vbmeta_prop->digest, sizeof(vbmeta_prop->digest), digest)) {
+ if (!hex_to_bytes(avb_verifier->digest_, sizeof(avb_verifier->digest_), digest)) {
LERROR << "Hash digest contains non-hexidecimal character: " << digest.c_str();
- return false;
+ return nullptr;
}
- return true;
+ return avb_verifier;
}
-template <typename Hasher>
-static std::pair<size_t, bool> verify_vbmeta_digest(const AvbSlotVerifyData& verify_data,
- const androidboot_vbmeta& vbmeta_prop) {
- size_t total_size = 0;
- Hasher hasher;
- for (size_t n = 0; n < verify_data.num_vbmeta_images; n++) {
- hasher.update(verify_data.vbmeta_images[n].vbmeta_data,
- verify_data.vbmeta_images[n].vbmeta_size);
- total_size += verify_data.vbmeta_images[n].vbmeta_size;
- }
-
- bool matched = (memcmp(hasher.finalize(), vbmeta_prop.digest, Hasher::DIGEST_SIZE) == 0);
-
- return std::make_pair(total_size, matched);
-}
-
-static bool verify_vbmeta_images(const AvbSlotVerifyData& verify_data,
- const androidboot_vbmeta& vbmeta_prop) {
+bool FsManagerAvbVerifier::VerifyVbmetaImages(const AvbSlotVerifyData& verify_data) {
if (verify_data.num_vbmeta_images == 0) {
LERROR << "No vbmeta images";
return false;
@@ -240,17 +257,17 @@
size_t total_size = 0;
bool digest_matched = false;
- if (vbmeta_prop.hash_alg == kSHA256) {
+ if (hash_alg_ == kSHA256) {
std::tie(total_size, digest_matched) =
- verify_vbmeta_digest<SHA256Hasher>(verify_data, vbmeta_prop);
- } else if (vbmeta_prop.hash_alg == kSHA512) {
+ verify_vbmeta_digest<SHA256Hasher>(verify_data, digest_);
+ } else if (hash_alg_ == kSHA512) {
std::tie(total_size, digest_matched) =
- verify_vbmeta_digest<SHA512Hasher>(verify_data, vbmeta_prop);
+ verify_vbmeta_digest<SHA512Hasher>(verify_data, digest_);
}
- if (total_size != vbmeta_prop.vbmeta_size) {
- LERROR << "total vbmeta size mismatch: " << total_size
- << " (expected: " << vbmeta_prop.vbmeta_size << ")";
+ if (total_size != vbmeta_size_) {
+ LERROR << "total vbmeta size mismatch: " << total_size << " (expected: " << vbmeta_size_
+ << ")";
return false;
}
@@ -319,7 +336,8 @@
static bool hashtree_dm_verity_setup(struct fstab_rec* fstab_entry,
const AvbHashtreeDescriptor& hashtree_desc,
- const std::string& salt, const std::string& root_digest) {
+ const std::string& salt, const std::string& root_digest,
+ bool wait_for_verity_dev) {
// Gets the device mapper fd.
android::base::unique_fd fd(open("/dev/device-mapper", O_RDWR));
if (fd < 0) {
@@ -358,13 +376,12 @@
// Marks the underlying block device as read-only.
fs_mgr_set_blk_ro(fstab_entry->blk_device);
- // TODO(bowgotsai): support verified all partition at boot.
// Updates fstab_rec->blk_device to verity device name.
free(fstab_entry->blk_device);
fstab_entry->blk_device = strdup(verity_blk_name.c_str());
// Makes sure we've set everything up properly.
- if (fs_mgr_test_access(verity_blk_name.c_str()) < 0) {
+ if (wait_for_verity_dev && fs_mgr_test_access(verity_blk_name.c_str()) < 0) {
return false;
}
@@ -408,8 +425,7 @@
continue;
}
if (desc.tag == AVB_DESCRIPTOR_TAG_HASHTREE) {
- desc_partition_name =
- (const uint8_t*)descriptors[j] + sizeof(AvbHashtreeDescriptor);
+ desc_partition_name = (const uint8_t*)descriptors[j] + sizeof(AvbHashtreeDescriptor);
if (!avb_hashtree_descriptor_validate_and_byteswap(
(AvbHashtreeDescriptor*)descriptors[j], out_hashtree_desc)) {
continue;
@@ -441,140 +457,97 @@
return true;
}
-static bool init_is_avb_used() {
- // When AVB is used, boot loader should set androidboot.vbmeta.{hash_alg,
- // size, digest} in kernel cmdline or in device tree. They will then be
- // imported by init process to system properties: ro.boot.vbmeta.{hash_alg, size, digest}.
- //
- // In case of early mount, init properties are not initialized, so we also
- // ensure we look into kernel command line and device tree if the property is
- // not found
- //
- // Checks hash_alg as an indicator for whether AVB is used.
- // We don't have to parse and check all of them here. The check will
- // be done in fs_mgr_load_vbmeta_images() and FS_MGR_SETUP_AVB_FAIL will
- // be returned when there is an error.
-
- std::string hash_alg;
- if (!fs_mgr_get_boot_config("vbmeta.hash_alg", &hash_alg)) {
- return false;
- }
- if (hash_alg == "sha256" || hash_alg == "sha512") {
- return true;
- }
- return false;
-}
-
-bool fs_mgr_is_avb_used() {
- static bool result = init_is_avb_used();
- return result;
-}
-
-int fs_mgr_load_vbmeta_images(struct fstab* fstab) {
- FS_MGR_CHECK(fstab != nullptr);
-
- // Gets the expected hash value of vbmeta images from
- // kernel cmdline.
- if (!load_vbmeta_prop(&fs_mgr_vbmeta_prop)) {
- return FS_MGR_SETUP_AVB_FAIL;
+FsManagerAvbUniquePtr FsManagerAvbHandle::Open(const std::string& device_file_by_name_prefix) {
+ if (device_file_by_name_prefix.empty()) {
+ LERROR << "Missing device file by-name prefix";
+ return nullptr;
}
- fs_mgr_avb_ops = fs_mgr_dummy_avb_ops_new(fstab);
- if (fs_mgr_avb_ops == nullptr) {
- LERROR << "Failed to allocate dummy avb_ops";
- return FS_MGR_SETUP_AVB_FAIL;
+ // Gets the expected hash value of vbmeta images from kernel cmdline.
+ std::unique_ptr<FsManagerAvbVerifier> avb_verifier = FsManagerAvbVerifier::Create();
+ if (!avb_verifier) {
+ LERROR << "Failed to create FsManagerAvbVerifier";
+ return nullptr;
}
- // Invokes avb_slot_verify() to load and verify all vbmeta images.
- // Sets requested_partitions to nullptr as it's to copy the contents
- // of HASH partitions into fs_mgr_avb_verify_data, which is not required as
- // fs_mgr only deals with HASHTREE partitions.
- const char *requested_partitions[] = {nullptr};
- std::string ab_suffix;
- std::string slot;
- if (fs_mgr_get_boot_config("slot", &slot)) {
- ab_suffix = "_" + slot;
- } else {
- // remove slot_suffix once bootloaders update to new androidboot.slot param
- fs_mgr_get_boot_config("slot_suffix", &ab_suffix);
+ FsManagerAvbUniquePtr avb_handle(new FsManagerAvbHandle());
+ if (!avb_handle) {
+ LERROR << "Failed to allocate FsManagerAvbHandle";
+ return nullptr;
}
- AvbSlotVerifyResult verify_result =
- avb_slot_verify(fs_mgr_avb_ops, requested_partitions, ab_suffix.c_str(),
- fs_mgr_vbmeta_prop.allow_verification_error, &fs_mgr_avb_verify_data);
+
+ FsManagerAvbOps avb_ops(device_file_by_name_prefix);
+ AvbSlotVerifyResult verify_result = avb_ops.AvbSlotVerify(
+ fs_mgr_get_slot_suffix(), avb_verifier->IsDeviceUnlocked(), &avb_handle->avb_slot_data_);
// Only allow two verify results:
// - AVB_SLOT_VERIFY_RESULT_OK.
// - AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION (for UNLOCKED state).
if (verify_result == AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION) {
- if (!fs_mgr_vbmeta_prop.allow_verification_error) {
+ if (!avb_verifier->IsDeviceUnlocked()) {
LERROR << "ERROR_VERIFICATION isn't allowed";
- goto fail;
+ return nullptr;
}
} else if (verify_result != AVB_SLOT_VERIFY_RESULT_OK) {
LERROR << "avb_slot_verify failed, result: " << verify_result;
- goto fail;
+ return nullptr;
}
// Verifies vbmeta images against the digest passed from bootloader.
- if (!verify_vbmeta_images(*fs_mgr_avb_verify_data, fs_mgr_vbmeta_prop)) {
- LERROR << "verify_vbmeta_images failed";
- goto fail;
+ if (!avb_verifier->VerifyVbmetaImages(*avb_handle->avb_slot_data_)) {
+ LERROR << "VerifyVbmetaImages failed";
+ return nullptr;
} else {
// Checks whether FLAGS_HASHTREE_DISABLED is set.
AvbVBMetaImageHeader vbmeta_header;
avb_vbmeta_image_header_to_host_byte_order(
- (AvbVBMetaImageHeader*)fs_mgr_avb_verify_data->vbmeta_images[0].vbmeta_data,
+ (AvbVBMetaImageHeader*)avb_handle->avb_slot_data_->vbmeta_images[0].vbmeta_data,
&vbmeta_header);
bool hashtree_disabled =
((AvbVBMetaImageFlags)vbmeta_header.flags & AVB_VBMETA_IMAGE_FLAGS_HASHTREE_DISABLED);
if (hashtree_disabled) {
- return FS_MGR_SETUP_AVB_HASHTREE_DISABLED;
+ avb_handle->status_ = kFsManagerAvbHandleHashtreeDisabled;
+ return avb_handle;
}
}
if (verify_result == AVB_SLOT_VERIFY_RESULT_OK) {
- return FS_MGR_SETUP_AVB_SUCCESS;
+ avb_handle->status_ = kFsManagerAvbHandleSuccess;
+ return avb_handle;
}
-
-fail:
- fs_mgr_unload_vbmeta_images();
- return FS_MGR_SETUP_AVB_FAIL;
+ return nullptr;
}
-void fs_mgr_unload_vbmeta_images() {
- if (fs_mgr_avb_verify_data != nullptr) {
- avb_slot_verify_data_free(fs_mgr_avb_verify_data);
+bool FsManagerAvbHandle::SetUpAvb(struct fstab_rec* fstab_entry, bool wait_for_verity_dev) {
+ if (!fstab_entry) return false;
+ if (!avb_slot_data_ || avb_slot_data_->num_vbmeta_images < 1) {
+ return false;
}
-
- if (fs_mgr_avb_ops != nullptr) {
- fs_mgr_dummy_avb_ops_free(fs_mgr_avb_ops);
+ if (status_ == kFsManagerAvbHandleHashtreeDisabled) {
+ LINFO << "AVB HASHTREE disabled on:" << fstab_entry->mount_point;
+ return true;
}
-}
-
-int fs_mgr_setup_avb(struct fstab_rec* fstab_entry) {
- if (!fstab_entry || !fs_mgr_avb_verify_data || fs_mgr_avb_verify_data->num_vbmeta_images < 1) {
- return FS_MGR_SETUP_AVB_FAIL;
- }
+ if (status_ != kFsManagerAvbHandleSuccess) return false;
std::string partition_name(basename(fstab_entry->mount_point));
if (!avb_validate_utf8((const uint8_t*)partition_name.c_str(), partition_name.length())) {
LERROR << "Partition name: " << partition_name.c_str() << " is not valid UTF-8.";
- return FS_MGR_SETUP_AVB_FAIL;
+ return false;
}
AvbHashtreeDescriptor hashtree_descriptor;
std::string salt;
std::string root_digest;
- if (!get_hashtree_descriptor(partition_name, *fs_mgr_avb_verify_data, &hashtree_descriptor,
- &salt, &root_digest)) {
- return FS_MGR_SETUP_AVB_FAIL;
+ if (!get_hashtree_descriptor(partition_name, *avb_slot_data_, &hashtree_descriptor, &salt,
+ &root_digest)) {
+ return false;
}
// Converts HASHTREE descriptor to verity_table_params.
- if (!hashtree_dm_verity_setup(fstab_entry, hashtree_descriptor, salt, root_digest)) {
- return FS_MGR_SETUP_AVB_FAIL;
+ if (!hashtree_dm_verity_setup(fstab_entry, hashtree_descriptor, salt, root_digest,
+ wait_for_verity_dev)) {
+ return false;
}
-
- return FS_MGR_SETUP_AVB_SUCCESS;
+ return true;
}
diff --git a/fs_mgr/fs_mgr_avb_ops.cpp b/fs_mgr/fs_mgr_avb_ops.cpp
index 8e49663..981e9fc 100644
--- a/fs_mgr/fs_mgr_avb_ops.cpp
+++ b/fs_mgr/fs_mgr_avb_ops.cpp
@@ -39,91 +39,10 @@
#include "fs_mgr_avb_ops.h"
#include "fs_mgr_priv.h"
-static std::string fstab_by_name_prefix;
-
-static std::string extract_by_name_prefix(struct fstab* fstab) {
- // In AVB, we can assume that there's an entry for the /misc mount
- // point in the fstab file and use that to get the device file for
- // the misc partition. The device needs not to have an actual /misc
- // partition. Then returns the prefix by removing the trailing "misc":
- //
- // - /dev/block/platform/soc.0/7824900.sdhci/by-name/misc ->
- // - /dev/block/platform/soc.0/7824900.sdhci/by-name/
-
- struct fstab_rec* fstab_entry = fs_mgr_get_entry_for_mount_point(fstab, "/misc");
- if (fstab_entry == nullptr) {
- LERROR << "/misc mount point not found in fstab";
- return "";
- }
-
- std::string full_path(fstab_entry->blk_device);
- size_t end_slash = full_path.find_last_of("/");
-
- return full_path.substr(0, end_slash + 1);
-}
-
-static AvbIOResult read_from_partition(AvbOps* ops ATTRIBUTE_UNUSED, const char* partition,
- int64_t offset, size_t num_bytes, void* buffer,
- size_t* out_num_read) {
- // The input |partition| name is with ab_suffix, e.g. system_a.
- // Slot suffix (e.g. _a) will be appended to the device file path
- // for partitions having 'slotselect' optin in fstab file, but it
- // won't be appended to the mount point.
- //
- // Appends |partition| to the fstab_by_name_prefix, which is obtained
- // by removing the trailing "misc" from the device file of /misc mount
- // point. e.g.,
- //
- // - /dev/block/platform/soc.0/7824900.sdhci/by-name/ ->
- // - /dev/block/platform/soc.0/7824900.sdhci/by-name/system_a
-
- std::string path = fstab_by_name_prefix + partition;
-
- // Ensures the device path (a symlink created by init) is ready to
- // access. fs_mgr_test_access() will test a few iterations if the
- // path doesn't exist yet.
- if (fs_mgr_test_access(path.c_str()) < 0) {
- return AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION;
- }
-
- android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(path.c_str(), O_RDONLY | O_CLOEXEC)));
-
- if (fd < 0) {
- PERROR << "Failed to open " << path.c_str();
- return AVB_IO_RESULT_ERROR_IO;
- }
-
- // If offset is negative, interprets its absolute value as the
- // number of bytes from the end of the partition.
- if (offset < 0) {
- off64_t total_size = lseek64(fd, 0, SEEK_END);
- if (total_size == -1) {
- LERROR << "Failed to lseek64 to end of the partition";
- return AVB_IO_RESULT_ERROR_IO;
- }
- offset = total_size + offset;
- // Repositions the offset to the beginning.
- if (lseek64(fd, 0, SEEK_SET) == -1) {
- LERROR << "Failed to lseek64 to the beginning of the partition";
- return AVB_IO_RESULT_ERROR_IO;
- }
- }
-
- // On Linux, we never get partial reads from block devices (except
- // for EOF).
- ssize_t num_read = TEMP_FAILURE_RETRY(pread64(fd, buffer, num_bytes, offset));
-
- if (num_read < 0 || (size_t)num_read != num_bytes) {
- PERROR << "Failed to read " << num_bytes << " bytes from " << path.c_str() << " offset "
- << offset;
- return AVB_IO_RESULT_ERROR_IO;
- }
-
- if (out_num_read != nullptr) {
- *out_num_read = num_read;
- }
-
- return AVB_IO_RESULT_OK;
+static AvbIOResult read_from_partition(AvbOps* ops, const char* partition, int64_t offset,
+ size_t num_bytes, void* buffer, size_t* out_num_read) {
+ return FsManagerAvbOps::GetInstanceFromAvbOps(ops)->ReadFromPartition(
+ partition, offset, num_bytes, buffer, out_num_read);
}
static AvbIOResult dummy_read_rollback_index(AvbOps* ops ATTRIBUTE_UNUSED,
@@ -145,7 +64,6 @@
// Addtionally, user-space should check
// androidboot.vbmeta.{hash_alg, size, digest} against the digest
// of all vbmeta images after invoking avb_slot_verify().
-
*out_is_trusted = true;
return AVB_IO_RESULT_OK;
}
@@ -170,28 +88,86 @@
return AVB_IO_RESULT_OK;
}
-AvbOps* fs_mgr_dummy_avb_ops_new(struct fstab* fstab) {
- AvbOps* ops;
-
- fstab_by_name_prefix = extract_by_name_prefix(fstab);
- if (fstab_by_name_prefix.empty()) return nullptr;
-
- ops = (AvbOps*)calloc(1, sizeof(AvbOps));
- if (ops == nullptr) {
- LERROR << "Error allocating memory for AvbOps";
- return nullptr;
+FsManagerAvbOps::FsManagerAvbOps(const std::string& device_file_by_name_prefix)
+ : device_file_by_name_prefix_(device_file_by_name_prefix) {
+ if (device_file_by_name_prefix_.back() != '/') {
+ device_file_by_name_prefix_ += '/';
}
+ // We only need to provide the implementation of read_from_partition()
+ // operation since that's all what is being used by the avb_slot_verify().
+ // Other I/O operations are only required in bootloader but not in
+ // user-space so we set them as dummy operations.
+ avb_ops_.read_from_partition = read_from_partition;
+ avb_ops_.read_rollback_index = dummy_read_rollback_index;
+ avb_ops_.validate_vbmeta_public_key = dummy_validate_vbmeta_public_key;
+ avb_ops_.read_is_device_unlocked = dummy_read_is_device_unlocked;
+ avb_ops_.get_unique_guid_for_partition = dummy_get_unique_guid_for_partition;
- // We only need these operations since that's all what is being used
- // by the avb_slot_verify(); Most of them are dummy operations because
- // they're only required in bootloader but not required in user-space.
- ops->read_from_partition = read_from_partition;
- ops->read_rollback_index = dummy_read_rollback_index;
- ops->validate_vbmeta_public_key = dummy_validate_vbmeta_public_key;
- ops->read_is_device_unlocked = dummy_read_is_device_unlocked;
- ops->get_unique_guid_for_partition = dummy_get_unique_guid_for_partition;
-
- return ops;
+ // Sets user_data for GetInstanceFromAvbOps() to convert it back to FsManagerAvbOps.
+ avb_ops_.user_data = this;
}
-void fs_mgr_dummy_avb_ops_free(AvbOps* ops) { free(ops); }
+AvbIOResult FsManagerAvbOps::ReadFromPartition(const char* partition, int64_t offset,
+ size_t num_bytes, void* buffer,
+ size_t* out_num_read) {
+ // Appends |partition| to the device_file_by_name_prefix_, e.g.,
+ // - /dev/block/platform/soc.0/7824900.sdhci/by-name/ ->
+ // - /dev/block/platform/soc.0/7824900.sdhci/by-name/system_a
+ std::string path = device_file_by_name_prefix_ + partition;
+
+ // Ensures the device path (a symlink created by init) is ready to
+ // access. fs_mgr_test_access() will test a few iterations if the
+ // path doesn't exist yet.
+ if (fs_mgr_test_access(path.c_str()) < 0) {
+ return AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION;
+ }
+
+ android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(path.c_str(), O_RDONLY | O_CLOEXEC)));
+ if (fd < 0) {
+ PERROR << "Failed to open " << path.c_str();
+ return AVB_IO_RESULT_ERROR_IO;
+ }
+
+ // If offset is negative, interprets its absolute value as the
+ // number of bytes from the end of the partition.
+ if (offset < 0) {
+ off64_t total_size = lseek64(fd, 0, SEEK_END);
+ if (total_size == -1) {
+ LERROR << "Failed to lseek64 to end of the partition";
+ return AVB_IO_RESULT_ERROR_IO;
+ }
+ offset = total_size + offset;
+ // Repositions the offset to the beginning.
+ if (lseek64(fd, 0, SEEK_SET) == -1) {
+ LERROR << "Failed to lseek64 to the beginning of the partition";
+ return AVB_IO_RESULT_ERROR_IO;
+ }
+ }
+
+ // On Linux, we never get partial reads from block devices (except
+ // for EOF).
+ ssize_t num_read = TEMP_FAILURE_RETRY(pread64(fd, buffer, num_bytes, offset));
+ if (num_read < 0 || (size_t)num_read != num_bytes) {
+ PERROR << "Failed to read " << num_bytes << " bytes from " << path.c_str() << " offset "
+ << offset;
+ return AVB_IO_RESULT_ERROR_IO;
+ }
+
+ if (out_num_read != nullptr) {
+ *out_num_read = num_read;
+ }
+
+ return AVB_IO_RESULT_OK;
+}
+
+AvbSlotVerifyResult FsManagerAvbOps::AvbSlotVerify(const std::string& ab_suffix,
+ bool allow_verification_error,
+ AvbSlotVerifyData** out_data) {
+ // Invokes avb_slot_verify() to load and verify all vbmeta images.
+ // Sets requested_partitions to nullptr as it's to copy the contents
+ // of HASH partitions into handle>avb_slot_data_, which is not required as
+ // fs_mgr only deals with HASHTREE partitions.
+ const char* requested_partitions[] = {nullptr};
+ return avb_slot_verify(&avb_ops_, requested_partitions, ab_suffix.c_str(),
+ allow_verification_error, out_data);
+}
diff --git a/fs_mgr/fs_mgr_avb_ops.h b/fs_mgr/fs_mgr_avb_ops.h
index bfdec9a..ec4a8c9 100644
--- a/fs_mgr/fs_mgr_avb_ops.h
+++ b/fs_mgr/fs_mgr_avb_ops.h
@@ -29,31 +29,34 @@
#include "fs_mgr.h"
-__BEGIN_DECLS
+// This class provides C++ bindings to interact with libavb, a small
+// self-contained piece of code that's intended to be used in bootloaders.
+// It mainly contains two functions:
+// - ReadFromPartition(): to read AVB metadata from a given partition.
+// It provides the implementation of AvbOps.read_from_partition() when
+// reading metadata through libavb.
+// - AvbSlotVerify(): the C++ binding of libavb->avb_slot_verify() to
+// read and verify the metadata and store it into the out_data parameter.
+// The caller MUST check the integrity of metadata against the
+// androidboot.vbmeta.{hash_alg, size, digest} values from /proc/cmdline.
+// e.g., see class FsManagerAvbVerifier for more details.
+//
+class FsManagerAvbOps {
+ public:
+ FsManagerAvbOps(const std::string& device_file_by_name_prefix);
-/* Allocates a "dummy" AvbOps instance solely for use in user-space.
- * Returns nullptr on OOM.
- *
- * It mainly provides read_from_partitions() for user-space to get
- * AvbSlotVerifyData.vbmeta_images[] and the caller MUST check their
- * integrity against the androidboot.vbmeta.{hash_alg, size, digest}
- * values from /proc/cmdline, e.g. verify_vbmeta_images()
- * in fs_mgr_avb.cpp.
- *
- * Other I/O operations are only required in boot loader so we set
- * them as dummy operations here.
- * - Will allow any public key for signing.
- * - returns 0 for any rollback index location.
- * - returns device is unlocked regardless of the actual state.
- * - returns a dummy guid for any partition.
- *
- * Frees with fs_mgr_dummy_avb_ops_free().
- */
-AvbOps* fs_mgr_dummy_avb_ops_new(struct fstab* fstab);
+ static FsManagerAvbOps* GetInstanceFromAvbOps(AvbOps* ops) {
+ return reinterpret_cast<FsManagerAvbOps*>(ops->user_data);
+ }
-/* Frees an AvbOps instance previously allocated with fs_mgr_avb_ops_new(). */
-void fs_mgr_dummy_avb_ops_free(AvbOps* ops);
+ AvbIOResult ReadFromPartition(const char* partition, int64_t offset, size_t num_bytes,
+ void* buffer, size_t* out_num_read);
-__END_DECLS
+ AvbSlotVerifyResult AvbSlotVerify(const std::string& ab_suffix, bool allow_verification_error,
+ AvbSlotVerifyData** out_data);
+ private:
+ AvbOps avb_ops_;
+ std::string device_file_by_name_prefix_;
+};
#endif /* __CORE_FS_MGR_AVB_OPS_H */
diff --git a/fs_mgr/fs_mgr_fstab.cpp b/fs_mgr/fs_mgr_fstab.cpp
index 0406efd..dc73c24 100644
--- a/fs_mgr/fs_mgr_fstab.cpp
+++ b/fs_mgr/fs_mgr_fstab.cpp
@@ -526,7 +526,7 @@
cnt++;
}
/* If an A/B partition, modify block device to be the real block device */
- if (fs_mgr_update_for_slotselect(fstab) != 0) {
+ if (!fs_mgr_update_for_slotselect(fstab)) {
LERROR << "Error updating for slotselect";
goto err;
}
@@ -768,6 +768,11 @@
return fstab->fs_mgr_flags & MF_VERIFY;
}
+int fs_mgr_is_avb(const struct fstab_rec *fstab)
+{
+ return fstab->fs_mgr_flags & MF_AVB;
+}
+
int fs_mgr_is_verifyatboot(const struct fstab_rec *fstab)
{
return fstab->fs_mgr_flags & MF_VERIFYATBOOT;
diff --git a/fs_mgr/fs_mgr_priv.h b/fs_mgr/fs_mgr_priv.h
index 377d2ec..c985462 100644
--- a/fs_mgr/fs_mgr_priv.h
+++ b/fs_mgr/fs_mgr_priv.h
@@ -41,8 +41,6 @@
#define PWARNING PLOG(WARNING) << FS_MGR_TAG
#define PERROR PLOG(ERROR) << FS_MGR_TAG
-__BEGIN_DECLS
-
#define CRYPTO_TMPFS_OPTIONS "size=256m,mode=0771,uid=1000,gid=1000"
#define WAIT_TIMEOUT 20
@@ -114,10 +112,9 @@
int fs_mgr_set_blk_ro(const char *blockdev);
int fs_mgr_test_access(const char *device);
-int fs_mgr_update_for_slotselect(struct fstab *fstab);
+bool fs_mgr_update_for_slotselect(struct fstab *fstab);
bool is_dt_compatible();
bool is_device_secure();
-
-__END_DECLS
+int load_verity_state(struct fstab_rec* fstab, int* mode);
#endif /* __CORE_FS_MGR_PRIV_H */
diff --git a/fs_mgr/fs_mgr_priv_avb.h b/fs_mgr/fs_mgr_priv_avb.h
deleted file mode 100644
index dce9f61..0000000
--- a/fs_mgr/fs_mgr_priv_avb.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (C) 2016 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.
- */
-
-#ifndef __CORE_FS_MGR_PRIV_AVB_H
-#define __CORE_FS_MGR_PRIV_AVB_H
-
-#ifndef __cplusplus
-#include <stdbool.h>
-#endif
-
-#include "fs_mgr.h"
-
-__BEGIN_DECLS
-
-#define FS_MGR_SETUP_AVB_HASHTREE_DISABLED (-2)
-#define FS_MGR_SETUP_AVB_FAIL (-1)
-#define FS_MGR_SETUP_AVB_SUCCESS 0
-
-bool fs_mgr_is_avb_used();
-
-/* Gets AVB metadata through external/avb/libavb for all partitions:
- * AvbSlotVerifyData.vbmeta_images[] and checks their integrity
- * against the androidboot.vbmeta.{hash_alg, size, digest} values
- * from /proc/cmdline.
- *
- * Return values:
- * - FS_MGR_SETUP_AVB_SUCCESS: the metadata cab be trusted.
- * - FS_MGR_SETUP_AVB_FAIL: any error when reading and verifying the
- * metadata, e.g. I/O error, digest value mismatch, size mismatch.
- * - FS_MGR_SETUP_AVB_HASHTREE_DISABLED: to support the existing
- * 'adb disable-verity' feature in Android. It's very helpful for
- * developers to make the filesystem writable to allow replacing
- * binaries on the device.
- */
-int fs_mgr_load_vbmeta_images(struct fstab* fstab);
-
-void fs_mgr_unload_vbmeta_images();
-
-int fs_mgr_setup_avb(struct fstab_rec* fstab_entry);
-
-__END_DECLS
-
-#endif /* __CORE_FS_MGR_PRIV_AVB_H */
diff --git a/fs_mgr/fs_mgr_priv_sha.h b/fs_mgr/fs_mgr_priv_sha.h
index 882411b..5b53eea 100644
--- a/fs_mgr/fs_mgr_priv_sha.h
+++ b/fs_mgr/fs_mgr_priv_sha.h
@@ -20,16 +20,18 @@
#include <openssl/sha.h>
class SHA256Hasher {
- private:
+ private:
SHA256_CTX sha256_ctx;
uint8_t hash[SHA256_DIGEST_LENGTH];
- public:
+ public:
enum { DIGEST_SIZE = SHA256_DIGEST_LENGTH };
SHA256Hasher() { SHA256_Init(&sha256_ctx); }
- void update(const void* data, size_t data_size) { SHA256_Update(&sha256_ctx, data, data_size); }
+ void update(const uint8_t* data, size_t data_size) {
+ SHA256_Update(&sha256_ctx, data, data_size);
+ }
const uint8_t* finalize() {
SHA256_Final(hash, &sha256_ctx);
@@ -38,11 +40,11 @@
};
class SHA512Hasher {
- private:
+ private:
SHA512_CTX sha512_ctx;
uint8_t hash[SHA512_DIGEST_LENGTH];
- public:
+ public:
enum { DIGEST_SIZE = SHA512_DIGEST_LENGTH };
SHA512Hasher() { SHA512_Init(&sha512_ctx); }
diff --git a/fs_mgr/fs_mgr_slotselect.cpp b/fs_mgr/fs_mgr_slotselect.cpp
index 7a45473..9ca15e2 100644
--- a/fs_mgr/fs_mgr_slotselect.cpp
+++ b/fs_mgr/fs_mgr_slotselect.cpp
@@ -16,37 +16,47 @@
#include <stdio.h>
+#include <string>
+
#include "fs_mgr.h"
#include "fs_mgr_priv.h"
-// Updates |fstab| for slot_suffix. Returns 0 on success, -1 on error.
-int fs_mgr_update_for_slotselect(struct fstab *fstab)
-{
+// Returns "_a" or "_b" based on two possible values in kernel cmdline:
+// - androidboot.slot = a or b OR
+// - androidboot.slot_suffix = _a or _b
+// TODO: remove slot_suffix once it's deprecated.
+std::string fs_mgr_get_slot_suffix() {
+ std::string slot;
+ std::string ab_suffix;
+
+ if (fs_mgr_get_boot_config("slot", &slot)) {
+ ab_suffix = "_" + slot;
+ } else if (!fs_mgr_get_boot_config("slot_suffix", &ab_suffix)) {
+ ab_suffix = "";
+ }
+ return ab_suffix;
+}
+
+// Updates |fstab| for slot_suffix. Returns true on success, false on error.
+bool fs_mgr_update_for_slotselect(struct fstab *fstab) {
int n;
- int got_suffix = 0;
- std::string suffix;
+ std::string ab_suffix;
for (n = 0; n < fstab->num_entries; n++) {
if (fstab->recs[n].fs_mgr_flags & MF_SLOTSELECT) {
char *tmp;
-
- if (!got_suffix) {
- std::string slot;
- if (fs_mgr_get_boot_config("slot", &slot)) {
- suffix = "_" + slot;
- } else if (!fs_mgr_get_boot_config("slot_suffix", &suffix)) {
- // remove slot_suffix once bootloaders update to new androidboot.slot param
- return -1;
- }
+ if (ab_suffix.empty()) {
+ ab_suffix = fs_mgr_get_slot_suffix();
+ // Returns false as non A/B devices should not have MF_SLOTSELECT.
+ if (ab_suffix.empty()) return false;
}
-
- if (asprintf(&tmp, "%s%s", fstab->recs[n].blk_device, suffix.c_str()) > 0) {
+ if (asprintf(&tmp, "%s%s", fstab->recs[n].blk_device, ab_suffix.c_str()) > 0) {
free(fstab->recs[n].blk_device);
fstab->recs[n].blk_device = tmp;
} else {
- return -1;
+ return false;
}
}
}
- return 0;
+ return true;
}
diff --git a/fs_mgr/fs_mgr_verity.cpp b/fs_mgr/fs_mgr_verity.cpp
index 8c7a8ca..0bf173b 100644
--- a/fs_mgr/fs_mgr_verity.cpp
+++ b/fs_mgr/fs_mgr_verity.cpp
@@ -653,8 +653,7 @@
offset);
}
-static int load_verity_state(struct fstab_rec *fstab, int *mode)
-{
+int load_verity_state(struct fstab_rec* fstab, int* mode) {
int match = 0;
off64_t offset = 0;
@@ -690,129 +689,6 @@
return read_verity_state(fstab->verity_loc, offset, mode);
}
-int fs_mgr_load_verity_state(int *mode)
-{
- int rc = -1;
- int i;
- int current;
- struct fstab *fstab = NULL;
-
- /* return the default mode, unless any of the verified partitions are in
- * logging mode, in which case return that */
- *mode = VERITY_MODE_DEFAULT;
-
- fstab = fs_mgr_read_fstab_default();
- if (!fstab) {
- LERROR << "Failed to read default fstab";
- goto out;
- }
-
- for (i = 0; i < fstab->num_entries; i++) {
- if (!fs_mgr_is_verified(&fstab->recs[i])) {
- continue;
- }
-
- rc = load_verity_state(&fstab->recs[i], ¤t);
- if (rc < 0) {
- continue;
- }
-
- if (current != VERITY_MODE_DEFAULT) {
- *mode = current;
- break;
- }
- }
-
- rc = 0;
-
-out:
- if (fstab) {
- fs_mgr_free_fstab(fstab);
- }
-
- return rc;
-}
-
-int fs_mgr_update_verity_state(fs_mgr_verity_state_callback callback)
-{
- alignas(dm_ioctl) char buffer[DM_BUF_SIZE];
- bool system_root = false;
- std::string mount_point;
- char propbuf[PROPERTY_VALUE_MAX];
- const char *status;
- int fd = -1;
- int i;
- int mode;
- int rc = -1;
- struct dm_ioctl *io = (struct dm_ioctl *) buffer;
- struct fstab *fstab = NULL;
-
- if (!callback) {
- return -1;
- }
-
- if (fs_mgr_load_verity_state(&mode) == -1) {
- return -1;
- }
-
- fd = TEMP_FAILURE_RETRY(open("/dev/device-mapper", O_RDWR | O_CLOEXEC));
- if (fd == -1) {
- PERROR << "Error opening device mapper";
- goto out;
- }
-
- property_get("ro.build.system_root_image", propbuf, "");
- system_root = !strcmp(propbuf, "true");
- fstab = fs_mgr_read_fstab_default();
- if (!fstab) {
- LERROR << "Failed to read default fstab";
- goto out;
- }
-
- for (i = 0; i < fstab->num_entries; i++) {
- if (!fs_mgr_is_verified(&fstab->recs[i])) {
- continue;
- }
-
- if (system_root && !strcmp(fstab->recs[i].mount_point, "/")) {
- mount_point = "system";
- } else {
- mount_point = basename(fstab->recs[i].mount_point);
- }
-
- fs_mgr_verity_ioctl_init(io, mount_point, 0);
-
- if (ioctl(fd, DM_TABLE_STATUS, io)) {
- if (fstab->recs[i].fs_mgr_flags & MF_VERIFYATBOOT) {
- status = "V";
- } else {
- PERROR << "Failed to query DM_TABLE_STATUS for "
- << mount_point.c_str();
- continue;
- }
- }
-
- status = &buffer[io->data_start + sizeof(struct dm_target_spec)];
-
- if (*status == 'C' || *status == 'V') {
- callback(&fstab->recs[i], mount_point.c_str(), mode, *status);
- }
- }
-
- rc = 0;
-
-out:
- if (fstab) {
- fs_mgr_free_fstab(fstab);
- }
-
- if (fd) {
- close(fd);
- }
-
- return rc;
-}
-
static void update_verity_table_blk_device(char *blk_device, char **table)
{
std::string result, word;
diff --git a/fs_mgr/include/fs_mgr.h b/fs_mgr/include/fs_mgr.h
index 4b626de..12db672 100644
--- a/fs_mgr/include/fs_mgr.h
+++ b/fs_mgr/include/fs_mgr.h
@@ -22,6 +22,12 @@
#include <stdbool.h>
#include <linux/dm-ioctl.h>
+// C++ only headers
+// TODO: move this into separate header files under include/fs_mgr/*.h
+#ifdef __cplusplus
+#include <string>
+#endif
+
// Magic number at start of verity metadata
#define VERITY_METADATA_MAGIC_NUMBER 0xb001b001
@@ -29,9 +35,7 @@
// turn verity off in userdebug builds.
#define VERITY_METADATA_MAGIC_DISABLE 0x46464f56 // "VOFF"
-#ifdef __cplusplus
-extern "C" {
-#endif
+__BEGIN_DECLS
// Verity modes
enum verity_mode {
@@ -109,8 +113,8 @@
int fs_mgr_unmount_all(struct fstab *fstab);
int fs_mgr_get_crypt_info(struct fstab *fstab, char *key_loc,
char *real_blk_device, int size);
-int fs_mgr_load_verity_state(int *mode);
-int fs_mgr_update_verity_state(fs_mgr_verity_state_callback callback);
+bool fs_mgr_load_verity_state(int* mode);
+bool fs_mgr_update_verity_state(fs_mgr_verity_state_callback callback);
int fs_mgr_add_entry(struct fstab *fstab,
const char *mount_point, const char *fs_type,
const char *blk_device);
@@ -119,6 +123,7 @@
int fs_mgr_is_nonremovable(const struct fstab_rec *fstab);
int fs_mgr_is_verified(const struct fstab_rec *fstab);
int fs_mgr_is_verifyatboot(const struct fstab_rec *fstab);
+int fs_mgr_is_avb(const struct fstab_rec *fstab);
int fs_mgr_is_encryptable(const struct fstab_rec *fstab);
int fs_mgr_is_file_encrypted(const struct fstab_rec *fstab);
const char* fs_mgr_get_file_encryption_mode(const struct fstab_rec *fstab);
@@ -139,8 +144,12 @@
#define FS_MGR_SETUP_VERITY_SUCCESS 0
int fs_mgr_setup_verity(struct fstab_rec *fstab, bool wait_for_verity_dev);
+__END_DECLS
+
+// C++ only functions
+// TODO: move this into separate header files under include/fs_mgr/*.h
#ifdef __cplusplus
-}
+std::string fs_mgr_get_slot_suffix();
#endif
#endif /* __CORE_FS_MGR_H */
diff --git a/fs_mgr/include/fs_mgr_avb.h b/fs_mgr/include/fs_mgr_avb.h
new file mode 100644
index 0000000..526a5ce
--- /dev/null
+++ b/fs_mgr/include/fs_mgr_avb.h
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+#ifndef __CORE_FS_MGR_AVB_H
+#define __CORE_FS_MGR_AVB_H
+
+#include <memory>
+#include <string>
+
+#include <libavb/libavb.h>
+
+#include "fs_mgr.h"
+
+enum FsManagerAvbHandleStatus {
+ kFsManagerAvbHandleSuccess = 0,
+ kFsManagerAvbHandleHashtreeDisabled = 1,
+ kFsManagerAvbHandleFail = 2,
+};
+
+class FsManagerAvbHandle;
+using FsManagerAvbUniquePtr = std::unique_ptr<FsManagerAvbHandle>;
+
+// Provides a factory method to return a unique_ptr pointing to itself and the
+// SetUpAvb() function to extract dm-verity parameters from AVB metadata to
+// load verity table into kernel through ioctl.
+class FsManagerAvbHandle {
+ public:
+ // The factory method to return a FsManagerAvbUniquePtr that holds
+ // the verified AVB (external/avb) metadata of all verified partitions
+ // in avb_slot_data_.vbmeta_images[].
+ //
+ // The metadata is checked against the following values from /proc/cmdline.
+ // - androidboot.vbmeta.{hash_alg, size, digest}.
+ //
+ // A typical usage will be:
+ // - FsManagerAvbUniquePtr handle = FsManagerAvbHandle::Open();
+ //
+ // Possible return values:
+ // - nullptr: any error when reading and verifying the metadata,
+ // e.g., I/O error, digest value mismatch, size mismatch, etc.
+ //
+ // - a valid unique_ptr with status kFsMgrAvbHandleHashtreeDisabled:
+ // to support the existing 'adb disable-verity' feature in Android.
+ // It's very helpful for developers to make the filesystem writable to
+ // allow replacing binaries on the device.
+ //
+ // - a valid unique_ptr with status kFsMgrAvbHandleSuccess: the metadata
+ // is verified and can be trusted.
+ //
+ static FsManagerAvbUniquePtr Open(const std::string& device_file_by_name_prefix);
+
+ // Sets up dm-verity on the given fstab entry.
+ // The 'wait_for_verity_dev' parameter makes this function wait for the
+ // verity device to get created before return.
+ // Returns true if the mount point is eligible to mount, it includes:
+ // - status_ is kFsMgrAvbHandleHashtreeDisabled or
+ // - status_ is kFsMgrAvbHandleSuccess and sending ioctl DM_TABLE_LOAD
+ // to load verity table is success.
+ // Otherwise, returns false.
+ bool SetUpAvb(fstab_rec* fstab_entry, bool wait_for_verity_dev);
+
+ bool AvbHashtreeDisabled() { return status_ == kFsManagerAvbHandleHashtreeDisabled; }
+
+ FsManagerAvbHandle(const FsManagerAvbHandle&) = delete; // no copy
+ FsManagerAvbHandle& operator=(const FsManagerAvbHandle&) = delete; // no assignment
+
+ FsManagerAvbHandle(FsManagerAvbHandle&&) noexcept = delete; // no move
+ FsManagerAvbHandle& operator=(FsManagerAvbHandle&&) noexcept = delete; // no move assignment
+
+ ~FsManagerAvbHandle() {
+ if (avb_slot_data_) {
+ avb_slot_verify_data_free(avb_slot_data_);
+ }
+ };
+
+ protected:
+ FsManagerAvbHandle() : avb_slot_data_(nullptr), status_(kFsManagerAvbHandleFail) {}
+
+ private:
+ AvbSlotVerifyData* avb_slot_data_;
+ FsManagerAvbHandleStatus status_;
+};
+
+#endif /* __CORE_FS_MGR_AVB_H */
diff --git a/include/backtrace b/include/backtrace
new file mode 120000
index 0000000..93ce2b1
--- /dev/null
+++ b/include/backtrace
@@ -0,0 +1 @@
+../libbacktrace/include/backtrace
\ No newline at end of file
diff --git a/include/nativebridge/native_bridge.h b/include/nativebridge/native_bridge.h
index 45266de..929b8ae 100644
--- a/include/nativebridge/native_bridge.h
+++ b/include/nativebridge/native_bridge.h
@@ -116,14 +116,25 @@
// Use NativeBridgeIsSupported() instead in non-namespace scenario.
bool NativeBridgeIsPathSupported(const char* path);
-// Initializes public and anonymous namespace at native bridge side.
+// Initializes anonymous namespace.
+// NativeBridge's peer of android_init_anonymous_namespace() of dynamic linker.
+//
+// The anonymous namespace is used in the case when a NativeBridge implementation
+// cannot identify the caller of dlopen/dlsym which happens for the code not loaded
+// by dynamic linker; for example calls from the mono-compiled code.
//
// Starting with v3, NativeBridge has two scenarios: with/without namespace.
// Should not use in non-namespace scenario.
-bool NativeBridgeInitNamespace(const char* public_ns_sonames,
- const char* anon_ns_library_path);
+bool NativeBridgeInitAnonymousNamespace(const char* public_ns_sonames,
+ const char* anon_ns_library_path);
-// Create a namespace and pass the key of related namespaces to native bridge.
+// Create new namespace in which native libraries will be loaded.
+// NativeBridge's peer of android_create_namespace() of dynamic linker.
+//
+// The libraries in the namespace are searched by folowing order:
+// 1. ld_library_path (Think of this as namespace-local LD_LIBRARY_PATH)
+// 2. In directories specified by DT_RUNPATH of the "needed by" binary.
+// 3. deault_library_path (This of this as namespace-local default library path)
//
// Starting with v3, NativeBridge has two scenarios: with/without namespace.
// Should not use in non-namespace scenario.
@@ -134,7 +145,17 @@
const char* permitted_when_isolated_path,
native_bridge_namespace_t* parent_ns);
+// Creates a link which shares some libraries from one namespace to another.
+// NativeBridge's peer of android_link_namespaces() of dynamic linker.
+//
+// Starting with v3, NativeBridge has two scenarios: with/without namespace.
+// Should not use in non-namespace scenario.
+bool NativeBridgeLinkNamespaces(native_bridge_namespace_t* from, native_bridge_namespace_t* to,
+ const char* shared_libs_sonames);
+
// Load a shared library with namespace key that is supported by the native bridge.
+// NativeBridge's peer of android_dlopen_ext() of dynamic linker, only supports namespace
+// extension.
//
// Starting with v3, NativeBridge has two scenarios: with/without namespace.
// Use NativeBridgeLoadLibrary() instead in non-namespace scenario.
@@ -152,7 +173,7 @@
// Parameters:
// runtime_cbs [IN] the pointer to NativeBridgeRuntimeCallbacks.
// Returns:
- // true iff initialization was successful.
+ // true if initialization was successful.
bool (*initialize)(const NativeBridgeRuntimeCallbacks* runtime_cbs, const char* private_dir,
const char* instruction_set);
@@ -194,10 +215,10 @@
// instruction set.
//
// Parameters:
- // instruction_set [IN] the instruction set of the app
+ // instruction_set [IN] the instruction set of the app
// Returns:
- // NULL if not supported by native bridge.
- // Otherwise, return all environment values to be set after fork.
+ // NULL if not supported by native bridge.
+ // Otherwise, return all environment values to be set after fork.
const struct NativeBridgeRuntimeValues* (*getAppEnv)(const char* instruction_set);
// Added callbacks in version 2.
@@ -206,9 +227,9 @@
// forwards- or backwards-compatible, and libnativebridge will then stop using it.
//
// Parameters:
- // bridge_version [IN] the version of libnativebridge.
+ // bridge_version [IN] the version of libnativebridge.
// Returns:
- // true iff the native bridge supports the given version of libnativebridge.
+ // true if the native bridge supports the given version of libnativebridge.
bool (*isCompatibleWith)(uint32_t bridge_version);
// A callback to retrieve a native bridge's signal handler for the specified signal. The runtime
@@ -217,12 +238,12 @@
// that will potentially lead to cycles.
//
// Parameters:
- // signal [IN] the signal for which the handler is asked for. Currently, only SIGSEGV is
+ // signal [IN] the signal for which the handler is asked for. Currently, only SIGSEGV is
// supported by the runtime.
// Returns:
- // NULL if the native bridge doesn't use a handler or doesn't want it to be managed by the
- // runtime.
- // Otherwise, a pointer to the signal handler.
+ // NULL if the native bridge doesn't use a handler or doesn't want it to be managed by the
+ // runtime.
+ // Otherwise, a pointer to the signal handler.
NativeBridgeSignalHandlerFn (*getSignalHandler)(int signal);
// Added callbacks in version 3.
@@ -231,7 +252,7 @@
// to zero then the dynamic library is unloaded.
//
// Parameters:
- // handle [IN] the handler of a dynamic library.
+ // handle [IN] the handler of a dynamic library.
//
// Returns:
// 0 on success, and nonzero on error.
@@ -257,33 +278,36 @@
// Use isSupported instead in non-namespace scenario.
bool (*isPathSupported)(const char* library_path);
- // Initializes anonymous namespace at native bridge side and pass the key of
- // two namespaces(default and anonymous) owned by dynamic linker to native bridge.
+ // Initializes anonymous namespace at native bridge side.
+ // NativeBridge's peer of android_init_anonymous_namespace() of dynamic linker.
+ //
+ // The anonymous namespace is used in the case when a NativeBridge implementation
+ // cannot identify the caller of dlopen/dlsym which happens for the code not loaded
+ // by dynamic linker; for example calls from the mono-compiled code.
//
// Parameters:
- // public_ns_sonames [IN] the name of "public" libraries.
- // anon_ns_library_path [IN] the library search path of (anonymous) namespace.
+ // public_ns_sonames [IN] the name of "public" libraries.
+ // anon_ns_library_path [IN] the library search path of (anonymous) namespace.
// Returns:
- // true if the pass is ok.
- // Otherwise, false.
+ // true if the pass is ok.
+ // Otherwise, false.
//
// Starting with v3, NativeBridge has two scenarios: with/without namespace.
// Should not use in non-namespace scenario.
- bool (*initNamespace)(const char* public_ns_sonames,
- const char* anon_ns_library_path);
+ bool (*initAnonymousNamespace)(const char* public_ns_sonames, const char* anon_ns_library_path);
-
- // Create a namespace and pass the key of releated namespaces to native bridge.
+ // Create new namespace in which native libraries will be loaded.
+ // NativeBridge's peer of android_create_namespace() of dynamic linker.
//
// Parameters:
- // name [IN] the name of the namespace.
- // ld_library_path [IN] the first set of library search paths of the namespace.
- // default_library_path [IN] the second set of library search path of the namespace.
- // type [IN] the attribute of the namespace.
- // permitted_when_isolated_path [IN] the permitted path for isolated namespace(if it is).
- // parent_ns [IN] the pointer of the parent namespace to be inherited from.
+ // name [IN] the name of the namespace.
+ // ld_library_path [IN] the first set of library search paths of the namespace.
+ // default_library_path [IN] the second set of library search path of the namespace.
+ // type [IN] the attribute of the namespace.
+ // permitted_when_isolated_path [IN] the permitted path for isolated namespace(if it is).
+ // parent_ns [IN] the pointer of the parent namespace to be inherited from.
// Returns:
- // native_bridge_namespace_t* for created namespace or nullptr in the case of error.
+ // native_bridge_namespace_t* for created namespace or nullptr in the case of error.
//
// Starting with v3, NativeBridge has two scenarios: with/without namespace.
// Should not use in non-namespace scenario.
@@ -294,7 +318,25 @@
const char* permitted_when_isolated_path,
native_bridge_namespace_t* parent_ns);
+ // Creates a link which shares some libraries from one namespace to another.
+ // NativeBridge's peer of android_link_namespaces() of dynamic linker.
+ //
+ // Parameters:
+ // from [IN] the namespace where libraries are accessed.
+ // to [IN] the namespace where libraries are loaded.
+ // shared_libs_sonames [IN] the libraries to be shared.
+ //
+ // Returns:
+ // Whether successed or not.
+ //
+ // Starting with v3, NativeBridge has two scenarios: with/without namespace.
+ // Should not use in non-namespace scenario.
+ bool (*linkNamespaces)(native_bridge_namespace_t* from, native_bridge_namespace_t* to,
+ const char* shared_libs_sonames);
+
// Load a shared library within a namespace.
+ // NativeBridge's peer of android_dlopen_ext() of dynamic linker, only supports namespace
+ // extension.
//
// Parameters:
// libpath [IN] path to the shared library
diff --git a/include/system b/include/system
new file mode 120000
index 0000000..91d45be
--- /dev/null
+++ b/include/system
@@ -0,0 +1 @@
+../libsystem/include/system/
\ No newline at end of file
diff --git a/include/ziparchive/zip_writer.h b/include/ziparchive/zip_writer.h
index 41ca2e1..08ead48 100644
--- a/include/ziparchive/zip_writer.h
+++ b/include/ziparchive/zip_writer.h
@@ -75,7 +75,8 @@
uint32_t uncompressed_size;
uint16_t last_mod_time;
uint16_t last_mod_date;
- uint32_t local_file_header_offset;
+ uint32_t padding_length;
+ off64_t local_file_header_offset;
};
static const char* ErrorCodeString(int32_t error_code);
@@ -172,6 +173,7 @@
};
FILE* file_;
+ bool seekable_;
off64_t current_offset_;
State state_;
std::vector<FileEntry> files_;
diff --git a/init/Android.mk b/init/Android.mk
index 1ca88d7..c9bf9fc 100644
--- a/init/Android.mk
+++ b/init/Android.mk
@@ -8,12 +8,16 @@
init_options += \
-DALLOW_LOCAL_PROP_OVERRIDE=1 \
-DALLOW_PERMISSIVE_SELINUX=1 \
- -DREBOOT_BOOTLOADER_ON_PANIC=1
+ -DREBOOT_BOOTLOADER_ON_PANIC=1 \
+ -DWORLD_WRITABLE_KMSG=1 \
+ -DDUMP_ON_UMOUNT_FAILURE=1
else
init_options += \
-DALLOW_LOCAL_PROP_OVERRIDE=0 \
-DALLOW_PERMISSIVE_SELINUX=0 \
- -DREBOOT_BOOTLOADER_ON_PANIC=0
+ -DREBOOT_BOOTLOADER_ON_PANIC=0 \
+ -DWORLD_WRITABLE_KMSG=0 \
+ -DDUMP_ON_UMOUNT_FAILURE=0
endif
ifneq (,$(filter eng,$(TARGET_BUILD_VARIANT)))
@@ -62,6 +66,7 @@
action.cpp \
capabilities.cpp \
descriptors.cpp \
+ devices.cpp \
import_parser.cpp \
init_parser.cpp \
log.cpp \
@@ -81,7 +86,6 @@
LOCAL_SRC_FILES:= \
bootchart.cpp \
builtins.cpp \
- devices.cpp \
init.cpp \
keychords.cpp \
property_service.cpp \
@@ -107,8 +111,8 @@
libfec_rs \
libsquashfs_utils \
liblogwrap \
- libcutils \
libext4_utils \
+ libcutils \
libbase \
libc \
libselinux \
@@ -138,13 +142,15 @@
include $(CLEAR_VARS)
LOCAL_MODULE := init_tests
LOCAL_SRC_FILES := \
+ devices_test.cpp \
init_parser_test.cpp \
property_service_test.cpp \
util_test.cpp \
LOCAL_SHARED_LIBRARIES += \
- libcutils \
libbase \
+ libcutils \
+ libselinux \
LOCAL_STATIC_LIBRARIES := libinit
LOCAL_SANITIZE := integer
diff --git a/init/action.cpp b/init/action.cpp
index 2ccf0bc..347edb0 100644
--- a/init/action.cpp
+++ b/init/action.cpp
@@ -16,16 +16,11 @@
#include "action.h"
-#include <errno.h>
-
+#include <android-base/logging.h>
#include <android-base/properties.h>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
-#include "builtins.h"
-#include "error.h"
-#include "init_parser.h"
-#include "log.h"
#include "util.h"
using android::base::Join;
diff --git a/init/bootchart.cpp b/init/bootchart.cpp
index beabea1..825603a 100644
--- a/init/bootchart.cpp
+++ b/init/bootchart.cpp
@@ -17,7 +17,6 @@
#include "bootchart.h"
#include <dirent.h>
-#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
@@ -31,9 +30,7 @@
#include <condition_variable>
#include <memory>
#include <mutex>
-#include <string>
#include <thread>
-#include <vector>
#include <android-base/file.h>
#include <android-base/logging.h>
diff --git a/init/builtins.cpp b/init/builtins.cpp
index 64c00e9..2327cdf 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -19,33 +19,28 @@
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
+#include <linux/loop.h>
+#include <linux/module.h>
#include <mntent.h>
#include <net/if.h>
-#include <signal.h>
#include <sched.h>
+#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <sys/socket.h>
#include <sys/mount.h>
#include <sys/resource.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
#include <sys/syscall.h>
+#include <sys/system_properties.h>
#include <sys/time.h>
#include <sys/types.h>
-#include <sys/stat.h>
#include <sys/wait.h>
#include <unistd.h>
-#include <linux/loop.h>
-#include <linux/module.h>
-
-#include <string>
-#include <thread>
-
-#include <selinux/android.h>
-#include <selinux/selinux.h>
-#include <selinux/label.h>
#include <android-base/file.h>
+#include <android-base/logging.h>
#include <android-base/parseint.h>
#include <android-base/properties.h>
#include <android-base/stringprintf.h>
@@ -55,14 +50,14 @@
#include <ext4_utils/ext4_crypt.h>
#include <ext4_utils/ext4_crypt_init_extensions.h>
#include <fs_mgr.h>
-#include <logwrap/logwrap.h>
+#include <selinux/android.h>
+#include <selinux/label.h>
+#include <selinux/selinux.h>
#include "action.h"
#include "bootchart.h"
-#include "devices.h"
#include "init.h"
#include "init_parser.h"
-#include "log.h"
#include "property_service.h"
#include "reboot.h"
#include "service.h"
@@ -612,7 +607,7 @@
bool runFsck = false;
bool commandInvalid = false;
- if (cmd_params.size() > 2) {
+ if (cmd_params.size() > 3) {
commandInvalid = true;
} else if (cmd_params[0] == "shutdown") {
cmd = ANDROID_RB_POWEROFF;
@@ -624,7 +619,7 @@
}
} else if (cmd_params[0] == "reboot") {
cmd = ANDROID_RB_RESTART2;
- if (cmd_params.size() == 2) {
+ if (cmd_params.size() >= 2) {
reboot_target = cmd_params[1];
// When rebooting to the bootloader notify the bootloader writing
// also the BCB.
@@ -636,6 +631,10 @@
<< err;
}
}
+ // If there is an additional bootloader parameter, pass it along
+ if (cmd_params.size() == 3) {
+ reboot_target += "," + cmd_params[2];
+ }
}
} else if (command == "thermal-shutdown") { // no additional parameter allowed
cmd = ANDROID_RB_THERMOFF;
@@ -678,11 +677,11 @@
static int do_verity_load_state(const std::vector<std::string>& args) {
int mode = -1;
- int rc = fs_mgr_load_verity_state(&mode);
- if (rc == 0 && mode != VERITY_MODE_DEFAULT) {
+ bool loaded = fs_mgr_load_verity_state(&mode);
+ if (loaded && mode != VERITY_MODE_DEFAULT) {
ActionManager::GetInstance().QueueEventTrigger("verity-logging");
}
- return rc;
+ return loaded ? 0 : 1;
}
static void verity_update_property(fstab_rec *fstab, const char *mount_point,
@@ -692,7 +691,7 @@
}
static int do_verity_update_state(const std::vector<std::string>& args) {
- return fs_mgr_update_verity_state(verity_update_property);
+ return fs_mgr_update_verity_state(verity_update_property) ? 0 : 1;
}
static int do_write(const std::vector<std::string>& args) {
diff --git a/init/descriptors.cpp b/init/descriptors.cpp
index 6e457cd..bc6bc8d 100644
--- a/init/descriptors.cpp
+++ b/init/descriptors.cpp
@@ -19,16 +19,15 @@
#include <ctype.h>
#include <fcntl.h>
#include <sys/stat.h>
-#include <sys/types.h>
#include <unistd.h>
+#include <android-base/logging.h>
#include <android-base/stringprintf.h>
#include <android-base/unique_fd.h>
#include <cutils/android_get_control_file.h>
#include <cutils/sockets.h>
#include "init.h"
-#include "log.h"
#include "util.h"
DescriptorInfo::DescriptorInfo(const std::string& name, const std::string& type, uid_t uid,
diff --git a/init/devices.cpp b/init/devices.cpp
index 405f92e..6cd3564 100644
--- a/init/devices.cpp
+++ b/init/devices.cpp
@@ -19,41 +19,41 @@
#include <fcntl.h>
#include <fnmatch.h>
#include <libgen.h>
+#include <linux/netlink.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/sendfile.h>
#include <sys/socket.h>
-#include <sys/stat.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/un.h>
#include <sys/wait.h>
#include <unistd.h>
-#include <linux/netlink.h>
-
+#include <algorithm>
#include <memory>
+#include <string>
#include <thread>
-
-#include <selinux/selinux.h>
-#include <selinux/label.h>
-#include <selinux/android.h>
-#include <selinux/avc.h>
-
-#include <private/android_filesystem_config.h>
+#include <vector>
#include <android-base/file.h>
+#include <android-base/logging.h>
#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
#include <android-base/unique_fd.h>
#include <cutils/list.h>
#include <cutils/uevent.h>
+#include <private/android_filesystem_config.h>
+#include <selinux/android.h>
+#include <selinux/avc.h>
+#include <selinux/label.h>
+#include <selinux/selinux.h>
#include "devices.h"
#include "ueventd_parser.h"
#include "util.h"
-#include "log.h"
#define SYSFS_PREFIX "/sys"
static const char *firmware_dirs[] = { "/etc/firmware",
@@ -182,9 +182,8 @@
}
}
-static mode_t get_device_perm(const char *path, const char **links,
- unsigned *uid, unsigned *gid)
-{
+static mode_t get_device_perm(const char* path, const std::vector<std::string>& links,
+ unsigned* uid, unsigned* gid) {
struct listnode *node;
struct perm_node *perm_node;
struct perms_ *dp;
@@ -193,26 +192,12 @@
* override ueventd.rc
*/
list_for_each_reverse(node, &dev_perms) {
- bool match = false;
-
perm_node = node_to_item(node, struct perm_node, plist);
dp = &perm_node->dp;
- if (perm_path_matches(path, dp)) {
- match = true;
- } else {
- if (links) {
- int i;
- for (i = 0; links[i]; i++) {
- if (perm_path_matches(links[i], dp)) {
- match = true;
- break;
- }
- }
- }
- }
-
- if (match) {
+ if (perm_path_matches(path, dp) ||
+ std::any_of(links.begin(), links.end(),
+ [dp](const auto& link) { return perm_path_matches(link.c_str(), dp); })) {
*uid = dp->uid;
*gid = dp->gid;
return dp->perm;
@@ -224,11 +209,8 @@
return 0600;
}
-static void make_device(const char *path,
- const char */*upath*/,
- int block, int major, int minor,
- const char **links)
-{
+static void make_device(const char* path, const char* /*upath*/, int block, int major, int minor,
+ const std::vector<std::string>& links) {
unsigned uid;
unsigned gid;
mode_t mode;
@@ -238,7 +220,12 @@
mode = get_device_perm(path, links, &uid, &gid) | (block ? S_IFBLK : S_IFCHR);
if (sehandle) {
- if (selabel_lookup_best_match(sehandle, &secontext, path, links, mode)) {
+ std::vector<const char*> c_links;
+ for (const auto& link : links) {
+ c_links.emplace_back(link.c_str());
+ }
+ c_links.emplace_back(nullptr);
+ if (selabel_lookup_best_match(sehandle, &secontext, path, &c_links[0], mode)) {
PLOG(ERROR) << "Device '" << path << "' not created; cannot find SELinux label";
return;
}
@@ -286,8 +273,7 @@
}
}
-static void add_platform_device(const char *path)
-{
+void add_platform_device(const char* path) {
int path_len = strlen(path);
struct platform_node *bus;
const char *name = path;
@@ -329,8 +315,7 @@
return NULL;
}
-static void remove_platform_device(const char *path)
-{
+void remove_platform_device(const char* path) {
struct listnode *node;
struct platform_node *bus;
@@ -362,60 +347,55 @@
/* Given a path that may start with a PCI device, populate the supplied buffer
* with the PCI domain/bus number and the peripheral ID and return 0.
* If it doesn't start with a PCI device, or there is some error, return -1 */
-static int find_pci_device_prefix(const char *path, char *buf, ssize_t buf_sz)
-{
- const char *start, *end;
+static bool find_pci_device_prefix(const std::string& path, std::string* result) {
+ result->clear();
- if (strncmp(path, "/devices/pci", 12))
- return -1;
+ if (!android::base::StartsWith(path, "/devices/pci")) return false;
/* Beginning of the prefix is the initial "pci" after "/devices/" */
- start = path + 9;
+ std::string::size_type start = 9;
/* End of the prefix is two path '/' later, capturing the domain/bus number
* and the peripheral ID. Example: pci0000:00/0000:00:1f.2 */
- end = strchr(start, '/');
- if (!end)
- return -1;
- end = strchr(end + 1, '/');
- if (!end)
- return -1;
+ auto end = path.find('/', start);
+ if (end == std::string::npos) return false;
- /* Make sure we have enough room for the string plus null terminator */
- if (end - start + 1 > buf_sz)
- return -1;
+ end = path.find('/', end + 1);
+ if (end == std::string::npos) return false;
- strncpy(buf, start, end - start);
- buf[end - start] = '\0';
- return 0;
+ auto length = end - start;
+ if (length <= 4) {
+ // The minimum string that will get to this check is 'pci/', which is malformed,
+ // so return false
+ return false;
+ }
+
+ *result = path.substr(start, length);
+ return true;
}
/* Given a path that may start with a virtual block device, populate
* the supplied buffer with the virtual block device ID and return 0.
* If it doesn't start with a virtual block device, or there is some
* error, return -1 */
-static int find_vbd_device_prefix(const char *path, char *buf, ssize_t buf_sz)
-{
- const char *start, *end;
+static bool find_vbd_device_prefix(const std::string& path, std::string* result) {
+ result->clear();
+
+ if (!android::base::StartsWith(path, "/devices/vbd-")) return false;
/* Beginning of the prefix is the initial "vbd-" after "/devices/" */
- if (strncmp(path, "/devices/vbd-", 13))
- return -1;
+ std::string::size_type start = 13;
/* End of the prefix is one path '/' later, capturing the
virtual block device ID. Example: 768 */
- start = path + 13;
- end = strchr(start, '/');
- if (!end)
- return -1;
+ auto end = path.find('/', start);
+ if (end == std::string::npos) return false;
- /* Make sure we have enough room for the string plus null terminator */
- if (end - start + 1 > buf_sz)
- return -1;
+ auto length = end - start;
+ if (length == 0) return false;
- strncpy(buf, start, end - start);
- buf[end - start] = '\0';
- return 0;
+ *result = path.substr(start, length);
+ return true;
}
static void parse_event(const char *msg, struct uevent *uevent)
@@ -473,118 +453,108 @@
}
}
-static char **get_character_device_symlinks(struct uevent *uevent)
-{
- const char *parent;
- const char *slash;
- char **links;
- int link_num = 0;
- int width;
- struct platform_node *pdev;
-
- pdev = find_platform_device(uevent->path);
- if (!pdev)
- return NULL;
-
- links = (char**) malloc(sizeof(char *) * 2);
- if (!links)
- return NULL;
- memset(links, 0, sizeof(char *) * 2);
+std::vector<std::string> get_character_device_symlinks(uevent* uevent) {
+ platform_node* pdev = find_platform_device(uevent->path);
+ if (!pdev) return {};
/* skip "/devices/platform/<driver>" */
- parent = strchr(uevent->path + pdev->path_len, '/');
- if (!parent)
- goto err;
+ std::string parent = std::string(uevent->path);
+ auto parent_start = parent.find('/', pdev->path_len);
+ if (parent_start == std::string::npos) return {};
- if (!strncmp(parent, "/usb", 4)) {
- /* skip root hub name and device. use device interface */
- while (*++parent && *parent != '/');
- if (*parent)
- while (*++parent && *parent != '/');
- if (!*parent)
- goto err;
- slash = strchr(++parent, '/');
- if (!slash)
- goto err;
- width = slash - parent;
- if (width <= 0)
- goto err;
+ parent.erase(0, parent_start);
- if (asprintf(&links[link_num], "/dev/usb/%s%.*s", uevent->subsystem, width, parent) > 0)
- link_num++;
- else
- links[link_num] = NULL;
- mkdir("/dev/usb", 0755);
- }
- else {
- goto err;
- }
+ if (!android::base::StartsWith(parent, "/usb")) return {};
+
+ // skip root hub name and device. use device interface
+ // skip 3 slashes, including the first / by starting the search at the 1st character, not 0th.
+ // then extract what comes between the 3rd and 4th slash
+ // e.g. "/usb/usb_device/name/tty2-1:1.0" -> "name"
+
+ std::string::size_type start = 0;
+ start = parent.find('/', start + 1);
+ if (start == std::string::npos) return {};
+
+ start = parent.find('/', start + 1);
+ if (start == std::string::npos) return {};
+
+ auto end = parent.find('/', start + 1);
+ if (end == std::string::npos) return {};
+
+ start++; // Skip the first '/'
+
+ auto length = end - start;
+ if (length == 0) return {};
+
+ auto name_string = parent.substr(start, length);
+
+ // TODO: remove std::string() when uevent->subsystem is an std::string
+ std::vector<std::string> links;
+ links.emplace_back("/dev/usb/" + std::string(uevent->subsystem) + name_string);
+
+ mkdir("/dev/usb", 0755);
return links;
-err:
- free(links);
- return NULL;
}
-static char **get_block_device_symlinks(struct uevent *uevent)
-{
- const char *device;
- struct platform_node *pdev;
- const char *slash;
- const char *type;
- char buf[256];
- char link_path[256];
- int link_num = 0;
- char *p;
+// replaces any unacceptable characters with '_', the
+// length of the resulting string is equal to the input string
+void sanitize_partition_name(std::string* string) {
+ const char* accept =
+ "abcdefghijklmnopqrstuvwxyz"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "0123456789"
+ "_-.";
+
+ if (!string) return;
+
+ std::string::size_type pos = 0;
+ while ((pos = string->find_first_not_of(accept, pos)) != std::string::npos) {
+ (*string)[pos] = '_';
+ }
+}
+
+std::vector<std::string> get_block_device_symlinks(uevent* uevent) {
+ std::string device;
+ struct platform_node* pdev;
+ std::string type;
pdev = find_platform_device(uevent->path);
if (pdev) {
device = pdev->name;
type = "platform";
- } else if (!find_pci_device_prefix(uevent->path, buf, sizeof(buf))) {
- device = buf;
+ } else if (find_pci_device_prefix(uevent->path, &device)) {
type = "pci";
- } else if (!find_vbd_device_prefix(uevent->path, buf, sizeof(buf))) {
- device = buf;
+ } else if (find_vbd_device_prefix(uevent->path, &device)) {
type = "vbd";
} else {
- return NULL;
+ return {};
}
- char **links = (char**) malloc(sizeof(char *) * 4);
- if (!links)
- return NULL;
- memset(links, 0, sizeof(char *) * 4);
+ std::vector<std::string> links;
LOG(VERBOSE) << "found " << type << " device " << device;
- snprintf(link_path, sizeof(link_path), "/dev/block/%s/%s", type, device);
+ auto link_path = "/dev/block/" + type + "/" + device;
if (uevent->partition_name) {
- p = strdup(uevent->partition_name);
- sanitize(p);
- if (strcmp(uevent->partition_name, p)) {
- LOG(VERBOSE) << "Linking partition '" << uevent->partition_name << "' as '" << p << "'";
+ std::string partition_name_sanitized(uevent->partition_name);
+ sanitize_partition_name(&partition_name_sanitized);
+ if (partition_name_sanitized != uevent->partition_name) {
+ LOG(VERBOSE) << "Linking partition '" << uevent->partition_name << "' as '"
+ << partition_name_sanitized << "'";
}
- if (asprintf(&links[link_num], "%s/by-name/%s", link_path, p) > 0)
- link_num++;
- else
- links[link_num] = NULL;
- free(p);
+ links.emplace_back(link_path + "/by-name/" + partition_name_sanitized);
}
if (uevent->partition_num >= 0) {
- if (asprintf(&links[link_num], "%s/by-num/p%d", link_path, uevent->partition_num) > 0)
- link_num++;
- else
- links[link_num] = NULL;
+ links.emplace_back(link_path + "/by-num/p" + std::to_string(uevent->partition_num));
}
- slash = strrchr(uevent->path, '/');
- if (asprintf(&links[link_num], "%s/%s", link_path, slash + 1) > 0)
- link_num++;
- else
- links[link_num] = NULL;
+ // TODO: remove uevent_path when uevent->path is an std::string
+ std::string uevent_path = uevent->path;
+ auto last_slash = uevent_path.rfind('/');
+ links.emplace_back(link_path + "/" + uevent_path.substr(last_slash + 1));
return links;
}
@@ -607,33 +577,21 @@
if (android::base::Readlink(newpath, &path) && path == oldpath) unlink(newpath);
}
-static void handle_device(const char *action, const char *devpath,
- const char *path, int block, int major, int minor, char **links)
-{
+static void handle_device(const char* action, const char* devpath, const char* path, int block,
+ int major, int minor, const std::vector<std::string>& links) {
if(!strcmp(action, "add")) {
- make_device(devpath, path, block, major, minor, (const char **)links);
- if (links) {
- for (int i = 0; links[i]; i++) {
- make_link_init(devpath, links[i]);
- }
+ make_device(devpath, path, block, major, minor, links);
+ for (const auto& link : links) {
+ make_link_init(devpath, link.c_str());
}
}
if(!strcmp(action, "remove")) {
- if (links) {
- for (int i = 0; links[i]; i++) {
- remove_link(devpath, links[i]);
- }
+ for (const auto& link : links) {
+ remove_link(devpath, link.c_str());
}
unlink(devpath);
}
-
- if (links) {
- for (int i = 0; links[i]; i++) {
- free(links[i]);
- }
- free(links);
- }
}
static void handle_platform_device_event(struct uevent *uevent)
@@ -646,95 +604,35 @@
remove_platform_device(path);
}
-static const char *parse_device_name(struct uevent *uevent, unsigned int len)
-{
- const char *name;
+static void handle_block_device_event(uevent* uevent) {
+ // if it's not a /dev device, nothing to do
+ if (uevent->major < 0 || uevent->minor < 0) return;
- /* if it's not a /dev device, nothing else to do */
- if((uevent->major < 0) || (uevent->minor < 0))
- return NULL;
-
- /* do we have a name? */
- name = strrchr(uevent->path, '/');
- if(!name)
- return NULL;
- name++;
-
- /* too-long names would overrun our buffer */
- if(strlen(name) > len) {
- LOG(ERROR) << "DEVPATH=" << name << " exceeds " << len << "-character limit on filename; ignoring event";
- return NULL;
- }
-
- return name;
-}
-
-#define DEVPATH_LEN 96
-#define MAX_DEV_NAME 64
-
-static void handle_block_device_event(struct uevent *uevent)
-{
- const char *base = "/dev/block/";
- const char *name;
- char devpath[DEVPATH_LEN];
- char **links = NULL;
-
- name = parse_device_name(uevent, MAX_DEV_NAME);
- if (!name)
- return;
-
- snprintf(devpath, sizeof(devpath), "%s%s", base, name);
+ const char* base = "/dev/block/";
make_dir(base, 0755);
+ std::string name = android::base::Basename(uevent->path);
+ std::string devpath = base + name;
+
+ std::vector<std::string> links;
if (!strncmp(uevent->path, "/devices/", 9))
links = get_block_device_symlinks(uevent);
- handle_device(uevent->action, devpath, uevent->path, 1,
- uevent->major, uevent->minor, links);
+ handle_device(uevent->action, devpath.c_str(), uevent->path, 1, uevent->major, uevent->minor,
+ links);
}
-static bool assemble_devpath(char *devpath, const char *dirname,
- const char *devname)
-{
- int s = snprintf(devpath, DEVPATH_LEN, "%s/%s", dirname, devname);
- if (s < 0) {
- PLOG(ERROR) << "failed to assemble device path; ignoring event";
- return false;
- } else if (s >= DEVPATH_LEN) {
- LOG(ERROR) << dirname << "/" << devname
- << " exceeds " << DEVPATH_LEN << "-character limit on path; ignoring event";
- return false;
- }
- return true;
-}
+static void handle_generic_device_event(uevent* uevent) {
+ // if it's not a /dev device, nothing to do
+ if (uevent->major < 0 || uevent->minor < 0) return;
-static void mkdir_recursive_for_devpath(const char *devpath)
-{
- char dir[DEVPATH_LEN];
- char *slash;
+ std::string name = android::base::Basename(uevent->path);
+ ueventd_subsystem* subsystem = ueventd_subsystem_find_by_name(uevent->subsystem);
- strcpy(dir, devpath);
- slash = strrchr(dir, '/');
- *slash = '\0';
- mkdir_recursive(dir, 0755);
-}
-
-static void handle_generic_device_event(struct uevent *uevent)
-{
- const char *base;
- const char *name;
- char devpath[DEVPATH_LEN] = {0};
- char **links = NULL;
-
- name = parse_device_name(uevent, MAX_DEV_NAME);
- if (!name)
- return;
-
- struct ueventd_subsystem *subsystem =
- ueventd_subsystem_find_by_name(uevent->subsystem);
+ std::string devpath;
if (subsystem) {
- const char *devname;
+ std::string devname;
switch (subsystem->devname_src) {
case DEVNAME_UEVENT_DEVNAME:
@@ -750,72 +648,35 @@
return;
}
- if (!assemble_devpath(devpath, subsystem->dirname, devname))
- return;
- mkdir_recursive_for_devpath(devpath);
+ // TODO: Remove std::string()
+ devpath = std::string(subsystem->dirname) + "/" + devname;
+ mkdir_recursive(android::base::Dirname(devpath), 0755);
} else if (!strncmp(uevent->subsystem, "usb", 3)) {
- if (!strcmp(uevent->subsystem, "usb")) {
+ if (!strcmp(uevent->subsystem, "usb")) {
if (uevent->device_name) {
- if (!assemble_devpath(devpath, "/dev", uevent->device_name))
- return;
- mkdir_recursive_for_devpath(devpath);
- }
- else {
- /* This imitates the file system that would be created
- * if we were using devfs instead.
- * Minors are broken up into groups of 128, starting at "001"
- */
- int bus_id = uevent->minor / 128 + 1;
- int device_id = uevent->minor % 128 + 1;
- /* build directories */
- make_dir("/dev/bus", 0755);
- make_dir("/dev/bus/usb", 0755);
- snprintf(devpath, sizeof(devpath), "/dev/bus/usb/%03d", bus_id);
- make_dir(devpath, 0755);
- snprintf(devpath, sizeof(devpath), "/dev/bus/usb/%03d/%03d", bus_id, device_id);
- }
- } else {
- /* ignore other USB events */
- return;
- }
- } else if (!strncmp(uevent->subsystem, "graphics", 8)) {
- base = "/dev/graphics/";
- make_dir(base, 0755);
- } else if (!strncmp(uevent->subsystem, "drm", 3)) {
- base = "/dev/dri/";
- make_dir(base, 0755);
- } else if (!strncmp(uevent->subsystem, "oncrpc", 6)) {
- base = "/dev/oncrpc/";
- make_dir(base, 0755);
- } else if (!strncmp(uevent->subsystem, "adsp", 4)) {
- base = "/dev/adsp/";
- make_dir(base, 0755);
- } else if (!strncmp(uevent->subsystem, "msm_camera", 10)) {
- base = "/dev/msm_camera/";
- make_dir(base, 0755);
- } else if(!strncmp(uevent->subsystem, "input", 5)) {
- base = "/dev/input/";
- make_dir(base, 0755);
- } else if(!strncmp(uevent->subsystem, "mtd", 3)) {
- base = "/dev/mtd/";
- make_dir(base, 0755);
- } else if(!strncmp(uevent->subsystem, "sound", 5)) {
- base = "/dev/snd/";
- make_dir(base, 0755);
- } else if(!strncmp(uevent->subsystem, "misc", 4) && !strncmp(name, "log_", 4)) {
- LOG(INFO) << "kernel logger is deprecated";
- base = "/dev/log/";
- make_dir(base, 0755);
- name += 4;
- } else
- base = "/dev/";
- links = get_character_device_symlinks(uevent);
+ // TODO: Remove std::string
+ devpath = "/dev/" + std::string(uevent->device_name);
+ } else {
+ // This imitates the file system that would be created
+ // if we were using devfs instead.
+ // Minors are broken up into groups of 128, starting at "001"
+ int bus_id = uevent->minor / 128 + 1;
+ int device_id = uevent->minor % 128 + 1;
+ devpath = android::base::StringPrintf("/dev/bus/usb/%03d/%03d", bus_id, device_id);
+ }
+ mkdir_recursive(android::base::Dirname(devpath), 0755);
+ } else {
+ // ignore other USB events
+ return;
+ }
+ } else {
+ devpath = "/dev/" + name;
+ }
- if (!devpath[0])
- snprintf(devpath, sizeof(devpath), "%s%s", base, name);
+ auto links = get_character_device_symlinks(uevent);
- handle_device(uevent->action, devpath, uevent->path, 0,
- uevent->major, uevent->minor, links);
+ handle_device(uevent->action, devpath.c_str(), uevent->path, 0, uevent->major, uevent->minor,
+ links);
}
static void handle_device_event(struct uevent *uevent)
diff --git a/init/devices.h b/init/devices.h
index 26a064b..f6183c9 100644
--- a/init/devices.h
+++ b/init/devices.h
@@ -17,9 +17,12 @@
#ifndef _INIT_DEVICES_H
#define _INIT_DEVICES_H
-#include <functional>
#include <sys/stat.h>
+#include <functional>
+#include <string>
+#include <vector>
+
enum coldboot_action_t {
// coldboot continues without creating the device for the uevent
COLDBOOT_CONTINUE = 0,
@@ -55,4 +58,11 @@
unsigned short wildcard);
int get_device_fd();
-#endif /* _INIT_DEVICES_H */
+// Exposed for testing
+void add_platform_device(const char* path);
+void remove_platform_device(const char* path);
+std::vector<std::string> get_character_device_symlinks(uevent* uevent);
+std::vector<std::string> get_block_device_symlinks(uevent* uevent);
+void sanitize_partition_name(std::string* string);
+
+#endif /* _INIT_DEVICES_H */
diff --git a/init/devices_test.cpp b/init/devices_test.cpp
new file mode 100644
index 0000000..5be0d88
--- /dev/null
+++ b/init/devices_test.cpp
@@ -0,0 +1,276 @@
+/*
+ * Copyright (C) 2017 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 <string>
+#include <vector>
+
+#include <android-base/scopeguard.h>
+#include <gtest/gtest.h>
+
+template <std::vector<std::string> (*Function)(uevent*)>
+void test_get_symlinks(const std::string& platform_device_name, uevent* uevent,
+ const std::vector<std::string> expected_links) {
+ add_platform_device(platform_device_name.c_str());
+ auto platform_device_remover = android::base::make_scope_guard(
+ [&platform_device_name]() { remove_platform_device(platform_device_name.c_str()); });
+
+ std::vector<std::string> result = Function(uevent);
+
+ auto expected_size = expected_links.size();
+ ASSERT_EQ(expected_size, result.size());
+ if (expected_size == 0) return;
+
+ // Explicitly iterate so the results are visible if a failure occurs
+ for (unsigned int i = 0; i < expected_size; ++i) {
+ EXPECT_EQ(expected_links[i], result[i]);
+ }
+}
+
+TEST(devices, get_character_device_symlinks_success) {
+ const char* platform_device = "/devices/platform/some_device_name";
+ uevent uevent = {
+ .path = "/devices/platform/some_device_name/usb/usb_device/name/tty2-1:1.0",
+ .subsystem = "tty",
+ };
+ std::vector<std::string> expected_result{"/dev/usb/ttyname"};
+
+ test_get_symlinks<get_character_device_symlinks>(platform_device, &uevent, expected_result);
+}
+
+TEST(devices, get_character_device_symlinks_no_pdev_match) {
+ const char* platform_device = "/devices/platform/some_device_name";
+ uevent uevent = {
+ .path = "/device/name/tty2-1:1.0", .subsystem = "tty",
+ };
+ std::vector<std::string> expected_result;
+
+ test_get_symlinks<get_character_device_symlinks>(platform_device, &uevent, expected_result);
+}
+
+TEST(devices, get_character_device_symlinks_nothing_after_platform_device) {
+ const char* platform_device = "/devices/platform/some_device_name";
+ uevent uevent = {
+ .path = "/devices/platform/some_device_name", .subsystem = "tty",
+ };
+ std::vector<std::string> expected_result;
+
+ test_get_symlinks<get_character_device_symlinks>(platform_device, &uevent, expected_result);
+}
+
+TEST(devices, get_character_device_symlinks_no_usb_found) {
+ const char* platform_device = "/devices/platform/some_device_name";
+ uevent uevent = {
+ .path = "/devices/platform/some_device_name/bad/bad/", .subsystem = "tty",
+ };
+ std::vector<std::string> expected_result;
+
+ test_get_symlinks<get_character_device_symlinks>(platform_device, &uevent, expected_result);
+}
+
+TEST(devices, get_character_device_symlinks_no_roothub) {
+ const char* platform_device = "/devices/platform/some_device_name";
+ uevent uevent = {
+ .path = "/devices/platform/some_device_name/usb/", .subsystem = "tty",
+ };
+ std::vector<std::string> expected_result;
+
+ test_get_symlinks<get_character_device_symlinks>(platform_device, &uevent, expected_result);
+}
+
+TEST(devices, get_character_device_symlinks_no_usb_device) {
+ const char* platform_device = "/devices/platform/some_device_name";
+ uevent uevent = {
+ .path = "/devices/platform/some_device_name/usb/usb_device/", .subsystem = "tty",
+ };
+ std::vector<std::string> expected_result;
+
+ test_get_symlinks<get_character_device_symlinks>(platform_device, &uevent, expected_result);
+}
+
+TEST(devices, get_character_device_symlinks_no_final_slash) {
+ const char* platform_device = "/devices/platform/some_device_name";
+ uevent uevent = {
+ .path = "/devices/platform/some_device_name/usb/usb_device/name", .subsystem = "tty",
+ };
+ std::vector<std::string> expected_result;
+
+ test_get_symlinks<get_character_device_symlinks>(platform_device, &uevent, expected_result);
+}
+
+TEST(devices, get_character_device_symlinks_no_final_name) {
+ const char* platform_device = "/devices/platform/some_device_name";
+ uevent uevent = {
+ .path = "/devices/platform/some_device_name/usb/usb_device//", .subsystem = "tty",
+ };
+ std::vector<std::string> expected_result;
+
+ test_get_symlinks<get_character_device_symlinks>(platform_device, &uevent, expected_result);
+}
+
+TEST(devices, get_block_device_symlinks_success_platform) {
+ // These are actual paths from bullhead
+ const char* platform_device = "/devices/soc.0/f9824900.sdhci";
+ uevent uevent = {
+ .path = "/devices/soc.0/f9824900.sdhci/mmc_host/mmc0/mmc0:0001/block/mmcblk0",
+ .partition_name = nullptr,
+ .partition_num = -1,
+ };
+ std::vector<std::string> expected_result{"/dev/block/platform/soc.0/f9824900.sdhci/mmcblk0"};
+
+ test_get_symlinks<get_block_device_symlinks>(platform_device, &uevent, expected_result);
+}
+
+TEST(devices, get_block_device_symlinks_success_platform_with_partition) {
+ // These are actual paths from bullhead
+ const char* platform_device = "/devices/soc.0/f9824900.sdhci";
+ uevent uevent = {
+ .path = "/devices/soc.0/f9824900.sdhci/mmc_host/mmc0/mmc0:0001/block/mmcblk0p1",
+ .partition_name = "modem",
+ .partition_num = 1,
+ };
+ std::vector<std::string> expected_result{
+ "/dev/block/platform/soc.0/f9824900.sdhci/by-name/modem",
+ "/dev/block/platform/soc.0/f9824900.sdhci/by-num/p1",
+ "/dev/block/platform/soc.0/f9824900.sdhci/mmcblk0p1",
+ };
+
+ test_get_symlinks<get_block_device_symlinks>(platform_device, &uevent, expected_result);
+}
+
+TEST(devices, get_block_device_symlinks_success_platform_with_partition_only_num) {
+ const char* platform_device = "/devices/soc.0/f9824900.sdhci";
+ uevent uevent = {
+ .path = "/devices/soc.0/f9824900.sdhci/mmc_host/mmc0/mmc0:0001/block/mmcblk0p1",
+ .partition_name = nullptr,
+ .partition_num = 1,
+ };
+ std::vector<std::string> expected_result{
+ "/dev/block/platform/soc.0/f9824900.sdhci/by-num/p1",
+ "/dev/block/platform/soc.0/f9824900.sdhci/mmcblk0p1",
+ };
+
+ test_get_symlinks<get_block_device_symlinks>(platform_device, &uevent, expected_result);
+}
+
+TEST(devices, get_block_device_symlinks_success_platform_with_partition_only_name) {
+ const char* platform_device = "/devices/soc.0/f9824900.sdhci";
+ uevent uevent = {
+ .path = "/devices/soc.0/f9824900.sdhci/mmc_host/mmc0/mmc0:0001/block/mmcblk0p1",
+ .partition_name = "modem",
+ .partition_num = -1,
+ };
+ std::vector<std::string> expected_result{
+ "/dev/block/platform/soc.0/f9824900.sdhci/by-name/modem",
+ "/dev/block/platform/soc.0/f9824900.sdhci/mmcblk0p1",
+ };
+
+ test_get_symlinks<get_block_device_symlinks>(platform_device, &uevent, expected_result);
+}
+
+TEST(devices, get_block_device_symlinks_success_pci) {
+ const char* platform_device = "/devices/do/not/match";
+ uevent uevent = {
+ .path = "/devices/pci0000:00/0000:00:1f.2/mmcblk0",
+ .partition_name = nullptr,
+ .partition_num = -1,
+ };
+ std::vector<std::string> expected_result{"/dev/block/pci/pci0000:00/0000:00:1f.2/mmcblk0"};
+
+ test_get_symlinks<get_block_device_symlinks>(platform_device, &uevent, expected_result);
+}
+
+TEST(devices, get_block_device_symlinks_pci_bad_format) {
+ const char* platform_device = "/devices/do/not/match";
+ uevent uevent = {
+ .path = "/devices/pci//mmcblk0", .partition_name = nullptr, .partition_num = -1,
+ };
+ std::vector<std::string> expected_result{};
+
+ test_get_symlinks<get_block_device_symlinks>(platform_device, &uevent, expected_result);
+}
+
+TEST(devices, get_block_device_symlinks_success_vbd) {
+ const char* platform_device = "/devices/do/not/match";
+ uevent uevent = {
+ .path = "/devices/vbd-1234/mmcblk0", .partition_name = nullptr, .partition_num = -1,
+ };
+ std::vector<std::string> expected_result{"/dev/block/vbd/1234/mmcblk0"};
+
+ test_get_symlinks<get_block_device_symlinks>(platform_device, &uevent, expected_result);
+}
+
+TEST(devices, get_block_device_symlinks_vbd_bad_format) {
+ const char* platform_device = "/devices/do/not/match";
+ uevent uevent = {
+ .path = "/devices/vbd-/mmcblk0", .partition_name = nullptr, .partition_num = -1,
+ };
+ std::vector<std::string> expected_result{};
+
+ test_get_symlinks<get_block_device_symlinks>(platform_device, &uevent, expected_result);
+}
+
+TEST(devices, get_block_device_symlinks_no_matches) {
+ const char* platform_device = "/devices/soc.0/f9824900.sdhci";
+ uevent uevent = {
+ .path = "/devices/soc.0/not_the_device/mmc_host/mmc0/mmc0:0001/block/mmcblk0p1",
+ .partition_name = nullptr,
+ .partition_num = -1,
+ };
+ std::vector<std::string> expected_result;
+
+ test_get_symlinks<get_block_device_symlinks>(platform_device, &uevent, expected_result);
+}
+
+TEST(devices, sanitize_null) {
+ sanitize_partition_name(nullptr);
+}
+
+TEST(devices, sanitize_empty) {
+ std::string empty;
+ sanitize_partition_name(&empty);
+ EXPECT_EQ(0u, empty.size());
+}
+
+TEST(devices, sanitize_allgood) {
+ std::string good =
+ "abcdefghijklmnopqrstuvwxyz"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "0123456789"
+ "_-.";
+ std::string good_copy = good;
+ sanitize_partition_name(&good);
+ EXPECT_EQ(good_copy, good);
+}
+
+TEST(devices, sanitize_somebad) {
+ std::string string = "abc!@#$%^&*()";
+ sanitize_partition_name(&string);
+ EXPECT_EQ("abc__________", string);
+}
+
+TEST(devices, sanitize_allbad) {
+ std::string string = "!@#$%^&*()";
+ sanitize_partition_name(&string);
+ EXPECT_EQ("__________", string);
+}
+
+TEST(devices, sanitize_onebad) {
+ std::string string = ")";
+ sanitize_partition_name(&string);
+ EXPECT_EQ("_", string);
+}
diff --git a/init/import_parser.cpp b/init/import_parser.cpp
index d52247b..8a2bcc2 100644
--- a/init/import_parser.cpp
+++ b/init/import_parser.cpp
@@ -16,12 +16,8 @@
#include "import_parser.h"
-#include "errno.h"
+#include <android-base/logging.h>
-#include <string>
-#include <vector>
-
-#include "log.h"
#include "util.h"
bool ImportParser::ParseSection(const std::vector<std::string>& args,
diff --git a/init/init.cpp b/init/init.cpp
index e14034f..6c09c99 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#include "init.h"
+
#include <ctype.h>
#include <dirent.h>
#include <errno.h>
@@ -42,6 +44,7 @@
#include <android-base/chrono_utils.h>
#include <android-base/file.h>
+#include <android-base/logging.h>
#include <android-base/properties.h>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
@@ -58,8 +61,8 @@
#include "bootchart.h"
#include "devices.h"
#include "fs_mgr.h"
+#include "fs_mgr_avb.h"
#include "import_parser.h"
-#include "init.h"
#include "init_parser.h"
#include "keychords.h"
#include "log.h"
@@ -480,42 +483,73 @@
}
}
-static constexpr char android_dt_dir[] = "/proc/device-tree/firmware/android";
-
-static bool is_dt_compatible() {
- std::string dt_value;
- std::string file_name = StringPrintf("%s/compatible", android_dt_dir);
-
- if (android::base::ReadFileToString(file_name, &dt_value)) {
- // trim the trailing '\0' out, otherwise the comparison
- // will produce false-negatives.
- dt_value.resize(dt_value.size() - 1);
- if (dt_value == "android,firmware") {
+/* Reads the content of device tree file into dt_value.
+ * Returns true if the read is success, false otherwise.
+ */
+static bool read_dt_file(const std::string& file_name, std::string* dt_value) {
+ if (android::base::ReadFileToString(file_name, dt_value)) {
+ if (!dt_value->empty()) {
+ dt_value->pop_back(); // Trim the trailing '\0' out.
return true;
}
}
-
return false;
}
-static bool is_dt_fstab_compatible() {
- std::string dt_value;
- std::string file_name = StringPrintf("%s/%s/compatible", android_dt_dir, "fstab");
+static const std::string kAndroidDtDir("/proc/device-tree/firmware/android/");
- if (android::base::ReadFileToString(file_name, &dt_value)) {
- dt_value.resize(dt_value.size() - 1);
- if (dt_value == "android,fstab") {
+static bool is_dt_value_expected(const std::string& dt_file_suffix,
+ const std::string& expected_value) {
+ std::string dt_value;
+ std::string file_name = kAndroidDtDir + dt_file_suffix;
+
+ if (read_dt_file(file_name, &dt_value)) {
+ if (dt_value == expected_value) {
return true;
}
}
-
return false;
}
+static inline bool is_dt_compatible() {
+ return is_dt_value_expected("compatible", "android,firmware");
+}
+
+static inline bool is_dt_fstab_compatible() {
+ return is_dt_value_expected("fstab/compatible", "android,fstab");
+}
+
+static inline bool is_dt_vbmeta_compatible() {
+ return is_dt_value_expected("vbmeta/compatible", "android,vbmeta");
+}
+
+// Gets the vbmeta config from device tree. Specifically, the 'parts' and 'by_name_prefix'.
+// /{
+// firmware {
+// android {
+// vbmeta {
+// compatible = "android,vbmeta";
+// parts = "vbmeta,boot,system,vendor"
+// by_name_prefix="/dev/block/platform/soc.0/f9824900.sdhci/by-name/"
+// };
+// };
+// };
+// }
+static bool get_vbmeta_config_from_dt(std::string* vbmeta_partitions,
+ std::string* device_file_by_name_prefix) {
+ std::string file_name = kAndroidDtDir + "vbmeta/parts";
+ if (!read_dt_file(file_name, vbmeta_partitions)) return false;
+
+ file_name = kAndroidDtDir + "vbmeta/by_name_prefix";
+ if (!read_dt_file(file_name, device_file_by_name_prefix)) return false;
+
+ return true;
+}
+
static void process_kernel_dt() {
if (!is_dt_compatible()) return;
- std::unique_ptr<DIR, int(*)(DIR*)>dir(opendir(android_dt_dir), closedir);
+ std::unique_ptr<DIR, int (*)(DIR*)> dir(opendir(kAndroidDtDir.c_str()), closedir);
if (!dir) return;
std::string dt_file;
@@ -525,7 +559,7 @@
continue;
}
- std::string file_name = StringPrintf("%s/%s", android_dt_dir, dp->d_name);
+ std::string file_name = kAndroidDtDir + dp->d_name;
android::base::ReadFileToString(file_name, &dt_file);
std::replace(dt_file.begin(), dt_file.end(), ',', '.');
@@ -716,14 +750,18 @@
return false;
}
std::string actual_plat_id;
- if (!read_first_line("/system/etc/selinux/plat_sepolicy.cil.sha256", &actual_plat_id)) {
- PLOG(INFO) << "Failed to read /system/etc/selinux/plat_sepolicy.cil.sha256";
+ if (!read_first_line("/system/etc/selinux/plat_and_mapping_sepolicy.cil.sha256",
+ &actual_plat_id)) {
+ PLOG(INFO) << "Failed to read "
+ "/system/etc/selinux/plat_and_mapping_sepolicy.cil.sha256";
return false;
}
std::string precompiled_plat_id;
- if (!read_first_line("/vendor/etc/selinux/precompiled_sepolicy.plat.sha256",
+ if (!read_first_line("/vendor/etc/selinux/precompiled_sepolicy.plat_and_mapping.sha256",
&precompiled_plat_id)) {
- PLOG(INFO) << "Failed to read /vendor/etc/selinux/precompiled_sepolicy.plat.sha256";
+ PLOG(INFO) << "Failed to read "
+ "/vendor/etc/selinux/"
+ "precompiled_sepolicy.plat_and_mapping.sha256";
return false;
}
if ((actual_plat_id.empty()) || (actual_plat_id != precompiled_plat_id)) {
@@ -795,7 +833,7 @@
"-M", "true",
// Target the highest policy language version supported by the kernel
"-c", std::to_string(max_policy_version).c_str(),
- "/vendor/etc/selinux/mapping_sepolicy.cil",
+ "/system/etc/selinux/mapping_sepolicy.cil",
"/vendor/etc/selinux/nonplat_sepolicy.cil",
"-o", compiled_sepolicy,
// We don't care about file_contexts output by the compiler
@@ -884,6 +922,9 @@
LOG(INFO) << "Running restorecon...";
restorecon("/dev");
restorecon("/dev/kmsg");
+ if constexpr (WORLD_WRITABLE_KMSG) {
+ restorecon("/dev/kmsg_debug");
+ }
restorecon("/dev/socket");
restorecon("/dev/random");
restorecon("/dev/urandom");
@@ -911,38 +952,100 @@
}
}
-static bool early_mount_one(struct fstab_rec* rec) {
- if (rec && fs_mgr_is_verified(rec)) {
- // setup verity and create the dm-XX block device
- // needed to mount this partition
- int ret = fs_mgr_setup_verity(rec, false);
- if (ret == FS_MGR_SETUP_VERITY_FAIL) {
- PLOG(ERROR) << "early_mount: Failed to setup verity for '" << rec->mount_point << "'";
+// Creates "/dev/block/dm-XX" for dm-verity by running coldboot on /sys/block/dm-XX.
+static void device_init_dm_device(const std::string& dm_device) {
+ const std::string device_name(basename(dm_device.c_str()));
+ const std::string syspath = "/sys/block/" + device_name;
+
+ device_init(syspath.c_str(), [&](uevent* uevent) -> coldboot_action_t {
+ if (uevent->device_name && device_name == uevent->device_name) {
+ LOG(VERBOSE) << "early_mount: creating dm-verity device : " << dm_device;
+ return COLDBOOT_STOP;
+ }
+ return COLDBOOT_CONTINUE;
+ });
+ device_close();
+}
+
+static bool vboot_1_0_mount_partitions(const std::vector<fstab_rec*>& fstab_recs) {
+ if (fstab_recs.empty()) return false;
+
+ for (auto rec : fstab_recs) {
+ bool need_create_dm_device = false;
+ if (fs_mgr_is_verified(rec)) {
+ // setup verity and create the dm-XX block device
+ // needed to mount this partition
+ int ret = fs_mgr_setup_verity(rec, false /* wait_for_verity_dev */);
+ if (ret == FS_MGR_SETUP_VERITY_DISABLED) {
+ LOG(INFO) << "verity disabled for '" << rec->mount_point << "'";
+ } else if (ret == FS_MGR_SETUP_VERITY_SUCCESS) {
+ need_create_dm_device = true;
+ } else {
+ PLOG(ERROR) << "early_mount: failed to setup verity for '" << rec->mount_point
+ << "'";
+ return false;
+ }
+ }
+ if (need_create_dm_device) {
+ // The exact block device name (rec->blk_device) is changed to "/dev/block/dm-XX".
+ // Need to create it because ueventd isn't started during early mount.
+ device_init_dm_device(rec->blk_device);
+ }
+ if (fs_mgr_do_mount_one(rec)) {
+ PLOG(ERROR) << "early_mount: failed to mount '" << rec->mount_point << "'";
return false;
}
-
- // The exact block device name is added as a mount source by
- // fs_mgr_setup_verity() in ->blk_device as "/dev/block/dm-XX"
- // We create that device by running coldboot on /sys/block/dm-XX
- std::string dm_device(basename(rec->blk_device));
- std::string syspath = StringPrintf("/sys/block/%s", dm_device.c_str());
- device_init(syspath.c_str(), [&](uevent* uevent) -> coldboot_action_t {
- if (uevent->device_name && !strcmp(dm_device.c_str(), uevent->device_name)) {
- LOG(VERBOSE) << "early_mount: creating dm-verity device : " << dm_device;
- return COLDBOOT_STOP;
- }
- return COLDBOOT_CONTINUE;
- });
- }
-
- if (rec && fs_mgr_do_mount_one(rec)) {
- PLOG(ERROR) << "early_mount: Failed to mount '" << rec->mount_point << "'";
- return false;
}
return true;
}
+static bool vboot_2_0_mount_partitions(const std::vector<fstab_rec*>& fstab_recs,
+ const std::string& device_file_by_name_prefix) {
+ if (fstab_recs.empty()) return false;
+
+ FsManagerAvbUniquePtr avb_handle = FsManagerAvbHandle::Open(device_file_by_name_prefix);
+ if (!avb_handle) {
+ LOG(INFO) << "Failed to Open FsManagerAvbHandle";
+ return false;
+ }
+
+ for (auto rec : fstab_recs) {
+ bool need_create_dm_device = false;
+ if (fs_mgr_is_avb(rec)) {
+ if (avb_handle->AvbHashtreeDisabled()) {
+ LOG(INFO) << "avb hashtree disabled for '" << rec->mount_point << "'";
+ } else if (avb_handle->SetUpAvb(rec, false /* wait_for_verity_dev */)) {
+ need_create_dm_device = true;
+ } else {
+ PLOG(ERROR) << "early_mount: failed to set up AVB on partition: '"
+ << rec->mount_point << "'";
+ return false;
+ }
+ }
+ if (need_create_dm_device) {
+ // The exact block device name (rec->blk_device) is changed to "/dev/block/dm-XX".
+ // Need to create it because ueventd isn't started during early mount.
+ device_init_dm_device(rec->blk_device);
+ }
+ if (fs_mgr_do_mount_one(rec)) {
+ PLOG(ERROR) << "early_mount: failed to mount '" << rec->mount_point << "'";
+ return false;
+ }
+ }
+
+ return true;
+}
+
+static bool mount_early_partitions(const std::vector<fstab_rec*>& fstab_recs,
+ const std::string& device_file_by_name_prefix) {
+ if (is_dt_vbmeta_compatible()) { // AVB (external/avb) is used to setup dm-verity.
+ return vboot_2_0_mount_partitions(fstab_recs, device_file_by_name_prefix);
+ } else {
+ return vboot_1_0_mount_partitions(fstab_recs);
+ }
+}
+
// Creates devices with uevent->partition_name matching one in the in/out
// partition_names. Note that the partition_names MUST have A/B suffix
// when A/B is used. Found partitions will then be removed from the
@@ -985,12 +1088,10 @@
});
}
-static bool get_early_partitions(const std::vector<fstab_rec*>& early_fstab_recs,
- std::set<std::string>* out_partitions, bool* out_need_verity) {
+static bool vboot_1_0_early_partitions(const std::vector<fstab_rec*>& early_fstab_recs,
+ std::set<std::string>* out_partitions,
+ bool* out_need_verity) {
std::string meta_partition;
- out_partitions->clear();
- *out_need_verity = false;
-
for (auto fstab_rec : early_fstab_recs) {
// don't allow verifyatboot for early mounted partitions
if (fs_mgr_is_verifyatboot(fstab_rec)) {
@@ -1029,6 +1130,40 @@
return true;
}
+// a.k.a. AVB (external/avb)
+static bool vboot_2_0_early_partitions(std::set<std::string>* out_partitions, bool* out_need_verity,
+ std::string* out_device_file_by_name_prefix) {
+ std::string vbmeta_partitions;
+ if (!get_vbmeta_config_from_dt(&vbmeta_partitions, out_device_file_by_name_prefix)) {
+ return false;
+ }
+ // libavb verifies AVB metadata on all verified partitions at once.
+ // e.g., The vbmeta_partitions will be "vbmeta,boot,system,vendor"
+ // for libavb to verify metadata, even if we only need to early mount /vendor.
+ std::vector<std::string> partitions = android::base::Split(vbmeta_partitions, ",");
+ std::string ab_suffix = fs_mgr_get_slot_suffix();
+ for (const auto& partition : partitions) {
+ out_partitions->emplace(partition + ab_suffix);
+ }
+ *out_need_verity = true;
+ return true;
+}
+
+static bool get_early_partitions(const std::vector<fstab_rec*>& early_fstab_recs,
+ std::set<std::string>* out_partitions, bool* out_need_verity,
+ std::string* out_device_file_by_name_prefix) {
+ *out_need_verity = false;
+ out_partitions->clear();
+ out_device_file_by_name_prefix->clear();
+
+ if (is_dt_vbmeta_compatible()) { // AVB (external/avb) is used to setup dm-verity.
+ return vboot_2_0_early_partitions(out_partitions, out_need_verity,
+ out_device_file_by_name_prefix);
+ } else {
+ return vboot_1_0_early_partitions(early_fstab_recs, out_partitions, out_need_verity);
+ }
+}
+
/* Early mount vendor and ODM partitions. The fstab is read from device-tree. */
static bool early_mount() {
// skip early mount if we're in recovery mode
@@ -1063,9 +1198,11 @@
if (early_fstab_recs.empty()) return true;
bool need_verity;
+ std::string device_file_by_name_prefix;
std::set<std::string> partition_names;
// partition_names MUST have A/B suffix when A/B is used
- if (!get_early_partitions(early_fstab_recs, &partition_names, &need_verity)) {
+ if (!get_early_partitions(early_fstab_recs, &partition_names, &need_verity,
+ &device_file_by_name_prefix)) {
return false;
}
@@ -1088,10 +1225,9 @@
[&](uevent* uevent) -> coldboot_action_t { return COLDBOOT_STOP; });
}
- for (auto fstab_rec : early_fstab_recs) {
- if (!early_mount_one(fstab_rec)) goto done;
+ if (mount_early_partitions(early_fstab_recs, device_file_by_name_prefix)) {
+ success = true;
}
- success = true;
done:
device_close();
@@ -1160,7 +1296,13 @@
setgroups(arraysize(groups), groups);
mount("sysfs", "/sys", "sysfs", 0, NULL);
mount("selinuxfs", "/sys/fs/selinux", "selinuxfs", 0, NULL);
+
mknod("/dev/kmsg", S_IFCHR | 0600, makedev(1, 11));
+
+ if constexpr (WORLD_WRITABLE_KMSG) {
+ mknod("/dev/kmsg_debug", S_IFCHR | 0622, makedev(1, 11));
+ }
+
mknod("/dev/random", S_IFCHR | 0666, makedev(1, 8));
mknod("/dev/urandom", S_IFCHR | 0666, makedev(1, 9));
diff --git a/init/init_parser.cpp b/init/init_parser.cpp
index a192862..53e670b 100644
--- a/init/init_parser.cpp
+++ b/init/init_parser.cpp
@@ -14,18 +14,17 @@
* limitations under the License.
*/
+#include "init_parser.h"
+
#include <dirent.h>
-#include <errno.h>
#include <fcntl.h>
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
+
#include "action.h"
-#include "init_parser.h"
-#include "log.h"
#include "parser.h"
#include "service.h"
-#include "util.h"
-
-#include <android-base/stringprintf.h>
Parser::Parser() {
}
diff --git a/init/init_parser.h b/init/init_parser.h
index f66ba52..6935fdf 100644
--- a/init/init_parser.h
+++ b/init/init_parser.h
@@ -18,6 +18,7 @@
#define _INIT_INIT_PARSER_H_
#include <map>
+#include <memory>
#include <string>
#include <vector>
diff --git a/init/init_parser_test.cpp b/init/init_parser_test.cpp
index 52aaa37..d8fd2ba 100644
--- a/init/init_parser_test.cpp
+++ b/init/init_parser_test.cpp
@@ -18,9 +18,7 @@
#include "init.h"
#include "service.h"
-#include "util.h"
-#include <errno.h>
#include <gtest/gtest.h>
#include <string>
diff --git a/init/keychords.cpp b/init/keychords.cpp
index 5801ea8..c572cee 100644
--- a/init/keychords.cpp
+++ b/init/keychords.cpp
@@ -14,19 +14,17 @@
* limitations under the License.
*/
-#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
-#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <linux/keychord.h>
#include <unistd.h>
+#include <android-base/logging.h>
#include <android-base/properties.h>
#include "init.h"
-#include "log.h"
#include "service.h"
static struct input_keychord *keychords = 0;
diff --git a/init/log.cpp b/init/log.cpp
index 6b32526..ee6489b 100644
--- a/init/log.cpp
+++ b/init/log.cpp
@@ -17,9 +17,10 @@
#include "log.h"
#include <fcntl.h>
+#include <linux/audit.h>
#include <string.h>
-#include <linux/audit.h>
+#include <android-base/logging.h>
#include <netlink/netlink.h>
#include <selinux/selinux.h>
diff --git a/init/log.h b/init/log.h
index 8fa6d74..29a27af 100644
--- a/init/log.h
+++ b/init/log.h
@@ -17,7 +17,7 @@
#ifndef _INIT_LOG_H_
#define _INIT_LOG_H_
-#include <android-base/logging.h>
+#include <sys/cdefs.h>
void InitKernelLogging(char* argv[]);
diff --git a/init/parser.cpp b/init/parser.cpp
index 45862b7..5953a88 100644
--- a/init/parser.cpp
+++ b/init/parser.cpp
@@ -4,7 +4,7 @@
#include <stdio.h>
#include <string.h>
-#include "log.h"
+#include <android-base/logging.h>
void parse_error(struct parse_state *state, const char *fmt, ...)
{
diff --git a/init/property_service.cpp b/init/property_service.cpp
index a4d8b5f..2aa89ff 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -14,46 +14,45 @@
* limitations under the License.
*/
+#include "property_service.h"
+
+#include <ctype.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
#include <inttypes.h>
+#include <limits.h>
+#include <netinet/in.h>
+#include <stdarg.h>
+#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
-#include <unistd.h>
#include <string.h>
-#include <ctype.h>
-#include <fcntl.h>
-#include <stdarg.h>
-#include <dirent.h>
-#include <limits.h>
-#include <errno.h>
+#include <sys/mman.h>
#include <sys/poll.h>
-
-#include <memory>
-#include <vector>
+#include <sys/select.h>
+#include <sys/types.h>
+#include <sys/un.h>
+#include <unistd.h>
#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
#include <sys/_system_properties.h>
-#include <sys/socket.h>
-#include <sys/un.h>
-#include <sys/select.h>
-#include <sys/types.h>
-#include <netinet/in.h>
-#include <sys/mman.h>
+#include <memory>
+#include <vector>
-#include <selinux/android.h>
-#include <selinux/selinux.h>
-#include <selinux/label.h>
-
-#include <fs_mgr.h>
#include <android-base/file.h>
+#include <android-base/logging.h>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
-#include "bootimg.h"
+#include <bootimg.h>
+#include <fs_mgr.h>
+#include <selinux/android.h>
+#include <selinux/label.h>
+#include <selinux/selinux.h>
-#include "property_service.h"
#include "init.h"
#include "util.h"
-#include "log.h"
using android::base::StringPrintf;
diff --git a/init/property_service.h b/init/property_service.h
index 994da63..9a5b6f6 100644
--- a/init/property_service.h
+++ b/init/property_service.h
@@ -17,9 +17,8 @@
#ifndef _INIT_PROPERTY_H
#define _INIT_PROPERTY_H
-#include <stddef.h>
#include <sys/socket.h>
-#include <sys/system_properties.h>
+
#include <string>
struct property_audit_data {
diff --git a/init/reboot.cpp b/init/reboot.cpp
index 62e5c85..d9ebd91 100644
--- a/init/reboot.cpp
+++ b/init/reboot.cpp
@@ -13,12 +13,17 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
+#include "reboot.h"
+
#include <dirent.h>
#include <fcntl.h>
+#include <linux/fs.h>
#include <mntent.h>
+#include <selinux/selinux.h>
#include <sys/cdefs.h>
+#include <sys/ioctl.h>
#include <sys/mount.h>
-#include <sys/quota.h>
#include <sys/reboot.h>
#include <sys/stat.h>
#include <sys/syscall.h>
@@ -27,25 +32,24 @@
#include <memory>
#include <set>
-#include <string>
#include <thread>
#include <vector>
#include <android-base/file.h>
+#include <android-base/logging.h>
#include <android-base/macros.h>
#include <android-base/properties.h>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
+#include <android-base/unique_fd.h>
#include <bootloader_message/bootloader_message.h>
#include <cutils/android_reboot.h>
#include <fs_mgr.h>
#include <logwrap/logwrap.h>
+#include <private/android_filesystem_config.h>
-#include "log.h"
#include "property_service.h"
-#include "reboot.h"
#include "service.h"
-#include "util.h"
using android::base::StringPrintf;
@@ -67,39 +71,58 @@
// Utility for struct mntent
class MountEntry {
public:
- explicit MountEntry(const mntent& entry, bool isMounted = true)
+ explicit MountEntry(const mntent& entry)
: mnt_fsname_(entry.mnt_fsname),
mnt_dir_(entry.mnt_dir),
mnt_type_(entry.mnt_type),
- is_mounted_(isMounted) {}
+ mnt_opts_(entry.mnt_opts) {}
- bool IsF2Fs() const { return mnt_type_ == "f2fs"; }
+ bool Umount() {
+ int r = umount2(mnt_dir_.c_str(), 0);
+ if (r == 0) {
+ LOG(INFO) << "umounted " << mnt_fsname_ << ":" << mnt_dir_ << " opts " << mnt_opts_;
+ return true;
+ } else {
+ PLOG(WARNING) << "cannot umount " << mnt_fsname_ << ":" << mnt_dir_ << " opts "
+ << mnt_opts_;
+ return false;
+ }
+ }
- bool IsExt4() const { return mnt_type_ == "ext4"; }
-
- bool is_mounted() const { return is_mounted_; }
-
- void set_is_mounted() { is_mounted_ = false; }
-
- const std::string& mnt_fsname() const { return mnt_fsname_; }
-
- const std::string& mnt_dir() const { return mnt_dir_; }
+ void DoFsck() {
+ int st;
+ if (IsF2Fs()) {
+ const char* f2fs_argv[] = {
+ "/system/bin/fsck.f2fs", "-f", mnt_fsname_.c_str(),
+ };
+ android_fork_execvp_ext(arraysize(f2fs_argv), (char**)f2fs_argv, &st, true, LOG_KLOG,
+ true, nullptr, nullptr, 0);
+ } else if (IsExt4()) {
+ const char* ext4_argv[] = {
+ "/system/bin/e2fsck", "-f", "-y", mnt_fsname_.c_str(),
+ };
+ android_fork_execvp_ext(arraysize(ext4_argv), (char**)ext4_argv, &st, true, LOG_KLOG,
+ true, nullptr, nullptr, 0);
+ }
+ }
static bool IsBlockDevice(const struct mntent& mntent) {
return android::base::StartsWith(mntent.mnt_fsname, "/dev/block");
}
static bool IsEmulatedDevice(const struct mntent& mntent) {
- static const std::string SDCARDFS_NAME = "sdcardfs";
- return android::base::StartsWith(mntent.mnt_fsname, "/data/") &&
- SDCARDFS_NAME == mntent.mnt_type;
+ return android::base::StartsWith(mntent.mnt_fsname, "/data/");
}
private:
+ bool IsF2Fs() const { return mnt_type_ == "f2fs"; }
+
+ bool IsExt4() const { return mnt_type_ == "ext4"; }
+
std::string mnt_fsname_;
std::string mnt_dir_;
std::string mnt_type_;
- bool is_mounted_;
+ std::string mnt_opts_;
};
// Turn off backlight while we are performing power down cleanup activities.
@@ -125,50 +148,6 @@
}
}
-static void DoFsck(const MountEntry& entry) {
- static constexpr int UNMOUNT_CHECK_TIMES = 10;
-
- if (!entry.IsF2Fs() && !entry.IsExt4()) return;
-
- int count = 0;
- while (count++ < UNMOUNT_CHECK_TIMES) {
- int fd = TEMP_FAILURE_RETRY(open(entry.mnt_fsname().c_str(), O_RDONLY | O_EXCL));
- if (fd >= 0) {
- /* |entry->mnt_dir| has sucessfully been unmounted. */
- close(fd);
- break;
- } else if (errno == EBUSY) {
- // Some processes using |entry->mnt_dir| are still alive. Wait for a
- // while then retry.
- std::this_thread::sleep_for(5000ms / UNMOUNT_CHECK_TIMES);
- continue;
- } else {
- /* Cannot open the device. Give up. */
- return;
- }
- }
-
- // NB: With watchdog still running, there is no cap on the time it takes
- // to complete the fsck, from the users perspective the device graphics
- // and responses are locked-up and they may choose to hold the power
- // button in frustration if it drags out.
-
- int st;
- if (entry.IsF2Fs()) {
- const char* f2fs_argv[] = {
- "/system/bin/fsck.f2fs", "-f", entry.mnt_fsname().c_str(),
- };
- android_fork_execvp_ext(arraysize(f2fs_argv), (char**)f2fs_argv, &st, true, LOG_KLOG, true,
- nullptr, nullptr, 0);
- } else if (entry.IsExt4()) {
- const char* ext4_argv[] = {
- "/system/bin/e2fsck", "-f", "-y", entry.mnt_fsname().c_str(),
- };
- android_fork_execvp_ext(arraysize(ext4_argv), (char**)ext4_argv, &st, true, LOG_KLOG, true,
- nullptr, nullptr, 0);
- }
-}
-
static void ShutdownVold() {
const char* vdc_argv[] = {"/system/bin/vdc", "volume", "shutdown"};
int status;
@@ -202,21 +181,11 @@
abort();
}
-static void DoSync() {
- // quota sync is not done by sync call, so should be done separately.
- // quota sync is in VFS level, so do it before sync, which goes down to fs level.
- int r = quotactl(QCMD(Q_SYNC, 0), nullptr, 0 /* do not care */, 0 /* do not care */);
- if (r < 0) {
- PLOG(ERROR) << "quotactl failed";
- }
- sync();
-}
-
/* Find all read+write block devices and emulated devices in /proc/mounts
* and add them to correpsponding list.
*/
static bool FindPartitionsToUmount(std::vector<MountEntry>* blockDevPartitions,
- std::vector<MountEntry>* emulatedPartitions) {
+ std::vector<MountEntry>* emulatedPartitions, bool dump) {
std::unique_ptr<std::FILE, int (*)(std::FILE*)> fp(setmntent("/proc/mounts", "r"), endmntent);
if (fp == nullptr) {
PLOG(ERROR) << "Failed to open /proc/mounts";
@@ -224,44 +193,63 @@
}
mntent* mentry;
while ((mentry = getmntent(fp.get())) != nullptr) {
- if (MountEntry::IsBlockDevice(*mentry) && hasmntopt(mentry, "rw")) {
- blockDevPartitions->emplace_back(*mentry);
+ if (dump) {
+ LOG(INFO) << "mount entry " << mentry->mnt_fsname << ":" << mentry->mnt_dir << " opts "
+ << mentry->mnt_opts << " type " << mentry->mnt_type;
+ } else if (MountEntry::IsBlockDevice(*mentry) && hasmntopt(mentry, "rw")) {
+ blockDevPartitions->emplace(blockDevPartitions->begin(), *mentry);
} else if (MountEntry::IsEmulatedDevice(*mentry)) {
- emulatedPartitions->emplace_back(*mentry);
+ emulatedPartitions->emplace(emulatedPartitions->begin(), *mentry);
}
}
return true;
}
-static bool UmountPartitions(std::vector<MountEntry>* partitions, int maxRetry, int flags) {
- static constexpr int SLEEP_AFTER_RETRY_US = 100000;
-
- bool umountDone;
- int retryCounter = 0;
-
- while (true) {
- umountDone = true;
- for (auto& entry : *partitions) {
- if (entry.is_mounted()) {
- int r = umount2(entry.mnt_dir().c_str(), flags);
- if (r == 0) {
- entry.set_is_mounted();
- LOG(INFO) << StringPrintf("umounted %s, flags:0x%x", entry.mnt_fsname().c_str(),
- flags);
- } else {
- umountDone = false;
- PLOG(WARNING) << StringPrintf("cannot umount %s, mnt_dir %s, flags:0x%x",
- entry.mnt_fsname().c_str(),
- entry.mnt_dir().c_str(), flags);
- }
- }
- }
- if (umountDone) break;
- retryCounter++;
- if (retryCounter >= maxRetry) break;
- usleep(SLEEP_AFTER_RETRY_US);
+static void DumpUmountDebuggingInfo() {
+ int status;
+ if (!security_getenforce()) {
+ LOG(INFO) << "Run lsof";
+ const char* lsof_argv[] = {"/system/bin/lsof"};
+ android_fork_execvp_ext(arraysize(lsof_argv), (char**)lsof_argv, &status, true, LOG_KLOG,
+ true, nullptr, nullptr, 0);
}
- return umountDone;
+ FindPartitionsToUmount(nullptr, nullptr, true);
+}
+
+static UmountStat UmountPartitions(int timeoutMs) {
+ Timer t;
+ UmountStat stat = UMOUNT_STAT_TIMEOUT;
+ int retry = 0;
+ /* data partition needs all pending writes to be completed and all emulated partitions
+ * umounted.If the current waiting is not good enough, give
+ * up and leave it to e2fsck after reboot to fix it.
+ */
+ while (true) {
+ std::vector<MountEntry> block_devices;
+ std::vector<MountEntry> emulated_devices;
+ if (!FindPartitionsToUmount(&block_devices, &emulated_devices, false)) {
+ return UMOUNT_STAT_ERROR;
+ }
+ if (block_devices.size() == 0) {
+ stat = UMOUNT_STAT_SUCCESS;
+ break;
+ }
+ if ((timeoutMs < t.duration_ms()) && retry > 0) { // try umount at least once
+ stat = UMOUNT_STAT_TIMEOUT;
+ break;
+ }
+ if (emulated_devices.size() > 0 &&
+ std::all_of(emulated_devices.begin(), emulated_devices.end(),
+ [](auto& entry) { return entry.Umount(); })) {
+ sync();
+ }
+ for (auto& entry : block_devices) {
+ entry.Umount();
+ }
+ retry++;
+ std::this_thread::sleep_for(100ms);
+ }
+ return stat;
}
static void KillAllProcesses() { android::base::WriteStringToFile("i", "/proc/sysrq-trigger"); }
@@ -277,56 +265,38 @@
*/
static UmountStat TryUmountAndFsck(bool runFsck, int timeoutMs) {
Timer t;
- std::vector<MountEntry> emulatedPartitions;
- std::vector<MountEntry> blockDevRwPartitions;
+ std::vector<MountEntry> block_devices;
+ std::vector<MountEntry> emulated_devices;
TurnOffBacklight(); // this part can take time. save power.
- if (!FindPartitionsToUmount(&blockDevRwPartitions, &emulatedPartitions)) {
+ if (runFsck && !FindPartitionsToUmount(&block_devices, &emulated_devices, false)) {
return UMOUNT_STAT_ERROR;
}
- if (emulatedPartitions.size() > 0) {
- LOG(WARNING) << "emulated partitions still exist, will umount";
- /* Pending writes in emulated partitions can fail umount. After a few trials, detach
- * it so that it can be umounted when all writes are done.
- */
- if (!UmountPartitions(&emulatedPartitions, 1, 0)) {
- UmountPartitions(&emulatedPartitions, 1, MNT_DETACH);
- }
- }
- DoSync(); // emulated partition change can lead to update
- UmountStat stat = UMOUNT_STAT_SUCCESS;
- /* data partition needs all pending writes to be completed and all emulated partitions
- * umounted. If umount failed in the above step, it DETACH is requested, so umount can
- * still happen while waiting for /data. If the current waiting is not good enough, give
- * up and leave it to e2fsck after reboot to fix it.
- */
- int remainingTimeMs = timeoutMs - t.duration_ms();
- // each retry takes 100ms, and run at least once.
- int retry = std::max(remainingTimeMs / 100, 1);
- if (!UmountPartitions(&blockDevRwPartitions, retry, 0)) {
- /* Last resort, kill all and try again */
- LOG(WARNING) << "umount still failing, trying kill all";
+
+ UmountStat stat = UmountPartitions(timeoutMs - t.duration_ms());
+ if (stat != UMOUNT_STAT_SUCCESS) {
+ LOG(INFO) << "umount timeout, last resort, kill all and try";
+ if (DUMP_ON_UMOUNT_FAILURE) DumpUmountDebuggingInfo();
KillAllProcesses();
- DoSync();
- if (!UmountPartitions(&blockDevRwPartitions, 1, 0)) {
- stat = UMOUNT_STAT_TIMEOUT;
- }
- }
- // fsck part is excluded from timeout check. It only runs for user initiated shutdown
- // and should not affect reboot time.
- if (stat == UMOUNT_STAT_SUCCESS && runFsck) {
- for (auto& entry : blockDevRwPartitions) {
- DoFsck(entry);
- }
+ // even if it succeeds, still it is timeout and do not run fsck with all processes killed
+ UmountPartitions(0);
+ if (DUMP_ON_UMOUNT_FAILURE) DumpUmountDebuggingInfo();
}
+ if (stat == UMOUNT_STAT_SUCCESS && runFsck) {
+ // fsck part is excluded from timeout check. It only runs for user initiated shutdown
+ // and should not affect reboot time.
+ for (auto& entry : block_devices) {
+ entry.DoFsck();
+ }
+ }
return stat;
}
static void __attribute__((noreturn)) DoThermalOff() {
LOG(WARNING) << "Thermal system shutdown";
- DoSync();
+ sync();
RebootSystem(ANDROID_RB_THERMOFF, "");
abort();
}
@@ -336,7 +306,8 @@
Timer t;
LOG(INFO) << "Reboot start, reason: " << reason << ", rebootTarget: " << rebootTarget;
- android::base::WriteStringToFile(StringPrintf("%s\n", reason.c_str()), LAST_REBOOT_REASON_FILE);
+ android::base::WriteStringToFile(StringPrintf("%s\n", reason.c_str()), LAST_REBOOT_REASON_FILE,
+ S_IRUSR | S_IWUSR, AID_SYSTEM, AID_SYSTEM);
if (cmd == ANDROID_RB_THERMOFF) { // do not wait if it is thermal
DoThermalOff();
@@ -426,8 +397,8 @@
// minimum safety steps before restarting
// 2. kill all services except ones that are necessary for the shutdown sequence.
- ServiceManager::GetInstance().ForEachService([&kill_after_apps](Service* s) {
- if (!s->IsShutdownCritical() || kill_after_apps.count(s->name())) s->Stop();
+ ServiceManager::GetInstance().ForEachService([](Service* s) {
+ if (!s->IsShutdownCritical()) s->Stop();
});
ServiceManager::GetInstance().ReapAnyOutstandingChildren();
@@ -435,12 +406,20 @@
Service* voldService = ServiceManager::GetInstance().FindServiceByName("vold");
if (voldService != nullptr && voldService->IsRunning()) {
ShutdownVold();
+ voldService->Stop();
} else {
LOG(INFO) << "vold not running, skipping vold shutdown";
}
+ // logcat stopped here
+ ServiceManager::GetInstance().ForEachService([&kill_after_apps](Service* s) {
+ if (kill_after_apps.count(s->name())) s->Stop();
+ });
// 4. sync, try umount, and optionally run fsck for user shutdown
- DoSync();
+ sync();
UmountStat stat = TryUmountAndFsck(runFsck, shutdownTimeout * 1000 - t.duration_ms());
+ // Follow what linux shutdown is doing: one more sync with little bit delay
+ sync();
+ std::this_thread::sleep_for(100ms);
LogShutdownTime(stat, &t);
// Reboot regardless of umount status. If umount fails, fsck after reboot will fix it.
RebootSystem(cmd, rebootTarget);
diff --git a/init/reboot.h b/init/reboot.h
index 3956249..6432fa5 100644
--- a/init/reboot.h
+++ b/init/reboot.h
@@ -17,6 +17,8 @@
#ifndef _INIT_REBOOT_H
#define _INIT_REBOOT_H
+#include <string>
+
/* Reboot / shutdown the system.
* cmd ANDROID_RB_* as defined in android_reboot.h
* reason Reason string like "reboot", "userrequested"
diff --git a/init/service.cpp b/init/service.cpp
index e89de9a..4adbbf0 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -24,28 +24,23 @@
#include <sys/prctl.h>
#include <sys/resource.h>
#include <sys/stat.h>
+#include <sys/system_properties.h>
#include <sys/time.h>
-#include <sys/types.h>
#include <sys/wait.h>
#include <termios.h>
#include <unistd.h>
-#include <selinux/selinux.h>
-
-#include <android-base/chrono_utils.h>
#include <android-base/file.h>
+#include <android-base/logging.h>
#include <android-base/parseint.h>
#include <android-base/properties.h>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
+#include <processgroup/processgroup.h>
+#include <selinux/selinux.h>
#include <system/thread_defs.h>
-#include <processgroup/processgroup.h>
-
-#include "action.h"
#include "init.h"
-#include "init_parser.h"
-#include "log.h"
#include "property_service.h"
#include "util.h"
diff --git a/init/service.h b/init/service.h
index d84ce02..5e89b9f 100644
--- a/init/service.h
+++ b/init/service.h
@@ -19,14 +19,13 @@
#include <sys/types.h>
-#include <cutils/iosched_policy.h>
-
#include <memory>
#include <set>
#include <string>
#include <vector>
#include <android-base/chrono_utils.h>
+#include <cutils/iosched_policy.h>
#include "action.h"
#include "capabilities.h"
diff --git a/init/signal_handler.cpp b/init/signal_handler.cpp
index 5e3acac..4d56d84 100644
--- a/init/signal_handler.cpp
+++ b/init/signal_handler.cpp
@@ -14,22 +14,17 @@
* limitations under the License.
*/
-#include <errno.h>
-#include <fcntl.h>
#include <signal.h>
-#include <stdio.h>
+#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
-#include <sys/wait.h>
#include <unistd.h>
+#include <android-base/logging.h>
#include <android-base/stringprintf.h>
-#include "action.h"
#include "init.h"
-#include "log.h"
#include "service.h"
-#include "util.h"
static int signal_write_fd = -1;
static int signal_read_fd = -1;
diff --git a/init/ueventd.cpp b/init/ueventd.cpp
index ba53e47..ea767a8 100644
--- a/init/ueventd.cpp
+++ b/init/ueventd.cpp
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#include "ueventd.h"
+
#include <ctype.h>
#include <fcntl.h>
#include <grp.h>
@@ -24,17 +26,15 @@
#include <stdlib.h>
#include <string.h>
-#include <sys/types.h>
-
+#include <android-base/logging.h>
#include <android-base/properties.h>
#include <android-base/stringprintf.h>
#include <selinux/selinux.h>
-#include "ueventd.h"
-#include "log.h"
-#include "util.h"
#include "devices.h"
+#include "log.h"
#include "ueventd_parser.h"
+#include "util.h"
int ueventd_main(int argc, char **argv)
{
diff --git a/init/ueventd.h b/init/ueventd.h
index d12d7fe..d44d1ca 100644
--- a/init/ueventd.h
+++ b/init/ueventd.h
@@ -17,9 +17,10 @@
#ifndef _INIT_UEVENTD_H_
#define _INIT_UEVENTD_H_
-#include <cutils/list.h>
#include <sys/types.h>
+#include <cutils/list.h>
+
enum devname_src_t {
DEVNAME_UNKNOWN = 0,
DEVNAME_UEVENT_DEVNAME,
diff --git a/init/ueventd_parser.cpp b/init/ueventd_parser.cpp
index 554c1e3..510d7bb 100644
--- a/init/ueventd_parser.cpp
+++ b/init/ueventd_parser.cpp
@@ -14,18 +14,18 @@
* limitations under the License.
*/
+#include "ueventd_parser.h"
+
#include <ctype.h>
-#include <errno.h>
-#include <stdio.h>
-#include <unistd.h>
#include <stdarg.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <unistd.h>
-#include "ueventd.h"
-#include "ueventd_parser.h"
+#include <android-base/logging.h>
+
#include "parser.h"
-#include "log.h"
#include "util.h"
static list_declare(subsystem_list);
diff --git a/init/util.cpp b/init/util.cpp
index bf4109c..32ae93d 100644
--- a/init/util.cpp
+++ b/init/util.cpp
@@ -14,26 +14,21 @@
* limitations under the License.
*/
+#include "util.h"
+
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
-#include <ftw.h>
#include <pwd.h>
#include <stdarg.h>
-#include <stdlib.h>
#include <stdio.h>
+#include <stdlib.h>
#include <string.h>
+#include <sys/socket.h>
+#include <sys/un.h>
#include <time.h>
#include <unistd.h>
-#include <selinux/android.h>
-#include <selinux/label.h>
-
-#include <sys/socket.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <sys/un.h>
-
#include <thread>
#include <android-base/file.h>
@@ -42,15 +37,13 @@
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
#include <android-base/unique_fd.h>
-
#include <cutils/android_reboot.h>
-/* for ANDROID_SOCKET_* */
#include <cutils/sockets.h>
+#include <selinux/android.h>
+#include <selinux/label.h>
#include "init.h"
-#include "log.h"
#include "reboot.h"
-#include "util.h"
using android::base::boot_clock;
@@ -201,61 +194,21 @@
return success;
}
-int mkdir_recursive(const char *pathname, mode_t mode)
-{
- char buf[128];
- const char *slash;
- const char *p = pathname;
- int width;
- int ret;
- struct stat info;
-
- while ((slash = strchr(p, '/')) != NULL) {
- width = slash - pathname;
- p = slash + 1;
- if (width < 0)
- break;
- if (width == 0)
- continue;
- if ((unsigned int)width > sizeof(buf) - 1) {
- LOG(ERROR) << "path too long for mkdir_recursive";
- return -1;
- }
- memcpy(buf, pathname, width);
- buf[width] = 0;
- if (stat(buf, &info) != 0) {
- ret = make_dir(buf, mode);
- if (ret && errno != EEXIST)
- return ret;
+int mkdir_recursive(const std::string& path, mode_t mode) {
+ std::string::size_type slash = 0;
+ while ((slash = path.find('/', slash + 1)) != std::string::npos) {
+ auto directory = path.substr(0, slash);
+ struct stat info;
+ if (stat(directory.c_str(), &info) != 0) {
+ auto ret = make_dir(directory.c_str(), mode);
+ if (ret && errno != EEXIST) return ret;
}
}
- ret = make_dir(pathname, mode);
- if (ret && errno != EEXIST)
- return ret;
+ auto ret = make_dir(path.c_str(), mode);
+ if (ret && errno != EEXIST) return ret;
return 0;
}
-/*
- * replaces any unacceptable characters with '_', the
- * length of the resulting string is equal to the input string
- */
-void sanitize(char *s)
-{
- const char* accept =
- "abcdefghijklmnopqrstuvwxyz"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
- "0123456789"
- "_-.";
-
- if (!s)
- return;
-
- while (*s) {
- s += strspn(s, accept);
- if (*s) *s++ = '_';
- }
-}
-
int wait_for_file(const char* filename, std::chrono::nanoseconds timeout) {
boot_clock::time_point timeout_time = boot_clock::now() + timeout;
while (boot_clock::now() < timeout_time) {
diff --git a/init/util.h b/init/util.h
index 1034c9b..0bb9cdf 100644
--- a/init/util.h
+++ b/init/util.h
@@ -60,8 +60,7 @@
unsigned int decode_uid(const char *s);
-int mkdir_recursive(const char *pathname, mode_t mode);
-void sanitize(char *p);
+int mkdir_recursive(const std::string& pathname, mode_t mode);
int wait_for_file(const char *filename, std::chrono::nanoseconds timeout);
void import_kernel_cmdline(bool in_qemu,
const std::function<void(const std::string&, const std::string&, bool)>&);
diff --git a/init/util_test.cpp b/init/util_test.cpp
index 0c0350a..b8b409a 100644
--- a/init/util_test.cpp
+++ b/init/util_test.cpp
@@ -120,3 +120,39 @@
EXPECT_EQ(UINT_MAX, decode_uid("toot"));
EXPECT_EQ(123U, decode_uid("123"));
}
+
+TEST(util, is_dir) {
+ TemporaryDir test_dir;
+ EXPECT_TRUE(is_dir(test_dir.path));
+ TemporaryFile tf;
+ EXPECT_FALSE(is_dir(tf.path));
+}
+
+// sehandle is needed for make_dir()
+// TODO: Remove once sehandle is encapsulated
+#include <selinux/label.h>
+selabel_handle* sehandle;
+
+TEST(util, mkdir_recursive) {
+ TemporaryDir test_dir;
+ std::string path = android::base::StringPrintf("%s/three/directories/deep", test_dir.path);
+ EXPECT_EQ(0, mkdir_recursive(path, 0755));
+ std::string path1 = android::base::StringPrintf("%s/three", test_dir.path);
+ EXPECT_TRUE(is_dir(path1.c_str()));
+ std::string path2 = android::base::StringPrintf("%s/three/directories", test_dir.path);
+ EXPECT_TRUE(is_dir(path1.c_str()));
+ std::string path3 = android::base::StringPrintf("%s/three/directories/deep", test_dir.path);
+ EXPECT_TRUE(is_dir(path1.c_str()));
+}
+
+TEST(util, mkdir_recursive_extra_slashes) {
+ TemporaryDir test_dir;
+ std::string path = android::base::StringPrintf("%s/three////directories/deep//", test_dir.path);
+ EXPECT_EQ(0, mkdir_recursive(path, 0755));
+ std::string path1 = android::base::StringPrintf("%s/three", test_dir.path);
+ EXPECT_TRUE(is_dir(path1.c_str()));
+ std::string path2 = android::base::StringPrintf("%s/three/directories", test_dir.path);
+ EXPECT_TRUE(is_dir(path1.c_str()));
+ std::string path3 = android::base::StringPrintf("%s/three/directories/deep", test_dir.path);
+ EXPECT_TRUE(is_dir(path1.c_str()));
+}
diff --git a/init/watchdogd.cpp b/init/watchdogd.cpp
index b196147..21c1e5b 100644
--- a/init/watchdogd.cpp
+++ b/init/watchdogd.cpp
@@ -16,11 +16,12 @@
#include <errno.h>
#include <fcntl.h>
+#include <linux/watchdog.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
-#include <linux/watchdog.h>
+#include <android-base/logging.h>
#include "log.h"
#include "util.h"
diff --git a/libbacktrace/Android.bp b/libbacktrace/Android.bp
index 8f74a1a..7de72a8 100644
--- a/libbacktrace/Android.bp
+++ b/libbacktrace/Android.bp
@@ -55,6 +55,11 @@
"UnwindPtrace.cpp",
]
+cc_library_headers {
+ name: "libbacktrace_headers",
+ export_include_dirs: ["include"],
+}
+
cc_library {
name: "libbacktrace",
defaults: ["libbacktrace_common"],
@@ -64,6 +69,8 @@
"BacktraceMap.cpp",
],
+ export_include_dirs: ["include"],
+
target: {
darwin: {
enabled: true,
diff --git a/include/backtrace/Backtrace.h b/libbacktrace/include/backtrace/Backtrace.h
similarity index 100%
rename from include/backtrace/Backtrace.h
rename to libbacktrace/include/backtrace/Backtrace.h
diff --git a/include/backtrace/BacktraceMap.h b/libbacktrace/include/backtrace/BacktraceMap.h
similarity index 100%
rename from include/backtrace/BacktraceMap.h
rename to libbacktrace/include/backtrace/BacktraceMap.h
diff --git a/include/backtrace/backtrace_constants.h b/libbacktrace/include/backtrace/backtrace_constants.h
similarity index 100%
rename from include/backtrace/backtrace_constants.h
rename to libbacktrace/include/backtrace/backtrace_constants.h
diff --git a/libcutils/fs_config.c b/libcutils/fs_config.c
index b26827c..5fc2386 100644
--- a/libcutils/fs_config.c
+++ b/libcutils/fs_config.c
@@ -227,25 +227,24 @@
/* clang-format on */
};
+static size_t strip(const char* path, size_t len, const char suffix[]) {
+ if (len < strlen(suffix)) return len;
+ if (strncmp(path + len - strlen(suffix), suffix, strlen(suffix))) return len;
+ return len - strlen(suffix);
+}
+
static int fs_config_open(int dir, int which, const char* target_out_path) {
int fd = -1;
if (target_out_path && *target_out_path) {
/* target_out_path is the path to the directory holding content of
* system partition but as we cannot guarantee it ends with '/system'
- * or a trailing slash or not, we need to strip them off. */
+ * or with or without a trailing slash, need to strip them carefully. */
char* name = NULL;
- int target_out_path_len = strlen(target_out_path);
-
- while ((target_out_path_len > 0) &&
- (target_out_path[target_out_path_len - strlen("/")] == '/')) {
- --target_out_path_len;
- }
- if ((target_out_path_len >= (int)strlen("/system")) &&
- !strcmp(target_out_path + target_out_path_len - strlen("/system"), "/system")) {
- target_out_path_len -= strlen("/system");
- }
- if (asprintf(&name, "%.*s%s", target_out_path_len, target_out_path, conf[which][dir]) != -1) {
+ size_t len = strlen(target_out_path);
+ len = strip(target_out_path, len, "/");
+ len = strip(target_out_path, len, "/system");
+ if (asprintf(&name, "%.*s%s", (int)len, target_out_path, conf[which][dir]) != -1) {
fd = TEMP_FAILURE_RETRY(open(name, O_RDONLY | O_BINARY));
free(name);
}
diff --git a/libcutils/sched_policy.cpp b/libcutils/sched_policy.cpp
index 73ca518..a9c061e 100644
--- a/libcutils/sched_policy.cpp
+++ b/libcutils/sched_policy.cpp
@@ -262,6 +262,8 @@
*policy = SP_FOREGROUND;
} else if (!strcmp(grpBuf, "foreground")) {
*policy = SP_FOREGROUND;
+ } else if (!strcmp(grpBuf, "system-background")) {
+ *policy = SP_SYSTEM;
} else if (!strcmp(grpBuf, "background")) {
*policy = SP_BACKGROUND;
} else if (!strcmp(grpBuf, "top-app")) {
diff --git a/liblog/Android.bp b/liblog/Android.bp
index bb8c3af..e74aa82 100644
--- a/liblog/Android.bp
+++ b/liblog/Android.bp
@@ -107,14 +107,16 @@
license: "NOTICE",
}
-cc_library_headers {
- name: "liblog_vndk_headers",
- export_include_dirs: ["include_vndk"],
-}
-
ndk_library {
- name: "liblog.ndk",
+ name: "liblog",
symbol_file: "liblog.map.txt",
first_version: "9",
unversioned_until: "current",
}
+
+llndk_library {
+ name: "liblog",
+ symbol_file: "liblog.map.txt",
+ unversioned: true,
+ export_include_dirs: ["include_vndk"],
+}
diff --git a/liblog/include/log/log_event_list.h b/liblog/include/log/log_event_list.h
index 55953fc..057be5d 100644
--- a/liblog/include/log/log_event_list.h
+++ b/liblog/include/log/log_event_list.h
@@ -17,6 +17,7 @@
#ifndef _LIBS_LOG_EVENT_LIST_H
#define _LIBS_LOG_EVENT_LIST_H
+#include <errno.h>
#include <stdint.h>
#if (defined(__cplusplus) && defined(_USING_LIBCXX))
@@ -148,6 +149,7 @@
return ctx;
}
+ /* return errors or transmit status */
int status() const {
return ret;
}
@@ -209,14 +211,16 @@
}
int write(log_id_t id = LOG_ID_EVENTS) {
+ /* facilitate -EBUSY retry */
+ if ((ret == -EBUSY) || (ret > 0)) ret = 0;
int retval = android_log_write_list(ctx, id);
- if (retval < 0) ret = retval;
+ /* existing errors trump transmission errors */
+ if (!ret) ret = retval;
return ret;
}
int operator<<(log_id_t id) {
- int retval = android_log_write_list(ctx, id);
- if (retval < 0) ret = retval;
+ write(id);
android_log_destroy(&ctx);
return ret;
}
diff --git a/liblog/liblog.map.txt b/liblog/liblog.map.txt
index 599dc90..c00f2a0 100644
--- a/liblog/liblog.map.txt
+++ b/liblog/liblog.map.txt
@@ -1,6 +1,10 @@
LIBLOG {
global:
+ android_name_to_log_id; # vndk
+ android_log_id_to_name; # vndk
__android_log_assert;
+ __android_log_buf_print; # vndk
+ __android_log_buf_write; # vndk
__android_log_print;
__android_log_vprint;
__android_log_write;
@@ -8,8 +12,27 @@
*;
};
+LIBLOG_L {
+ global:
+ android_logger_clear; # vndk
+ android_logger_get_id; # vndk
+ android_logger_get_log_readable_size; # vndk
+ android_logger_get_log_version; # vndk
+ android_logger_get_log_size; # vndk
+ android_logger_list_alloc; # vndk
+ android_logger_list_alloc_time; # vndk
+ android_logger_list_free; # vndk
+ android_logger_list_open; # vndk
+ android_logger_list_read; # vndk
+ android_logger_open; # vndk
+ android_logger_set_log_size; # vndk
+};
+
LIBLOG_M {
global:
+ android_logger_get_prune_list; # vndk
+ android_logger_set_prune_list; # vndk
+ android_logger_get_statistics; # vndk
__android_log_is_loggable;
};
diff --git a/liblog/properties.c b/liblog/properties.c
index 0b0ef52..adf1900 100644
--- a/liblog/properties.c
+++ b/liblog/properties.c
@@ -95,7 +95,7 @@
/* calculate the size of our key temporary buffer */
const size_t taglen = tag ? len : 0;
/* sizeof(log_namespace) = strlen(log_namespace) + 1 */
- char key[sizeof(log_namespace) + taglen]; /* may be > PROP_NAME_MAX */
+ char key[sizeof(log_namespace) + taglen];
char* kp;
size_t i;
char c = 0;
@@ -108,7 +108,8 @@
* Where the missing tag matches all tags and becomes the
* system global default. We do not support ro.log.tag* .
*/
- static char last_tag[PROP_NAME_MAX];
+ static char* last_tag;
+ static size_t last_tag_len;
static uint32_t global_serial;
/* some compilers erroneously see uninitialized use. !not_locked */
uint32_t current_global_serial = 0;
@@ -147,25 +148,29 @@
if (taglen) {
int local_change_detected = change_detected;
if (!not_locked) {
- if (!last_tag[0] || (last_tag[0] != tag[0]) ||
- strncmp(
- last_tag + 1, tag + 1,
- (len < sizeof(last_tag)) ? (len - 1) : (sizeof(last_tag) - 1)) ||
- ((len < sizeof(last_tag)) && last_tag[len])) {
+ if (!last_tag || !last_tag[0] || (last_tag[0] != tag[0]) ||
+ strncmp(last_tag + 1, tag + 1, last_tag_len - 1)) {
/* invalidate log.tag.<tag> cache */
for (i = 0; i < (sizeof(tag_cache) / sizeof(tag_cache[0])); ++i) {
tag_cache[i].cache.pinfo = NULL;
tag_cache[i].c = '\0';
}
- last_tag[0] = '\0';
+ if (last_tag) last_tag[0] = '\0';
local_change_detected = 1;
}
- if (!last_tag[0]) {
- if (len < sizeof(last_tag)) {
+ if (!last_tag || !last_tag[0]) {
+ if (!last_tag) {
+ last_tag = calloc(1, len + 1);
+ last_tag_len = 0;
+ if (last_tag) last_tag_len = len + 1;
+ } else if (len >= last_tag_len) {
+ last_tag = realloc(last_tag, len + 1);
+ last_tag_len = 0;
+ if (last_tag) last_tag_len = len + 1;
+ }
+ if (last_tag) {
strncpy(last_tag, tag, len);
last_tag[len] = '\0';
- } else {
- strncpy(last_tag, tag, sizeof(last_tag));
}
}
}
@@ -435,7 +440,7 @@
int flag) {
struct cache_property property = { { NULL, -1 }, { 0 } };
if (flag & BOOL_DEFAULT_FLAG_PERSIST) {
- char newkey[PROP_NAME_MAX];
+ char newkey[strlen("persist.") + strlen(key) + 1];
snprintf(newkey, sizeof(newkey), "ro.%s", key);
refresh_cache_property(&property, newkey);
property.cache.pinfo = NULL;
@@ -600,8 +605,8 @@
evaluate_property_get_size
/* clang-format on */
};
- char key_persist[PROP_NAME_MAX];
- char key_ro[PROP_NAME_MAX];
+ char key_persist[strlen(global_tunable) + strlen(".security") + 1];
+ char key_ro[strlen(global_default) + strlen(".security") + 1];
struct cache2_property_size local = {
/* clang-format off */
PTHREAD_MUTEX_INITIALIZER, 0,
diff --git a/libnativebridge/native_bridge.cc b/libnativebridge/native_bridge.cc
index 83f35b1..050373a 100644
--- a/libnativebridge/native_bridge.cc
+++ b/libnativebridge/native_bridge.cc
@@ -573,11 +573,11 @@
return false;
}
-bool NativeBridgeInitNamespace(const char* public_ns_sonames,
- const char* anon_ns_library_path) {
+bool NativeBridgeInitAnonymousNamespace(const char* public_ns_sonames,
+ const char* anon_ns_library_path) {
if (NativeBridgeInitialized()) {
if (isCompatibleWith(NAMESPACE_VERSION)) {
- return callbacks->initNamespace(public_ns_sonames, anon_ns_library_path);
+ return callbacks->initAnonymousNamespace(public_ns_sonames, anon_ns_library_path);
} else {
ALOGE("not compatible with version %d, cannot init namespace", NAMESPACE_VERSION);
}
@@ -608,6 +608,19 @@
return nullptr;
}
+bool NativeBridgeLinkNamespaces(native_bridge_namespace_t* from, native_bridge_namespace_t* to,
+ const char* shared_libs_sonames) {
+ if (NativeBridgeInitialized()) {
+ if (isCompatibleWith(NAMESPACE_VERSION)) {
+ return callbacks->linkNamespaces(from, to, shared_libs_sonames);
+ } else {
+ ALOGE("not compatible with version %d, cannot init namespace", NAMESPACE_VERSION);
+ }
+ }
+
+ return false;
+}
+
void* NativeBridgeLoadLibraryExt(const char* libpath, int flag, native_bridge_namespace_t* ns) {
if (NativeBridgeInitialized()) {
if (isCompatibleWith(NAMESPACE_VERSION)) {
diff --git a/libnativebridge/tests/Android.mk b/libnativebridge/tests/Android.mk
index 4c3e862..c9468f0 100644
--- a/libnativebridge/tests/Android.mk
+++ b/libnativebridge/tests/Android.mk
@@ -24,7 +24,7 @@
NativeBridge3UnloadLibrary_test.cpp \
NativeBridge3GetError_test.cpp \
NativeBridge3IsPathSupported_test.cpp \
- NativeBridge3InitNamespace_test.cpp \
+ NativeBridge3InitAnonymousNamespace_test.cpp \
NativeBridge3CreateNamespace_test.cpp \
NativeBridge3LoadLibraryExt_test.cpp
diff --git a/libnativebridge/tests/DummyNativeBridge3.cpp b/libnativebridge/tests/DummyNativeBridge3.cpp
index 13fce85..4ef1c82 100644
--- a/libnativebridge/tests/DummyNativeBridge3.cpp
+++ b/libnativebridge/tests/DummyNativeBridge3.cpp
@@ -76,8 +76,8 @@
return true;
}
-extern "C" bool native_bridge3_initNamespace(const char* /* public_ns_sonames */,
- const char* /* anon_ns_library_path */) {
+extern "C" bool native_bridge3_initAnonymousNamespace(const char* /* public_ns_sonames */,
+ const char* /* anon_ns_library_path */) {
return true;
}
@@ -91,30 +91,34 @@
return nullptr;
}
+extern "C" bool native_bridge3_linkNamespaces(android::native_bridge_namespace_t* /* from */,
+ android::native_bridge_namespace_t* /* to */,
+ const char* /* shared_libs_soname */) {
+ return true;
+}
+
extern "C" void* native_bridge3_loadLibraryExt(const char* /* libpath */,
int /* flag */,
android::native_bridge_namespace_t* /* ns */) {
return nullptr;
}
-
-android::NativeBridgeCallbacks NativeBridgeItf {
- // v1
- .version = 3,
- .initialize = &native_bridge3_initialize,
- .loadLibrary = &native_bridge3_loadLibrary,
- .getTrampoline = &native_bridge3_getTrampoline,
- .isSupported = &native_bridge3_isSupported,
- .getAppEnv = &native_bridge3_getAppEnv,
- // v2
- .isCompatibleWith = &native_bridge3_isCompatibleWith,
- .getSignalHandler = &native_bridge3_getSignalHandler,
- // v3
- .unloadLibrary = &native_bridge3_unloadLibrary,
- .getError = &native_bridge3_getError,
- .isPathSupported = &native_bridge3_isPathSupported,
- .initNamespace = &native_bridge3_initNamespace,
- .createNamespace = &native_bridge3_createNamespace,
- .loadLibraryExt = &native_bridge3_loadLibraryExt
-};
-
+android::NativeBridgeCallbacks NativeBridgeItf{
+ // v1
+ .version = 3,
+ .initialize = &native_bridge3_initialize,
+ .loadLibrary = &native_bridge3_loadLibrary,
+ .getTrampoline = &native_bridge3_getTrampoline,
+ .isSupported = &native_bridge3_isSupported,
+ .getAppEnv = &native_bridge3_getAppEnv,
+ // v2
+ .isCompatibleWith = &native_bridge3_isCompatibleWith,
+ .getSignalHandler = &native_bridge3_getSignalHandler,
+ // v3
+ .unloadLibrary = &native_bridge3_unloadLibrary,
+ .getError = &native_bridge3_getError,
+ .isPathSupported = &native_bridge3_isPathSupported,
+ .initAnonymousNamespace = &native_bridge3_initAnonymousNamespace,
+ .createNamespace = &native_bridge3_createNamespace,
+ .linkNamespaces = &native_bridge3_linkNamespaces,
+ .loadLibraryExt = &native_bridge3_loadLibraryExt};
diff --git a/libnativebridge/tests/NativeBridge3InitAnonymousNamespace_test.cpp b/libnativebridge/tests/NativeBridge3InitAnonymousNamespace_test.cpp
new file mode 100644
index 0000000..b0d6b09
--- /dev/null
+++ b/libnativebridge/tests/NativeBridge3InitAnonymousNamespace_test.cpp
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2016 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 "NativeBridgeTest.h"
+
+namespace android {
+
+constexpr const char* kNativeBridgeLibrary3 = "libnativebridge3-dummy.so";
+
+TEST_F(NativeBridgeTest, V3_InitAnonymousNamespace) {
+ // Init
+ ASSERT_TRUE(LoadNativeBridge(kNativeBridgeLibrary3, nullptr));
+ ASSERT_TRUE(NativeBridgeAvailable());
+ ASSERT_TRUE(PreInitializeNativeBridge(".", "isa"));
+ ASSERT_TRUE(NativeBridgeAvailable());
+ ASSERT_TRUE(InitializeNativeBridge(nullptr, nullptr));
+ ASSERT_TRUE(NativeBridgeAvailable());
+
+ ASSERT_EQ(3U, NativeBridgeGetVersion());
+ ASSERT_EQ(true, NativeBridgeInitAnonymousNamespace(nullptr, nullptr));
+
+ // Clean-up code_cache
+ ASSERT_EQ(0, rmdir(kCodeCache));
+}
+
+} // namespace android
diff --git a/libnativebridge/tests/NativeBridge3InitNamespace_test.cpp b/libnativebridge/tests/NativeBridge3InitNamespace_test.cpp
deleted file mode 100644
index ae0fd2b..0000000
--- a/libnativebridge/tests/NativeBridge3InitNamespace_test.cpp
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (C) 2016 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 "NativeBridgeTest.h"
-
-namespace android {
-
-constexpr const char* kNativeBridgeLibrary3 = "libnativebridge3-dummy.so";
-
-TEST_F(NativeBridgeTest, V3_InitNamespace) {
- // Init
- ASSERT_TRUE(LoadNativeBridge(kNativeBridgeLibrary3, nullptr));
- ASSERT_TRUE(NativeBridgeAvailable());
- ASSERT_TRUE(PreInitializeNativeBridge(".", "isa"));
- ASSERT_TRUE(NativeBridgeAvailable());
- ASSERT_TRUE(InitializeNativeBridge(nullptr, nullptr));
- ASSERT_TRUE(NativeBridgeAvailable());
-
- ASSERT_EQ(3U, NativeBridgeGetVersion());
- ASSERT_EQ(true, NativeBridgeInitNamespace(nullptr, nullptr));
-
- // Clean-up code_cache
- ASSERT_EQ(0, rmdir(kCodeCache));
-}
-
-} // namespace android
diff --git a/libnativeloader/native_loader.cpp b/libnativeloader/native_loader.cpp
index 74f2f1d..f3391d1 100644
--- a/libnativeloader/native_loader.cpp
+++ b/libnativeloader/native_loader.cpp
@@ -183,6 +183,11 @@
return false;
}
+ if (!NativeBridgeLinkNamespaces(ns, nullptr, public_libraries_.c_str())) {
+ *error_msg = NativeBridgeGetError();
+ return false;
+ }
+
native_loader_ns = NativeLoaderNamespace(ns);
}
@@ -324,8 +329,8 @@
// and now initialize native bridge namespaces if necessary.
if (NativeBridgeInitialized()) {
- initialized_ = NativeBridgeInitNamespace(public_libraries_.c_str(),
- is_native_bridge ? library_path : nullptr);
+ initialized_ = NativeBridgeInitAnonymousNamespace(public_libraries_.c_str(),
+ is_native_bridge ? library_path : nullptr);
if (!initialized_) {
*error_msg = NativeBridgeGetError();
}
diff --git a/libsystem/Android.bp b/libsystem/Android.bp
new file mode 100644
index 0000000..4d076d5
--- /dev/null
+++ b/libsystem/Android.bp
@@ -0,0 +1,4 @@
+cc_library_headers {
+ name: "libsystem_headers",
+ export_include_dirs: ["include"],
+}
diff --git a/include/system/camera.h b/libsystem/include/system/camera.h
similarity index 100%
rename from include/system/camera.h
rename to libsystem/include/system/camera.h
diff --git a/include/system/graphics.h b/libsystem/include/system/graphics.h
similarity index 100%
rename from include/system/graphics.h
rename to libsystem/include/system/graphics.h
diff --git a/include/system/qemu_pipe.h b/libsystem/include/system/qemu_pipe.h
similarity index 100%
rename from include/system/qemu_pipe.h
rename to libsystem/include/system/qemu_pipe.h
diff --git a/include/system/radio.h b/libsystem/include/system/radio.h
similarity index 100%
rename from include/system/radio.h
rename to libsystem/include/system/radio.h
diff --git a/include/system/thread_defs.h b/libsystem/include/system/thread_defs.h
similarity index 100%
rename from include/system/thread_defs.h
rename to libsystem/include/system/thread_defs.h
diff --git a/include/system/window.h b/libsystem/include/system/window.h
similarity index 100%
rename from include/system/window.h
rename to libsystem/include/system/window.h
diff --git a/libunwindstack/Android.bp b/libunwindstack/Android.bp
index ee646de..e35593f 100644
--- a/libunwindstack/Android.bp
+++ b/libunwindstack/Android.bp
@@ -54,6 +54,7 @@
"ElfInterfaceArm.cpp",
"Log.cpp",
"Regs.cpp",
+ "Maps.cpp",
"Memory.cpp",
"Symbols.cpp",
],
@@ -97,6 +98,7 @@
"tests/ElfInterfaceTest.cpp",
"tests/ElfTest.cpp",
"tests/LogFake.cpp",
+ "tests/MapsTest.cpp",
"tests/MemoryFake.cpp",
"tests/MemoryFileTest.cpp",
"tests/MemoryLocalTest.cpp",
diff --git a/libunwindstack/Maps.cpp b/libunwindstack/Maps.cpp
new file mode 100644
index 0000000..b369c43
--- /dev/null
+++ b/libunwindstack/Maps.cpp
@@ -0,0 +1,196 @@
+/*
+ * Copyright (C) 2016 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 <errno.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <android-base/unique_fd.h>
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "Maps.h"
+
+MapInfo* Maps::Find(uint64_t pc) {
+ if (maps_.empty()) {
+ return nullptr;
+ }
+ size_t first = 0;
+ size_t last = maps_.size();
+ while (first < last) {
+ size_t index = (first + last) / 2;
+ MapInfo* cur = &maps_[index];
+ if (pc >= cur->start && pc < cur->end) {
+ return cur;
+ } else if (pc < cur->start) {
+ last = index;
+ } else {
+ first = index + 1;
+ }
+ }
+ return nullptr;
+}
+
+bool Maps::ParseLine(const char* line, MapInfo* map_info) {
+ char permissions[5];
+ int name_pos;
+ // Linux /proc/<pid>/maps lines:
+ // 6f000000-6f01e000 rwxp 00000000 00:0c 16389419 /system/lib/libcomposer.so
+ if (sscanf(line, "%" SCNx64 "-%" SCNx64 " %4s %" SCNx64 " %*x:%*x %*d %n", &map_info->start,
+ &map_info->end, permissions, &map_info->offset, &name_pos) != 4) {
+ return false;
+ }
+ map_info->flags = PROT_NONE;
+ if (permissions[0] == 'r') {
+ map_info->flags |= PROT_READ;
+ }
+ if (permissions[1] == 'w') {
+ map_info->flags |= PROT_WRITE;
+ }
+ if (permissions[2] == 'x') {
+ map_info->flags |= PROT_EXEC;
+ }
+
+ map_info->name = &line[name_pos];
+ size_t length = map_info->name.length() - 1;
+ if (map_info->name[length] == '\n') {
+ map_info->name.erase(length);
+ }
+ // Mark a device map in /dev/and not in /dev/ashmem/ specially.
+ if (!map_info->name.empty() && map_info->name.substr(0, 5) == "/dev/" &&
+ map_info->name.substr(5, 7) != "ashmem/") {
+ map_info->flags |= MAPS_FLAGS_DEVICE_MAP;
+ }
+
+ return true;
+}
+
+bool Maps::Parse() {
+ std::unique_ptr<FILE, decltype(&fclose)> fp(fopen(GetMapsFile().c_str(), "re"), fclose);
+ if (!fp) {
+ return false;
+ }
+
+ bool valid = true;
+ char* line = nullptr;
+ size_t line_len;
+ while (getline(&line, &line_len, fp.get()) > 0) {
+ MapInfo map_info;
+ if (!ParseLine(line, &map_info)) {
+ valid = false;
+ break;
+ }
+
+ maps_.push_back(map_info);
+ }
+ free(line);
+
+ return valid;
+}
+
+Maps::~Maps() {
+ for (auto& map : maps_) {
+ delete map.elf;
+ map.elf = nullptr;
+ }
+}
+
+bool BufferMaps::Parse() {
+ const char* start_of_line = buffer_;
+ do {
+ std::string line;
+ const char* end_of_line = strchr(start_of_line, '\n');
+ if (end_of_line == nullptr) {
+ line = start_of_line;
+ } else {
+ end_of_line++;
+ line = std::string(start_of_line, end_of_line - start_of_line);
+ }
+
+ MapInfo map_info;
+ if (!ParseLine(line.c_str(), &map_info)) {
+ return false;
+ }
+ maps_.push_back(map_info);
+
+ start_of_line = end_of_line;
+ } while (start_of_line != nullptr && *start_of_line != '\0');
+ return true;
+}
+
+const std::string RemoteMaps::GetMapsFile() const {
+ return "/proc/" + std::to_string(pid_) + "/maps";
+}
+
+bool OfflineMaps::Parse() {
+ // Format of maps information:
+ // <uint64_t> StartOffset
+ // <uint64_t> EndOffset
+ // <uint64_t> offset
+ // <uint16_t> flags
+ // <uint16_t> MapNameLength
+ // <VariableLengthValue> MapName
+ android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(file_.c_str(), O_RDONLY)));
+ if (fd == -1) {
+ return false;
+ }
+
+ std::vector<char> name;
+ while (true) {
+ MapInfo map_info;
+ ssize_t bytes = TEMP_FAILURE_RETRY(read(fd, &map_info.start, sizeof(map_info.start)));
+ if (bytes == 0) {
+ break;
+ }
+ if (bytes == -1 || bytes != sizeof(map_info.start)) {
+ return false;
+ }
+ bytes = TEMP_FAILURE_RETRY(read(fd, &map_info.end, sizeof(map_info.end)));
+ if (bytes == -1 || bytes != sizeof(map_info.end)) {
+ return false;
+ }
+ bytes = TEMP_FAILURE_RETRY(read(fd, &map_info.offset, sizeof(map_info.offset)));
+ if (bytes == -1 || bytes != sizeof(map_info.offset)) {
+ return false;
+ }
+ bytes = TEMP_FAILURE_RETRY(read(fd, &map_info.flags, sizeof(map_info.flags)));
+ if (bytes == -1 || bytes != sizeof(map_info.flags)) {
+ return false;
+ }
+ uint16_t len;
+ bytes = TEMP_FAILURE_RETRY(read(fd, &len, sizeof(len)));
+ if (bytes == -1 || bytes != sizeof(len)) {
+ return false;
+ }
+ if (len > 0) {
+ name.resize(len);
+ bytes = TEMP_FAILURE_RETRY(read(fd, name.data(), len));
+ if (bytes == -1 || bytes != len) {
+ return false;
+ }
+ map_info.name = std::string(name.data(), len);
+ }
+ maps_.push_back(map_info);
+ }
+ return true;
+}
diff --git a/libunwindstack/Maps.h b/libunwindstack/Maps.h
new file mode 100644
index 0000000..239b64a
--- /dev/null
+++ b/libunwindstack/Maps.h
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#ifndef _LIBUNWINDSTACK_MAPS_H
+#define _LIBUNWINDSTACK_MAPS_H
+
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <string>
+#include <vector>
+
+#include "Elf.h"
+#include "MapInfo.h"
+
+// Special flag to indicate a map is in /dev/. However, a map in
+// /dev/ashmem/... does not set this flag.
+static constexpr int MAPS_FLAGS_DEVICE_MAP = 0x8000;
+
+class Maps {
+ public:
+ Maps() = default;
+ virtual ~Maps();
+
+ MapInfo* Find(uint64_t pc);
+
+ bool ParseLine(const char* line, MapInfo* map_info);
+
+ virtual bool Parse();
+
+ virtual const std::string GetMapsFile() const { return ""; }
+
+ typedef std::vector<MapInfo>::iterator iterator;
+ iterator begin() { return maps_.begin(); }
+ iterator end() { return maps_.end(); }
+
+ typedef std::vector<MapInfo>::const_iterator const_iterator;
+ const_iterator begin() const { return maps_.begin(); }
+ const_iterator end() const { return maps_.end(); }
+
+ size_t Total() { return maps_.size(); }
+
+ protected:
+ std::vector<MapInfo> maps_;
+};
+
+class RemoteMaps : public Maps {
+ public:
+ RemoteMaps(pid_t pid) : pid_(pid) {}
+ virtual ~RemoteMaps() = default;
+
+ virtual const std::string GetMapsFile() const override;
+
+ private:
+ pid_t pid_;
+};
+
+class LocalMaps : public RemoteMaps {
+ public:
+ LocalMaps() : RemoteMaps(getpid()) {}
+ virtual ~LocalMaps() = default;
+};
+
+class BufferMaps : public Maps {
+ public:
+ BufferMaps(const char* buffer) : buffer_(buffer) {}
+ virtual ~BufferMaps() = default;
+
+ bool Parse() override;
+
+ private:
+ const char* buffer_;
+};
+
+class FileMaps : public Maps {
+ public:
+ FileMaps(const std::string& file) : file_(file) {}
+ virtual ~FileMaps() = default;
+
+ const std::string GetMapsFile() const override { return file_; }
+
+ protected:
+ const std::string file_;
+};
+
+class OfflineMaps : public FileMaps {
+ public:
+ OfflineMaps(const std::string& file) : FileMaps(file) {}
+ virtual ~OfflineMaps() = default;
+
+ bool Parse() override;
+};
+
+#endif // _LIBUNWINDSTACK_MAPS_H
diff --git a/libunwindstack/tests/MapsTest.cpp b/libunwindstack/tests/MapsTest.cpp
new file mode 100644
index 0000000..7eb9bae
--- /dev/null
+++ b/libunwindstack/tests/MapsTest.cpp
@@ -0,0 +1,237 @@
+/*
+ * Copyright (C) 2016 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/mman.h>
+
+#include <android-base/file.h>
+#include <android-base/test_utils.h>
+#include <gtest/gtest.h>
+
+#include "Maps.h"
+
+TEST(MapsTest, parse_permissions) {
+ BufferMaps maps(
+ "1000-2000 ---- 00000000 00:00 0\n"
+ "2000-3000 r--- 00000000 00:00 0\n"
+ "3000-4000 -w-- 00000000 00:00 0\n"
+ "4000-5000 --x- 00000000 00:00 0\n"
+ "5000-6000 rwx- 00000000 00:00 0\n");
+
+ ASSERT_TRUE(maps.Parse());
+ ASSERT_EQ(5U, maps.Total());
+ auto it = maps.begin();
+ ASSERT_EQ(PROT_NONE, it->flags);
+ ASSERT_EQ(0x1000U, it->start);
+ ASSERT_EQ(0x2000U, it->end);
+ ASSERT_EQ(0U, it->offset);
+ ASSERT_EQ("", it->name);
+ ++it;
+ ASSERT_EQ(PROT_READ, it->flags);
+ ASSERT_EQ(0x2000U, it->start);
+ ASSERT_EQ(0x3000U, it->end);
+ ASSERT_EQ(0U, it->offset);
+ ASSERT_EQ("", it->name);
+ ++it;
+ ASSERT_EQ(PROT_WRITE, it->flags);
+ ASSERT_EQ(0x3000U, it->start);
+ ASSERT_EQ(0x4000U, it->end);
+ ASSERT_EQ(0U, it->offset);
+ ASSERT_EQ("", it->name);
+ ++it;
+ ASSERT_EQ(PROT_EXEC, it->flags);
+ ASSERT_EQ(0x4000U, it->start);
+ ASSERT_EQ(0x5000U, it->end);
+ ASSERT_EQ(0U, it->offset);
+ ASSERT_EQ("", it->name);
+ ++it;
+ ASSERT_EQ(PROT_READ | PROT_WRITE | PROT_EXEC, it->flags);
+ ASSERT_EQ(0x5000U, it->start);
+ ASSERT_EQ(0x6000U, it->end);
+ ASSERT_EQ(0U, it->offset);
+ ASSERT_EQ("", it->name);
+ ++it;
+ ASSERT_EQ(it, maps.end());
+}
+
+TEST(MapsTest, parse_name) {
+ BufferMaps maps(
+ "720b29b000-720b29e000 rw-p 00000000 00:00 0\n"
+ "720b29e000-720b29f000 rw-p 00000000 00:00 0 /system/lib/fake.so\n"
+ "720b29f000-720b2a0000 rw-p 00000000 00:00 0");
+
+ ASSERT_TRUE(maps.Parse());
+ ASSERT_EQ(3U, maps.Total());
+ auto it = maps.begin();
+ ASSERT_EQ("", it->name);
+ ASSERT_EQ(0x720b29b000U, it->start);
+ ASSERT_EQ(0x720b29e000U, it->end);
+ ASSERT_EQ(0U, it->offset);
+ ASSERT_EQ(PROT_READ | PROT_WRITE, it->flags);
+ ++it;
+ ASSERT_EQ("/system/lib/fake.so", it->name);
+ ASSERT_EQ(0x720b29e000U, it->start);
+ ASSERT_EQ(0x720b29f000U, it->end);
+ ASSERT_EQ(0U, it->offset);
+ ASSERT_EQ(PROT_READ | PROT_WRITE, it->flags);
+ ++it;
+ ASSERT_EQ("", it->name);
+ ASSERT_EQ(0x720b29f000U, it->start);
+ ASSERT_EQ(0x720b2a0000U, it->end);
+ ASSERT_EQ(0U, it->offset);
+ ASSERT_EQ(PROT_READ | PROT_WRITE, it->flags);
+ ++it;
+ ASSERT_EQ(it, maps.end());
+}
+
+TEST(MapsTest, parse_offset) {
+ BufferMaps maps(
+ "a000-e000 rw-p 00000000 00:00 0 /system/lib/fake.so\n"
+ "e000-f000 rw-p 00a12345 00:00 0 /system/lib/fake.so\n");
+
+ ASSERT_TRUE(maps.Parse());
+ ASSERT_EQ(2U, maps.Total());
+ auto it = maps.begin();
+ ASSERT_EQ(0U, it->offset);
+ ASSERT_EQ(0xa000U, it->start);
+ ASSERT_EQ(0xe000U, it->end);
+ ASSERT_EQ(PROT_READ | PROT_WRITE, it->flags);
+ ASSERT_EQ("/system/lib/fake.so", it->name);
+ ++it;
+ ASSERT_EQ(0xa12345U, it->offset);
+ ASSERT_EQ(0xe000U, it->start);
+ ASSERT_EQ(0xf000U, it->end);
+ ASSERT_EQ(PROT_READ | PROT_WRITE, it->flags);
+ ASSERT_EQ("/system/lib/fake.so", it->name);
+ ++it;
+ ASSERT_EQ(maps.end(), it);
+}
+
+TEST(MapsTest, device) {
+ BufferMaps maps(
+ "a000-e000 rw-p 00000000 00:00 0 /dev/\n"
+ "f000-f100 rw-p 00000000 00:00 0 /dev/does_not_exist\n"
+ "f100-f200 rw-p 00000000 00:00 0 /dev/ashmem/does_not_exist\n"
+ "f200-f300 rw-p 00000000 00:00 0 /devsomething/does_not_exist\n");
+
+ ASSERT_TRUE(maps.Parse());
+ ASSERT_EQ(4U, maps.Total());
+ auto it = maps.begin();
+ ASSERT_TRUE(it->flags & 0x8000);
+ ASSERT_EQ("/dev/", it->name);
+ ++it;
+ ASSERT_TRUE(it->flags & 0x8000);
+ ASSERT_EQ("/dev/does_not_exist", it->name);
+ ++it;
+ ASSERT_FALSE(it->flags & 0x8000);
+ ASSERT_EQ("/dev/ashmem/does_not_exist", it->name);
+ ++it;
+ ASSERT_FALSE(it->flags & 0x8000);
+ ASSERT_EQ("/devsomething/does_not_exist", it->name);
+}
+
+TEST(MapsTest, file_smoke) {
+ TemporaryFile tf;
+ ASSERT_TRUE(tf.fd != -1);
+
+ ASSERT_TRUE(
+ android::base::WriteStringToFile("720b29b000-720b29e000 r-xp a0000000 00:00 0 /fake.so\n"
+ "720b2b0000-720b2e0000 r-xp b0000000 00:00 0 /fake2.so\n"
+ "720b2e0000-720b2f0000 r-xp c0000000 00:00 0 /fake3.so\n",
+ tf.path, 0660, getuid(), getgid()));
+
+ FileMaps maps(tf.path);
+
+ ASSERT_TRUE(maps.Parse());
+ ASSERT_EQ(3U, maps.Total());
+ auto it = maps.begin();
+ ASSERT_EQ(0x720b29b000U, it->start);
+ ASSERT_EQ(0x720b29e000U, it->end);
+ ASSERT_EQ(0xa0000000U, it->offset);
+ ASSERT_EQ(PROT_READ | PROT_EXEC, it->flags);
+ ASSERT_EQ("/fake.so", it->name);
+ ++it;
+ ASSERT_EQ(0x720b2b0000U, it->start);
+ ASSERT_EQ(0x720b2e0000U, it->end);
+ ASSERT_EQ(0xb0000000U, it->offset);
+ ASSERT_EQ(PROT_READ | PROT_EXEC, it->flags);
+ ASSERT_EQ("/fake2.so", it->name);
+ ++it;
+ ASSERT_EQ(0x720b2e0000U, it->start);
+ ASSERT_EQ(0x720b2f0000U, it->end);
+ ASSERT_EQ(0xc0000000U, it->offset);
+ ASSERT_EQ(PROT_READ | PROT_EXEC, it->flags);
+ ASSERT_EQ("/fake3.so", it->name);
+ ++it;
+ ASSERT_EQ(it, maps.end());
+}
+
+TEST(MapsTest, find) {
+ BufferMaps maps(
+ "1000-2000 r--p 00000010 00:00 0 /system/lib/fake1.so\n"
+ "3000-4000 -w-p 00000020 00:00 0 /system/lib/fake2.so\n"
+ "6000-8000 --xp 00000030 00:00 0 /system/lib/fake3.so\n"
+ "a000-b000 rw-p 00000040 00:00 0 /system/lib/fake4.so\n"
+ "e000-f000 rwxp 00000050 00:00 0 /system/lib/fake5.so\n");
+ ASSERT_TRUE(maps.Parse());
+ ASSERT_EQ(5U, maps.Total());
+
+ ASSERT_TRUE(maps.Find(0x500) == nullptr);
+ ASSERT_TRUE(maps.Find(0x2000) == nullptr);
+ ASSERT_TRUE(maps.Find(0x5010) == nullptr);
+ ASSERT_TRUE(maps.Find(0x9a00) == nullptr);
+ ASSERT_TRUE(maps.Find(0xf000) == nullptr);
+ ASSERT_TRUE(maps.Find(0xf010) == nullptr);
+
+ MapInfo* info = maps.Find(0x1000);
+ ASSERT_TRUE(info != nullptr);
+ ASSERT_EQ(0x1000U, info->start);
+ ASSERT_EQ(0x2000U, info->end);
+ ASSERT_EQ(0x10U, info->offset);
+ ASSERT_EQ(PROT_READ, info->flags);
+ ASSERT_EQ("/system/lib/fake1.so", info->name);
+
+ info = maps.Find(0x3020);
+ ASSERT_TRUE(info != nullptr);
+ ASSERT_EQ(0x3000U, info->start);
+ ASSERT_EQ(0x4000U, info->end);
+ ASSERT_EQ(0x20U, info->offset);
+ ASSERT_EQ(PROT_WRITE, info->flags);
+ ASSERT_EQ("/system/lib/fake2.so", info->name);
+
+ info = maps.Find(0x6020);
+ ASSERT_TRUE(info != nullptr);
+ ASSERT_EQ(0x6000U, info->start);
+ ASSERT_EQ(0x8000U, info->end);
+ ASSERT_EQ(0x30U, info->offset);
+ ASSERT_EQ(PROT_EXEC, info->flags);
+ ASSERT_EQ("/system/lib/fake3.so", info->name);
+
+ info = maps.Find(0xafff);
+ ASSERT_TRUE(info != nullptr);
+ ASSERT_EQ(0xa000U, info->start);
+ ASSERT_EQ(0xb000U, info->end);
+ ASSERT_EQ(0x40U, info->offset);
+ ASSERT_EQ(PROT_READ | PROT_WRITE, info->flags);
+ ASSERT_EQ("/system/lib/fake4.so", info->name);
+
+ info = maps.Find(0xe500);
+ ASSERT_TRUE(info != nullptr);
+ ASSERT_EQ(0xe000U, info->start);
+ ASSERT_EQ(0xf000U, info->end);
+ ASSERT_EQ(0x50U, info->offset);
+ ASSERT_EQ(PROT_READ | PROT_WRITE | PROT_EXEC, info->flags);
+ ASSERT_EQ("/system/lib/fake5.so", info->name);
+}
diff --git a/libutils/Android.bp b/libutils/Android.bp
index 2b7412b..b46ad62 100644
--- a/libutils/Android.bp
+++ b/libutils/Android.bp
@@ -14,6 +14,7 @@
cc_library_headers {
name: "libutils_headers",
+ vendor_available: true,
host_supported: true,
export_include_dirs: ["include"],
target: {
@@ -28,6 +29,7 @@
cc_library {
name: "libutils",
+ vendor_available: true,
host_supported: true,
srcs: [
diff --git a/libziparchive/zip_archive.cc b/libziparchive/zip_archive.cc
index 0ac6f2c..246575f 100644
--- a/libziparchive/zip_archive.cc
+++ b/libziparchive/zip_archive.cc
@@ -563,6 +563,17 @@
// Paranoia: Match the values specified in the local file header
// to those specified in the central directory.
+
+ // Verify that the central directory and local file header agree on the use of a trailing
+ // Data Descriptor.
+ if ((lfh->gpb_flags & kGPBDDFlagMask) != (cdr->gpb_flags & kGPBDDFlagMask)) {
+ ALOGW("Zip: gpb flag mismatch. expected {%04" PRIx16 "}, was {%04" PRIx16 "}",
+ cdr->gpb_flags, lfh->gpb_flags);
+ return kInconsistentInformation;
+ }
+
+ // If there is no trailing data descriptor, verify that the central directory and local file
+ // header agree on the crc, compressed, and uncompressed sizes of the entry.
if ((lfh->gpb_flags & kGPBDDFlagMask) == 0) {
data->has_data_descriptor = 0;
if (data->compressed_length != lfh->compressed_size
diff --git a/libziparchive/zip_writer.cc b/libziparchive/zip_writer.cc
index 7600528..6d28bdb 100644
--- a/libziparchive/zip_writer.cc
+++ b/libziparchive/zip_writer.cc
@@ -18,6 +18,7 @@
#include <cstdio>
#include <sys/param.h>
+#include <sys/stat.h>
#include <zlib.h>
#define DEF_MEM_LEVEL 8 // normally in zutil.h?
@@ -84,11 +85,19 @@
delete stream;
}
-ZipWriter::ZipWriter(FILE* f) : file_(f), current_offset_(0), state_(State::kWritingZip),
- z_stream_(nullptr, DeleteZStream), buffer_(kBufSize) {
+ZipWriter::ZipWriter(FILE* f) : file_(f), seekable_(false), current_offset_(0),
+ state_(State::kWritingZip), z_stream_(nullptr, DeleteZStream),
+ buffer_(kBufSize) {
+ // Check if the file is seekable (regular file). If fstat fails, that's fine, subsequent calls
+ // will fail as well.
+ struct stat file_stats;
+ if (fstat(fileno(f), &file_stats) == 0) {
+ seekable_ = S_ISREG(file_stats.st_mode);
+ }
}
ZipWriter::ZipWriter(ZipWriter&& writer) : file_(writer.file_),
+ seekable_(writer.seekable_),
current_offset_(writer.current_offset_),
state_(writer.state_),
files_(std::move(writer.files_)),
@@ -100,6 +109,7 @@
ZipWriter& ZipWriter::operator=(ZipWriter&& writer) {
file_ = writer.file_;
+ seekable_ = writer.seekable_;
current_offset_ = writer.current_offset_;
state_ = writer.state_;
files_ = std::move(writer.files_);
@@ -159,6 +169,30 @@
*out_time = ptm->tm_hour << 11 | ptm->tm_min << 5 | ptm->tm_sec >> 1;
}
+static void CopyFromFileEntry(const ZipWriter::FileEntry& src, bool use_data_descriptor,
+ LocalFileHeader* dst) {
+ dst->lfh_signature = LocalFileHeader::kSignature;
+ if (use_data_descriptor) {
+ // Set this flag to denote that a DataDescriptor struct will appear after the data,
+ // containing the crc and size fields.
+ dst->gpb_flags |= kGPBDDFlagMask;
+
+ // The size and crc fields must be 0.
+ dst->compressed_size = 0u;
+ dst->uncompressed_size = 0u;
+ dst->crc32 = 0u;
+ } else {
+ dst->compressed_size = src.compressed_size;
+ dst->uncompressed_size = src.uncompressed_size;
+ dst->crc32 = src.crc32;
+ }
+ dst->compression_method = src.compression_method;
+ dst->last_mod_time = src.last_mod_time;
+ dst->last_mod_date = src.last_mod_date;
+ dst->file_name_length = src.path.size();
+ dst->extra_field_length = src.padding_length;
+}
+
int32_t ZipWriter::StartAlignedEntryWithTime(const char* path, size_t flags,
time_t time, uint32_t alignment) {
if (state_ != State::kWritingZip) {
@@ -173,66 +207,58 @@
return kInvalidAlignment;
}
- current_file_entry_ = {};
- current_file_entry_.path = path;
- current_file_entry_.local_file_header_offset = current_offset_;
+ FileEntry file_entry = {};
+ file_entry.local_file_header_offset = current_offset_;
+ file_entry.path = path;
- if (!IsValidEntryName(reinterpret_cast<const uint8_t*>(current_file_entry_.path.data()),
- current_file_entry_.path.size())) {
+ if (!IsValidEntryName(reinterpret_cast<const uint8_t*>(file_entry.path.data()),
+ file_entry.path.size())) {
return kInvalidEntryName;
}
- LocalFileHeader header = {};
- header.lfh_signature = LocalFileHeader::kSignature;
-
- // Set this flag to denote that a DataDescriptor struct will appear after the data,
- // containing the crc and size fields.
- header.gpb_flags |= kGPBDDFlagMask;
-
if (flags & ZipWriter::kCompress) {
- current_file_entry_.compression_method = kCompressDeflated;
+ file_entry.compression_method = kCompressDeflated;
int32_t result = PrepareDeflate();
if (result != kNoError) {
return result;
}
} else {
- current_file_entry_.compression_method = kCompressStored;
+ file_entry.compression_method = kCompressStored;
}
- header.compression_method = current_file_entry_.compression_method;
- ExtractTimeAndDate(time, ¤t_file_entry_.last_mod_time, ¤t_file_entry_.last_mod_date);
- header.last_mod_time = current_file_entry_.last_mod_time;
- header.last_mod_date = current_file_entry_.last_mod_date;
+ ExtractTimeAndDate(time, &file_entry.last_mod_time, &file_entry.last_mod_date);
- header.file_name_length = current_file_entry_.path.size();
-
- off64_t offset = current_offset_ + sizeof(header) + current_file_entry_.path.size();
+ off_t offset = current_offset_ + sizeof(LocalFileHeader) + file_entry.path.size();
std::vector<char> zero_padding;
if (alignment != 0 && (offset & (alignment - 1))) {
// Pad the extra field so the data will be aligned.
uint16_t padding = alignment - (offset % alignment);
- header.extra_field_length = padding;
+ file_entry.padding_length = padding;
offset += padding;
- zero_padding.resize(padding);
- memset(zero_padding.data(), 0, zero_padding.size());
+ zero_padding.resize(padding, 0);
}
+ LocalFileHeader header = {};
+ // Always start expecting a data descriptor. When the data has finished being written,
+ // if it is possible to seek back, the GPB flag will reset and the sizes written.
+ CopyFromFileEntry(file_entry, true /*use_data_descriptor*/, &header);
+
if (fwrite(&header, sizeof(header), 1, file_) != 1) {
return HandleError(kIoError);
}
- if (fwrite(path, sizeof(*path), current_file_entry_.path.size(), file_)
- != current_file_entry_.path.size()) {
+ if (fwrite(path, sizeof(*path), file_entry.path.size(), file_) != file_entry.path.size()) {
return HandleError(kIoError);
}
- if (header.extra_field_length != 0 &&
- fwrite(zero_padding.data(), 1, header.extra_field_length, file_)
- != header.extra_field_length) {
+ if (file_entry.padding_length != 0 &&
+ fwrite(zero_padding.data(), 1, file_entry.padding_length, file_)
+ != file_entry.padding_length) {
return HandleError(kIoError);
}
+ current_file_entry_ = std::move(file_entry);
current_offset_ = offset;
state_ = State::kWritingEntry;
return kNoError;
@@ -405,23 +431,41 @@
}
}
- const uint32_t sig = DataDescriptor::kOptSignature;
- if (fwrite(&sig, sizeof(sig), 1, file_) != 1) {
- state_ = State::kError;
- return kIoError;
- }
+ if ((current_file_entry_.compression_method & kCompressDeflated) || !seekable_) {
+ // Some versions of ZIP don't allow STORED data to have a trailing DataDescriptor.
+ // If this file is not seekable, or if the data is compressed, write a DataDescriptor.
+ const uint32_t sig = DataDescriptor::kOptSignature;
+ if (fwrite(&sig, sizeof(sig), 1, file_) != 1) {
+ return HandleError(kIoError);
+ }
- DataDescriptor dd = {};
- dd.crc32 = current_file_entry_.crc32;
- dd.compressed_size = current_file_entry_.compressed_size;
- dd.uncompressed_size = current_file_entry_.uncompressed_size;
- if (fwrite(&dd, sizeof(dd), 1, file_) != 1) {
- return HandleError(kIoError);
+ DataDescriptor dd = {};
+ dd.crc32 = current_file_entry_.crc32;
+ dd.compressed_size = current_file_entry_.compressed_size;
+ dd.uncompressed_size = current_file_entry_.uncompressed_size;
+ if (fwrite(&dd, sizeof(dd), 1, file_) != 1) {
+ return HandleError(kIoError);
+ }
+ current_offset_ += sizeof(DataDescriptor::kOptSignature) + sizeof(dd);
+ } else {
+ // Seek back to the header and rewrite to include the size.
+ if (fseeko(file_, current_file_entry_.local_file_header_offset, SEEK_SET) != 0) {
+ return HandleError(kIoError);
+ }
+
+ LocalFileHeader header = {};
+ CopyFromFileEntry(current_file_entry_, false /*use_data_descriptor*/, &header);
+
+ if (fwrite(&header, sizeof(header), 1, file_) != 1) {
+ return HandleError(kIoError);
+ }
+
+ if (fseeko(file_, current_offset_, SEEK_SET) != 0) {
+ return HandleError(kIoError);
+ }
}
files_.emplace_back(std::move(current_file_entry_));
-
- current_offset_ += sizeof(DataDescriptor::kOptSignature) + sizeof(dd);
state_ = State::kWritingZip;
return kNoError;
}
@@ -431,11 +475,13 @@
return kInvalidState;
}
- off64_t startOfCdr = current_offset_;
+ off_t startOfCdr = current_offset_;
for (FileEntry& file : files_) {
CentralDirectoryRecord cdr = {};
cdr.record_signature = CentralDirectoryRecord::kSignature;
- cdr.gpb_flags |= kGPBDDFlagMask;
+ if ((file.compression_method & kCompressDeflated) || !seekable_) {
+ cdr.gpb_flags |= kGPBDDFlagMask;
+ }
cdr.compression_method = file.compression_method;
cdr.last_mod_time = file.last_mod_time;
cdr.last_mod_date = file.last_mod_date;
@@ -443,7 +489,7 @@
cdr.compressed_size = file.compressed_size;
cdr.uncompressed_size = file.uncompressed_size;
cdr.file_name_length = file.path.size();
- cdr.local_file_header_offset = file.local_file_header_offset;
+ cdr.local_file_header_offset = static_cast<uint32_t>(file.local_file_header_offset);
if (fwrite(&cdr, sizeof(cdr), 1, file_) != 1) {
return HandleError(kIoError);
}
@@ -473,7 +519,7 @@
// Since we can BackUp() and potentially finish writing at an offset less than one we had
// already written at, we must truncate the file.
- if (ftruncate64(fileno(file_), current_offset_) != 0) {
+ if (ftruncate(fileno(file_), current_offset_) != 0) {
return HandleError(kIoError);
}
diff --git a/libziparchive/zip_writer_test.cc b/libziparchive/zip_writer_test.cc
index 30f4950..5b526a4 100644
--- a/libziparchive/zip_writer_test.cc
+++ b/libziparchive/zip_writer_test.cc
@@ -64,6 +64,7 @@
ZipEntry data;
ASSERT_EQ(0, FindEntry(handle, ZipString("file.txt"), &data));
EXPECT_EQ(kCompressStored, data.method);
+ EXPECT_EQ(0u, data.has_data_descriptor);
EXPECT_EQ(strlen(expected), data.compressed_length);
ASSERT_EQ(strlen(expected), data.uncompressed_length);
ASSERT_TRUE(AssertFileEntryContentsEq(expected, handle, &data));
diff --git a/logd/main.cpp b/logd/main.cpp
index 946485b..18029eb 100644
--- a/logd/main.cpp
+++ b/logd/main.cpp
@@ -407,6 +407,11 @@
// logging plugins like auditd and restart control. Additional
// transitory per-client threads are created for each reader.
int main(int argc, char* argv[]) {
+ // logd is written under the assumption that the timezone is UTC.
+ // If TZ is not set, persist.sys.timezone is looked up in some time utility
+ // libc functions, including mktime. It confuses the logd time handling,
+ // so here explicitly set TZ to UTC, which overrides the property.
+ setenv("TZ", "UTC", 1);
// issue reinit command. KISS argument parsing.
if ((argc > 1) && argv[1] && !strcmp(argv[1], "--reinit")) {
return issueReinit();
diff --git a/rootdir/init.rc b/rootdir/init.rc
index ff96c14..a43b0e1 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -301,9 +301,6 @@
start logd
start hwservicemanager
- # HALs required before data is mounted
- class_start early_hal
-
# once everything is setup, no need to modify /
mount rootfs rootfs / ro remount
# Mount shared so changes propagate into child namespaces
@@ -351,6 +348,10 @@
# create the lost+found directories, so as to enforce our permissions
mkdir /cache/lost+found 0770 root root
+on late-fs
+ # HALs required before storage encryption can get unlocked (FBE/FDE)
+ class_start early_hal
+
on post-fs-data
# We chown/chmod /data again so because mount is run as root + defaults
chown system system /data
@@ -405,7 +406,7 @@
mkdir /data/misc/boottrace 0771 system shell
mkdir /data/misc/update_engine 0700 root root
mkdir /data/misc/trace 0700 root root
- mkdir /data/misc/reboot 0700 root root
+ mkdir /data/misc/reboot 0700 system system
# profile file layout
mkdir /data/misc/profiles 0771 system system
mkdir /data/misc/profiles/cur 0771 system system
@@ -643,6 +644,12 @@
on property:sys.boot_completed=1
bootchart stop
+on property:sys.boot_completed=1 && property:ro.build.type=user
+ write /proc/sys/kernel/modules_disabled 1
+
+on property:sys.boot_completed=1 && property:ro.build.type=userdebug
+ write /proc/sys/kernel/modules_disabled 1
+
# system server cannot write to /proc/sys files,
# and chown/chmod does not work for /proc/sys/ entries.
# So proxy writes through init.
diff --git a/rootdir/ueventd.rc b/rootdir/ueventd.rc
index 0633a68..1609ef2 100644
--- a/rootdir/ueventd.rc
+++ b/rootdir/ueventd.rc
@@ -1,5 +1,37 @@
subsystem adf
- devname uevent_devname
+ devname uevent_devname
+
+subsystem graphics
+ devname uevent_devpath
+ dirname /dev/graphics
+
+subsystem drm
+ devname uevent_devpath
+ dirname /dev/dri
+
+subsystem oncrpc
+ devname uevent_devpath
+ dirname /dev/oncrpc
+
+subsystem adsp
+ devname uevent_devpath
+ dirname /dev/adsp
+
+subsystem msm_camera
+ devname uevent_devpath
+ dirname /dev/msm_camera
+
+subsystem input
+ devname uevent_devpath
+ dirname /dev/input
+
+subsystem mtd
+ devname uevent_devpath
+ dirname /dev/mtd
+
+subsystem sound
+ devname uevent_devpath
+ dirname /dev/snd
# ueventd can only set permissions on device nodes and their associated
# sysfs attributes, not on arbitrary paths.
@@ -21,9 +53,6 @@
/dev/binder 0666 root root
/dev/hwbinder 0666 root root
-# Anyone can read the logs, but if they're not in the "logs"
-# group, then they'll only see log entries for their UID.
-/dev/log/* 0666 root log
/dev/pmsg0 0222 root log
# the msm hw3d client device node is world writable/readable.
diff --git a/toolbox/Android.mk b/toolbox/Android.mk
index d6ead1a..aa755ed 100644
--- a/toolbox/Android.mk
+++ b/toolbox/Android.mk
@@ -95,3 +95,13 @@
LOCAL_MODULE := grep
LOCAL_POST_INSTALL_CMD := $(hide) $(foreach t,egrep fgrep,ln -sf grep $(TARGET_OUT)/bin/$(t);)
include $(BUILD_EXECUTABLE)
+
+
+# We build gzip separately, so it can provide gunzip and zcat too.
+include $(CLEAR_VARS)
+LOCAL_MODULE := gzip
+LOCAL_SRC_FILES := gzip.c
+LOCAL_CFLAGS += -Wall -Werror
+LOCAL_SHARED_LIBRARIES += libz
+LOCAL_POST_INSTALL_CMD := $(hide) $(foreach t,gunzip zcat,ln -sf gzip $(TARGET_OUT)/bin/$(t);)
+include $(BUILD_EXECUTABLE)
diff --git a/toolbox/gzip.c b/toolbox/gzip.c
new file mode 100644
index 0000000..62c4518
--- /dev/null
+++ b/toolbox/gzip.c
@@ -0,0 +1,261 @@
+/* gzip.c - gzip/gunzip/zcat tools for gzip data
+ *
+ * Copyright 2017 The Android Open Source Project
+ *
+ * GZIP RFC: http://www.ietf.org/rfc/rfc1952.txt
+
+TODO: port to toybox.
+
+*/
+
+#define _GNU_SOURCE
+
+#include <errno.h>
+#include <error.h>
+#include <fcntl.h>
+#include <getopt.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+
+#include <zlib.h>
+
+// toybox-style flags/globals.
+#define FLAG_c 1
+#define FLAG_d 2
+#define FLAG_f 4
+#define FLAG_k 8
+static struct {
+ int optflags;
+} toys;
+static struct {
+ int level;
+} TT;
+
+static void xstat(const char *path, struct stat *sb)
+{
+ if (stat(path, sb)) error(1, errno, "stat %s", path);
+}
+
+static void fix_time(const char *path, struct stat *sb)
+{
+ struct timespec times[] = { sb->st_atim, sb->st_mtim };
+
+ if (utimensat(AT_FDCWD, path, times, 0)) error(1, errno, "utimes");
+}
+
+static FILE *xfdopen(const char *name, int flags, mode_t open_mode,
+ const char *mode)
+{
+ FILE *fp;
+ int fd;
+
+ if (!strcmp(name, "-")) fd = dup((*mode == 'r') ? 0 : 1);
+ else fd = open(name, flags, open_mode);
+
+ if (fd == -1) error(1, errno, "open %s (%s)", name, mode);
+ fp = fdopen(fd, mode);
+ if (fp == NULL) error(1, errno, "fopen %s (%s)", name, mode);
+ return fp;
+}
+
+static gzFile xgzopen(const char *name, int flags, mode_t open_mode,
+ const char *mode)
+{
+ gzFile f;
+ int fd;
+
+ if (!strcmp(name, "-")) fd = dup((*mode == 'r') ? 0 : 1);
+ else fd = open(name, flags, open_mode);
+
+ if (fd == -1) error(1, errno, "open %s (%s)", name, mode);
+ f = gzdopen(fd, mode);
+ if (f == NULL) error(1, errno, "gzdopen %s (%s)", name, mode);
+ return f;
+}
+
+static void gzfatal(gzFile f, char *what)
+{
+ int err;
+ const char *msg = gzerror(f, &err);
+
+ error(1, (err == Z_ERRNO) ? errno : 0, "%s: %s", what, msg);
+}
+
+static void gunzip(char *arg)
+{
+ struct stat sb;
+ char buf[BUFSIZ];
+ int len, both_files;
+ char *in_name, *out_name;
+ gzFile in;
+ FILE *out;
+
+ // "gunzip x.gz" will decompress "x.gz" to "x".
+ len = strlen(arg);
+ if (len > 3 && !strcmp(arg+len-3, ".gz")) {
+ in_name = strdup(arg);
+ out_name = strdup(arg);
+ out_name[len-3] = '\0';
+ } else if (!strcmp(arg, "-")) {
+ // "-" means stdin; assume output to stdout.
+ // TODO: require -f to read compressed data from tty?
+ in_name = strdup("-");
+ out_name = strdup("-");
+ } else error(1, 0, "unknown suffix");
+
+ if (toys.optflags&FLAG_c) {
+ free(out_name);
+ out_name = strdup("-");
+ }
+
+ both_files = strcmp(in_name, "-") && strcmp(out_name, "-");
+ if (both_files) xstat(in_name, &sb);
+
+ in = xgzopen(in_name, O_RDONLY, 0, "r");
+ out = xfdopen(out_name, O_CREAT|O_WRONLY|((toys.optflags&FLAG_f)?0:O_EXCL),
+ both_files?sb.st_mode:0666, "w");
+
+ while ((len = gzread(in, buf, sizeof(buf))) > 0) {
+ if (fwrite(buf, 1, len, out) != (size_t) len) error(1, errno, "fwrite");
+ }
+ if (len < 0) gzfatal(in, "gzread");
+ if (fclose(out)) error(1, errno, "fclose");
+ if (gzclose(in) != Z_OK) error(1, 0, "gzclose");
+
+ if (both_files) fix_time(out_name, &sb);
+ if (!(toys.optflags&(FLAG_c|FLAG_k))) unlink(in_name);
+ free(in_name);
+ free(out_name);
+}
+
+static void gzip(char *in_name)
+{
+ char buf[BUFSIZ];
+ size_t len;
+ char *out_name;
+ FILE *in;
+ gzFile out;
+ struct stat sb;
+ int both_files;
+
+ if (toys.optflags&FLAG_c) {
+ out_name = strdup("-");
+ } else {
+ if (asprintf(&out_name, "%s.gz", in_name) == -1) {
+ error(1, errno, "asprintf");
+ }
+ }
+
+ both_files = strcmp(in_name, "-") && strcmp(out_name, "-");
+ if (both_files) xstat(in_name, &sb);
+
+ snprintf(buf, sizeof(buf), "w%d", TT.level);
+ in = xfdopen(in_name, O_RDONLY, 0, "r");
+ out = xgzopen(out_name, O_CREAT|O_WRONLY|((toys.optflags&FLAG_f)?0:O_EXCL),
+ both_files?sb.st_mode:0, buf);
+
+ while ((len = fread(buf, 1, sizeof(buf), in)) > 0) {
+ if (gzwrite(out, buf, len) != (int) len) gzfatal(out, "gzwrite");
+ }
+ if (ferror(in)) error(1, errno, "fread");
+ if (fclose(in)) error(1, errno, "fclose");
+ if (gzclose(out) != Z_OK) error(1, 0, "gzclose");
+
+ if (both_files) fix_time(out_name, &sb);
+ if (!(toys.optflags&(FLAG_c|FLAG_k))) unlink(in_name);
+ free(out_name);
+}
+
+static void do_file(char *arg)
+{
+ if (toys.optflags&FLAG_d) gunzip(arg);
+ else gzip(arg);
+}
+
+static void usage()
+{
+ char *cmd = basename(getprogname());
+
+ printf("usage: %s [-c] [-d] [-f] [-#] [FILE...]\n", cmd);
+ printf("\n");
+ if (!strcmp(cmd, "zcat")) {
+ printf("Decompress files to stdout. Like `gzip -dc`.\n");
+ printf("\n");
+ printf("-c\tOutput to stdout\n");
+ printf("-f\tForce: allow read from tty\n");
+ } else if (!strcmp(cmd, "gunzip")) {
+ printf("Decompress files. With no files, decompresses stdin to stdout.\n");
+ printf("On success, the input files are removed and replaced by new\n");
+ printf("files without the .gz suffix.\n");
+ printf("\n");
+ printf("-c\tOutput to stdout\n");
+ printf("-f\tForce: allow read from tty\n");
+ printf("-k\tKeep input files (don't remove)\n");
+ } else { // gzip
+ printf("Compress files. With no files, compresses stdin to stdout.\n");
+ printf("On success, the input files are removed and replaced by new\n");
+ printf("files with the .gz suffix.\n");
+ printf("\n");
+ printf("-c\tOutput to stdout\n");
+ printf("-d\tDecompress (act as gunzip)\n");
+ printf("-f\tForce: allow overwrite of output file\n");
+ printf("-k\tKeep input files (don't remove)\n");
+ printf("-#\tCompression level 1-9 (1:fastest, 6:default, 9:best)\n");
+ }
+ printf("\n");
+}
+
+int main(int argc, char *argv[])
+{
+ char *cmd = basename(argv[0]);
+ int opt_ch;
+
+ toys.optflags = 0;
+ TT.level = 6;
+
+ if (!strcmp(cmd, "gunzip")) {
+ // gunzip == gzip -d
+ toys.optflags = FLAG_d;
+ } else if (!strcmp(cmd, "zcat")) {
+ // zcat == gzip -dc
+ toys.optflags = (FLAG_c|FLAG_d);
+ }
+
+ while ((opt_ch = getopt(argc, argv, "cdfhk123456789")) != -1) {
+ switch (opt_ch) {
+ case 'c': toys.optflags |= FLAG_c; break;
+ case 'd': toys.optflags |= FLAG_d; break;
+ case 'f': toys.optflags |= FLAG_f; break;
+ case 'k': toys.optflags |= FLAG_k; break;
+
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ TT.level = opt_ch - '0';
+ break;
+
+ default:
+ usage();
+ return 1;
+ }
+ }
+
+ if (optind == argc) {
+ // With no arguments, we go from stdin to stdout.
+ toys.optflags |= FLAG_c;
+ do_file("-");
+ return 0;
+ }
+
+ // Otherwise process each file in turn.
+ while (optind < argc) do_file(argv[optind++]);
+ return 0;
+}
diff --git a/trusty/keymaster/Android.mk b/trusty/keymaster/Android.mk
index 0ebf52d..2d614ae 100644
--- a/trusty/keymaster/Android.mk
+++ b/trusty/keymaster/Android.mk
@@ -32,7 +32,7 @@
LOCAL_MODULE := trusty_keymaster_tipc
LOCAL_SRC_FILES := \
trusty_keymaster_device.cpp \
- trusty_keymaster_ipc.c \
+ trusty_keymaster_ipc.cpp \
trusty_keymaster_main.cpp
LOCAL_SHARED_LIBRARIES := \
libcrypto \
@@ -40,6 +40,7 @@
libkeymaster1 \
libtrusty \
libkeymaster_messages \
+ libsoftkeymasterdevice \
liblog
include $(BUILD_EXECUTABLE)
@@ -53,7 +54,7 @@
LOCAL_MODULE := keystore.trusty
LOCAL_MODULE_RELATIVE_PATH := hw
LOCAL_SRC_FILES := module.cpp \
- trusty_keymaster_ipc.c \
+ trusty_keymaster_ipc.cpp \
trusty_keymaster_device.cpp
LOCAL_CLFAGS = -fvisibility=hidden -Wall -Werror
LOCAL_SHARED_LIBRARIES := \
diff --git a/trusty/keymaster/keymaster_ipc.h b/trusty/keymaster/keymaster_ipc.h
index 48fa53d..b38eb05 100644
--- a/trusty/keymaster/keymaster_ipc.h
+++ b/trusty/keymaster/keymaster_ipc.h
@@ -16,13 +16,15 @@
#pragma once
+// clang-format off
+
#define KEYMASTER_PORT "com.android.trusty.keymaster"
#define KEYMASTER_MAX_BUFFER_LENGTH 4096
// Commands
-enum keymaster_command {
- KEYMASTER_RESP_BIT = 1,
- KEYMASTER_REQ_SHIFT = 1,
+enum keymaster_command : uint32_t {
+ KEYMASTER_RESP_BIT = 1,
+ KEYMASTER_REQ_SHIFT = 1,
KM_GENERATE_KEY = (0 << KEYMASTER_REQ_SHIFT),
KM_BEGIN_OPERATION = (1 << KEYMASTER_REQ_SHIFT),
@@ -40,6 +42,9 @@
KM_GET_SUPPORTED_IMPORT_FORMATS = (13 << KEYMASTER_REQ_SHIFT),
KM_GET_SUPPORTED_EXPORT_FORMATS = (14 << KEYMASTER_REQ_SHIFT),
KM_GET_KEY_CHARACTERISTICS = (15 << KEYMASTER_REQ_SHIFT),
+ KM_ATTEST_KEY = (16 << KEYMASTER_REQ_SHIFT),
+ KM_UPGRADE_KEY = (17 << KEYMASTER_REQ_SHIFT),
+ KM_CONFIGURE = (18 << KEYMASTER_REQ_SHIFT),
};
#ifdef __ANDROID__
@@ -50,8 +55,8 @@
* @payload: start of the serialized command specific payload
*/
struct keymaster_message {
- uint32_t cmd;
- uint8_t payload[0];
+ uint32_t cmd;
+ uint8_t payload[0];
};
#endif
diff --git a/trusty/keymaster/module.cpp b/trusty/keymaster/module.cpp
index 81597d9..b472680 100644
--- a/trusty/keymaster/module.cpp
+++ b/trusty/keymaster/module.cpp
@@ -26,14 +26,15 @@
/*
* Generic device handling
*/
-static int trusty_keymaster_open(const hw_module_t* module, const char* name,
- hw_device_t** device) {
- if (strcmp(name, KEYSTORE_KEYMASTER) != 0)
+static int trusty_keymaster_open(const hw_module_t* module, const char* name, hw_device_t** device) {
+ if (strcmp(name, KEYSTORE_KEYMASTER) != 0) {
return -EINVAL;
+ }
TrustyKeymasterDevice* dev = new TrustyKeymasterDevice(module);
- if (dev == NULL)
+ if (dev == NULL) {
return -ENOMEM;
+ }
*device = dev->hw_device();
// Do not delete dev; it will get cleaned up when the caller calls device->close(), and must
// exist until then.
@@ -47,14 +48,14 @@
struct keystore_module HAL_MODULE_INFO_SYM __attribute__((visibility("default"))) = {
.common =
{
- .tag = HARDWARE_MODULE_TAG,
- .module_api_version = KEYMASTER_MODULE_API_VERSION_0_3,
- .hal_api_version = HARDWARE_HAL_API_VERSION,
- .id = KEYSTORE_HARDWARE_MODULE_ID,
- .name = "Trusty Keymaster HAL",
- .author = "The Android Open Source Project",
- .methods = &keystore_module_methods,
- .dso = 0,
- .reserved = {},
+ .tag = HARDWARE_MODULE_TAG,
+ .module_api_version = KEYMASTER_MODULE_API_VERSION_2_0,
+ .hal_api_version = HARDWARE_HAL_API_VERSION,
+ .id = KEYSTORE_HARDWARE_MODULE_ID,
+ .name = "Trusty Keymaster HAL",
+ .author = "The Android Open Source Project",
+ .methods = &keystore_module_methods,
+ .dso = 0,
+ .reserved = {},
},
};
diff --git a/trusty/keymaster/trusty_keymaster_device.cpp b/trusty/keymaster/trusty_keymaster_device.cpp
index 1368f88..5f16fd0 100644
--- a/trusty/keymaster/trusty_keymaster_device.cpp
+++ b/trusty/keymaster/trusty_keymaster_device.cpp
@@ -25,49 +25,53 @@
#include <string.h>
#include <time.h>
+#include <algorithm>
#include <type_traits>
-#include <hardware/keymaster0.h>
+#include <hardware/keymaster2.h>
#include <keymaster/authorization_set.h>
#include <log/log.h>
+#include "keymaster_ipc.h"
#include "trusty_keymaster_device.h"
#include "trusty_keymaster_ipc.h"
-#include "keymaster_ipc.h"
-const uint32_t SEND_BUF_SIZE = 8192;
-const uint32_t RECV_BUF_SIZE = 8192;
+const uint32_t RECV_BUF_SIZE = PAGE_SIZE;
+const uint32_t SEND_BUF_SIZE = (PAGE_SIZE - sizeof(struct keymaster_message) - 16 /* tipc header */);
+
+const size_t kMaximumAttestationChallengeLength = 128;
+const size_t kMaximumFinishInputLength = 2048;
namespace keymaster {
static keymaster_error_t translate_error(int err) {
switch (err) {
- case 0:
- return KM_ERROR_OK;
- case -EPERM:
- case -EACCES:
- return KM_ERROR_SECURE_HW_ACCESS_DENIED;
+ case 0:
+ return KM_ERROR_OK;
+ case -EPERM:
+ case -EACCES:
+ return KM_ERROR_SECURE_HW_ACCESS_DENIED;
- case -ECANCELED:
- return KM_ERROR_OPERATION_CANCELLED;
+ case -ECANCELED:
+ return KM_ERROR_OPERATION_CANCELLED;
- case -ENODEV:
- return KM_ERROR_UNIMPLEMENTED;
+ case -ENODEV:
+ return KM_ERROR_UNIMPLEMENTED;
- case -ENOMEM:
- return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+ case -ENOMEM:
+ return KM_ERROR_MEMORY_ALLOCATION_FAILED;
- case -EBUSY:
- return KM_ERROR_SECURE_HW_BUSY;
+ case -EBUSY:
+ return KM_ERROR_SECURE_HW_BUSY;
- case -EIO:
- return KM_ERROR_SECURE_HW_COMMUNICATION_FAILED;
+ case -EIO:
+ return KM_ERROR_SECURE_HW_COMMUNICATION_FAILED;
- case -EOVERFLOW:
- return KM_ERROR_INVALID_INPUT_LENGTH;
+ case -EOVERFLOW:
+ return KM_ERROR_INVALID_INPUT_LENGTH;
- default:
- return KM_ERROR_UNKNOWN_ERROR;
+ default:
+ return KM_ERROR_UNKNOWN_ERROR;
}
}
@@ -75,31 +79,36 @@
static_assert(std::is_standard_layout<TrustyKeymasterDevice>::value,
"TrustyKeymasterDevice must be standard layout");
static_assert(offsetof(TrustyKeymasterDevice, device_) == 0,
- "device_ must be the first member of KeymasterOpenSsl");
+ "device_ must be the first member of TrustyKeymasterDevice");
static_assert(offsetof(TrustyKeymasterDevice, device_.common) == 0,
- "common must be the first member of keymaster_device");
+ "common must be the first member of keymaster2_device");
ALOGI("Creating device");
ALOGD("Device address: %p", this);
- memset(&device_, 0, sizeof(device_));
+ device_ = {};
device_.common.tag = HARDWARE_DEVICE_TAG;
device_.common.version = 1;
device_.common.module = const_cast<hw_module_t*>(module);
device_.common.close = close_device;
- device_.flags = KEYMASTER_BLOBS_ARE_STANDALONE | KEYMASTER_SUPPORTS_EC;
+ device_.flags = KEYMASTER_SUPPORTS_EC;
- device_.generate_keypair = generate_keypair;
- device_.import_keypair = import_keypair;
- device_.get_keypair_public = get_keypair_public;
- device_.delete_keypair = NULL;
- device_.delete_all = NULL;
- device_.sign_data = sign_data;
- device_.verify_data = verify_data;
-
- device_.context = NULL;
+ device_.configure = configure;
+ device_.add_rng_entropy = add_rng_entropy;
+ device_.generate_key = generate_key;
+ device_.get_key_characteristics = get_key_characteristics;
+ device_.import_key = import_key;
+ device_.export_key = export_key;
+ device_.attest_key = attest_key;
+ device_.upgrade_key = upgrade_key;
+ device_.delete_key = nullptr;
+ device_.delete_all_keys = nullptr;
+ device_.begin = begin;
+ device_.update = update;
+ device_.finish = finish;
+ device_.abort = abort;
int rc = trusty_keymaster_connect();
error_ = translate_error(rc);
@@ -110,11 +119,11 @@
GetVersionRequest version_request;
GetVersionResponse version_response;
- error_ = Send(version_request, &version_response);
+ error_ = Send(KM_GET_VERSION, version_request, &version_response);
if (error_ == KM_ERROR_INVALID_ARGUMENT || error_ == KM_ERROR_UNIMPLEMENTED) {
- ALOGI("\"Bad parameters\" error on GetVersion call. Assuming version 0.");
- message_version_ = 0;
- error_ = KM_ERROR_OK;
+ ALOGE("\"Bad parameters\" error on GetVersion call. Version 0 is not supported.");
+ error_ = KM_ERROR_VERSION_MISMATCH;
+ return;
}
message_version_ = MessageVersion(version_response.major_ver, version_response.minor_ver,
version_response.subminor_ver);
@@ -130,261 +139,510 @@
trusty_keymaster_disconnect();
}
-const uint64_t HUNDRED_YEARS = 1000LL * 60 * 60 * 24 * 365 * 100;
+namespace {
-int TrustyKeymasterDevice::generate_keypair(const keymaster_keypair_t key_type,
- const void* key_params, uint8_t** key_blob,
- size_t* key_blob_length) {
- ALOGD("Device received generate_keypair");
+// Allocates a new buffer with malloc and copies the contents of |buffer| to it. Caller takes
+// ownership of the returned buffer.
+uint8_t* DuplicateBuffer(const uint8_t* buffer, size_t size) {
+ uint8_t* tmp = reinterpret_cast<uint8_t*>(malloc(size));
+ if (tmp) {
+ memcpy(tmp, buffer, size);
+ }
+ return tmp;
+}
- if (error_ != KM_ERROR_OK)
+template <typename RequestType>
+void AddClientAndAppData(const keymaster_blob_t* client_id, const keymaster_blob_t* app_data,
+ RequestType* request) {
+ request->additional_params.Clear();
+ if (client_id) {
+ request->additional_params.push_back(TAG_APPLICATION_ID, *client_id);
+ }
+ if (app_data) {
+ request->additional_params.push_back(TAG_APPLICATION_DATA, *app_data);
+ }
+}
+
+} // unnamed namespace
+
+keymaster_error_t TrustyKeymasterDevice::configure(const keymaster_key_param_set_t* params) {
+ ALOGD("Device received configure\n");
+
+ if (error_ != KM_ERROR_OK) {
return error_;
-
- GenerateKeyRequest req(message_version_);
- StoreNewKeyParams(&req.key_description);
-
- switch (key_type) {
- case TYPE_RSA: {
- req.key_description.push_back(TAG_ALGORITHM, KM_ALGORITHM_RSA);
- const keymaster_rsa_keygen_params_t* rsa_params =
- static_cast<const keymaster_rsa_keygen_params_t*>(key_params);
- ALOGD("Generating RSA pair, modulus size: %u, public exponent: %lu",
- rsa_params->modulus_size, rsa_params->public_exponent);
- req.key_description.push_back(TAG_KEY_SIZE, rsa_params->modulus_size);
- req.key_description.push_back(TAG_RSA_PUBLIC_EXPONENT, rsa_params->public_exponent);
- break;
+ }
+ if (!params) {
+ return KM_ERROR_UNEXPECTED_NULL_POINTER;
}
- case TYPE_EC: {
- req.key_description.push_back(TAG_ALGORITHM, KM_ALGORITHM_EC);
- const keymaster_ec_keygen_params_t* ec_params =
- static_cast<const keymaster_ec_keygen_params_t*>(key_params);
- ALOGD("Generating ECDSA pair, key size: %u", ec_params->field_size);
- req.key_description.push_back(TAG_KEY_SIZE, ec_params->field_size);
- break;
- }
- default:
- ALOGD("Received request for unsuported key type %d", key_type);
- return KM_ERROR_UNSUPPORTED_ALGORITHM;
+ AuthorizationSet params_copy(*params);
+ ConfigureRequest request;
+ if (!params_copy.GetTagValue(TAG_OS_VERSION, &request.os_version) ||
+ !params_copy.GetTagValue(TAG_OS_PATCHLEVEL, &request.os_patchlevel)) {
+ ALOGD("Configuration parameters must contain OS version and patch level");
+ return KM_ERROR_INVALID_ARGUMENT;
}
- GenerateKeyResponse rsp(message_version_);
- ALOGD("Sending generate request");
- keymaster_error_t err = Send(req, &rsp);
+ ConfigureResponse response;
+ keymaster_error_t err = Send(KM_CONFIGURE, request, &response);
if (err != KM_ERROR_OK) {
- ALOGE("Got error %d from send", err);
return err;
}
- *key_blob_length = rsp.key_blob.key_material_size;
- *key_blob = static_cast<uint8_t*>(malloc(*key_blob_length));
- memcpy(*key_blob, rsp.key_blob.key_material, *key_blob_length);
- ALOGD("Returning %d bytes in key blob\n", (int)*key_blob_length);
-
return KM_ERROR_OK;
}
-struct EVP_PKEY_Delete {
- void operator()(EVP_PKEY* p) const { EVP_PKEY_free(p); }
-};
+keymaster_error_t TrustyKeymasterDevice::add_rng_entropy(const uint8_t* data, size_t data_length) {
+ ALOGD("Device received add_rng_entropy");
-struct PKCS8_PRIV_KEY_INFO_Delete {
- void operator()(PKCS8_PRIV_KEY_INFO* p) const { PKCS8_PRIV_KEY_INFO_free(p); }
-};
-
-int TrustyKeymasterDevice::import_keypair(const uint8_t* key, const size_t key_length,
- uint8_t** key_blob, size_t* key_blob_length) {
- ALOGD("Device received import_keypair");
- if (error_ != KM_ERROR_OK)
+ if (error_ != KM_ERROR_OK) {
return error_;
+ }
- if (!key)
+ AddEntropyRequest request;
+ request.random_data.Reinitialize(data, data_length);
+ AddEntropyResponse response;
+ return Send(KM_ADD_RNG_ENTROPY, request, &response);
+}
+
+keymaster_error_t TrustyKeymasterDevice::generate_key(
+ const keymaster_key_param_set_t* params, keymaster_key_blob_t* key_blob,
+ keymaster_key_characteristics_t* characteristics) {
+ ALOGD("Device received generate_key");
+
+ if (error_ != KM_ERROR_OK) {
+ return error_;
+ }
+ if (!params) {
return KM_ERROR_UNEXPECTED_NULL_POINTER;
-
- if (!key_blob || !key_blob_length)
+ }
+ if (!key_blob) {
return KM_ERROR_OUTPUT_PARAMETER_NULL;
+ }
+
+ GenerateKeyRequest request(message_version_);
+ request.key_description.Reinitialize(*params);
+ request.key_description.push_back(TAG_CREATION_DATETIME, java_time(time(NULL)));
+
+ GenerateKeyResponse response(message_version_);
+ keymaster_error_t err = Send(KM_GENERATE_KEY, request, &response);
+ if (err != KM_ERROR_OK) {
+ return err;
+ }
+
+ key_blob->key_material_size = response.key_blob.key_material_size;
+ key_blob->key_material =
+ DuplicateBuffer(response.key_blob.key_material, response.key_blob.key_material_size);
+ if (!key_blob->key_material) {
+ return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+ }
+
+ if (characteristics) {
+ response.enforced.CopyToParamSet(&characteristics->hw_enforced);
+ response.unenforced.CopyToParamSet(&characteristics->sw_enforced);
+ }
+
+ return KM_ERROR_OK;
+}
+
+keymaster_error_t TrustyKeymasterDevice::get_key_characteristics(
+ const keymaster_key_blob_t* key_blob, const keymaster_blob_t* client_id,
+ const keymaster_blob_t* app_data, keymaster_key_characteristics_t* characteristics) {
+ ALOGD("Device received get_key_characteristics");
+
+ if (error_ != KM_ERROR_OK) {
+ return error_;
+ }
+ if (!key_blob || !key_blob->key_material) {
+ return KM_ERROR_UNEXPECTED_NULL_POINTER;
+ }
+ if (!characteristics) {
+ return KM_ERROR_OUTPUT_PARAMETER_NULL;
+ }
+
+ GetKeyCharacteristicsRequest request;
+ request.SetKeyMaterial(*key_blob);
+ AddClientAndAppData(client_id, app_data, &request);
+
+ GetKeyCharacteristicsResponse response;
+ keymaster_error_t err = Send(KM_GET_KEY_CHARACTERISTICS, request, &response);
+ if (err != KM_ERROR_OK) {
+ return err;
+ }
+
+ response.enforced.CopyToParamSet(&characteristics->hw_enforced);
+ response.unenforced.CopyToParamSet(&characteristics->sw_enforced);
+
+ return KM_ERROR_OK;
+}
+
+keymaster_error_t TrustyKeymasterDevice::import_key(
+ const keymaster_key_param_set_t* params, keymaster_key_format_t key_format,
+ const keymaster_blob_t* key_data, keymaster_key_blob_t* key_blob,
+ keymaster_key_characteristics_t* characteristics) {
+ ALOGD("Device received import_key");
+
+ if (error_ != KM_ERROR_OK) {
+ return error_;
+ }
+ if (!params || !key_data) {
+ return KM_ERROR_UNEXPECTED_NULL_POINTER;
+ }
+ if (!key_blob) {
+ return KM_ERROR_OUTPUT_PARAMETER_NULL;
+ }
ImportKeyRequest request(message_version_);
- StoreNewKeyParams(&request.key_description);
- keymaster_algorithm_t algorithm;
- keymaster_error_t err = GetPkcs8KeyAlgorithm(key, key_length, &algorithm);
- if (err != KM_ERROR_OK)
- return err;
- request.key_description.push_back(TAG_ALGORITHM, algorithm);
+ request.key_description.Reinitialize(*params);
+ request.key_description.push_back(TAG_CREATION_DATETIME, java_time(time(NULL)));
- request.SetKeyMaterial(key, key_length);
- request.key_format = KM_KEY_FORMAT_PKCS8;
+ request.key_format = key_format;
+ request.SetKeyMaterial(key_data->data, key_data->data_length);
+
ImportKeyResponse response(message_version_);
- err = Send(request, &response);
- if (err != KM_ERROR_OK)
+ keymaster_error_t err = Send(KM_IMPORT_KEY, request, &response);
+ if (err != KM_ERROR_OK) {
return err;
+ }
- *key_blob_length = response.key_blob.key_material_size;
- *key_blob = static_cast<uint8_t*>(malloc(*key_blob_length));
- memcpy(*key_blob, response.key_blob.key_material, *key_blob_length);
- printf("Returning %d bytes in key blob\n", (int)*key_blob_length);
+ key_blob->key_material_size = response.key_blob.key_material_size;
+ key_blob->key_material =
+ DuplicateBuffer(response.key_blob.key_material, response.key_blob.key_material_size);
+ if (!key_blob->key_material) {
+ return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+ }
+
+ if (characteristics) {
+ response.enforced.CopyToParamSet(&characteristics->hw_enforced);
+ response.unenforced.CopyToParamSet(&characteristics->sw_enforced);
+ }
return KM_ERROR_OK;
}
-keymaster_error_t TrustyKeymasterDevice::GetPkcs8KeyAlgorithm(const uint8_t* key, size_t key_length,
- keymaster_algorithm_t* algorithm) {
- if (key == NULL) {
- ALOGE("No key specified for import");
+keymaster_error_t TrustyKeymasterDevice::export_key(keymaster_key_format_t export_format,
+ const keymaster_key_blob_t* key_to_export,
+ const keymaster_blob_t* client_id,
+ const keymaster_blob_t* app_data,
+ keymaster_blob_t* export_data) {
+ ALOGD("Device received export_key");
+
+ if (error_ != KM_ERROR_OK) {
+ return error_;
+ }
+ if (!key_to_export || !key_to_export->key_material) {
return KM_ERROR_UNEXPECTED_NULL_POINTER;
}
-
- UniquePtr<PKCS8_PRIV_KEY_INFO, PKCS8_PRIV_KEY_INFO_Delete> pkcs8(
- d2i_PKCS8_PRIV_KEY_INFO(NULL, &key, key_length));
- if (pkcs8.get() == NULL) {
- ALOGE("Could not parse PKCS8 key blob");
- return KM_ERROR_INVALID_KEY_BLOB;
+ if (!export_data) {
+ return KM_ERROR_OUTPUT_PARAMETER_NULL;
}
- UniquePtr<EVP_PKEY, EVP_PKEY_Delete> pkey(EVP_PKCS82PKEY(pkcs8.get()));
- if (pkey.get() == NULL) {
- ALOGE("Could not extract key from PKCS8 key blob");
- return KM_ERROR_INVALID_KEY_BLOB;
- }
-
- switch (EVP_PKEY_type(pkey->type)) {
- case EVP_PKEY_RSA:
- *algorithm = KM_ALGORITHM_RSA;
- break;
- case EVP_PKEY_EC:
- *algorithm = KM_ALGORITHM_EC;
- break;
- default:
- ALOGE("Unsupported algorithm %d", EVP_PKEY_type(pkey->type));
- return KM_ERROR_UNSUPPORTED_ALGORITHM;
- }
-
- return KM_ERROR_OK;
-}
-
-int TrustyKeymasterDevice::get_keypair_public(const uint8_t* key_blob, const size_t key_blob_length,
- uint8_t** x509_data, size_t* x509_data_length) {
- ALOGD("Device received get_keypair_public");
- if (error_ != KM_ERROR_OK)
- return error_;
+ export_data->data = nullptr;
+ export_data->data_length = 0;
ExportKeyRequest request(message_version_);
- request.SetKeyMaterial(key_blob, key_blob_length);
- request.key_format = KM_KEY_FORMAT_X509;
+ request.key_format = export_format;
+ request.SetKeyMaterial(*key_to_export);
+ AddClientAndAppData(client_id, app_data, &request);
+
ExportKeyResponse response(message_version_);
- keymaster_error_t err = Send(request, &response);
- if (err != KM_ERROR_OK)
+ keymaster_error_t err = Send(KM_EXPORT_KEY, request, &response);
+ if (err != KM_ERROR_OK) {
return err;
+ }
- *x509_data_length = response.key_data_length;
- *x509_data = static_cast<uint8_t*>(malloc(*x509_data_length));
- memcpy(*x509_data, response.key_data, *x509_data_length);
- printf("Returning %d bytes in x509 key\n", (int)*x509_data_length);
+ export_data->data_length = response.key_data_length;
+ export_data->data = DuplicateBuffer(response.key_data, response.key_data_length);
+ if (!export_data->data) {
+ return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+ }
return KM_ERROR_OK;
}
-int TrustyKeymasterDevice::sign_data(const void* signing_params, const uint8_t* key_blob,
- const size_t key_blob_length, const uint8_t* data,
- const size_t data_length, uint8_t** signed_data,
- size_t* signed_data_length) {
- ALOGD("Device received sign_data, %d", error_);
- if (error_ != KM_ERROR_OK)
+keymaster_error_t TrustyKeymasterDevice::attest_key(const keymaster_key_blob_t* key_to_attest,
+ const keymaster_key_param_set_t* attest_params,
+ keymaster_cert_chain_t* cert_chain) {
+ ALOGD("Device received attest_key");
+
+ if (error_ != KM_ERROR_OK) {
return error_;
+ }
+ if (!key_to_attest || !attest_params) {
+ return KM_ERROR_UNEXPECTED_NULL_POINTER;
+ }
+ if (!cert_chain) {
+ return KM_ERROR_OUTPUT_PARAMETER_NULL;
+ }
- BeginOperationRequest begin_request(message_version_);
- begin_request.purpose = KM_PURPOSE_SIGN;
- begin_request.SetKeyMaterial(key_blob, key_blob_length);
- keymaster_error_t err = StoreSigningParams(signing_params, key_blob, key_blob_length,
- &begin_request.additional_params);
+ cert_chain->entry_count = 0;
+ cert_chain->entries = nullptr;
+
+ AttestKeyRequest request;
+ request.SetKeyMaterial(*key_to_attest);
+ request.attest_params.Reinitialize(*attest_params);
+
+ keymaster_blob_t attestation_challenge = {};
+ request.attest_params.GetTagValue(TAG_ATTESTATION_CHALLENGE, &attestation_challenge);
+ if (attestation_challenge.data_length > kMaximumAttestationChallengeLength) {
+ ALOGE("%zu-byte attestation challenge; only %zu bytes allowed",
+ attestation_challenge.data_length, kMaximumAttestationChallengeLength);
+ return KM_ERROR_INVALID_INPUT_LENGTH;
+ }
+
+ AttestKeyResponse response;
+ keymaster_error_t err = Send(KM_ATTEST_KEY, request, &response);
if (err != KM_ERROR_OK) {
- ALOGE("Error extracting signing params: %d", err);
return err;
}
- BeginOperationResponse begin_response(message_version_);
- ALOGD("Sending signing request begin");
- err = Send(begin_request, &begin_response);
- if (err != KM_ERROR_OK) {
- ALOGE("Error sending sign begin: %d", err);
- return err;
+ // Allocate and clear storage for cert_chain.
+ keymaster_cert_chain_t& rsp_chain = response.certificate_chain;
+ cert_chain->entries = reinterpret_cast<keymaster_blob_t*>(
+ malloc(rsp_chain.entry_count * sizeof(*cert_chain->entries)));
+ if (!cert_chain->entries) {
+ return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+ }
+ cert_chain->entry_count = rsp_chain.entry_count;
+ for (keymaster_blob_t& entry : array_range(cert_chain->entries, cert_chain->entry_count)) {
+ entry = {};
}
- UpdateOperationRequest update_request(message_version_);
- update_request.op_handle = begin_response.op_handle;
- update_request.input.Reinitialize(data, data_length);
- UpdateOperationResponse update_response(message_version_);
- ALOGD("Sending signing request update");
- err = Send(update_request, &update_response);
- if (err != KM_ERROR_OK) {
- ALOGE("Error sending sign update: %d", err);
- return err;
+ // Copy cert_chain contents
+ size_t i = 0;
+ for (keymaster_blob_t& entry : array_range(rsp_chain.entries, rsp_chain.entry_count)) {
+ cert_chain->entries[i].data = DuplicateBuffer(entry.data, entry.data_length);
+ if (!cert_chain->entries[i].data) {
+ keymaster_free_cert_chain(cert_chain);
+ return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+ }
+ cert_chain->entries[i].data_length = entry.data_length;
+ ++i;
}
- FinishOperationRequest finish_request(message_version_);
- finish_request.op_handle = begin_response.op_handle;
- FinishOperationResponse finish_response(message_version_);
- ALOGD("Sending signing request finish");
- err = Send(finish_request, &finish_response);
- if (err != KM_ERROR_OK) {
- ALOGE("Error sending sign finish: %d", err);
- return err;
- }
-
- *signed_data_length = finish_response.output.available_read();
- *signed_data = static_cast<uint8_t*>(malloc(*signed_data_length));
- if (!finish_response.output.read(*signed_data, *signed_data_length)) {
- ALOGE("Error reading response data: %d", err);
- return KM_ERROR_UNKNOWN_ERROR;
- }
return KM_ERROR_OK;
}
-int TrustyKeymasterDevice::verify_data(const void* signing_params, const uint8_t* key_blob,
- const size_t key_blob_length, const uint8_t* signed_data,
- const size_t signed_data_length, const uint8_t* signature,
- const size_t signature_length) {
- ALOGD("Device received verify_data");
- if (error_ != KM_ERROR_OK)
+keymaster_error_t TrustyKeymasterDevice::upgrade_key(const keymaster_key_blob_t* key_to_upgrade,
+ const keymaster_key_param_set_t* upgrade_params,
+ keymaster_key_blob_t* upgraded_key) {
+ ALOGD("Device received upgrade_key");
+
+ if (error_ != KM_ERROR_OK) {
return error_;
+ }
+ if (!key_to_upgrade || !upgrade_params) {
+ return KM_ERROR_UNEXPECTED_NULL_POINTER;
+ }
+ if (!upgraded_key) {
+ return KM_ERROR_OUTPUT_PARAMETER_NULL;
+ }
- BeginOperationRequest begin_request(message_version_);
- begin_request.purpose = KM_PURPOSE_VERIFY;
- begin_request.SetKeyMaterial(key_blob, key_blob_length);
- keymaster_error_t err = StoreSigningParams(signing_params, key_blob, key_blob_length,
- &begin_request.additional_params);
- if (err != KM_ERROR_OK)
- return err;
+ UpgradeKeyRequest request;
+ request.SetKeyMaterial(*key_to_upgrade);
+ request.upgrade_params.Reinitialize(*upgrade_params);
- BeginOperationResponse begin_response(message_version_);
- err = Send(begin_request, &begin_response);
- if (err != KM_ERROR_OK)
+ UpgradeKeyResponse response;
+ keymaster_error_t err = Send(KM_UPGRADE_KEY, request, &response);
+ if (err != KM_ERROR_OK) {
return err;
+ }
- UpdateOperationRequest update_request(message_version_);
- update_request.op_handle = begin_response.op_handle;
- update_request.input.Reinitialize(signed_data, signed_data_length);
- UpdateOperationResponse update_response(message_version_);
- err = Send(update_request, &update_response);
- if (err != KM_ERROR_OK)
- return err;
+ upgraded_key->key_material_size = response.upgraded_key.key_material_size;
+ upgraded_key->key_material = DuplicateBuffer(response.upgraded_key.key_material,
+ response.upgraded_key.key_material_size);
+ if (!upgraded_key->key_material) {
+ return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+ }
- FinishOperationRequest finish_request(message_version_);
- finish_request.op_handle = begin_response.op_handle;
- finish_request.signature.Reinitialize(signature, signature_length);
- FinishOperationResponse finish_response(message_version_);
- err = Send(finish_request, &finish_response);
- if (err != KM_ERROR_OK)
- return err;
return KM_ERROR_OK;
}
+keymaster_error_t TrustyKeymasterDevice::begin(keymaster_purpose_t purpose,
+ const keymaster_key_blob_t* key,
+ const keymaster_key_param_set_t* in_params,
+ keymaster_key_param_set_t* out_params,
+ keymaster_operation_handle_t* operation_handle) {
+ ALOGD("Device received begin");
+
+ if (error_ != KM_ERROR_OK) {
+ return error_;
+ }
+ if (!key || !key->key_material) {
+ return KM_ERROR_UNEXPECTED_NULL_POINTER;
+ }
+ if (!operation_handle) {
+ return KM_ERROR_OUTPUT_PARAMETER_NULL;
+ }
+
+ if (out_params) {
+ *out_params = {};
+ }
+
+ BeginOperationRequest request;
+ request.purpose = purpose;
+ request.SetKeyMaterial(*key);
+ request.additional_params.Reinitialize(*in_params);
+
+ BeginOperationResponse response;
+ keymaster_error_t err = Send(KM_BEGIN_OPERATION, request, &response);
+ if (err != KM_ERROR_OK) {
+ return err;
+ }
+
+ if (response.output_params.size() > 0) {
+ if (out_params) {
+ response.output_params.CopyToParamSet(out_params);
+ } else {
+ return KM_ERROR_OUTPUT_PARAMETER_NULL;
+ }
+ }
+ *operation_handle = response.op_handle;
+
+ return KM_ERROR_OK;
+}
+
+keymaster_error_t TrustyKeymasterDevice::update(keymaster_operation_handle_t operation_handle,
+ const keymaster_key_param_set_t* in_params,
+ const keymaster_blob_t* input,
+ size_t* input_consumed,
+ keymaster_key_param_set_t* out_params,
+ keymaster_blob_t* output) {
+ ALOGD("Device received update");
+
+ if (error_ != KM_ERROR_OK) {
+ return error_;
+ }
+ if (!input) {
+ return KM_ERROR_UNEXPECTED_NULL_POINTER;
+ }
+ if (!input_consumed) {
+ return KM_ERROR_OUTPUT_PARAMETER_NULL;
+ }
+
+ if (out_params) {
+ *out_params = {};
+ }
+ if (output) {
+ *output = {};
+ }
+
+ UpdateOperationRequest request;
+ request.op_handle = operation_handle;
+ if (in_params) {
+ request.additional_params.Reinitialize(*in_params);
+ }
+ if (input && input->data_length > 0) {
+ size_t max_input_size = SEND_BUF_SIZE - request.SerializedSize();
+ request.input.Reinitialize(input->data, std::min(input->data_length, max_input_size));
+ }
+
+ UpdateOperationResponse response;
+ keymaster_error_t err = Send(KM_UPDATE_OPERATION, request, &response);
+ if (err != KM_ERROR_OK) {
+ return err;
+ }
+
+ if (response.output_params.size() > 0) {
+ if (out_params) {
+ response.output_params.CopyToParamSet(out_params);
+ } else {
+ return KM_ERROR_OUTPUT_PARAMETER_NULL;
+ }
+ }
+ *input_consumed = response.input_consumed;
+ if (output) {
+ output->data_length = response.output.available_read();
+ output->data = DuplicateBuffer(response.output.peek_read(), output->data_length);
+ if (!output->data) {
+ return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+ }
+ } else if (response.output.available_read() > 0) {
+ return KM_ERROR_OUTPUT_PARAMETER_NULL;
+ }
+
+ return KM_ERROR_OK;
+}
+
+keymaster_error_t TrustyKeymasterDevice::finish(keymaster_operation_handle_t operation_handle,
+ const keymaster_key_param_set_t* in_params,
+ const keymaster_blob_t* input,
+ const keymaster_blob_t* signature,
+ keymaster_key_param_set_t* out_params,
+ keymaster_blob_t* output) {
+ ALOGD("Device received finish");
+
+ if (error_ != KM_ERROR_OK) {
+ return error_;
+ }
+ if (input && input->data_length > kMaximumFinishInputLength) {
+ return KM_ERROR_INVALID_ARGUMENT;
+ }
+
+ if (out_params) {
+ *out_params = {};
+ }
+ if (output) {
+ *output = {};
+ }
+
+ FinishOperationRequest request;
+ request.op_handle = operation_handle;
+ if (signature && signature->data && signature->data_length > 0) {
+ request.signature.Reinitialize(signature->data, signature->data_length);
+ }
+ if (input && input->data && input->data_length) {
+ request.input.Reinitialize(input->data, input->data_length);
+ }
+ if (in_params) {
+ request.additional_params.Reinitialize(*in_params);
+ }
+
+ FinishOperationResponse response;
+ keymaster_error_t err = Send(KM_FINISH_OPERATION, request, &response);
+ if (err != KM_ERROR_OK) {
+ return err;
+ }
+
+ if (response.output_params.size() > 0) {
+ if (out_params) {
+ response.output_params.CopyToParamSet(out_params);
+ } else {
+ return KM_ERROR_OUTPUT_PARAMETER_NULL;
+ }
+ }
+ if (output) {
+ output->data_length = response.output.available_read();
+ output->data = DuplicateBuffer(response.output.peek_read(), output->data_length);
+ if (!output->data) {
+ return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+ }
+ } else if (response.output.available_read() > 0) {
+ return KM_ERROR_OUTPUT_PARAMETER_NULL;
+ }
+
+ return KM_ERROR_OK;
+}
+
+keymaster_error_t TrustyKeymasterDevice::abort(keymaster_operation_handle_t operation_handle) {
+ ALOGD("Device received abort");
+
+ if (error_ != KM_ERROR_OK) {
+ return error_;
+ }
+
+ AbortOperationRequest request;
+ request.op_handle = operation_handle;
+ AbortOperationResponse response;
+ return Send(KM_ABORT_OPERATION, request, &response);
+}
+
hw_device_t* TrustyKeymasterDevice::hw_device() {
return &device_.common;
}
-static inline TrustyKeymasterDevice* convert_device(const keymaster0_device_t* dev) {
- return reinterpret_cast<TrustyKeymasterDevice*>(const_cast<keymaster0_device_t*>(dev));
+static inline TrustyKeymasterDevice* convert_device(const keymaster2_device_t* dev) {
+ return reinterpret_cast<TrustyKeymasterDevice*>(const_cast<keymaster2_device_t*>(dev));
}
/* static */
@@ -394,52 +652,111 @@
}
/* static */
-int TrustyKeymasterDevice::generate_keypair(const keymaster0_device_t* dev,
- const keymaster_keypair_t key_type,
- const void* key_params, uint8_t** keyBlob,
- size_t* keyBlobLength) {
- ALOGD("Generate keypair, sending to device: %p", convert_device(dev));
- return convert_device(dev)->generate_keypair(key_type, key_params, keyBlob, keyBlobLength);
+keymaster_error_t TrustyKeymasterDevice::configure(const keymaster2_device_t* dev,
+ const keymaster_key_param_set_t* params) {
+ return convert_device(dev)->configure(params);
}
/* static */
-int TrustyKeymasterDevice::import_keypair(const keymaster0_device_t* dev, const uint8_t* key,
- const size_t key_length, uint8_t** key_blob,
- size_t* key_blob_length) {
- return convert_device(dev)->import_keypair(key, key_length, key_blob, key_blob_length);
+keymaster_error_t TrustyKeymasterDevice::add_rng_entropy(const keymaster2_device_t* dev,
+ const uint8_t* data, size_t data_length) {
+ return convert_device(dev)->add_rng_entropy(data, data_length);
}
/* static */
-int TrustyKeymasterDevice::get_keypair_public(const keymaster0_device_t* dev,
- const uint8_t* key_blob, const size_t key_blob_length,
- uint8_t** x509_data, size_t* x509_data_length) {
- return convert_device(dev)
- ->get_keypair_public(key_blob, key_blob_length, x509_data, x509_data_length);
+keymaster_error_t TrustyKeymasterDevice::generate_key(
+ const keymaster2_device_t* dev, const keymaster_key_param_set_t* params,
+ keymaster_key_blob_t* key_blob, keymaster_key_characteristics_t* characteristics) {
+ return convert_device(dev)->generate_key(params, key_blob, characteristics);
}
/* static */
-int TrustyKeymasterDevice::sign_data(const keymaster0_device_t* dev, const void* params,
- const uint8_t* keyBlob, const size_t keyBlobLength,
- const uint8_t* data, const size_t dataLength,
- uint8_t** signedData, size_t* signedDataLength) {
- return convert_device(dev)
- ->sign_data(params, keyBlob, keyBlobLength, data, dataLength, signedData, signedDataLength);
+keymaster_error_t TrustyKeymasterDevice::get_key_characteristics(
+ const keymaster2_device_t* dev, const keymaster_key_blob_t* key_blob,
+ const keymaster_blob_t* client_id, const keymaster_blob_t* app_data,
+ keymaster_key_characteristics_t* characteristics) {
+ return convert_device(dev)->get_key_characteristics(key_blob, client_id, app_data,
+ characteristics);
}
/* static */
-int TrustyKeymasterDevice::verify_data(const keymaster0_device_t* dev, const void* params,
- const uint8_t* keyBlob, const size_t keyBlobLength,
- const uint8_t* signedData, const size_t signedDataLength,
- const uint8_t* signature, const size_t signatureLength) {
- return convert_device(dev)->verify_data(params, keyBlob, keyBlobLength, signedData,
- signedDataLength, signature, signatureLength);
+keymaster_error_t TrustyKeymasterDevice::import_key(
+ const keymaster2_device_t* dev, const keymaster_key_param_set_t* params,
+ keymaster_key_format_t key_format, const keymaster_blob_t* key_data,
+ keymaster_key_blob_t* key_blob, keymaster_key_characteristics_t* characteristics) {
+ return convert_device(dev)->import_key(params, key_format, key_data, key_blob, characteristics);
+}
+
+/* static */
+keymaster_error_t TrustyKeymasterDevice::export_key(const keymaster2_device_t* dev,
+ keymaster_key_format_t export_format,
+ const keymaster_key_blob_t* key_to_export,
+ const keymaster_blob_t* client_id,
+ const keymaster_blob_t* app_data,
+ keymaster_blob_t* export_data) {
+ return convert_device(dev)->export_key(export_format, key_to_export, client_id, app_data,
+ export_data);
+}
+
+/* static */
+keymaster_error_t TrustyKeymasterDevice::attest_key(const keymaster2_device_t* dev,
+ const keymaster_key_blob_t* key_to_attest,
+ const keymaster_key_param_set_t* attest_params,
+ keymaster_cert_chain_t* cert_chain) {
+ return convert_device(dev)->attest_key(key_to_attest, attest_params, cert_chain);
+}
+
+/* static */
+keymaster_error_t TrustyKeymasterDevice::upgrade_key(const keymaster2_device_t* dev,
+ const keymaster_key_blob_t* key_to_upgrade,
+ const keymaster_key_param_set_t* upgrade_params,
+ keymaster_key_blob_t* upgraded_key) {
+ return convert_device(dev)->upgrade_key(key_to_upgrade, upgrade_params, upgraded_key);
+}
+
+/* static */
+keymaster_error_t TrustyKeymasterDevice::begin(const keymaster2_device_t* dev,
+ keymaster_purpose_t purpose,
+ const keymaster_key_blob_t* key,
+ const keymaster_key_param_set_t* in_params,
+ keymaster_key_param_set_t* out_params,
+ keymaster_operation_handle_t* operation_handle) {
+ return convert_device(dev)->begin(purpose, key, in_params, out_params, operation_handle);
+}
+
+/* static */
+keymaster_error_t TrustyKeymasterDevice::update(
+ const keymaster2_device_t* dev, keymaster_operation_handle_t operation_handle,
+ const keymaster_key_param_set_t* in_params, const keymaster_blob_t* input,
+ size_t* input_consumed, keymaster_key_param_set_t* out_params, keymaster_blob_t* output) {
+ return convert_device(dev)->update(operation_handle, in_params, input, input_consumed,
+ out_params, output);
+}
+
+/* static */
+keymaster_error_t TrustyKeymasterDevice::finish(const keymaster2_device_t* dev,
+ keymaster_operation_handle_t operation_handle,
+ const keymaster_key_param_set_t* in_params,
+ const keymaster_blob_t* input,
+ const keymaster_blob_t* signature,
+ keymaster_key_param_set_t* out_params,
+ keymaster_blob_t* output) {
+ return convert_device(dev)->finish(operation_handle, in_params, input, signature, out_params,
+ output);
+}
+
+/* static */
+keymaster_error_t TrustyKeymasterDevice::abort(const keymaster2_device_t* dev,
+ keymaster_operation_handle_t operation_handle) {
+ return convert_device(dev)->abort(operation_handle);
}
keymaster_error_t TrustyKeymasterDevice::Send(uint32_t command, const Serializable& req,
KeymasterResponse* rsp) {
uint32_t req_size = req.SerializedSize();
- if (req_size > SEND_BUF_SIZE)
+ if (req_size > SEND_BUF_SIZE) {
return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+ }
uint8_t send_buf[SEND_BUF_SIZE];
Eraser send_buf_eraser(send_buf, SEND_BUF_SIZE);
req.Serialize(send_buf, send_buf + req_size);
@@ -448,7 +765,7 @@
uint8_t recv_buf[RECV_BUF_SIZE];
Eraser recv_buf_eraser(recv_buf, RECV_BUF_SIZE);
uint32_t rsp_size = RECV_BUF_SIZE;
- printf("Sending %d byte request\n", (int)req.SerializedSize());
+ ALOGV("Sending %d byte request\n", (int)req.SerializedSize());
int rc = trusty_keymaster_call(command, send_buf, req_size, recv_buf, &rsp_size);
if (rc < 0) {
ALOGE("tipc error: %d\n", rc);
@@ -458,8 +775,8 @@
ALOGV("Received %d byte response\n", rsp_size);
}
- const keymaster_message* msg = (keymaster_message *) recv_buf;
- const uint8_t *p = msg->payload;
+ const keymaster_message* msg = (keymaster_message*)recv_buf;
+ const uint8_t* p = msg->payload;
if (!rsp->Deserialize(&p, p + rsp_size)) {
ALOGE("Error deserializing response of size %d\n", (int)rsp_size);
return KM_ERROR_UNKNOWN_ERROR;
@@ -470,65 +787,4 @@
return rsp->error;
}
-keymaster_error_t TrustyKeymasterDevice::StoreSigningParams(const void* signing_params,
- const uint8_t* key_blob,
- size_t key_blob_length,
- AuthorizationSet* auth_set) {
- uint8_t* pub_key_data;
- size_t pub_key_data_length;
- int err = get_keypair_public(&device_, key_blob, key_blob_length, &pub_key_data,
- &pub_key_data_length);
- if (err < 0) {
- ALOGE("Error %d extracting public key to determine algorithm", err);
- return KM_ERROR_INVALID_KEY_BLOB;
- }
- UniquePtr<uint8_t, Malloc_Delete> pub_key(pub_key_data);
-
- const uint8_t* p = pub_key_data;
- UniquePtr<EVP_PKEY, EVP_PKEY_Delete> pkey(
- d2i_PUBKEY(nullptr /* allocate new struct */, &p, pub_key_data_length));
-
- switch (EVP_PKEY_type(pkey->type)) {
- case EVP_PKEY_RSA: {
- const keymaster_rsa_sign_params_t* rsa_params =
- reinterpret_cast<const keymaster_rsa_sign_params_t*>(signing_params);
- if (rsa_params->digest_type != DIGEST_NONE)
- return KM_ERROR_UNSUPPORTED_DIGEST;
- if (rsa_params->padding_type != PADDING_NONE)
- return KM_ERROR_UNSUPPORTED_PADDING_MODE;
- if (!auth_set->push_back(TAG_DIGEST, KM_DIGEST_NONE) ||
- !auth_set->push_back(TAG_PADDING, KM_PAD_NONE))
- return KM_ERROR_MEMORY_ALLOCATION_FAILED;
- } break;
- case EVP_PKEY_EC: {
- const keymaster_ec_sign_params_t* ecdsa_params =
- reinterpret_cast<const keymaster_ec_sign_params_t*>(signing_params);
- if (ecdsa_params->digest_type != DIGEST_NONE)
- return KM_ERROR_UNSUPPORTED_DIGEST;
- if (!auth_set->push_back(TAG_DIGEST, KM_DIGEST_NONE))
- return KM_ERROR_MEMORY_ALLOCATION_FAILED;
- } break;
- default:
- return KM_ERROR_UNSUPPORTED_ALGORITHM;
- }
- return KM_ERROR_OK;
-}
-
-void TrustyKeymasterDevice::StoreNewKeyParams(AuthorizationSet* auth_set) {
- auth_set->push_back(TAG_PURPOSE, KM_PURPOSE_SIGN);
- auth_set->push_back(TAG_PURPOSE, KM_PURPOSE_VERIFY);
- auth_set->push_back(TAG_ALL_USERS);
- auth_set->push_back(TAG_NO_AUTH_REQUIRED);
- uint64_t now = java_time(time(NULL));
- auth_set->push_back(TAG_CREATION_DATETIME, now);
- auth_set->push_back(TAG_ORIGINATION_EXPIRE_DATETIME, now + HUNDRED_YEARS);
- if (message_version_ == 0) {
- auth_set->push_back(TAG_DIGEST_OLD, KM_DIGEST_NONE);
- auth_set->push_back(TAG_PADDING_OLD, KM_PAD_NONE);
- } else {
- auth_set->push_back(TAG_DIGEST, KM_DIGEST_NONE);
- auth_set->push_back(TAG_PADDING, KM_PAD_NONE);
- }
-}
-
} // namespace keymaster
diff --git a/trusty/keymaster/trusty_keymaster_device.h b/trusty/keymaster/trusty_keymaster_device.h
index 68cf40c..cfada1b 100644
--- a/trusty/keymaster/trusty_keymaster_device.h
+++ b/trusty/keymaster/trusty_keymaster_device.h
@@ -14,19 +14,16 @@
* limitations under the License.
*/
-#ifndef EXTERNAL_KEYMASTER_TRUSTY_KEYMASTER_DEVICE_H_
-#define EXTERNAL_KEYMASTER_TRUSTY_KEYMASTER_DEVICE_H_
+#ifndef TRUSTY_KEYMASTER_TRUSTY_KEYMASTER_DEVICE_H_
+#define TRUSTY_KEYMASTER_TRUSTY_KEYMASTER_DEVICE_H_
-#include <hardware/keymaster0.h>
-
+#include <hardware/keymaster2.h>
#include <keymaster/android_keymaster_messages.h>
-#include "keymaster_ipc.h"
-
namespace keymaster {
/**
- * Software OpenSSL-based Keymaster device.
+ * Trusty Keymaster device.
*
* IMPORTANT MAINTAINER NOTE: Pointers to instances of this class must be castable to hw_device_t
* and keymaster_device. This means it must remain a standard layout class (no virtual functions and
@@ -46,79 +43,111 @@
keymaster_error_t session_error() { return error_; }
- int generate_keypair(const keymaster_keypair_t key_type, const void* key_params,
- uint8_t** key_blob, size_t* key_blob_length);
- int import_keypair(const uint8_t* key, const size_t key_length, uint8_t** key_blob,
- size_t* key_blob_length);
- int get_keypair_public(const uint8_t* key_blob, const size_t key_blob_length,
- uint8_t** x509_data, size_t* x509_data_length);
- int sign_data(const void* signing_params, const uint8_t* key_blob, const size_t key_blob_length,
- const uint8_t* data, const size_t data_length, uint8_t** signed_data,
- size_t* signed_data_length);
- int verify_data(const void* signing_params, const uint8_t* key_blob,
- const size_t key_blob_length, const uint8_t* signed_data,
- const size_t signed_data_length, const uint8_t* signature,
- const size_t signature_length);
+ keymaster_error_t configure(const keymaster_key_param_set_t* params);
+ keymaster_error_t add_rng_entropy(const uint8_t* data, size_t data_length);
+ keymaster_error_t generate_key(const keymaster_key_param_set_t* params,
+ keymaster_key_blob_t* key_blob,
+ keymaster_key_characteristics_t* characteristics);
+ keymaster_error_t get_key_characteristics(const keymaster_key_blob_t* key_blob,
+ const keymaster_blob_t* client_id,
+ const keymaster_blob_t* app_data,
+ keymaster_key_characteristics_t* character);
+ keymaster_error_t import_key(const keymaster_key_param_set_t* params,
+ keymaster_key_format_t key_format,
+ const keymaster_blob_t* key_data, keymaster_key_blob_t* key_blob,
+ keymaster_key_characteristics_t* characteristics);
+ keymaster_error_t export_key(keymaster_key_format_t export_format,
+ const keymaster_key_blob_t* key_to_export,
+ const keymaster_blob_t* client_id,
+ const keymaster_blob_t* app_data, keymaster_blob_t* export_data);
+ keymaster_error_t attest_key(const keymaster_key_blob_t* key_to_attest,
+ const keymaster_key_param_set_t* attest_params,
+ keymaster_cert_chain_t* cert_chain);
+ keymaster_error_t upgrade_key(const keymaster_key_blob_t* key_to_upgrade,
+ const keymaster_key_param_set_t* upgrade_params,
+ keymaster_key_blob_t* upgraded_key);
+ keymaster_error_t begin(keymaster_purpose_t purpose, const keymaster_key_blob_t* key,
+ const keymaster_key_param_set_t* in_params,
+ keymaster_key_param_set_t* out_params,
+ keymaster_operation_handle_t* operation_handle);
+ keymaster_error_t update(keymaster_operation_handle_t operation_handle,
+ const keymaster_key_param_set_t* in_params,
+ const keymaster_blob_t* input, size_t* input_consumed,
+ keymaster_key_param_set_t* out_params, keymaster_blob_t* output);
+ keymaster_error_t finish(keymaster_operation_handle_t operation_handle,
+ const keymaster_key_param_set_t* in_params,
+ const keymaster_blob_t* input, const keymaster_blob_t* signature,
+ keymaster_key_param_set_t* out_params, keymaster_blob_t* output);
+ keymaster_error_t abort(keymaster_operation_handle_t operation_handle);
private:
keymaster_error_t Send(uint32_t command, const Serializable& request,
KeymasterResponse* response);
- keymaster_error_t Send(const GenerateKeyRequest& request, GenerateKeyResponse* response) {
- return Send(KM_GENERATE_KEY, request, response);
- }
- keymaster_error_t Send(const BeginOperationRequest& request, BeginOperationResponse* response) {
- return Send(KM_BEGIN_OPERATION, request, response);
- }
- keymaster_error_t Send(const UpdateOperationRequest& request,
- UpdateOperationResponse* response) {
- return Send(KM_UPDATE_OPERATION, request, response);
- }
- keymaster_error_t Send(const FinishOperationRequest& request,
- FinishOperationResponse* response) {
- return Send(KM_FINISH_OPERATION, request, response);
- }
- keymaster_error_t Send(const ImportKeyRequest& request, ImportKeyResponse* response) {
- return Send(KM_IMPORT_KEY, request, response);
- }
- keymaster_error_t Send(const ExportKeyRequest& request, ExportKeyResponse* response) {
- return Send(KM_EXPORT_KEY, request, response);
- }
- keymaster_error_t Send(const GetVersionRequest& request, GetVersionResponse* response) {
- return Send(KM_GET_VERSION, request, response);
- }
-
- keymaster_error_t StoreSigningParams(const void* signing_params, const uint8_t* key_blob,
- size_t key_blob_length, AuthorizationSet* auth_set);
- void StoreNewKeyParams(AuthorizationSet* auth_set);
- keymaster_error_t GetPkcs8KeyAlgorithm(const uint8_t* key, size_t key_length,
- keymaster_algorithm_t* algorithm);
/*
* These static methods are the functions referenced through the function pointers in
* keymaster_device. They're all trivial wrappers.
*/
static int close_device(hw_device_t* dev);
- static int generate_keypair(const keymaster0_device_t* dev, const keymaster_keypair_t key_type,
- const void* key_params, uint8_t** keyBlob, size_t* keyBlobLength);
- static int import_keypair(const keymaster0_device_t* dev, const uint8_t* key,
- const size_t key_length, uint8_t** key_blob, size_t* key_blob_length);
- static int get_keypair_public(const keymaster0_device_t* dev, const uint8_t* key_blob,
- const size_t key_blob_length, uint8_t** x509_data,
- size_t* x509_data_length);
- static int sign_data(const keymaster0_device_t* dev, const void* signing_params,
- const uint8_t* key_blob, const size_t key_blob_length, const uint8_t* data,
- const size_t data_length, uint8_t** signed_data,
- size_t* signed_data_length);
- static int verify_data(const keymaster0_device_t* dev, const void* signing_params,
- const uint8_t* key_blob, const size_t key_blob_length,
- const uint8_t* signed_data, const size_t signed_data_length,
- const uint8_t* signature, const size_t signature_length);
+ static keymaster_error_t configure(const keymaster2_device_t* dev,
+ const keymaster_key_param_set_t* params);
+ static keymaster_error_t add_rng_entropy(const keymaster2_device_t* dev, const uint8_t* data,
+ size_t data_length);
+ static keymaster_error_t generate_key(const keymaster2_device_t* dev,
+ const keymaster_key_param_set_t* params,
+ keymaster_key_blob_t* key_blob,
+ keymaster_key_characteristics_t* characteristics);
+ static keymaster_error_t get_key_characteristics(const keymaster2_device_t* dev,
+ const keymaster_key_blob_t* key_blob,
+ const keymaster_blob_t* client_id,
+ const keymaster_blob_t* app_data,
+ keymaster_key_characteristics_t* character);
+ static keymaster_error_t import_key(const keymaster2_device_t* dev,
+ const keymaster_key_param_set_t* params,
+ keymaster_key_format_t key_format,
+ const keymaster_blob_t* key_data,
+ keymaster_key_blob_t* key_blob,
+ keymaster_key_characteristics_t* characteristics);
+ static keymaster_error_t export_key(const keymaster2_device_t* dev,
+ keymaster_key_format_t export_format,
+ const keymaster_key_blob_t* key_to_export,
+ const keymaster_blob_t* client_id,
+ const keymaster_blob_t* app_data,
+ keymaster_blob_t* export_data);
+ static keymaster_error_t attest_key(const keymaster2_device_t* dev,
+ const keymaster_key_blob_t* key_to_attest,
+ const keymaster_key_param_set_t* attest_params,
+ keymaster_cert_chain_t* cert_chain);
+ static keymaster_error_t upgrade_key(const keymaster2_device_t* dev,
+ const keymaster_key_blob_t* key_to_upgrade,
+ const keymaster_key_param_set_t* upgrade_params,
+ keymaster_key_blob_t* upgraded_key);
+ static keymaster_error_t delete_key(const keymaster2_device_t* dev,
+ const keymaster_key_blob_t* key);
+ static keymaster_error_t delete_all_keys(const keymaster2_device_t* dev);
+ static keymaster_error_t begin(const keymaster2_device_t* dev, keymaster_purpose_t purpose,
+ const keymaster_key_blob_t* key,
+ const keymaster_key_param_set_t* in_params,
+ keymaster_key_param_set_t* out_params,
+ keymaster_operation_handle_t* operation_handle);
+ static keymaster_error_t update(const keymaster2_device_t* dev,
+ keymaster_operation_handle_t operation_handle,
+ const keymaster_key_param_set_t* in_params,
+ const keymaster_blob_t* input, size_t* input_consumed,
+ keymaster_key_param_set_t* out_params, keymaster_blob_t* output);
+ static keymaster_error_t finish(const keymaster2_device_t* dev,
+ keymaster_operation_handle_t operation_handle,
+ const keymaster_key_param_set_t* in_params,
+ const keymaster_blob_t* input, const keymaster_blob_t* signature,
+ keymaster_key_param_set_t* out_params, keymaster_blob_t* output);
+ static keymaster_error_t abort(const keymaster2_device_t* dev,
+ keymaster_operation_handle_t operation_handle);
- keymaster0_device_t device_;
+ keymaster2_device_t device_;
keymaster_error_t error_;
int32_t message_version_;
};
} // namespace keymaster
-#endif // EXTERNAL_KEYMASTER_TRUSTY_KEYMASTER_DEVICE_H_
+#endif // TRUSTY_KEYMASTER_TRUSTY_KEYMASTER_DEVICE_H_
diff --git a/trusty/keymaster/trusty_keymaster_ipc.c b/trusty/keymaster/trusty_keymaster_ipc.cpp
similarity index 75%
rename from trusty/keymaster/trusty_keymaster_ipc.c
rename to trusty/keymaster/trusty_keymaster_ipc.cpp
index 88546af..cdc2778 100644
--- a/trusty/keymaster/trusty_keymaster_ipc.c
+++ b/trusty/keymaster/trusty_keymaster_ipc.cpp
@@ -26,8 +26,8 @@
#include <log/log.h>
#include <trusty/tipc.h>
-#include "trusty_keymaster_ipc.h"
#include "keymaster_ipc.h"
+#include "trusty_keymaster_ipc.h"
#define TRUSTY_DEVICE_NAME "/dev/trusty-ipc-dev0"
@@ -43,15 +43,15 @@
return 0;
}
-int trusty_keymaster_call(uint32_t cmd, void *in, uint32_t in_size, uint8_t *out,
- uint32_t *out_size) {
+int trusty_keymaster_call(uint32_t cmd, void* in, uint32_t in_size, uint8_t* out,
+ uint32_t* out_size) {
if (handle_ == 0) {
ALOGE("not connected\n");
return -EINVAL;
}
size_t msg_size = in_size + sizeof(struct keymaster_message);
- struct keymaster_message *msg = malloc(msg_size);
+ struct keymaster_message* msg = reinterpret_cast<struct keymaster_message*>(malloc(msg_size));
msg->cmd = cmd;
memcpy(msg->payload, in, in_size);
@@ -59,31 +59,30 @@
free(msg);
if (rc < 0) {
- ALOGE("failed to send cmd (%d) to %s: %s\n", cmd,
- KEYMASTER_PORT, strerror(errno));
+ ALOGE("failed to send cmd (%d) to %s: %s\n", cmd, KEYMASTER_PORT, strerror(errno));
return -errno;
}
rc = read(handle_, out, *out_size);
if (rc < 0) {
- ALOGE("failed to retrieve response for cmd (%d) to %s: %s\n",
- cmd, KEYMASTER_PORT, strerror(errno));
+ ALOGE("failed to retrieve response for cmd (%d) to %s: %s\n", cmd, KEYMASTER_PORT,
+ strerror(errno));
return -errno;
}
- if ((size_t) rc < sizeof(struct keymaster_message)) {
- ALOGE("invalid response size (%d)\n", (int) rc);
+ if ((size_t)rc < sizeof(struct keymaster_message)) {
+ ALOGE("invalid response size (%d)\n", (int)rc);
return -EINVAL;
}
- msg = (struct keymaster_message *) out;
+ msg = (struct keymaster_message*)out;
if ((cmd | KEYMASTER_RESP_BIT) != msg->cmd) {
ALOGE("invalid command (%d)", msg->cmd);
return -EINVAL;
}
- *out_size = ((size_t) rc) - sizeof(struct keymaster_message);
+ *out_size = ((size_t)rc) - sizeof(struct keymaster_message);
return rc;
}
@@ -92,4 +91,3 @@
tipc_close(handle_);
}
}
-
diff --git a/trusty/keymaster/trusty_keymaster_ipc.h b/trusty/keymaster/trusty_keymaster_ipc.h
index 9785247..c15f7c1 100644
--- a/trusty/keymaster/trusty_keymaster_ipc.h
+++ b/trusty/keymaster/trusty_keymaster_ipc.h
@@ -14,11 +14,16 @@
* limitations under the License.
*/
+#ifndef TRUSTY_KEYMASTER_TRUSTY_KEYMASTER_IPC_H_
+#define TRUSTY_KEYMASTER_TRUSTY_KEYMASTER_IPC_H_
+
__BEGIN_DECLS
int trusty_keymaster_connect(void);
-int trusty_keymaster_call(uint32_t cmd, void *in, uint32_t in_size, uint8_t *out,
- uint32_t *out_size);
+int trusty_keymaster_call(uint32_t cmd, void* in, uint32_t in_size, uint8_t* out,
+ uint32_t* out_size);
void trusty_keymaster_disconnect(void);
__END_DECLS
+
+#endif // TRUSTY_KEYMASTER_TRUSTY_KEYMASTER_IPC_H_
diff --git a/trusty/keymaster/trusty_keymaster_main.cpp b/trusty/keymaster/trusty_keymaster_main.cpp
index 7ed880e..9c2ae2d 100644
--- a/trusty/keymaster/trusty_keymaster_main.cpp
+++ b/trusty/keymaster/trusty_keymaster_main.cpp
@@ -14,7 +14,10 @@
* limitations under the License.
*/
+#include <keymaster/keymaster_configuration.h>
+
#include <stdio.h>
+#include <memory>
#include <openssl/evp.h>
#include <openssl/x509.h>
@@ -102,6 +105,28 @@
0xd1, 0x1f, 0xd4, 0x49, 0x49, 0xe0, 0xb2, 0x18, 0x3b, 0xfe};
unsigned int ec_privkey_pk8_der_len = 138;
+keymaster_key_param_t ec_params[] = {
+ keymaster_param_enum(KM_TAG_ALGORITHM, KM_ALGORITHM_EC),
+ keymaster_param_long(KM_TAG_EC_CURVE, KM_EC_CURVE_P_521),
+ keymaster_param_enum(KM_TAG_PURPOSE, KM_PURPOSE_SIGN),
+ keymaster_param_enum(KM_TAG_PURPOSE, KM_PURPOSE_VERIFY),
+ keymaster_param_enum(KM_TAG_DIGEST, KM_DIGEST_NONE),
+ keymaster_param_bool(KM_TAG_NO_AUTH_REQUIRED),
+};
+keymaster_key_param_set_t ec_param_set = {ec_params, sizeof(ec_params) / sizeof(*ec_params)};
+
+keymaster_key_param_t rsa_params[] = {
+ keymaster_param_enum(KM_TAG_ALGORITHM, KM_ALGORITHM_RSA),
+ keymaster_param_int(KM_TAG_KEY_SIZE, 1024),
+ keymaster_param_long(KM_TAG_RSA_PUBLIC_EXPONENT, 65537),
+ keymaster_param_enum(KM_TAG_PURPOSE, KM_PURPOSE_SIGN),
+ keymaster_param_enum(KM_TAG_PURPOSE, KM_PURPOSE_VERIFY),
+ keymaster_param_enum(KM_TAG_PADDING, KM_PAD_NONE),
+ keymaster_param_enum(KM_TAG_DIGEST, KM_DIGEST_NONE),
+ keymaster_param_bool(KM_TAG_NO_AUTH_REQUIRED),
+};
+keymaster_key_param_set_t rsa_param_set = {rsa_params, sizeof(rsa_params) / sizeof(*rsa_params)};
+
struct EVP_PKEY_Delete {
void operator()(EVP_PKEY* p) const { EVP_PKEY_free(p); }
};
@@ -110,41 +135,70 @@
void operator()(EVP_PKEY_CTX* p) { EVP_PKEY_CTX_free(p); }
};
+static bool do_operation(TrustyKeymasterDevice* device, keymaster_purpose_t purpose,
+ keymaster_key_blob_t* key, keymaster_blob_t* input,
+ keymaster_blob_t* signature, keymaster_blob_t* output) {
+ keymaster_key_param_t params[] = {
+ keymaster_param_enum(KM_TAG_PADDING, KM_PAD_NONE),
+ keymaster_param_enum(KM_TAG_DIGEST, KM_DIGEST_NONE),
+ };
+ keymaster_key_param_set_t param_set = {params, sizeof(params) / sizeof(*params)};
+ keymaster_operation_handle_t op_handle;
+ keymaster_error_t error = device->begin(purpose, key, ¶m_set, nullptr, &op_handle);
+ if (error != KM_ERROR_OK) {
+ printf("Keymaster begin() failed: %d\n", error);
+ return false;
+ }
+ size_t input_consumed;
+ error = device->update(op_handle, nullptr, input, &input_consumed, nullptr, nullptr);
+ if (error != KM_ERROR_OK) {
+ printf("Keymaster update() failed: %d\n", error);
+ return false;
+ }
+ if (input_consumed != input->data_length) {
+ // This should never happen. If it does, it's a bug in the keymaster implementation.
+ printf("Keymaster update() did not consume all data.\n");
+ device->abort(op_handle);
+ return false;
+ }
+ error = device->finish(op_handle, nullptr, nullptr, signature, nullptr, output);
+ if (error != KM_ERROR_OK) {
+ printf("Keymaster finish() failed: %d\n", error);
+ return false;
+ }
+ return true;
+}
+
static bool test_import_rsa(TrustyKeymasterDevice* device) {
printf("===================\n");
printf("= RSA Import Test =\n");
printf("===================\n\n");
printf("=== Importing RSA keypair === \n");
- uint8_t* key;
- size_t size;
- int error = device->import_keypair(rsa_privkey_pk8_der, rsa_privkey_pk8_der_len, &key, &size);
+ keymaster_key_blob_t key;
+ keymaster_blob_t private_key = {rsa_privkey_pk8_der, rsa_privkey_pk8_der_len};
+ int error = device->import_key(&rsa_param_set, KM_KEY_FORMAT_PKCS8, &private_key, &key, nullptr);
if (error != KM_ERROR_OK) {
- printf("Error importing key pair: %d\n\n", error);
+ printf("Error importing RSA key: %d\n\n", error);
return false;
}
- UniquePtr<uint8_t[]> key_deleter(key);
+ std::unique_ptr<const uint8_t[]> key_deleter(key.key_material);
printf("=== Signing with imported RSA key ===\n");
- keymaster_rsa_sign_params_t sign_params = {DIGEST_NONE, PADDING_NONE};
size_t message_len = 1024 / 8;
- UniquePtr<uint8_t[]> message(new uint8_t[message_len]);
+ std::unique_ptr<uint8_t[]> message(new uint8_t[message_len]);
memset(message.get(), 'a', message_len);
- uint8_t* signature;
- size_t signature_len;
- error = device->sign_data(&sign_params, key, size, message.get(), message_len, &signature,
- &signature_len);
- if (error != KM_ERROR_OK) {
- printf("Error signing data with imported RSA key: %d\n\n", error);
+ keymaster_blob_t input = {message.get(), message_len}, signature;
+
+ if (!do_operation(device, KM_PURPOSE_SIGN, &key, &input, nullptr, &signature)) {
+ printf("Error signing data with imported RSA key\n\n");
return false;
}
- UniquePtr<uint8_t[]> signature_deleter(signature);
+ std::unique_ptr<const uint8_t[]> signature_deleter(signature.data);
printf("=== Verifying with imported RSA key === \n");
- error = device->verify_data(&sign_params, key, size, message.get(), message_len, signature,
- signature_len);
- if (error != KM_ERROR_OK) {
- printf("Error verifying data with imported RSA key: %d\n\n", error);
+ if (!do_operation(device, KM_PURPOSE_VERIFY, &key, &input, &signature, nullptr)) {
+ printf("Error verifying data with imported RSA key\n\n");
return false;
}
@@ -158,67 +212,58 @@
printf("============\n\n");
printf("=== Generating RSA key pair ===\n");
- keymaster_rsa_keygen_params_t params;
- params.public_exponent = 65537;
- params.modulus_size = 2048;
-
- uint8_t* key;
- size_t size;
- int error = device->generate_keypair(TYPE_RSA, ¶ms, &key, &size);
+ keymaster_key_blob_t key;
+ int error = device->generate_key(&rsa_param_set, &key, nullptr);
if (error != KM_ERROR_OK) {
printf("Error generating RSA key pair: %d\n\n", error);
return false;
}
- UniquePtr<uint8_t[]> deleter(key);
+ std::unique_ptr<const uint8_t[]> key_deleter(key.key_material);
printf("=== Signing with RSA key === \n");
- keymaster_rsa_sign_params_t sign_params = {DIGEST_NONE, PADDING_NONE};
- size_t message_len = params.modulus_size / 8;
- UniquePtr<uint8_t[]> message(new uint8_t[message_len]);
+ size_t message_len = 1024 / 8;
+ std::unique_ptr<uint8_t[]> message(new uint8_t[message_len]);
memset(message.get(), 'a', message_len);
- uint8_t* signature;
- size_t signature_len;
- error = device->sign_data(&sign_params, key, size, message.get(), message_len, &signature,
- &signature_len);
- if (error != KM_ERROR_OK) {
- printf("Error signing data with RSA key: %d\n\n", error);
+ keymaster_blob_t input = {message.get(), message_len}, signature;
+
+ if (!do_operation(device, KM_PURPOSE_SIGN, &key, &input, nullptr, &signature)) {
+ printf("Error signing data with RSA key\n\n");
return false;
}
- UniquePtr<uint8_t[]> signature_deleter(signature);
+ std::unique_ptr<const uint8_t[]> signature_deleter(signature.data);
printf("=== Verifying with RSA key === \n");
- error = device->verify_data(&sign_params, key, size, message.get(), message_len, signature,
- signature_len);
- if (error != KM_ERROR_OK) {
- printf("Error verifying data with RSA key: %d\n\n", error);
+ if (!do_operation(device, KM_PURPOSE_VERIFY, &key, &input, &signature, nullptr)) {
+ printf("Error verifying data with RSA key\n\n");
return false;
}
printf("=== Exporting RSA public key ===\n");
- uint8_t* exported_key;
- size_t exported_size;
- error = device->get_keypair_public(key, size, &exported_key, &exported_size);
+ keymaster_blob_t exported_key;
+ error = device->export_key(KM_KEY_FORMAT_X509, &key, nullptr, nullptr, &exported_key);
if (error != KM_ERROR_OK) {
printf("Error exporting RSA public key: %d\n\n", error);
return false;
}
printf("=== Verifying with exported key ===\n");
- const uint8_t* tmp = exported_key;
- UniquePtr<EVP_PKEY, EVP_PKEY_Delete> pkey(d2i_PUBKEY(NULL, &tmp, exported_size));
- UniquePtr<EVP_PKEY_CTX, EVP_PKEY_CTX_Delete> ctx(EVP_PKEY_CTX_new(pkey.get(), NULL));
+ const uint8_t* tmp = exported_key.data;
+ std::unique_ptr<EVP_PKEY, EVP_PKEY_Delete> pkey(
+ d2i_PUBKEY(NULL, &tmp, exported_key.data_length));
+ std::unique_ptr<EVP_PKEY_CTX, EVP_PKEY_CTX_Delete> ctx(EVP_PKEY_CTX_new(pkey.get(), NULL));
if (EVP_PKEY_verify_init(ctx.get()) != 1) {
- printf("Error initializing openss EVP context\n");
+ printf("Error initializing openss EVP context\n\n");
return false;
}
if (EVP_PKEY_type(pkey->type) != EVP_PKEY_RSA) {
- printf("Exported key was the wrong type?!?\n");
+ printf("Exported key was the wrong type?!?\n\n");
return false;
}
EVP_PKEY_CTX_set_rsa_padding(ctx.get(), RSA_NO_PADDING);
- if (EVP_PKEY_verify(ctx.get(), signature, signature_len, message.get(), message_len) != 1) {
- printf("Verification with exported pubkey failed.\n");
+ if (EVP_PKEY_verify(ctx.get(), signature.data, signature.data_length, message.get(),
+ message_len) != 1) {
+ printf("Verification with exported pubkey failed.\n\n");
return false;
} else {
printf("Verification succeeded\n");
@@ -234,35 +279,31 @@
printf("=====================\n\n");
printf("=== Importing ECDSA keypair === \n");
- uint8_t* key;
- size_t size;
- int error = device->import_keypair(ec_privkey_pk8_der, ec_privkey_pk8_der_len, &key, &size);
+ keymaster_key_blob_t key;
+ keymaster_blob_t private_key = {ec_privkey_pk8_der, ec_privkey_pk8_der_len};
+ int error = device->import_key(&ec_param_set, KM_KEY_FORMAT_PKCS8, &private_key, &key, nullptr);
if (error != KM_ERROR_OK) {
- printf("Error importing key pair: %d\n\n", error);
+ printf("Error importing ECDSA key: %d\n\n", error);
return false;
}
- UniquePtr<uint8_t[]> deleter(key);
+ std::unique_ptr<const uint8_t[]> deleter(key.key_material);
printf("=== Signing with imported ECDSA key ===\n");
keymaster_ec_sign_params_t sign_params = {DIGEST_NONE};
size_t message_len = 30 /* arbitrary */;
- UniquePtr<uint8_t[]> message(new uint8_t[message_len]);
+ std::unique_ptr<uint8_t[]> message(new uint8_t[message_len]);
memset(message.get(), 'a', message_len);
- uint8_t* signature;
- size_t signature_len;
- error = device->sign_data(&sign_params, key, size, message.get(), message_len, &signature,
- &signature_len);
- if (error != KM_ERROR_OK) {
- printf("Error signing data with imported ECDSA key: %d\n\n", error);
+ keymaster_blob_t input = {message.get(), message_len}, signature;
+
+ if (!do_operation(device, KM_PURPOSE_SIGN, &key, &input, nullptr, &signature)) {
+ printf("Error signing data with imported ECDSA key\n\n");
return false;
}
- UniquePtr<uint8_t[]> signature_deleter(signature);
+ std::unique_ptr<const uint8_t[]> signature_deleter(signature.data);
printf("=== Verifying with imported ECDSA key === \n");
- error = device->verify_data(&sign_params, key, size, message.get(), message_len, signature,
- signature_len);
- if (error != KM_ERROR_OK) {
- printf("Error verifying data with imported ECDSA key: %d\n\n", error);
+ if (!do_operation(device, KM_PURPOSE_VERIFY, &key, &input, &signature, nullptr)) {
+ printf("Error verifying data with imported ECDSA key\n\n");
return false;
}
@@ -276,64 +317,57 @@
printf("==============\n\n");
printf("=== Generating ECDSA key pair ===\n");
- keymaster_ec_keygen_params_t params;
- params.field_size = 521;
- uint8_t* key;
- size_t size;
- int error = device->generate_keypair(TYPE_EC, ¶ms, &key, &size);
- if (error != 0) {
+ keymaster_key_blob_t key;
+ int error = device->generate_key(&ec_param_set, &key, nullptr);
+ if (error != KM_ERROR_OK) {
printf("Error generating ECDSA key pair: %d\n\n", error);
return false;
}
- UniquePtr<uint8_t[]> deleter(key);
+ std::unique_ptr<const uint8_t[]> key_deleter(key.key_material);
printf("=== Signing with ECDSA key === \n");
- keymaster_ec_sign_params_t sign_params = {DIGEST_NONE};
size_t message_len = 30 /* arbitrary */;
- UniquePtr<uint8_t[]> message(new uint8_t[message_len]);
+ std::unique_ptr<uint8_t[]> message(new uint8_t[message_len]);
memset(message.get(), 'a', message_len);
- uint8_t* signature;
- size_t signature_len;
- error = device->sign_data(&sign_params, key, size, message.get(), message_len, &signature,
- &signature_len);
- if (error != KM_ERROR_OK) {
- printf("Error signing data with ECDSA key: %d\n\n", error);
+ keymaster_blob_t input = {message.get(), message_len}, signature;
+
+ if (!do_operation(device, KM_PURPOSE_SIGN, &key, &input, nullptr, &signature)) {
+ printf("Error signing data with ECDSA key\n\n");
return false;
}
- UniquePtr<uint8_t[]> signature_deleter(signature);
+ std::unique_ptr<const uint8_t[]> signature_deleter(signature.data);
printf("=== Verifying with ECDSA key === \n");
- error = device->verify_data(&sign_params, key, size, message.get(), message_len, signature,
- signature_len);
- if (error != KM_ERROR_OK) {
- printf("Error verifying data with ECDSA key: %d\n\n", error);
+ if (!do_operation(device, KM_PURPOSE_VERIFY, &key, &input, &signature, nullptr)) {
+ printf("Error verifying data with ECDSA key\n\n");
return false;
}
printf("=== Exporting ECDSA public key ===\n");
- uint8_t* exported_key;
- size_t exported_size;
- error = device->get_keypair_public(key, size, &exported_key, &exported_size);
+ keymaster_blob_t exported_key;
+ error = device->export_key(KM_KEY_FORMAT_X509, &key, nullptr, nullptr, &exported_key);
if (error != KM_ERROR_OK) {
printf("Error exporting ECDSA public key: %d\n\n", error);
return false;
}
printf("=== Verifying with exported key ===\n");
- const uint8_t* tmp = exported_key;
- UniquePtr<EVP_PKEY, EVP_PKEY_Delete> pkey(d2i_PUBKEY(NULL, &tmp, exported_size));
- UniquePtr<EVP_PKEY_CTX, EVP_PKEY_CTX_Delete> ctx(EVP_PKEY_CTX_new(pkey.get(), NULL));
+ const uint8_t* tmp = exported_key.data;
+ std::unique_ptr<EVP_PKEY, EVP_PKEY_Delete> pkey(
+ d2i_PUBKEY(NULL, &tmp, exported_key.data_length));
+ std::unique_ptr<EVP_PKEY_CTX, EVP_PKEY_CTX_Delete> ctx(EVP_PKEY_CTX_new(pkey.get(), NULL));
if (EVP_PKEY_verify_init(ctx.get()) != 1) {
- printf("Error initializing openss EVP context\n");
+ printf("Error initializing openssl EVP context\n\n");
return false;
}
if (EVP_PKEY_type(pkey->type) != EVP_PKEY_EC) {
- printf("Exported key was the wrong type?!?\n");
+ printf("Exported key was the wrong type?!?\n\n");
return false;
}
- if (EVP_PKEY_verify(ctx.get(), signature, signature_len, message.get(), message_len) != 1) {
- printf("Verification with exported pubkey failed.\n");
+ if (EVP_PKEY_verify(ctx.get(), signature.data, signature.data_length, message.get(),
+ message_len) != 1) {
+ printf("Verification with exported pubkey failed.\n\n");
return false;
} else {
printf("Verification succeeded\n");
@@ -344,8 +378,8 @@
}
int main(void) {
-
TrustyKeymasterDevice device(NULL);
+ keymaster::ConfigureDevice(reinterpret_cast<keymaster2_device_t*>(&device));
if (device.session_error() != KM_ERROR_OK) {
printf("Failed to initialize Trusty session: %d\n", device.session_error());
return 1;