1 /*
2 * Copyright (C) 2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15 #include "key_control.h"
16
17 #include <bits/fcntl.h>
18 #include <ctype.h>
19 #include <sys/syscall.h>
20 #include <fcntl.h>
21 #include <stdbool.h>
22 #include <stdint.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <sys/ioctl.h>
26 #include <unistd.h>
27 #include <linux/keyctl.h>
28
29 #include "fscrypt_log.h"
30 #include "fscrypt_sysparam.h"
31 #include "init_utils.h"
32 #include "securec.h"
33
KeyCtrlGetKeyringId(key_serial_t id,int create)34 key_serial_t KeyCtrlGetKeyringId(key_serial_t id, int create)
35 {
36 return syscall(__NR_keyctl, KEYCTL_GET_KEYRING_ID, id, create);
37 }
38
KeyCtrlAddKey(const char * type,const char * description,const key_serial_t ringId)39 key_serial_t KeyCtrlAddKey(const char *type, const char *description,
40 const key_serial_t ringId)
41 {
42 return syscall(__NR_add_key, type, description, NULL, 0, ringId);
43 }
44
KeyCtrlAddKeyEx(const char * type,const char * description,struct fscrypt_key * fsKey,const key_serial_t ringId)45 key_serial_t KeyCtrlAddKeyEx(const char *type, const char *description,
46 struct fscrypt_key *fsKey, const key_serial_t ringId)
47 {
48 return syscall(__NR_add_key, type, description,
49 (void *)(fsKey), sizeof(struct fscrypt_key),
50 ringId);
51 }
52
KeyCtrlAddKeySdp(const char * type,const char * description,struct EncryptionKeySdp * fsKey,const key_serial_t ringId)53 key_serial_t KeyCtrlAddKeySdp(const char *type, const char *description,
54 struct EncryptionKeySdp *fsKey, const key_serial_t ringId)
55 {
56 return syscall(__NR_add_key, type, description,
57 (void *)(fsKey), sizeof(struct EncryptionKeySdp),
58 ringId);
59 }
60
KeyCtrlSearch(key_serial_t ringId,const char * type,const char * description,key_serial_t destRingId)61 long KeyCtrlSearch(key_serial_t ringId, const char *type, const char *description,
62 key_serial_t destRingId)
63 {
64 return syscall(__NR_keyctl, KEYCTL_SEARCH, ringId, type,
65 description, destRingId);
66 }
67
KeyCtrlUnlink(key_serial_t key,key_serial_t keyring)68 long KeyCtrlUnlink(key_serial_t key, key_serial_t keyring)
69 {
70 return syscall(__NR_keyctl, KEYCTL_UNLINK, key, keyring);
71 }
72
FsIoctl(const char * mnt,unsigned long cmd,void * arg)73 static bool FsIoctl(const char *mnt, unsigned long cmd, void *arg)
74 {
75 char *realPath = realpath(mnt, NULL);
76 if (realPath == NULL) {
77 FSCRYPT_LOGE("realpath failed");
78 return false;
79 }
80
81 int fd = open(realPath, O_DIRECTORY | O_NOFOLLOW | O_CLOEXEC);
82 free(realPath);
83 if (fd < 0) {
84 FSCRYPT_LOGE("open %s failed, errno:%d", mnt, errno);
85 return false;
86 }
87 if (ioctl(fd, cmd, arg) != 0) {
88 FSCRYPT_LOGE("ioctl to %s failed, errno:%d", mnt, errno);
89 (void)close(fd);
90 return false;
91 }
92 (void)close(fd);
93 FSCRYPT_LOGI("success");
94 return true;
95 }
96
97 #ifdef SUPPORT_FSCRYPT_V2
KeyCtrlInstallKey(const char * mnt,struct fscrypt_add_key_arg * arg)98 bool KeyCtrlInstallKey(const char *mnt, struct fscrypt_add_key_arg *arg)
99 {
100 FSCRYPT_LOGI("enter");
101 return FsIoctl(mnt, FS_IOC_ADD_ENCRYPTION_KEY, (void *)(arg));
102 }
103
KeyCtrlRemoveKey(const char * mnt,struct fscrypt_remove_key_arg * arg)104 bool KeyCtrlRemoveKey(const char *mnt, struct fscrypt_remove_key_arg *arg)
105 {
106 FSCRYPT_LOGI("enter");
107 return FsIoctl(mnt, FS_IOC_REMOVE_ENCRYPTION_KEY, (void *)arg);
108 }
109
KeyCtrlGetKeyStatus(const char * mnt,struct fscrypt_get_key_status_arg * arg)110 bool KeyCtrlGetKeyStatus(const char *mnt, struct fscrypt_get_key_status_arg *arg)
111 {
112 FSCRYPT_LOGI("enter");
113 return FsIoctl(mnt, FS_IOC_GET_ENCRYPTION_KEY_STATUS, (void *)(arg));
114 }
115
KeyCtrlGetPolicyEx(const char * path,struct fscrypt_get_policy_ex_arg * policy)116 bool KeyCtrlGetPolicyEx(const char *path, struct fscrypt_get_policy_ex_arg *policy)
117 {
118 FSCRYPT_LOGI("enter");
119 return FsIoctl(path, FS_IOC_GET_ENCRYPTION_POLICY_EX, (void *)(policy));
120 }
121 #endif
122
KeyCtrlSetPolicy(const char * path,union FscryptPolicy * policy)123 bool KeyCtrlSetPolicy(const char *path, union FscryptPolicy *policy)
124 {
125 FSCRYPT_LOGI("enter");
126 return FsIoctl(path, FS_IOC_SET_ENCRYPTION_POLICY, (void *)(policy));
127 }
128
KeyCtrlGetPolicy(const char * path,struct fscrypt_policy * policy)129 bool KeyCtrlGetPolicy(const char *path, struct fscrypt_policy *policy)
130 {
131 FSCRYPT_LOGI("enter");
132 return FsIoctl(path, FS_IOC_GET_ENCRYPTION_POLICY, (void *)(policy));
133 }
134
CheckKernelFscrypt(const char * mnt)135 static uint8_t CheckKernelFscrypt(const char *mnt)
136 {
137 char *realPath = realpath(mnt, NULL);
138 if (realPath == NULL) {
139 FSCRYPT_LOGE("realpath failed");
140 return FSCRYPT_INVALID;
141 }
142
143 int fd = open(realPath, O_RDONLY | O_DIRECTORY | O_CLOEXEC);
144 free(realPath);
145 if (fd < 0) {
146 FSCRYPT_LOGE("open policy file failed, errno: %d", errno);
147 return FSCRYPT_INVALID;
148 }
149
150 #ifdef SUPPORT_FSCRYPT_V2
151 errno = 0;
152 (void)ioctl(fd, FS_IOC_ADD_ENCRYPTION_KEY, NULL);
153 (void)close(fd);
154 if (errno == EOPNOTSUPP) {
155 FSCRYPT_LOGE("Kernel doesn't support fscrypt v1 or v2.");
156 return FSCRYPT_INVALID;
157 } else if (errno == ENOTTY) {
158 FSCRYPT_LOGE("Kernel doesn't support fscrypt v2, pls use v1.");
159 return FSCRYPT_V1;
160 } else if (errno == EFAULT) {
161 FSCRYPT_LOGI("Kernel is support fscrypt v2.");
162 return FSCRYPT_V2;
163 }
164 FSCRYPT_LOGE("Unexpected errno: %d", errno);
165 return FSCRYPT_INVALID;
166 #else
167 (void)close(fd);
168 return FSCRYPT_V1;
169 #endif
170 }
171
KeyCtrlGetFscryptVersion(const char * mnt)172 uint8_t KeyCtrlGetFscryptVersion(const char *mnt)
173 {
174 uint8_t version = CheckKernelFscrypt(mnt);
175 return version;
176 }
177
KeyCtrlHasFscryptSyspara(void)178 bool KeyCtrlHasFscryptSyspara(void)
179 {
180 FSCRYPT_LOGI("enter");
181 char tmp[POLICY_BUF_SIZE] = { 0 };
182 uint32_t len = POLICY_BUF_SIZE;
183 int ret = GetFscryptParameter(FSCRYPT_POLICY_KEY, "", tmp, &len);
184 if (ret != 0) {
185 FSCRYPT_LOGE("fscrypt config parameter not set, not enable fscrypt");
186 return false;
187 }
188
189 return true;
190 }
191
KeyCtrlLoadVersion(const char * keyPath)192 uint8_t KeyCtrlLoadVersion(const char *keyPath)
193 {
194 if (!keyPath) {
195 FSCRYPT_LOGE("key path is null");
196 return FSCRYPT_INVALID;
197 }
198 char pathLen = strlen(keyPath) + strlen(PATH_FSCRYPT_VER) + 1;
199 char *path = (char *)malloc(pathLen);
200 if (!path) {
201 FSCRYPT_LOGE("no memory for full key path");
202 return FSCRYPT_INVALID;
203 }
204 path[0] = '\0';
205 if (strncat_s(path, pathLen - strlen(PATH_FSCRYPT_VER), keyPath, strlen(keyPath)) != EOK) {
206 free(path);
207 FSCRYPT_LOGE("KEY path strcat error");
208 return FSCRYPT_INVALID;
209 }
210 if (strncat_s(path, pathLen, PATH_FSCRYPT_VER, strlen(PATH_FSCRYPT_VER)) != EOK) {
211 free(path);
212 FSCRYPT_LOGE("version path strcat error");
213 return FSCRYPT_INVALID;
214 }
215
216 char *buf = ReadFileToBuf(path);
217 free(path);
218 if (!buf) {
219 FSCRYPT_LOGE("read fscrypt version file failed");
220 return FSCRYPT_INVALID;
221 }
222 if (isdigit(*buf)) {
223 int ver = atoi(buf);
224 if (ver == FSCRYPT_V1 || ver == FSCRYPT_V2) {
225 free(buf);
226 FSCRYPT_LOGI("version %d loaded", ver);
227 return ver;
228 }
229 }
230 free(buf);
231
232 FSCRYPT_LOGE("bad version content");
233 return FSCRYPT_INVALID;
234 }
235