From f0a242f73d3b1f1b95a6fe2dcb7dee1e55a6c02c Mon Sep 17 00:00:00 2001 From: Victor Hsieh Date: Mon, 26 Aug 2019 11:26:27 -0700 Subject: [PATCH] Refactor mini-keyctl and split a static library Test: mini-keyctl still works in command line Bug: 112038744 Change-Id: I08006d8befa69e4bf416a2bed9e1813725877147 --- libkeyutils/Android.bp | 14 -- libkeyutils/mini_keyctl.cpp | 90 ------------- libkeyutils/mini_keyctl/Android.bp | 27 ++++ .../mini_keyctl.cpp} | 122 ++++++++++-------- libkeyutils/mini_keyctl/mini_keyctl_utils.cpp | 83 ++++++++++++ libkeyutils/mini_keyctl/mini_keyctl_utils.h | 28 ++++ libkeyutils/mini_keyctl_utils.h | 35 ----- 7 files changed, 206 insertions(+), 193 deletions(-) delete mode 100644 libkeyutils/mini_keyctl.cpp create mode 100644 libkeyutils/mini_keyctl/Android.bp rename libkeyutils/{mini_keyctl_utils.cpp => mini_keyctl/mini_keyctl.cpp} (56%) create mode 100644 libkeyutils/mini_keyctl/mini_keyctl_utils.cpp create mode 100644 libkeyutils/mini_keyctl/mini_keyctl_utils.h delete mode 100644 libkeyutils/mini_keyctl_utils.h diff --git a/libkeyutils/Android.bp b/libkeyutils/Android.bp index dda491a08..b388e9555 100644 --- a/libkeyutils/Android.bp +++ b/libkeyutils/Android.bp @@ -16,17 +16,3 @@ cc_test { srcs: ["keyutils_test.cpp"], test_suites: ["device-tests"], } - -cc_binary { - name: "mini-keyctl", - srcs: [ - "mini_keyctl.cpp", - "mini_keyctl_utils.cpp" - ], - shared_libs: [ - "libbase", - "libkeyutils", - "liblog", - ], - cflags: ["-Werror", "-Wall", "-Wextra", "-fexceptions"], -} diff --git a/libkeyutils/mini_keyctl.cpp b/libkeyutils/mini_keyctl.cpp deleted file mode 100644 index fe89e62ab..000000000 --- a/libkeyutils/mini_keyctl.cpp +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (C) 2019 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. - */ - -/* - * A tool loads keys to keyring. - */ - -#include "mini_keyctl_utils.h" - -#include -#include -#include - -#include - -static void Usage(int exit_code) { - fprintf(stderr, "usage: mini-keyctl [args,]\n"); - fprintf(stderr, " mini-keyctl add \n"); - fprintf(stderr, " mini-keyctl padd \n"); - fprintf(stderr, " mini-keyctl unlink \n"); - fprintf(stderr, " mini-keyctl restrict_keyring \n"); - fprintf(stderr, " mini-keyctl security \n"); - _exit(exit_code); -} - -static key_serial_t parseKeyOrDie(const char* str) { - key_serial_t key; - if (!android::base::ParseInt(str, &key)) { - error(1 /* exit code */, 0 /* errno */, "Unparsable key: '%s'\n", str); - } - return key; -} - -int main(int argc, const char** argv) { - if (argc < 2) Usage(1); - const std::string action = argv[1]; - - if (action == "add") { - if (argc != 6) Usage(1); - std::string type = argv[2]; - std::string desc = argv[3]; - std::string data = argv[4]; - std::string keyring = argv[5]; - return Add(type, desc, data, keyring); - } else if (action == "padd") { - if (argc != 5) Usage(1); - std::string type = argv[2]; - std::string desc = argv[3]; - std::string keyring = argv[4]; - return Padd(type, desc, keyring); - } else if (action == "restrict_keyring") { - if (argc != 3) Usage(1); - std::string keyring = argv[2]; - return RestrictKeyring(keyring); - } else if (action == "unlink") { - if (argc != 4) Usage(1); - key_serial_t key = parseKeyOrDie(argv[2]); - const std::string keyring = argv[3]; - return Unlink(key, keyring); - } else if (action == "security") { - if (argc != 3) Usage(1); - const char* key_str = argv[2]; - key_serial_t key = parseKeyOrDie(key_str); - std::string context = RetrieveSecurityContext(key); - if (context.empty()) { - perror(key_str); - return 1; - } - fprintf(stderr, "%s\n", context.c_str()); - return 0; - } else { - fprintf(stderr, "Unrecognized action: %s\n", action.c_str()); - Usage(1); - } - - return 0; -} diff --git a/libkeyutils/mini_keyctl/Android.bp b/libkeyutils/mini_keyctl/Android.bp new file mode 100644 index 000000000..a04a3db24 --- /dev/null +++ b/libkeyutils/mini_keyctl/Android.bp @@ -0,0 +1,27 @@ +cc_library_static { + name: "libmini_keyctl_static", + srcs: [ + "mini_keyctl_utils.cpp" + ], + shared_libs: [ + "libbase", + "libkeyutils", + ], + cflags: ["-Werror", "-Wall", "-Wextra"], + export_include_dirs: ["."], +} + +cc_binary { + name: "mini-keyctl", + srcs: [ + "mini_keyctl.cpp", + ], + static_libs: [ + "libmini_keyctl_static", + ], + shared_libs: [ + "libbase", + "libkeyutils", + ], + cflags: ["-Werror", "-Wall", "-Wextra"], +} diff --git a/libkeyutils/mini_keyctl_utils.cpp b/libkeyutils/mini_keyctl/mini_keyctl.cpp similarity index 56% rename from libkeyutils/mini_keyctl_utils.cpp rename to libkeyutils/mini_keyctl/mini_keyctl.cpp index 79b468087..8aace9adb 100644 --- a/libkeyutils/mini_keyctl_utils.cpp +++ b/libkeyutils/mini_keyctl/mini_keyctl.cpp @@ -14,79 +14,48 @@ * limitations under the License. */ -#include +/* + * A tool loads keys to keyring. + */ #include #include #include +#include #include #include -#include #include #include -#include #include -#include #include #include -#include -#include #include +#include -static constexpr int kMaxCertSize = 4096; +constexpr int kMaxCertSize = 4096; -static std::vector SplitBySpace(const std::string& s) { - std::istringstream iss(s); - return std::vector{std::istream_iterator{iss}, - std::istream_iterator{}}; +static void Usage(int exit_code) { + fprintf(stderr, "usage: mini-keyctl [args,]\n"); + fprintf(stderr, " mini-keyctl add \n"); + fprintf(stderr, " mini-keyctl padd \n"); + fprintf(stderr, " mini-keyctl unlink \n"); + fprintf(stderr, " mini-keyctl restrict_keyring \n"); + fprintf(stderr, " mini-keyctl security \n"); + _exit(exit_code); } -// Find the keyring id. Because request_key(2) syscall is not available or the key is -// kernel keyring, the id is looked up from /proc/keys. The keyring description may contain other -// information in the descritption section depending on the key type, only the first word in the -// keyring description is used for searching. -static key_serial_t GetKeyringIdOrDie(const std::string& keyring_desc) { - // If the keyring id is already a hex number, directly convert it to keyring id - key_serial_t keyring_id; - if (android::base::ParseInt(keyring_desc.c_str(), &keyring_id)) { - return keyring_id; +static key_serial_t parseKeyOrDie(const char* str) { + key_serial_t key; + if (!android::base::ParseInt(str, &key)) { + error(1 /* exit code */, 0 /* errno */, "Unparsable key: '%s'\n", str); } - - // Only keys allowed by SELinux rules will be shown here. - std::ifstream proc_keys_file("/proc/keys"); - if (!proc_keys_file.is_open()) { - error(1, errno, "Failed to open /proc/keys"); - return -1; - } - - std::string line; - while (getline(proc_keys_file, line)) { - std::vector tokens = SplitBySpace(line); - if (tokens.size() < 9) { - continue; - } - std::string key_id = "0x" + tokens[0]; - std::string key_type = tokens[7]; - // The key description may contain space. - std::string key_desc_prefix = tokens[8]; - // The prefix has a ":" at the end - std::string key_desc_pattern = keyring_desc + ":"; - if (key_type != "keyring" || key_desc_prefix != key_desc_pattern) { - continue; - } - if (!android::base::ParseInt(key_id.c_str(), &keyring_id)) { - error(1, 0, "Unexpected key format in /proc/keys: %s", key_id.c_str()); - return -1; - } - return keyring_id; - } - return -1; + return key; } int Unlink(key_serial_t key, const std::string& keyring) { - key_serial_t keyring_id = GetKeyringIdOrDie(keyring); + key_serial_t keyring_id = android::GetKeyringId(keyring); if (keyctl_unlink(key, keyring_id) < 0) { error(1, errno, "Failed to unlink key %x from keyring %s", key, keyring.c_str()); return 1; @@ -101,7 +70,7 @@ int Add(const std::string& type, const std::string& desc, const std::string& dat return 1; } - key_serial_t keyring_id = GetKeyringIdOrDie(keyring); + key_serial_t keyring_id = android::GetKeyringId(keyring); key_serial_t key = add_key(type.c_str(), desc.c_str(), data.c_str(), data.size(), keyring_id); if (key < 0) { @@ -114,7 +83,7 @@ int Add(const std::string& type, const std::string& desc, const std::string& dat } int Padd(const std::string& type, const std::string& desc, const std::string& keyring) { - key_serial_t keyring_id = GetKeyringIdOrDie(keyring); + key_serial_t keyring_id = android::GetKeyringId(keyring); // read from stdin to get the certificates std::istreambuf_iterator begin(std::cin), end; @@ -137,7 +106,7 @@ int Padd(const std::string& type, const std::string& desc, const std::string& ke } int RestrictKeyring(const std::string& keyring) { - key_serial_t keyring_id = GetKeyringIdOrDie(keyring); + key_serial_t keyring_id = android::GetKeyringId(keyring); if (keyctl_restrict_keyring(keyring_id, nullptr, nullptr) < 0) { error(1, errno, "Cannot restrict keyring '%s'", keyring.c_str()); return 1; @@ -162,3 +131,48 @@ std::string RetrieveSecurityContext(key_serial_t key) { context.resize(retval); return context; } + +int main(int argc, const char** argv) { + if (argc < 2) Usage(1); + const std::string action = argv[1]; + + if (action == "add") { + if (argc != 6) Usage(1); + std::string type = argv[2]; + std::string desc = argv[3]; + std::string data = argv[4]; + std::string keyring = argv[5]; + return Add(type, desc, data, keyring); + } else if (action == "padd") { + if (argc != 5) Usage(1); + std::string type = argv[2]; + std::string desc = argv[3]; + std::string keyring = argv[4]; + return Padd(type, desc, keyring); + } else if (action == "restrict_keyring") { + if (argc != 3) Usage(1); + std::string keyring = argv[2]; + return RestrictKeyring(keyring); + } else if (action == "unlink") { + if (argc != 4) Usage(1); + key_serial_t key = parseKeyOrDie(argv[2]); + const std::string keyring = argv[3]; + return Unlink(key, keyring); + } else if (action == "security") { + if (argc != 3) Usage(1); + const char* key_str = argv[2]; + key_serial_t key = parseKeyOrDie(key_str); + std::string context = RetrieveSecurityContext(key); + if (context.empty()) { + perror(key_str); + return 1; + } + fprintf(stderr, "%s\n", context.c_str()); + return 0; + } else { + fprintf(stderr, "Unrecognized action: %s\n", action.c_str()); + Usage(1); + } + + return 0; +} diff --git a/libkeyutils/mini_keyctl/mini_keyctl_utils.cpp b/libkeyutils/mini_keyctl/mini_keyctl_utils.cpp new file mode 100644 index 000000000..fb9503f14 --- /dev/null +++ b/libkeyutils/mini_keyctl/mini_keyctl_utils.cpp @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2019 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 + +#include +#include +#include +#include +#include + +#include +#include + +namespace android { + +namespace { + +std::vector SplitBySpace(const std::string& s) { + std::istringstream iss(s); + return std::vector{std::istream_iterator{iss}, + std::istream_iterator{}}; +} + +} // namespace + +// Find the keyring id. request_key(2) only finds keys in the process, session or thread keyring +// hierarchy, but not internal keyring of a kernel subsystem (e.g. .fs-verity). To support all +// cases, this function looks up a keyring's ID by parsing /proc/keys. The keyring description may +// contain other information in the descritption section depending on the key type, only the first +// word in the keyring description is used for searching. +key_serial_t GetKeyringId(const std::string& keyring_desc) { + // If the keyring id is already a hex number, directly convert it to keyring id + key_serial_t keyring_id; + if (android::base::ParseInt(keyring_desc.c_str(), &keyring_id)) { + return keyring_id; + } + + // Only keys allowed by SELinux rules will be shown here. + std::ifstream proc_keys_file("/proc/keys"); + if (!proc_keys_file.is_open()) { + PLOG(ERROR) << "Failed to open /proc/keys"; + return -1; + } + + std::string line; + while (getline(proc_keys_file, line)) { + std::vector tokens = SplitBySpace(line); + if (tokens.size() < 9) { + continue; + } + std::string key_id = "0x" + tokens[0]; + std::string key_type = tokens[7]; + // The key description may contain space. + std::string key_desc_prefix = tokens[8]; + // The prefix has a ":" at the end + std::string key_desc_pattern = keyring_desc + ":"; + if (key_type != "keyring" || key_desc_prefix != key_desc_pattern) { + continue; + } + if (!android::base::ParseInt(key_id.c_str(), &keyring_id)) { + LOG(ERROR) << "Unexpected key format in /proc/keys: " << key_id; + return -1; + } + return keyring_id; + } + return -1; +} + +} // namespace android diff --git a/libkeyutils/mini_keyctl/mini_keyctl_utils.h b/libkeyutils/mini_keyctl/mini_keyctl_utils.h new file mode 100644 index 000000000..cc31d29ce --- /dev/null +++ b/libkeyutils/mini_keyctl/mini_keyctl_utils.h @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2019 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 _MINI_KEYCTL_MINI_KEYCTL_UTILS_H_ +#define _MINI_KEYCTL_MINI_KEYCTL_UTILS_H_ + +#include + +#include + +namespace android { +key_serial_t GetKeyringId(const std::string& keyring_desc); +} // namespace android + +#endif // _MINI_KEYCTL_MINI_KEYCTL_UTILS_H_ diff --git a/libkeyutils/mini_keyctl_utils.h b/libkeyutils/mini_keyctl_utils.h deleted file mode 100644 index 3616831af..000000000 --- a/libkeyutils/mini_keyctl_utils.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (C) 2019 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 "include/keyutils.h" - -#include - -// Add key to a keyring. Returns non-zero if error happens. -int Add(const std::string& type, const std::string& desc, const std::string& data, - const std::string& keyring); - -// Add key from stdin to a keyring. Returns non-zero if error happens. -int Padd(const std::string& type, const std::string& desc, const std::string& keyring); - -// Removes the link from a keyring to a key if exists. Return non-zero if error happens. -int Unlink(key_serial_t key, const std::string& keyring); - -// Apply key-linking to a keyring. Return non-zero if error happens. -int RestrictKeyring(const std::string& keyring); - -// Retrieves a key's security context. Return the context string, or empty string on error. -std::string RetrieveSecurityContext(key_serial_t key);