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
31 #define ARRAY_LEN(array) (sizeof((array)) / sizeof((array)[0]))
32
33 typedef struct FscrtpyItem_ {
34 char *key;
35 uint8_t value;
36 }FscrtpyItem;
37
38 typedef struct EncryptPolicy_ {
39 uint8_t version;
40 uint8_t fileName;
41 uint8_t content;
42 uint8_t flags;
43 bool hwWrappedKey;
44 }EncryptPolicy;
45
46 static EncryptPolicy g_fscryptPolicy = {
47 FSCRYPT_V2,
48 FSCRYPT_MODE_AES_256_CTS,
49 FSCRYPT_MODE_AES_256_XTS,
50 FSCRYPT_POLICY_FLAGS_PAD_32,
51 false
52 };
53
54 enum FscryptOptins {
55 FSCRYPT_VERSION_NUM = 0,
56 FSCRYPT_FILENAME_MODE,
57 FSCRYPT_CONTENT_MODE,
58 FSCRYPT_OPTIONS_MAX,
59 };
60
61 static const FscrtpyItem ALL_VERSION[] = {
62 {"1", FSCRYPT_V1},
63 {"2", FSCRYPT_V2},
64 };
65
66 static const FscrtpyItem FILENAME_MODES[] = {
67 {"aes-256-cts", FSCRYPT_MODE_AES_256_CTS},
68 };
69
70 static const FscrtpyItem CONTENTS_MODES[] = {
71 {"aes-256-xts", FSCRYPT_MODE_AES_256_XTS},
72 };
73
74 static bool g_fscryptEnabled = false;
75 static bool g_fscryptInited = false;
76
77 static const char *GLOBAL_FSCRYPT_DIR[] = {
78 "/data/app/el1/bundle/public",
79 "/data/service/el1/public",
80 "/data/chipset/el1/public",
81 };
82
83 static const char *DEVICE_EL1_DIR = "/data/service/el0/storage_daemon/sd";
84 static const char *PATH_KEYDESC = "/key_desc";
85 #ifdef SUPPORT_FSCRYPT_V2
86 static const char *PATH_KEYID = "/key_id";
87 #endif
88
IsSupportedPolicyKey(const char * key,const FscrtpyItem * items,size_t len)89 static bool IsSupportedPolicyKey(const char *key,
90 const FscrtpyItem *items,
91 size_t len)
92 {
93 for (size_t i = 0 ; i < len; i++) {
94 if (strncmp(key, items[i].key, strlen(items[i].key)) == 0) {
95 return true;
96 }
97 }
98 return false;
99 }
100
IsSupportedPolicy(const char * policy,enum FscryptOptins number)101 static bool IsSupportedPolicy(const char *policy,
102 enum FscryptOptins number)
103 {
104 if ((number >= FSCRYPT_OPTIONS_MAX) || (!policy)) {
105 return false;
106 }
107
108 switch (number) {
109 case FSCRYPT_VERSION_NUM:
110 return IsSupportedPolicyKey(policy, ALL_VERSION,
111 ARRAY_LEN(ALL_VERSION));
112 case FSCRYPT_FILENAME_MODE:
113 return IsSupportedPolicyKey(policy, FILENAME_MODES,
114 ARRAY_LEN(FILENAME_MODES));
115 case FSCRYPT_CONTENT_MODE:
116 return IsSupportedPolicyKey(policy, CONTENTS_MODES,
117 ARRAY_LEN(CONTENTS_MODES));
118 default:
119 return false;
120 }
121 return false;
122 }
123
FscryptSetSysparam(const char * policy)124 int FscryptSetSysparam(const char *policy)
125 {
126 if (!policy) {
127 return -EINVAL;
128 }
129
130 char *tmp = strdup(policy);
131 if (!tmp) {
132 FSCRYPT_LOGE("No memory for policy option");
133 return -ENOMEM;
134 }
135 int optNums = 0;
136 char **options = SplitStringExt(tmp, ":", &optNums, FSCRYPT_OPTIONS_MAX);
137 free(tmp);
138 if (!options) {
139 return -ENOMEM;
140 }
141 if (optNums != FSCRYPT_OPTIONS_MAX) {
142 FSCRYPT_LOGE("Mount fscrypt option setting error, not enabled crypto!");
143 FreeStringVector(options, optNums);
144 return -EFAULT;
145 }
146
147 // check supported policy
148 for (enum FscryptOptins i = FSCRYPT_VERSION_NUM; i < FSCRYPT_OPTIONS_MAX; i++) {
149 char *temp = options[i];
150 if (!IsSupportedPolicy(temp, i)) {
151 FSCRYPT_LOGE("Not supported policy, %s", temp);
152 FreeStringVector(options, optNums);
153 return -ENOTSUP;
154 }
155 }
156 FreeStringVector(options, optNums);
157
158 int ret = SetFscryptParameter(FSCRYPT_POLICY_KEY, policy);
159 if (ret < 0) {
160 FSCRYPT_LOGE("Set fscrypt system parameter failed %d", ret);
161 return ret;
162 }
163 g_fscryptEnabled = true;
164 g_fscryptInited = false; // need to re-init
165
166 return 0;
167 }
168
PraseOnePloicyValue(uint8_t * value,const char * key,const FscrtpyItem * table,size_t numbers)169 static void PraseOnePloicyValue(uint8_t *value, const char *key,
170 const FscrtpyItem *table, size_t numbers)
171 {
172 for (size_t i = 0; i < numbers; i++) {
173 size_t len = strlen(table[i].key);
174 if (strncmp(key, table[i].key, len) == 0 &&
175 strlen(key) == len) {
176 *value = table[i].value;
177 return;
178 }
179 }
180 FSCRYPT_LOGE("Have not found value for the key!");
181 }
182
InitFscryptPolicy(void)183 int InitFscryptPolicy(void)
184 {
185 if (g_fscryptInited) {
186 FSCRYPT_LOGI("Have been init");
187 return 0;
188 }
189 char policy[POLICY_BUF_SIZE];
190 uint32_t len = POLICY_BUF_SIZE - 1;
191 int ret = GetFscryptParameter(FSCRYPT_POLICY_KEY, "", policy, &len);
192 if (ret != 0) {
193 FSCRYPT_LOGI("Get fscrypt policy failed");
194 return -ENOTSUP;
195 }
196 int count = 0;
197 char **option = SplitStringExt(policy, ":", &count, FSCRYPT_OPTIONS_MAX);
198 if (!option) {
199 FSCRYPT_LOGE("Fscrypt setting error");
200 return -ENOTSUP;
201 }
202 if (count != FSCRYPT_OPTIONS_MAX) {
203 FSCRYPT_LOGE("Fscrypt policy count error");
204 FreeStringVector(option, count);
205 return -ENOTSUP;
206 }
207
208 PraseOnePloicyValue(&g_fscryptPolicy.version, option[FSCRYPT_VERSION_NUM],
209 ALL_VERSION, ARRAY_LEN(ALL_VERSION));
210 PraseOnePloicyValue(&g_fscryptPolicy.fileName, option[FSCRYPT_FILENAME_MODE],
211 FILENAME_MODES, ARRAY_LEN(FILENAME_MODES));
212 PraseOnePloicyValue(&g_fscryptPolicy.content, option[FSCRYPT_CONTENT_MODE],
213 CONTENTS_MODES, ARRAY_LEN(CONTENTS_MODES));
214
215 FreeStringVector(option, count);
216 g_fscryptInited = true;
217 FSCRYPT_LOGI("Fscrypt policy init success");
218
219 return 0;
220 }
221
222 /*
223 * Splic full path, Caller need to free *buf after using
224 * if return success.
225 *
226 * @path: base key path
227 * @name: fscrypt file, so as /key_id
228 * @buf: splic result if return 0
229 */
SpliceKeyPath(const char * path,size_t pathLen,const char * name,size_t nameLen,char ** buf)230 static int SpliceKeyPath(const char *path, size_t pathLen,
231 const char *name, size_t nameLen,
232 char **buf)
233 {
234 FSCRYPT_LOGI("key path %s, name %s", path, name);
235 *buf = NULL;
236 size_t bufMax = pathLen + nameLen + 1;
237 char *tmpBuf = (char *)malloc(bufMax);
238 if (!tmpBuf) {
239 FSCRYPT_LOGE("No memory for fscrypt v1 path buffer");
240 return -ENOMEM;
241 }
242 tmpBuf[0] = '\0';
243
244 int ret = strncat_s(tmpBuf, bufMax, path, pathLen);
245 if (ret != 0) {
246 free(tmpBuf);
247 FSCRYPT_LOGE("splic previous path error");
248 return ret;
249 }
250 ret = strncat_s(tmpBuf, bufMax, name, nameLen);
251 if (ret != 0) {
252 free(tmpBuf);
253 FSCRYPT_LOGE("splic later path error");
254 return ret;
255 }
256 *buf = tmpBuf;
257
258 return 0;
259 }
260
ReadKeyFile(const char * path,char * buf,size_t len)261 static int ReadKeyFile(const char *path, char *buf, size_t len)
262 {
263 if (!path || !buf) {
264 FSCRYPT_LOGE("path or buf is null");
265 return -EINVAL;
266 }
267 struct stat st = {0};
268 if (stat(path, &st) != 0) {
269 FSCRYPT_LOGE("stat file failed");
270 return -EFAULT;
271 }
272 if ((size_t)st.st_size != len) {
273 FSCRYPT_LOGE("target file size is not equal to buf len");
274 return -EFAULT;
275 }
276
277 int fd = open(path, O_RDONLY);
278 if (fd < 0) {
279 FSCRYPT_LOGE("key file read open failed");
280 return -EFAULT;
281 }
282 if (read(fd, buf, len) != (ssize_t)len) {
283 FSCRYPT_LOGE("bad file content");
284 (void)close(fd);
285 return -EBADF;
286 }
287 (void)close(fd);
288
289 return 0;
290 }
291
SetPolicyLegacy(const char * keyDescPath,const char * toEncrypt,union FscryptPolicy * arg)292 static int SetPolicyLegacy(const char *keyDescPath,
293 const char *toEncrypt,
294 union FscryptPolicy *arg)
295 {
296 char keyDesc[FSCRYPT_KEY_DESCRIPTOR_SIZE] = {0};
297 int ret = ReadKeyFile(keyDescPath, keyDesc, FSCRYPT_KEY_DESCRIPTOR_SIZE);
298 if (ret != 0) {
299 return ret;
300 }
301 arg->v1.version = FSCRYPT_POLICY_V1;
302 ret = memcpy_s(arg->v1.master_key_descriptor,
303 FSCRYPT_KEY_DESCRIPTOR_SIZE, keyDesc, FSCRYPT_KEY_DESCRIPTOR_SIZE);
304 if (ret != 0) {
305 FSCRYPT_LOGE("memcpy_s copy failed");
306 return ret;
307 }
308 if (!KeyCtrlSetPolicy(toEncrypt, arg)) {
309 FSCRYPT_LOGE("Set Policy v1 failed");
310 return -EFAULT;
311 }
312 return 0;
313 }
314
315 #ifdef SUPPORT_FSCRYPT_V2
SetPolicyV2(const char * keyIdPath,const char * toEncrypt,union FscryptPolicy * arg)316 static int SetPolicyV2(const char *keyIdPath,
317 const char *toEncrypt,
318 union FscryptPolicy *arg)
319 {
320 char keyId[FSCRYPT_KEY_IDENTIFIER_SIZE] = {0};
321 int ret = ReadKeyFile(keyIdPath, keyId, FSCRYPT_KEY_IDENTIFIER_SIZE);
322 if (ret != 0) {
323 return ret;
324 }
325 arg->v2.version = FSCRYPT_POLICY_V2;
326 ret = memcpy_s(arg->v2.master_key_identifier,
327 FSCRYPT_KEY_IDENTIFIER_SIZE, keyId, FSCRYPT_KEY_IDENTIFIER_SIZE);
328 if (ret != 0) {
329 FSCRYPT_LOGE("memcpy_s copy failed");
330 return ret;
331 }
332 if (!KeyCtrlSetPolicy(toEncrypt, arg)) {
333 FSCRYPT_LOGE("Set Policy v2 failed");
334 return -EFAULT;
335 }
336 return 0;
337 }
338 #endif
339
LoadAndSetPolicy(const char * keyDir,const char * dir)340 int LoadAndSetPolicy(const char *keyDir, const char *dir)
341 {
342 if (!keyDir || !dir) {
343 FSCRYPT_LOGE("set policy parameters is null");
344 return -EINVAL;
345 }
346 int ret = InitFscryptPolicy();
347 if (ret != 0) {
348 FSCRYPT_LOGE("Get fscrypt policy error %d", ret);
349 return ret;
350 }
351
352 union FscryptPolicy arg;
353 (void)memset_s(&arg, sizeof(arg), 0, sizeof(arg));
354 arg.v1.filenames_encryption_mode = g_fscryptPolicy.fileName;
355 arg.v1.contents_encryption_mode = g_fscryptPolicy.content;
356 arg.v1.flags = g_fscryptPolicy.flags;
357
358 char *pathBuf = NULL;
359 ret = -ENOTSUP;
360
361 uint8_t fscryptVer = KeyCtrlLoadVersion(keyDir);
362 if (fscryptVer == FSCRYPT_V1) {
363 ret = SpliceKeyPath(keyDir, strlen(keyDir), PATH_KEYDESC,
364 strlen(PATH_KEYDESC), &pathBuf);
365 if (ret != 0) {
366 FSCRYPT_LOGE("path splice error");
367 return ret;
368 }
369 ret = SetPolicyLegacy(pathBuf, dir, &arg);
370 #ifdef SUPPORT_FSCRYPT_V2
371 } else if (fscryptVer == FSCRYPT_V2) {
372 ret = SpliceKeyPath(keyDir, strlen(keyDir), PATH_KEYID,
373 strlen(PATH_KEYID), &pathBuf);
374 if (ret != 0) {
375 FSCRYPT_LOGE("path splice error");
376 return ret;
377 }
378 ret = SetPolicyV2(pathBuf, dir, &arg);
379 #endif
380 }
381 if (pathBuf != NULL) {
382 free(pathBuf);
383 }
384
385 return ret;
386 }
387
SetGlobalEl1DirPolicy(const char * dir)388 int SetGlobalEl1DirPolicy(const char *dir)
389 {
390 if (!g_fscryptEnabled) {
391 FSCRYPT_LOGI("Fscrypt have not enabled");
392 return 0;
393 }
394 for (size_t i = 0; i < ARRAY_LEN(GLOBAL_FSCRYPT_DIR); i++) {
395 size_t tmpLen = strlen(GLOBAL_FSCRYPT_DIR[i]);
396 if ((strncmp(dir, GLOBAL_FSCRYPT_DIR[i], tmpLen) == 0) &&
397 (strlen(dir) == tmpLen)) {
398 return LoadAndSetPolicy(DEVICE_EL1_DIR, dir);
399 }
400 }
401 return 0;
402 }
403
GetFscryptVersionFromPolicy(void)404 uint8_t GetFscryptVersionFromPolicy(void)
405 {
406 return g_fscryptPolicy.version;
407 }
408