1 /*
2 * Copyright (C) 2019 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <mini_keyctl_utils.h>
18
19 #include <fstream>
20 #include <iterator>
21 #include <sstream>
22 #include <string>
23 #include <vector>
24
25 #include <android-base/logging.h>
26 #include <android-base/parseint.h>
27
28 namespace android {
29
30 namespace {
31
SplitBySpace(const std::string & s)32 std::vector<std::string> SplitBySpace(const std::string& s) {
33 std::istringstream iss(s);
34 return std::vector<std::string>{std::istream_iterator<std::string>{iss},
35 std::istream_iterator<std::string>{}};
36 }
37
38 } // namespace
39
40 // Find the keyring id. request_key(2) only finds keys in the process, session or thread keyring
41 // hierarchy, but not internal keyring of a kernel subsystem (e.g. .fs-verity). To support all
42 // cases, this function looks up a keyring's ID by parsing /proc/keys. The keyring description may
43 // contain other information in the descritption section depending on the key type, only the first
44 // word in the keyring description is used for searching.
GetKeyringId(const std::string & keyring_desc)45 key_serial_t GetKeyringId(const std::string& keyring_desc) {
46 // If the keyring id is already a hex number, directly convert it to keyring id
47 key_serial_t keyring_id;
48 if (android::base::ParseInt(keyring_desc.c_str(), &keyring_id)) {
49 return keyring_id;
50 }
51
52 // Only keys allowed by SELinux rules will be shown here.
53 std::ifstream proc_keys_file("/proc/keys");
54 if (!proc_keys_file.is_open()) {
55 PLOG(ERROR) << "Failed to open /proc/keys";
56 return -1;
57 }
58
59 std::string line;
60 while (getline(proc_keys_file, line)) {
61 std::vector<std::string> tokens = SplitBySpace(line);
62 if (tokens.size() < 9) {
63 continue;
64 }
65 std::string key_id = "0x" + tokens[0];
66 std::string key_type = tokens[7];
67 // The key description may contain space.
68 std::string key_desc_prefix = tokens[8];
69 // The prefix has a ":" at the end
70 std::string key_desc_pattern = keyring_desc + ":";
71 if (key_type != "keyring" || key_desc_prefix != key_desc_pattern) {
72 continue;
73 }
74 if (!android::base::ParseInt(key_id.c_str(), &keyring_id)) {
75 LOG(ERROR) << "Unexpected key format in /proc/keys: " << key_id;
76 return -1;
77 }
78 return keyring_id;
79 }
80 return -1;
81 }
82
83 } // namespace android
84