diff options
author | Florian Mayer <fmayer@google.com> | 2022-10-03 16:23:19 +0000 |
---|---|---|
committer | Gerrit Code Review <noreply-gerritcodereview@google.com> | 2022-10-03 16:23:19 +0000 |
commit | 92db9b882212de33cd506f3aad4211be4f6d9d8f (patch) | |
tree | d1d321a3dde79de1340dc1e49aa9daafc2156dcd /mtectrl | |
parent | 9dc4f921bb19a6d948f4fd04099e22bbf0768cc8 (diff) | |
parent | e0e618d3ae4af0d0215eca060dd6d7f52f6fd7fc (diff) | |
download | extras-92db9b882212de33cd506f3aad4211be4f6d9d8f.tar.gz |
Merge changes from topic "mtectrlsync"
* changes:
[MTE] add test for mtectrl
[MTE] Keep property and misc partition state synced
Diffstat (limited to 'mtectrl')
-rw-r--r-- | mtectrl/Android.bp | 15 | ||||
-rw-r--r-- | mtectrl/mtectrl.cc | 155 | ||||
-rw-r--r-- | mtectrl/mtectrl.rc | 7 | ||||
-rw-r--r-- | mtectrl/mtectrl_test.cc | 129 |
4 files changed, 272 insertions, 34 deletions
diff --git a/mtectrl/Android.bp b/mtectrl/Android.bp index bc84f8cd..688ca7dd 100644 --- a/mtectrl/Android.bp +++ b/mtectrl/Android.bp @@ -25,3 +25,18 @@ cc_binary { ], init_rc: ["mtectrl.rc"], } + +cc_test { + name: "mtectrl_test", + srcs: ["mtectrl_test.cc"], + test_suites: ["general-tests"], + // shell cannot use /system/bin/mtectrl + require_root: true, + shared_libs: [ + "libbootloader_message", + "libbase", + ], + static_libs: [ + "libgmock", + ] +} diff --git a/mtectrl/mtectrl.cc b/mtectrl/mtectrl.cc index eefc1588..8ec518a4 100644 --- a/mtectrl/mtectrl.cc +++ b/mtectrl/mtectrl.cc @@ -14,62 +14,152 @@ * limitations under the License. */ +#include <getopt.h> +#include <unistd.h> + +#include <android-base/file.h> #include <android-base/logging.h> +#include <android-base/properties.h> #include <android-base/strings.h> #include <bootloader_message/bootloader_message.h> +#include <functional> #include <iostream> -int main(int argc, char** argv) { - if (argc != 2 && argc != 3) { - std::cerr << "Usage: " << argv[0] - << " none|memtag|memtag-once|memtag-kernel|memtag-kernel-once[,.." - ".] [default|force_on|force_off]\n"; - return 1; - } - std::string value = argv[1]; - misc_memtag_message m = {.version = MISC_MEMTAG_MESSAGE_VERSION, - .magic = MISC_MEMTAG_MAGIC_HEADER}; - bool valid_value = true; +void AddItem(std::string* s, const char* item) { + if (!s->empty()) *s += ","; + *s += item; +} + +void UpdateProp(const char* prop_name, const misc_memtag_message& m) { + std::string prop_str; + if (m.memtag_mode & MISC_MEMTAG_MODE_MEMTAG) AddItem(&prop_str, "memtag"); + if (m.memtag_mode & MISC_MEMTAG_MODE_MEMTAG_ONCE) AddItem(&prop_str, "memtag-once"); + if (m.memtag_mode & MISC_MEMTAG_MODE_MEMTAG_KERNEL) AddItem(&prop_str, "memtag-kernel"); + if (m.memtag_mode & MISC_MEMTAG_MODE_MEMTAG_KERNEL_ONCE) AddItem(&prop_str, "memtag-kernel-once"); + if (m.memtag_mode & MISC_MEMTAG_MODE_MEMTAG_OFF) AddItem(&prop_str, "memtag-off"); + if (android::base::GetProperty(prop_name, "") != prop_str) + android::base::SetProperty(prop_name, prop_str); +} + +void PrintUsage(const char* progname) { + std::cerr << "Usage: " << progname + << " [-s PROPERTY_NAME] none|memtag|memtag-once|memtag-kernel|memtag-kernel-once[,.." + ".] [default|force_on|force_off]\n" + << " " << progname << " -s PROPERTY_NAME\n"; +} + +int StringToMode(const char* value) { + int memtag_mode = 0; for (const auto& field : android::base::Split(value, ",")) { if (field == "memtag") { - m.memtag_mode |= MISC_MEMTAG_MODE_MEMTAG; + memtag_mode |= MISC_MEMTAG_MODE_MEMTAG; } else if (field == "memtag-once") { - m.memtag_mode |= MISC_MEMTAG_MODE_MEMTAG_ONCE; + memtag_mode |= MISC_MEMTAG_MODE_MEMTAG_ONCE; } else if (field == "memtag-kernel") { - m.memtag_mode |= MISC_MEMTAG_MODE_MEMTAG_KERNEL; + memtag_mode |= MISC_MEMTAG_MODE_MEMTAG_KERNEL; } else if (field == "memtag-kernel-once") { - m.memtag_mode |= MISC_MEMTAG_MODE_MEMTAG_KERNEL_ONCE; + memtag_mode |= MISC_MEMTAG_MODE_MEMTAG_KERNEL_ONCE; } else if (field == "memtag-off") { - m.memtag_mode |= MISC_MEMTAG_MODE_MEMTAG_OFF; + memtag_mode |= MISC_MEMTAG_MODE_MEMTAG_OFF; } else if (field != "none") { LOG(ERROR) << "Unknown value for mode: " << field; - valid_value = false; - m = {.version = MISC_MEMTAG_MESSAGE_VERSION, .magic = MISC_MEMTAG_MAGIC_HEADER}; - break; + return -1; } } - bool valid_override = true; - std::string override_value; - if (argc == 3) { - override_value = argv[2]; - } + return memtag_mode; +} + +bool HandleOverride(const std::string& override_value, misc_memtag_message* m) { if (override_value == "force_off") { // If the force_off override is active, only allow MEMTAG_MODE_MEMTAG_ONCE. - m.memtag_mode |= MISC_MEMTAG_MODE_MEMTAG_OFF; - m.memtag_mode &= ~MISC_MEMTAG_MODE_MEMTAG; + m->memtag_mode |= MISC_MEMTAG_MODE_MEMTAG_OFF; + m->memtag_mode &= ~MISC_MEMTAG_MODE_MEMTAG; } else if (override_value == "force_on") { - m.memtag_mode |= MISC_MEMTAG_MODE_MEMTAG; - m.memtag_mode &= ~MISC_MEMTAG_MODE_MEMTAG_OFF; + m->memtag_mode |= MISC_MEMTAG_MODE_MEMTAG; + m->memtag_mode &= ~MISC_MEMTAG_MODE_MEMTAG_OFF; } else if (!override_value.empty() && override_value != "default") { - LOG(ERROR) << "Unknown value for override: " << override_value; - valid_override = false; + return false; } + return true; +} + +int main(int argc, char** argv) { + const char* set_prop = nullptr; + int opt; + std::function<bool(misc_memtag_message*, std::string*)> read_memtag_message = + ReadMiscMemtagMessage; + std::function<bool(const misc_memtag_message&, std::string*)> write_memtag_message = + WriteMiscMemtagMessage; + while ((opt = getopt(argc, argv, "s:t:")) != -1) { + switch (opt) { + case 's': + set_prop = optarg; + break; + case 't': { + // Use different fake misc partition for testing. + const char* filename = optarg; + int fd = open(filename, O_RDWR | O_CLOEXEC); + CHECK_NE(fd, -1); + CHECK_NE(ftruncate(fd, sizeof(misc_memtag_message)), -1); + read_memtag_message = [fd](misc_memtag_message* m, std::string*) { + CHECK(android::base::ReadFully(fd, m, sizeof(*m))); + return true; + }; + write_memtag_message = [fd](const misc_memtag_message& m, std::string*) { + CHECK(android::base::WriteFully(fd, &m, sizeof(m))); + return true; + }; + break; + } + default: + PrintUsage(argv[0]); + return 1; + } + } + + const char* value = optind < argc ? argv[optind++] : nullptr; + const char* override_value = optind < argc ? argv[optind++] : nullptr; + + if (optind != argc) { // Unknown argument. + PrintUsage(argv[0]); + return 1; + } + + if (!value && set_prop) { + std::string err; + misc_memtag_message m = {}; + if (!read_memtag_message(&m, &err)) { + LOG(ERROR) << "Failed to read memtag message: " << err; + return 1; + } + if (m.magic != MISC_MEMTAG_MAGIC_HEADER || m.version != MISC_MEMTAG_MESSAGE_VERSION) { + UpdateProp(set_prop, {}); + return 0; + } + UpdateProp(set_prop, m); + return 0; + } + + if (!value) { + PrintUsage(argv[0]); + return 1; + } + + misc_memtag_message m = {.version = MISC_MEMTAG_MESSAGE_VERSION, + .magic = MISC_MEMTAG_MAGIC_HEADER}; + int memtag_mode = StringToMode(value); + bool valid_value = memtag_mode != -1; + m.memtag_mode = valid_value ? memtag_mode : 0; + + bool valid_override = true; + if (override_value) valid_override = HandleOverride(override_value, &m); + if (!valid_value && !valid_override) { return 1; } std::string err; - if (!WriteMiscMemtagMessage(m, &err)) { + if (!write_memtag_message(m, &err)) { LOG(ERROR) << "Failed to apply mode: " << value << ", override: " << override_value << err; return 1; } else { @@ -84,7 +174,8 @@ int main(int argc, char** argv) { verb = "Partially applied"; } LOG(INFO) << verb << " mode: " << value << ", " - << "override: " << override_value << parse_error; + << "override: " << (override_value ? override_value : "") << parse_error; + if (set_prop) UpdateProp(set_prop, m); return !valid_value || !valid_override; } } diff --git a/mtectrl/mtectrl.rc b/mtectrl/mtectrl.rc index 05bdaa23..7dfef007 100644 --- a/mtectrl/mtectrl.rc +++ b/mtectrl/mtectrl.rc @@ -13,7 +13,10 @@ # limitations under the License. on property:arm64.memtag.bootctl=* - exec -- /system/bin/mtectrl ${arm64.memtag.bootctl:-none} ${persist.device_config.memory_safety_native.bootloader_override:-default} + exec -- /system/bin/mtectrl -s arm64.memtag.bootctl ${arm64.memtag.bootctl:-none} ${persist.device_config.memory_safety_native.bootloader_override:-default} on property:persist.device_config.memory_safety_native.bootloader_override=* - exec -- /system/bin/mtectrl ${arm64.memtag.bootctl:-none} ${persist.device_config.memory_safety_native.bootloader_override:-default} + exec -- /system/bin/mtectrl -s arm64.memtag.bootctl ${arm64.memtag.bootctl:-none} ${persist.device_config.memory_safety_native.bootloader_override:-default} + +on init + exec -- /system/bin/mtectrl -s arm64.memtag.bootctl diff --git a/mtectrl/mtectrl_test.cc b/mtectrl/mtectrl_test.cc new file mode 100644 index 00000000..d99c6b44 --- /dev/null +++ b/mtectrl/mtectrl_test.cc @@ -0,0 +1,129 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <stdio.h> + +#include <gmock/gmock.h> +#include <gtest/gtest.h> + +#include <android-base/file.h> +#include <android-base/logging.h> +#include <android-base/properties.h> +#include <bootloader_message/bootloader_message.h> + +namespace { +using ::testing::StartsWith; + +int mtectrl(const char* arg) { + std::string cmd = "mtectrl -t /data/local/tmp/misc_memtag "; + cmd += arg; + return system(cmd.c_str()); +} + +std::string GetMisc() { + std::string data; + CHECK(android::base::ReadFileToString("/data/local/tmp/misc_memtag", &data, false)); + return data; +} + +std::string TestProperty() { + return android::base::GetProperty("arm64.memtag.test_bootctl", ""); +} +} // namespace + +class MteCtrlTest : public ::testing::Test { + void SetUp() override { + // Empty fake misc partition. + int fd = creat("/data/local/tmp/misc_memtag", 0600); + CHECK(fd != -1); + CHECK(ftruncate(fd, sizeof(misc_memtag_message)) != -1); + close(fd); + android::base::SetProperty("arm64.memtag.test_bootctl", "INVALID"); + } + void TearDown() override { + CHECK(unlink("/data/local/tmp/misc_memtag") == 0); + } +}; + +TEST_F(MteCtrlTest, invalid) { + EXPECT_NE(mtectrl("memtag-invalid"), 0); + EXPECT_NE(mtectrl("memtag override-invalid"), 0); +} + +TEST_F(MteCtrlTest, set_once) { + ASSERT_EQ(mtectrl("memtag-once"), 0); + EXPECT_THAT(GetMisc(), StartsWith("\x01\x5a\xfe\xfe\x5a\x02")); +} + +TEST_F(MteCtrlTest, set_once_kernel) { + ASSERT_EQ(mtectrl("memtag-once,memtag-kernel"), 0); + EXPECT_THAT(GetMisc(), StartsWith("\x01\x5a\xfe\xfe\x5a\x06")); +} + +TEST_F(MteCtrlTest, set_memtag) { + ASSERT_EQ(mtectrl("memtag"), 0); + EXPECT_THAT(GetMisc(), StartsWith("\x01\x5a\xfe\xfe\x5a\x01")); +} + +TEST_F(MteCtrlTest, set_memtag_force_off) { + ASSERT_EQ(mtectrl("memtag force_off"), 0); + EXPECT_THAT(GetMisc(), StartsWith("\x01\x5a\xfe\xfe\x5a\x10")); +} + +TEST_F(MteCtrlTest, read_memtag) { + ASSERT_EQ(mtectrl("memtag"), 0); + ASSERT_EQ(mtectrl("-s arm64.memtag.test_bootctl"), 0); + EXPECT_EQ(TestProperty(), "memtag"); +} + +TEST_F(MteCtrlTest, set_read_memtag) { + ASSERT_EQ(mtectrl("-s arm64.memtag.test_bootctl memtag"), 0); + EXPECT_EQ(TestProperty(), "memtag"); +} + +TEST_F(MteCtrlTest, set_read_force_off) { + ASSERT_EQ(mtectrl("-s arm64.memtag.test_bootctl memtag,memtag-once force_off"), 0); + EXPECT_EQ(TestProperty(), "memtag-once,memtag-off"); +} + +TEST_F(MteCtrlTest, override) { + ASSERT_EQ(mtectrl("memtag"), 0); + ASSERT_EQ(mtectrl("memtag-once"), 0); + EXPECT_THAT(GetMisc(), StartsWith("\x01\x5a\xfe\xfe\x5a\x02")); +} + +TEST_F(MteCtrlTest, read_empty) { + ASSERT_EQ(mtectrl("-s arm64.memtag.test_bootctl"), 0); + EXPECT_EQ(TestProperty(), ""); +} + +TEST_F(MteCtrlTest, force_off_invalid_mode) { + mtectrl("-s arm64.memtag.test_bootctl memtag-invalid force_off"); + EXPECT_EQ(TestProperty(), "memtag-off"); + EXPECT_THAT(GetMisc(), StartsWith("\x01\x5a\xfe\xfe\x5a\x10")); +} + +TEST_F(MteCtrlTest, force_on_invalid_mode) { + mtectrl("-s arm64.memtag.test_bootctl memtag-invalid force_on"); + EXPECT_EQ(TestProperty(), "memtag"); + EXPECT_THAT(GetMisc(), StartsWith("\x01\x5a\xfe\xfe\x5a\x01")); +} + +TEST_F(MteCtrlTest, mode_invalid_override) { + mtectrl("-s arm64.memtag.test_bootctl memtag force_invalid"); + EXPECT_EQ(TestProperty(), "memtag"); + EXPECT_THAT(GetMisc(), StartsWith("\x01\x5a\xfe\xfe\x5a\x01")); +} |