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 "fscrypt_control.h"
16 
17 #include <fcntl.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include <stdbool.h>
21 #include <sys/stat.h>
22 #include <sys/types.h>
23 #include <unistd.h>
24 
25 #include "fscrypt_log.h"
26 #include "fscrypt_sysparam.h"
27 #include "init_utils.h"
28 #include "key_control.h"
29 #include "securec.h"
30 #include <sys/ioctl.h>
31 
32 #define ARRAY_LEN(array) (sizeof((array)) / sizeof((array)[0]))
33 
34 typedef struct FscrtpyItem_ {
35     char *key;
36     uint8_t value;
37 }FscrtpyItem;
38 
39 typedef struct EncryptPolicy_ {
40     uint8_t version;
41     uint8_t fileName;
42     uint8_t content;
43     uint8_t flags;
44     bool hwWrappedKey;
45 }EncryptPolicy;
46 
47 static EncryptPolicy g_fscryptPolicy = {
48     FSCRYPT_V2,
49     FSCRYPT_MODE_AES_256_CTS,
50     FSCRYPT_MODE_AES_256_XTS,
51     FSCRYPT_POLICY_FLAGS_PAD_32,
52     false
53 };
54 
55 enum FscryptOptins {
56     FSCRYPT_VERSION_NUM = 0,
57     FSCRYPT_FILENAME_MODE,
58     FSCRYPT_CONTENT_MODE,
59     FSCRYPT_OPTIONS_MAX,
60 };
61 
62 static const FscrtpyItem ALL_VERSION[] = {
63     {"1", FSCRYPT_V1},
64     {"2", FSCRYPT_V2},
65 };
66 
67 static const FscrtpyItem FILENAME_MODES[] = {
68     {"aes-256-cts", FSCRYPT_MODE_AES_256_CTS},
69 };
70 
71 static const FscrtpyItem CONTENTS_MODES[] = {
72     {"aes-256-xts", FSCRYPT_MODE_AES_256_XTS},
73 };
74 
75 static bool g_fscryptEnabled = false;
76 static bool g_fscryptInited = false;
77 
78 static const char *GLOBAL_FSCRYPT_DIR[] = {
79     "/data/app/el1/bundle/public",
80     "/data/service/el1/public",
81     "/data/chipset/el1/public",
82 };
83 
84 static const char *DEVICE_EL1_DIR = "/data/service/el0/storage_daemon/sd";
85 static const char *PATH_KEYDESC = "/key_desc";
86 #ifdef SUPPORT_FSCRYPT_V2
87 static const char *PATH_KEYID = "/key_id";
88 #endif
89 
IsSupportedPolicyKey(const char * key,const FscrtpyItem * items,size_t len)90 static bool IsSupportedPolicyKey(const char *key,
91                                  const FscrtpyItem *items,
92                                  size_t len)
93 {
94     for (size_t i = 0 ; i < len; i++) {
95         if (strncmp(key, items[i].key, strlen(items[i].key)) == 0) {
96             return true;
97         }
98     }
99     return false;
100 }
101 
IsSupportedPolicy(const char * policy,enum FscryptOptins number)102 static bool IsSupportedPolicy(const char *policy,
103                               enum FscryptOptins number)
104 {
105     if ((number >= FSCRYPT_OPTIONS_MAX) || (!policy)) {
106         return false;
107     }
108 
109     switch (number) {
110         case FSCRYPT_VERSION_NUM:
111             return IsSupportedPolicyKey(policy, ALL_VERSION,
112                 ARRAY_LEN(ALL_VERSION));
113         case FSCRYPT_FILENAME_MODE:
114             return IsSupportedPolicyKey(policy, FILENAME_MODES,
115                 ARRAY_LEN(FILENAME_MODES));
116         case FSCRYPT_CONTENT_MODE:
117             return IsSupportedPolicyKey(policy, CONTENTS_MODES,
118                 ARRAY_LEN(CONTENTS_MODES));
119         default:
120             return false;
121     }
122     return false;
123 }
124 
FscryptSetSysparam(const char * policy)125 int FscryptSetSysparam(const char *policy)
126 {
127     if (!policy) {
128         return -EINVAL;
129     }
130 
131     char *tmp = strdup(policy);
132     if (!tmp) {
133         FSCRYPT_LOGE("No memory for policy option");
134         return -ENOMEM;
135     }
136     int optNums = 0;
137     char **options = SplitStringExt(tmp, ":", &optNums, FSCRYPT_OPTIONS_MAX);
138     free(tmp);
139     if (!options) {
140         return -ENOMEM;
141     }
142     if (optNums != FSCRYPT_OPTIONS_MAX) {
143         FSCRYPT_LOGE("Mount fscrypt option setting error, not enabled crypto!");
144         FreeStringVector(options, optNums);
145         return -EFAULT;
146     }
147 
148     // check supported policy
149     for (enum FscryptOptins i = FSCRYPT_VERSION_NUM; i < FSCRYPT_OPTIONS_MAX; i++) {
150         char *temp = options[i];
151         if (!IsSupportedPolicy(temp, i)) {
152             FSCRYPT_LOGE("Not supported policy, %s", temp);
153             FreeStringVector(options, optNums);
154             return -ENOTSUP;
155         }
156     }
157     FreeStringVector(options, optNums);
158 
159     int ret = SetFscryptParameter(FSCRYPT_POLICY_KEY, policy);
160     if (ret < 0) {
161         FSCRYPT_LOGE("Set fscrypt system parameter failed %d", ret);
162         return ret;
163     }
164     g_fscryptEnabled = true;
165     g_fscryptInited = false; // need to re-init
166 
167     return 0;
168 }
169 
170 #ifdef USER_CRYPTO_MANAGER
PraseOnePloicyValue(uint8_t * value,const char * key,const FscrtpyItem * table,size_t numbers)171 static void PraseOnePloicyValue(uint8_t *value, const char *key,
172                                 const FscrtpyItem *table, size_t numbers)
173 {
174     for (size_t i = 0; i < numbers; i++) {
175         size_t len = strlen(table[i].key);
176         if (strncmp(key, table[i].key, len) == 0 &&
177             strlen(key) == len) {
178             *value = table[i].value;
179             return;
180         }
181     }
182     FSCRYPT_LOGE("Have not found value for the key!");
183 }
184 #endif
185 
InitFscryptPolicy(void)186 int InitFscryptPolicy(void)
187 {
188 #ifdef USER_CRYPTO_MANAGER
189     if (g_fscryptInited) {
190         FSCRYPT_LOGI("Have been init");
191         return 0;
192     }
193     char policy[POLICY_BUF_SIZE];
194     uint32_t len = POLICY_BUF_SIZE - 1;
195     int ret = GetFscryptParameter(FSCRYPT_POLICY_KEY, "", policy, &len);
196     if (ret != 0) {
197         FSCRYPT_LOGI("Get fscrypt policy failed");
198         return -ENOTSUP;
199     }
200     int count = 0;
201     char **option = SplitStringExt(policy, ":", &count, FSCRYPT_OPTIONS_MAX);
202     if (!option) {
203         FSCRYPT_LOGE("Fscrypt setting error");
204         return -ENOTSUP;
205     }
206     if (count != FSCRYPT_OPTIONS_MAX) {
207         FSCRYPT_LOGE("Fscrypt policy count error");
208         FreeStringVector(option, count);
209         return -ENOTSUP;
210     }
211 
212     PraseOnePloicyValue(&g_fscryptPolicy.version, option[FSCRYPT_VERSION_NUM],
213         ALL_VERSION, ARRAY_LEN(ALL_VERSION));
214     PraseOnePloicyValue(&g_fscryptPolicy.fileName, option[FSCRYPT_FILENAME_MODE],
215         FILENAME_MODES, ARRAY_LEN(FILENAME_MODES));
216     PraseOnePloicyValue(&g_fscryptPolicy.content, option[FSCRYPT_CONTENT_MODE],
217         CONTENTS_MODES, ARRAY_LEN(CONTENTS_MODES));
218 
219     FreeStringVector(option, count);
220     g_fscryptInited = true;
221     FSCRYPT_LOGI("Fscrypt policy init success");
222 #endif
223 
224     return 0;
225 }
226 
227 /*
228  * Splic full path, Caller need to free *buf after using
229  * if return success.
230  *
231  * @path: base key path
232  * @name: fscrypt file, so as /key_id
233  * @buf: splic result if return 0
234  */
SpliceKeyPath(const char * path,size_t pathLen,const char * name,size_t nameLen,char ** buf)235 static int SpliceKeyPath(const char *path, size_t pathLen,
236                          const char *name, size_t nameLen,
237                          char **buf)
238 {
239     FSCRYPT_LOGI("key path %s, name %s", path, name);
240     *buf = NULL;
241     size_t bufMax = pathLen + nameLen + 1;
242     char *tmpBuf = (char *)malloc(bufMax);
243     if (!tmpBuf) {
244         FSCRYPT_LOGE("No memory for fscrypt v1 path buffer");
245         return -ENOMEM;
246     }
247     tmpBuf[0] = '\0';
248 
249     int ret = strncat_s(tmpBuf, bufMax, path, pathLen);
250     if (ret != 0) {
251         free(tmpBuf);
252         FSCRYPT_LOGE("splic previous path error");
253         return ret;
254     }
255     ret = strncat_s(tmpBuf, bufMax, name, nameLen);
256     if (ret != 0) {
257         free(tmpBuf);
258         FSCRYPT_LOGE("splic later path error");
259         return ret;
260     }
261     *buf = tmpBuf;
262 
263     return 0;
264 }
265 
ReadKeyFile(const char * path,char * buf,size_t len)266 static int ReadKeyFile(const char *path, char *buf, size_t len)
267 {
268     if (!path || !buf) {
269         FSCRYPT_LOGE("path or buf is null");
270         return -EINVAL;
271     }
272     struct stat st = {0};
273     if (stat(path, &st) != 0) {
274         FSCRYPT_LOGE("stat file failed");
275         return -EFAULT;
276     }
277     if ((size_t)st.st_size != len) {
278         FSCRYPT_LOGE("target file size is not equal to buf len");
279         return -EFAULT;
280     }
281     char *realPath = realpath(path, NULL);
282     if (realPath == NULL) {
283         FSCRYPT_LOGE("realpath failed");
284         return -EFAULT;
285     }
286 
287     int fd = open(realPath, O_RDONLY);
288     free(realPath);
289     if (fd < 0) {
290         FSCRYPT_LOGE("key file read open failed");
291         return -EFAULT;
292     }
293     if (read(fd, buf, len) != (ssize_t)len) {
294         FSCRYPT_LOGE("bad file content");
295         (void)close(fd);
296         return -EBADF;
297     }
298     (void)close(fd);
299 
300     return 0;
301 }
302 
SetPolicyLegacy(const char * keyDescPath,const char * toEncrypt,union FscryptPolicy * arg)303 static int SetPolicyLegacy(const char *keyDescPath,
304                            const char *toEncrypt,
305                            union FscryptPolicy *arg)
306 {
307     char keyDesc[FSCRYPT_KEY_DESCRIPTOR_SIZE] = {0};
308     int ret = ReadKeyFile(keyDescPath, keyDesc, FSCRYPT_KEY_DESCRIPTOR_SIZE);
309     if (ret != 0) {
310         return ret;
311     }
312     arg->v1.version = FSCRYPT_POLICY_V1;
313     ret = memcpy_s(arg->v1.master_key_descriptor,
314         FSCRYPT_KEY_DESCRIPTOR_SIZE, keyDesc, FSCRYPT_KEY_DESCRIPTOR_SIZE);
315     if (ret != 0) {
316         FSCRYPT_LOGE("memcpy_s copy failed");
317         return ret;
318     }
319     if (!KeyCtrlSetPolicy(toEncrypt, arg)) {
320         FSCRYPT_LOGE("Set Policy v1 failed");
321         return -EFAULT;
322     }
323     return 0;
324 }
325 
326 #ifdef SUPPORT_FSCRYPT_V2
SetPolicyV2(const char * keyIdPath,const char * toEncrypt,union FscryptPolicy * arg)327 static int SetPolicyV2(const char *keyIdPath,
328                        const char *toEncrypt,
329                        union FscryptPolicy *arg)
330 {
331     char keyId[FSCRYPT_KEY_IDENTIFIER_SIZE] = {0};
332     int ret = ReadKeyFile(keyIdPath, keyId, FSCRYPT_KEY_IDENTIFIER_SIZE);
333     if (ret != 0) {
334         return ret;
335     }
336     arg->v2.version = FSCRYPT_POLICY_V2;
337     ret = memcpy_s(arg->v2.master_key_identifier,
338         FSCRYPT_KEY_IDENTIFIER_SIZE, keyId, FSCRYPT_KEY_IDENTIFIER_SIZE);
339     if (ret != 0) {
340         FSCRYPT_LOGE("memcpy_s copy failed");
341         return ret;
342     }
343     if (!KeyCtrlSetPolicy(toEncrypt, arg)) {
344         FSCRYPT_LOGE("Set Policy v2 failed");
345         return -EFAULT;
346     }
347     return 0;
348 }
349 #endif
350 
LoadAndSetPolicy(const char * keyDir,const char * dir)351 int LoadAndSetPolicy(const char *keyDir, const char *dir)
352 {
353     if (!keyDir || !dir) {
354         FSCRYPT_LOGE("set policy parameters is null");
355         return -EINVAL;
356     }
357     int ret = InitFscryptPolicy();
358     if (ret != 0) {
359         FSCRYPT_LOGE("Get fscrypt policy error %d", ret);
360         return ret;
361     }
362 
363     union FscryptPolicy arg;
364     (void)memset_s(&arg, sizeof(arg), 0, sizeof(arg));
365     arg.v1.filenames_encryption_mode = g_fscryptPolicy.fileName;
366     arg.v1.contents_encryption_mode = g_fscryptPolicy.content;
367     arg.v1.flags = g_fscryptPolicy.flags;
368 
369     char *pathBuf = NULL;
370     ret = -ENOTSUP;
371 
372     uint8_t fscryptVer = KeyCtrlLoadVersion(keyDir);
373     if (fscryptVer == FSCRYPT_V1) {
374         ret = SpliceKeyPath(keyDir, strlen(keyDir), PATH_KEYDESC,
375             strlen(PATH_KEYDESC), &pathBuf);
376         if (ret != 0) {
377             FSCRYPT_LOGE("path splice error");
378             return ret;
379         }
380         ret = SetPolicyLegacy(pathBuf, dir, &arg);
381         if (ret != 0) {
382             FSCRYPT_LOGE("SetPolicyLegacy fail, ret: %d", ret);
383         }
384 #ifdef SUPPORT_FSCRYPT_V2
385     } else if (fscryptVer == FSCRYPT_V2) {
386         ret = SpliceKeyPath(keyDir, strlen(keyDir), PATH_KEYID,
387             strlen(PATH_KEYID), &pathBuf);
388         if (ret != 0) {
389             FSCRYPT_LOGE("path splice error");
390             return ret;
391         }
392         ret = SetPolicyV2(pathBuf, dir, &arg);
393         if (ret != 0) {
394             FSCRYPT_LOGE("SetPolicyV2 fail, ret: %d", ret);
395         }
396 #endif
397     }
398     if (pathBuf != NULL) {
399         free(pathBuf);
400         pathBuf = NULL;
401     }
402 
403     return ret;
404 }
405 
ActSetFileXattrActSetFileXattr(const char * path,char * keyDesc,int storageType)406 static int ActSetFileXattrActSetFileXattr(const char *path, char *keyDesc, int storageType)
407 {
408     struct FscryptSdpPolicy PolicySDP = {0, 0, 0, 0, 0, {0, 0, 0, 0, 0, 0, 0, 0}};
409     PolicySDP.version = SDP_VERSIOIN;
410     PolicySDP.sdpclass = storageType;
411     PolicySDP.contentsEncryptionMode = SDP_CONTENTS_ENCRYPTION_MODE;
412     PolicySDP.filenamesEncryptionMode = SDP_FILENAMES_ENCRYPTION_MODE;
413     PolicySDP.flags = SDP_FLAGS;
414 
415     int ret = memcpy_s((char *)PolicySDP.masterKeyDescriptor, FS_KEY_DESC_SIZE, (char *)keyDesc,
416                        FSCRYPT_KEY_DESCRIPTOR_SIZE);
417     if (ret != 0) {
418         FSCRYPT_LOGE("memcpy_s copy failed");
419         return -errno;
420     }
421     int fd = open((char *)path, O_DIRECTORY | O_NOFOLLOW | O_CLOEXEC);
422     if (fd < 0) {
423         FSCRYPT_LOGE("install File or Directory open failed: %{public}d", errno);
424         return -errno;
425     }
426     ret = ioctl(fd, F2FS_IOC_SET_SDP_ENCRYPTION_POLICY, &PolicySDP);
427     if (ret != 0) {
428         FSCRYPT_LOGE("ioctl fbex_cmd failed, ret: 0x%{public}X, errno: %{public}d", ret, errno);
429         close(fd);
430         return ret;
431     }
432     close(fd);
433     return ret;
434 }
435 
LoadAndSetEceAndSecePolicy(const char * keyDir,const char * dir,int type)436 int LoadAndSetEceAndSecePolicy(const char *keyDir, const char *dir, int type)
437 {
438     int el3Key = 3; // el3
439     int el4Key = 4; // el4
440     if (!keyDir || !dir) {
441         FSCRYPT_LOGE("set policy parameters is null");
442         return -EINVAL;
443     }
444     char *pathBuf = NULL;
445     int ret = SpliceKeyPath(keyDir, strlen(keyDir), PATH_KEYDESC, strlen(PATH_KEYDESC), &pathBuf);
446     if (ret != 0) {
447         FSCRYPT_LOGE("path splice error");
448         return ret;
449     }
450 
451     uint8_t fscryptVer = KeyCtrlLoadVersion(keyDir);
452     if (fscryptVer == FSCRYPT_V1) {
453         if (type == el3Key || type == el4Key) {
454             if (type == el3Key) {
455                 type = FSCRYPT_SDP_SECE_CLASS;
456             } else {
457                 type = FSCRYPT_SDP_ECE_CLASS;
458             }
459             char keyDesc[FSCRYPT_KEY_DESCRIPTOR_SIZE] = {0};
460             ret = ReadKeyFile(pathBuf, keyDesc, FSCRYPT_KEY_DESCRIPTOR_SIZE);
461             if (ret != 0) {
462                 return ret;
463             }
464             ret = ActSetFileXattrActSetFileXattr(dir, keyDesc, type);
465             if (ret != 0) {
466                 FSCRYPT_LOGE("ActSetFileXattr failed");
467                 return ret;
468             }
469         }
470 #ifdef SUPPORT_FSCRYPT_V2
471     } else if (fscryptVer == FSCRYPT_V2) {
472         return 0;
473 #endif
474     }
475     if (pathBuf != NULL) {
476         free(pathBuf);
477     }
478     return ret;
479 }
480 
SetGlobalEl1DirPolicy(const char * dir)481 int SetGlobalEl1DirPolicy(const char *dir)
482 {
483     if (!g_fscryptEnabled) {
484         FSCRYPT_LOGI("Fscrypt have not enabled");
485         return 0;
486     }
487     for (size_t i = 0; i < ARRAY_LEN(GLOBAL_FSCRYPT_DIR); i++) {
488         size_t tmpLen = strlen(GLOBAL_FSCRYPT_DIR[i]);
489         if ((strncmp(dir, GLOBAL_FSCRYPT_DIR[i], tmpLen) == 0) && (strlen(dir) == tmpLen)) {
490             return LoadAndSetPolicy(DEVICE_EL1_DIR, dir);
491         }
492     }
493     return 0;
494 }
495 
GetFscryptVersionFromPolicy(void)496 uint8_t GetFscryptVersionFromPolicy(void)
497 {
498     return g_fscryptPolicy.version;
499 }
500