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 
KeyCtrlAddAppAsdpKey(const char * type,const char * description,struct EncryptAsdpKey * fsKey,const key_serial_t ringId)61 key_serial_t KeyCtrlAddAppAsdpKey(const char *type,
62                                   const char *description,
63                                   struct EncryptAsdpKey *fsKey,
64                                   const key_serial_t ringId)
65 {
66     return syscall(__NR_add_key, type, description,
67                    (void *)(fsKey), sizeof(struct EncryptAsdpKey),
68                    ringId);
69 }
70 
KeyCtrlSearch(key_serial_t ringId,const char * type,const char * description,key_serial_t destRingId)71 long KeyCtrlSearch(key_serial_t ringId, const char *type, const char *description,
72     key_serial_t destRingId)
73 {
74     return syscall(__NR_keyctl, KEYCTL_SEARCH, ringId, type,
75         description, destRingId);
76 }
77 
KeyCtrlUnlink(key_serial_t key,key_serial_t keyring)78 long KeyCtrlUnlink(key_serial_t key, key_serial_t keyring)
79 {
80     return syscall(__NR_keyctl, KEYCTL_UNLINK, key, keyring);
81 }
82 
FsIoctl(const char * mnt,unsigned long cmd,void * arg)83 static bool FsIoctl(const char *mnt, unsigned long cmd, void *arg)
84 {
85     char *realPath = realpath(mnt, NULL);
86     if (realPath == NULL) {
87         FSCRYPT_LOGE("realpath failed");
88         return false;
89     }
90 
91     int fd = open(realPath, O_DIRECTORY | O_NOFOLLOW | O_CLOEXEC);
92     free(realPath);
93     if (fd < 0) {
94         FSCRYPT_LOGE("open %s failed, errno:%d", mnt, errno);
95         return false;
96     }
97     if (ioctl(fd, cmd, arg) != 0) {
98         FSCRYPT_LOGE("ioctl to %s failed, errno:%d", mnt, errno);
99         (void)close(fd);
100         return false;
101     }
102     (void)close(fd);
103     FSCRYPT_LOGI("success");
104     return true;
105 }
106 
107 #ifdef SUPPORT_FSCRYPT_V2
KeyCtrlInstallKey(const char * mnt,struct fscrypt_add_key_arg * arg)108 bool KeyCtrlInstallKey(const char *mnt, struct fscrypt_add_key_arg *arg)
109 {
110     FSCRYPT_LOGI("enter");
111     return FsIoctl(mnt, FS_IOC_ADD_ENCRYPTION_KEY, (void *)(arg));
112 }
113 
KeyCtrlRemoveKey(const char * mnt,struct fscrypt_remove_key_arg * arg)114 bool KeyCtrlRemoveKey(const char *mnt, struct fscrypt_remove_key_arg *arg)
115 {
116     FSCRYPT_LOGI("enter");
117     return FsIoctl(mnt, FS_IOC_REMOVE_ENCRYPTION_KEY, (void *)arg);
118 }
119 
KeyCtrlGetKeyStatus(const char * mnt,struct fscrypt_get_key_status_arg * arg)120 bool KeyCtrlGetKeyStatus(const char *mnt, struct fscrypt_get_key_status_arg *arg)
121 {
122     FSCRYPT_LOGI("enter");
123     return FsIoctl(mnt, FS_IOC_GET_ENCRYPTION_KEY_STATUS, (void *)(arg));
124 }
125 
KeyCtrlGetPolicyEx(const char * path,struct fscrypt_get_policy_ex_arg * policy)126 bool KeyCtrlGetPolicyEx(const char *path, struct fscrypt_get_policy_ex_arg *policy)
127 {
128     FSCRYPT_LOGI("enter");
129     return FsIoctl(path, FS_IOC_GET_ENCRYPTION_POLICY_EX, (void *)(policy));
130 }
131 #endif
132 
KeyCtrlSetPolicy(const char * path,union FscryptPolicy * policy)133 bool KeyCtrlSetPolicy(const char *path, union FscryptPolicy *policy)
134 {
135     FSCRYPT_LOGI("enter");
136     return FsIoctl(path, FS_IOC_SET_ENCRYPTION_POLICY, (void *)(policy));
137 }
138 
KeyCtrlGetPolicy(const char * path,struct fscrypt_policy * policy)139 bool KeyCtrlGetPolicy(const char *path, struct fscrypt_policy *policy)
140 {
141     FSCRYPT_LOGI("enter");
142     return FsIoctl(path, FS_IOC_GET_ENCRYPTION_POLICY, (void *)(policy));
143 }
144 
CheckKernelFscrypt(const char * mnt)145 static uint8_t CheckKernelFscrypt(const char *mnt)
146 {
147     char *realPath = realpath(mnt, NULL);
148     if (realPath == NULL) {
149         FSCRYPT_LOGE("realpath failed");
150         return FSCRYPT_INVALID;
151     }
152 
153     int fd = open(realPath, O_RDONLY | O_DIRECTORY | O_CLOEXEC);
154     free(realPath);
155     if (fd < 0) {
156         FSCRYPT_LOGE("open policy file failed, errno: %d", errno);
157         return FSCRYPT_INVALID;
158     }
159 
160 #ifdef SUPPORT_FSCRYPT_V2
161     errno = 0;
162     (void)ioctl(fd, FS_IOC_ADD_ENCRYPTION_KEY, NULL);
163     (void)close(fd);
164     if (errno == EOPNOTSUPP) {
165         FSCRYPT_LOGE("Kernel doesn't support fscrypt v1 or v2.");
166         return FSCRYPT_INVALID;
167     } else if (errno == ENOTTY) {
168         FSCRYPT_LOGE("Kernel doesn't support fscrypt v2, pls use v1.");
169         return FSCRYPT_V1;
170     } else if (errno == EFAULT) {
171         FSCRYPT_LOGI("Kernel is support fscrypt v2.");
172         return FSCRYPT_V2;
173     }
174     FSCRYPT_LOGE("Unexpected errno: %d", errno);
175     return FSCRYPT_INVALID;
176 #else
177     (void)close(fd);
178     return FSCRYPT_V1;
179 #endif
180 }
181 
KeyCtrlGetFscryptVersion(const char * mnt)182 uint8_t KeyCtrlGetFscryptVersion(const char *mnt)
183 {
184     uint8_t version = CheckKernelFscrypt(mnt);
185     return version;
186 }
187 
KeyCtrlHasFscryptSyspara(void)188 bool KeyCtrlHasFscryptSyspara(void)
189 {
190     char tmp[POLICY_BUF_SIZE] = { 0 };
191     uint32_t len = POLICY_BUF_SIZE;
192     int ret = GetFscryptParameter(FSCRYPT_POLICY_KEY, "", tmp, &len);
193     if (ret != 0) {
194         FSCRYPT_LOGE("fscrypt config parameter not set, not enable fscrypt");
195         return false;
196     }
197 
198     return true;
199 }
200 
KeyCtrlLoadVersion(const char * keyPath)201 uint8_t KeyCtrlLoadVersion(const char *keyPath)
202 {
203     if (!keyPath) {
204         FSCRYPT_LOGE("key path is null");
205         return FSCRYPT_INVALID;
206     }
207     char pathLen = strlen(keyPath) + strlen(PATH_FSCRYPT_VER) + 1;
208     char *path = (char *)malloc(pathLen);
209     if (!path) {
210         FSCRYPT_LOGE("no memory for full key path");
211         return FSCRYPT_INVALID;
212     }
213     path[0] = '\0';
214     if (strncat_s(path, pathLen - strlen(PATH_FSCRYPT_VER), keyPath, strlen(keyPath)) != EOK) {
215         free(path);
216         FSCRYPT_LOGE("KEY path strcat error");
217         return FSCRYPT_INVALID;
218     }
219     if (strncat_s(path, pathLen, PATH_FSCRYPT_VER, strlen(PATH_FSCRYPT_VER)) != EOK) {
220         free(path);
221         FSCRYPT_LOGE("version path strcat error");
222         return FSCRYPT_INVALID;
223     }
224 
225     char *buf = ReadFileToBuf(path);
226     free(path);
227     if (!buf) {
228         FSCRYPT_LOGE("read fscrypt version file failed");
229         return FSCRYPT_INVALID;
230     }
231     if (isdigit(*buf)) {
232         int ver = atoi(buf);
233         if (ver == FSCRYPT_V1 || ver == FSCRYPT_V2) {
234             free(buf);
235             FSCRYPT_LOGI("version %d loaded", ver);
236             return ver;
237         }
238         FSCRYPT_LOGE("version loaded failed. ver = %d", ver);
239     }
240     FSCRYPT_LOGE("bad version content. buf = %s", buf);
241     free(buf);
242     return FSCRYPT_V1;
243 }
244