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