• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * client_hash_auth.c
3  *
4  * function for CA code hash auth
5  *
6  * Copyright (C) 2022 Huawei Technologies Co., Ltd.
7  *
8  * This software is licensed under the terms of the GNU General Public
9  * License version 2, as published by the Free Software Foundation, and
10  * may be copied, distributed, and modified under those terms.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  */
17 #include "client_hash_auth.h"
18 #include <linux/string.h>
19 #include <linux/mutex.h>
20 #include <linux/types.h>
21 #include <linux/rwsem.h>
22 #ifdef CONFIG_AUTH_SUPPORT_UNAME
23 #include <linux/fs.h>
24 #endif
25 #ifdef CONFIG_CLIENT_AUTH
26 #include <linux/mm.h>
27 #include <linux/dcache.h>
28 #include <linux/mm_types.h>
29 #include <linux/highmem.h>
30 #include <linux/cred.h>
31 #include <linux/slab.h>
32 #include <linux/sched/mm.h>
33 #endif
34 #ifdef CONFIG_AUTH_HASH
35 #include <crypto/hash.h>
36 #endif
37 #include <securec.h>
38 
39 #include "tc_ns_log.h"
40 #include "auth_base_impl.h"
41 
42 #ifdef CONFIG_AUTH_HASH
43 #define SHA256_DIGEST_LENGTH 32
44 #define FIXED_PKG_NAME_LENGTH 256
45 struct sdesc_hash {
46 	struct shash_desc shash;
47 	char ctx[];
48 };
49 #endif
50 
51 #if defined (CONFIG_ANDROID_HIDL) || defined (CONFIG_MDC_HAL_AUTH)
52 
check_proc_state(bool is_hidl,struct task_struct ** hidl_struct,const struct tc_ns_client_context * context)53 static int check_proc_state(bool is_hidl, struct task_struct **hidl_struct,
54 	const struct tc_ns_client_context *context)
55 {
56 	bool check_value = false;
57 
58 	if (is_hidl) {
59 		rcu_read_lock();
60 		*hidl_struct = pid_task(find_vpid(context->calling_pid),
61 			PIDTYPE_PID);
62 		check_value = !*hidl_struct ||
63 			(*hidl_struct)->state == TASK_DEAD;
64 		if (check_value) {
65 			tloge("task is dead\n");
66 			rcu_read_unlock();
67 			return -EFAULT;
68 		}
69 
70 		get_task_struct(*hidl_struct);
71 		rcu_read_unlock();
72 		return EOK;
73 	}
74 
75 	return EOK;
76 }
77 
get_hidl_client_task(bool is_hidl_task,struct tc_ns_client_context * context,struct task_struct ** cur_struct)78 static int get_hidl_client_task(bool is_hidl_task, struct tc_ns_client_context *context,
79 	struct task_struct **cur_struct)
80 {
81 	int ret;
82 	struct task_struct *hidl_struct = NULL;
83 
84 	ret = check_proc_state(is_hidl_task, &hidl_struct, context);
85 	if (ret)
86 		return ret;
87 
88 	if (hidl_struct)
89 		*cur_struct = hidl_struct;
90 	else
91 		*cur_struct = current;
92 
93 	return EOK;
94 }
95 
96 #endif
97 
98 #ifdef CONFIG_CLIENT_AUTH
99 #define LIBTEEC_CODE_PAGE_SIZE 8
100 #define DEFAULT_TEXT_OFF 0
101 #define LIBTEEC_NAME_MAX_LEN 50
102 
103 const char g_libso[KIND_OF_SO][LIBTEEC_NAME_MAX_LEN] = {
104 	"libteec_vendor.so",
105 #ifndef CONFIG_CMS_CAHASH_AUTH
106 #ifndef CONFIG_CADAEMON_AUTH
107 	"libteec.huawei.so",
108 #else
109 	"libteec.so",
110 #endif
111 #endif
112 };
113 
find_lib_code_area(struct mm_struct * mm,struct vm_area_struct ** lib_code_area,int so_index)114 static int find_lib_code_area(struct mm_struct *mm,
115 	struct vm_area_struct **lib_code_area, int so_index)
116 {
117 	struct vm_area_struct *vma = NULL;
118 	bool is_valid_vma = false;
119 	bool is_so_exists = false;
120 	bool param_check = (!mm || !mm->mmap ||
121 		!lib_code_area || so_index >= KIND_OF_SO);
122 
123 	if (param_check) {
124 		tloge("illegal input params\n");
125 		return -EFAULT;
126 	}
127 	for (vma = mm->mmap; vma; vma = vma->vm_next) {
128 		is_valid_vma = (vma->vm_file &&
129 			vma->vm_file->f_path.dentry &&
130 			vma->vm_file->f_path.dentry->d_name.name);
131 		if (is_valid_vma) {
132 			is_so_exists = !strcmp(g_libso[so_index],
133 				vma->vm_file->f_path.dentry->d_name.name);
134 			if (is_so_exists && (vma->vm_flags & VM_EXEC)) {
135 				*lib_code_area = vma;
136 				tlogd("so name is %s\n",
137 					vma->vm_file->f_path.dentry->d_name.name);
138 				return EOK;
139 			}
140 		}
141 	}
142 	return -EFAULT;
143 }
144 
145 struct get_code_info {
146 	unsigned long code_start;
147 	unsigned long code_end;
148 	unsigned long code_size;
149 };
update_so_hash(struct mm_struct * mm,struct task_struct * cur_struct,struct shash_desc * shash,int so_index)150 static int update_so_hash(struct mm_struct *mm,
151 	struct task_struct *cur_struct, struct shash_desc *shash, int so_index)
152 {
153 	struct vm_area_struct *vma = NULL;
154 	int rc = -EFAULT;
155 	struct get_code_info code_info;
156 	unsigned long in_size;
157 	struct page *ptr_page = NULL;
158 	void *ptr_base = NULL;
159 
160 	if (find_lib_code_area(mm, &vma, so_index)) {
161 		tlogd("get lib code vma area failed\n");
162 		return -EFAULT;
163 	}
164 
165 	code_info.code_start = vma->vm_start;
166 	code_info.code_end = vma->vm_end;
167 	code_info.code_size = code_info.code_end - code_info.code_start;
168 
169 	while (code_info.code_start < code_info.code_end) {
170 		// Get a handle of the page we want to read
171 #if (KERNEL_VERSION(5, 10, 0) <= LINUX_VERSION_CODE)
172 		rc = get_user_pages_remote(mm, code_info.code_start,
173 			1, FOLL_FORCE, &ptr_page, NULL, NULL);
174 #else
175 		rc = get_user_pages_remote(cur_struct, mm, code_info.code_start,
176 			1, FOLL_FORCE, &ptr_page, NULL, NULL);
177 #endif
178 		if (rc != 1) {
179 			tloge("get user pages locked error[0x%x]\n", rc);
180 			rc = -EFAULT;
181 			break;
182 		}
183 
184 		ptr_base = kmap_atomic(ptr_page);
185 		if (!ptr_base) {
186 			rc = -EFAULT;
187 			put_page(ptr_page);
188 			break;
189 		}
190 		in_size = (code_info.code_size > PAGE_SIZE) ? PAGE_SIZE : code_info.code_size;
191 
192 		rc = crypto_shash_update(shash, ptr_base, in_size);
193 		if (rc) {
194 			kunmap_atomic(ptr_base);
195 			put_page(ptr_page);
196 			break;
197 		}
198 		kunmap_atomic(ptr_base);
199 		put_page(ptr_page);
200 		code_info.code_start += in_size;
201 		code_info.code_size = code_info.code_end - code_info.code_start;
202 	}
203 	return rc;
204 }
205 
206 /* Calculate the SHA256 library digest */
calc_task_so_hash(unsigned char * digest,uint32_t dig_len,struct task_struct * cur_struct,int so_index)207 static int calc_task_so_hash(unsigned char *digest, uint32_t dig_len,
208 	struct task_struct *cur_struct, int so_index)
209 {
210 	struct mm_struct *mm = NULL;
211 	int rc;
212 	size_t size;
213 	size_t shash_size;
214 	struct sdesc *desc = NULL;
215 
216 	if (!digest || dig_len != SHA256_DIGEST_LENTH) {
217 		tloge("tee hash: digest is NULL\n");
218 		return -EFAULT;
219 	}
220 
221 	shash_size = crypto_shash_descsize(get_shash_handle());
222 	size = sizeof(desc->shash) + shash_size;
223 	if (size < sizeof(desc->shash) || size < shash_size) {
224 		tloge("size overflow\n");
225 		return -ENOMEM;
226 	}
227 
228 	desc = kzalloc(size, GFP_KERNEL);
229 	if (ZERO_OR_NULL_PTR((unsigned long)(uintptr_t)desc)) {
230 		tloge("alloc desc failed\n");
231 		return -ENOMEM;
232 	}
233 
234 	desc->shash.tfm = get_shash_handle();
235 	if (crypto_shash_init(&desc->shash)) {
236 		kfree(desc);
237 		return -EFAULT;
238 	}
239 
240 	mm = get_task_mm(cur_struct);
241 	if (!mm) {
242 		tloge("so does not have mm struct\n");
243 		if (memset_s(digest, MAX_SHA_256_SZ, 0, dig_len))
244 			tloge("memset digest failed\n");
245 		kfree(desc);
246 		return -EFAULT;
247 	}
248 
249 	down_read(&mm_sem_lock(mm));
250 	rc = update_so_hash(mm, cur_struct, &desc->shash, so_index);
251 	up_read(&mm_sem_lock(mm));
252 	mmput(mm);
253 	if (!rc)
254 		rc = crypto_shash_final(&desc->shash, digest);
255 	kfree(desc);
256 	return rc;
257 }
258 
proc_calc_hash(uint8_t kernel_api,struct tc_ns_session * session,struct task_struct * cur_struct,uint32_t pub_key_len)259 static int proc_calc_hash(uint8_t kernel_api, struct tc_ns_session *session,
260 	struct task_struct *cur_struct, uint32_t pub_key_len)
261 {
262 	int rc, i;
263 	int so_found = 0;
264 
265 	mutex_crypto_hash_lock();
266 	if (kernel_api == TEE_REQ_FROM_USER_MODE) {
267 		for (i = 0; so_found < NUM_OF_SO && i < KIND_OF_SO; i++) {
268 			rc = calc_task_so_hash(session->auth_hash_buf + MAX_SHA_256_SZ * so_found,
269 				(uint32_t)SHA256_DIGEST_LENTH, cur_struct, i);
270 			if (!rc)
271 				so_found++;
272 		}
273 		if (so_found != NUM_OF_SO)
274 			tlogd("so library found: %d\n", so_found);
275 	} else {
276 		tlogd("request from kernel\n");
277 	}
278 
279 #ifdef CONFIG_ASAN_DEBUG
280 	tloge("so auth disabled for ASAN debug\n");
281 	uint32_t so_hash_len = MAX_SHA_256_SZ * NUM_OF_SO;
282 	errno_t sret = memset_s(session->auth_hash_buf, so_hash_len, 0, so_hash_len);
283 	if (sret) {
284 		mutex_crypto_hash_unlock();
285 		tloge("memset so hash failed\n");
286 		return -EFAULT;
287 	}
288 #endif
289 
290 	rc = calc_task_hash(session->auth_hash_buf + MAX_SHA_256_SZ * NUM_OF_SO,
291 		(uint32_t)SHA256_DIGEST_LENTH, cur_struct, pub_key_len);
292 	if (rc) {
293 		mutex_crypto_hash_unlock();
294 		tloge("tee calc ca hash failed\n");
295 		return -EFAULT;
296 	}
297 	mutex_crypto_hash_unlock();
298 	return EOK;
299 }
300 
calc_client_auth_hash(struct tc_ns_dev_file * dev_file,struct tc_ns_client_context * context,struct tc_ns_session * session)301 int calc_client_auth_hash(struct tc_ns_dev_file *dev_file,
302 	struct tc_ns_client_context *context, struct tc_ns_session *session)
303 {
304 	int ret;
305 	struct task_struct *cur_struct = NULL;
306 	bool check = false;
307 #if defined(CONFIG_ANDROID_HIDL) || defined(CONFIG_MDC_HAL_AUTH)
308 	bool is_hidl_srvc = false;
309 #endif
310 	check = (!dev_file || !context || !session);
311 	if (check) {
312 		tloge("bad params\n");
313 		return -EFAULT;
314 	}
315 
316 	if (tee_init_shash_handle("sha256")) {
317 		tloge("init code hash error\n");
318 		return -EFAULT;
319 	}
320 
321 #if defined(CONFIG_ANDROID_HIDL) || defined(CONFIG_MDC_HAL_AUTH)
322 	if(!current->mm) {
323 		tlogd("kernel thread need not check\n");
324 		ret = ENTER_BYPASS_CHANNEL;
325 	} else {
326 #ifdef CONFIG_CADAEMON_AUTH
327 		/* for OH */
328 		ret = check_cadaemon_auth();
329 #else
330 		/* for HO and MDC/DC */
331 		ret = check_hidl_auth();
332 #endif
333 	}
334 	if (ret != CHECK_ACCESS_SUCC) {
335 		if (ret != ENTER_BYPASS_CHANNEL) {
336 			tloge("hidl service may be exploited ret 0x%x\n", ret);
337 			return -EACCES;
338 		}
339 		/* native\kernel ca task this branch */
340 	} else {
341 		/* android hidl\mdc secmgr(libteec\kms) task this branch */
342 		is_hidl_srvc = true;
343 	}
344 	ret = get_hidl_client_task(is_hidl_srvc, context, &cur_struct);
345 	if (ret)
346 		return -EFAULT;
347 #else
348 	cur_struct = current;
349 #endif
350 
351 	ret = proc_calc_hash(dev_file->kernel_api, session, cur_struct, dev_file->pub_key_len);
352 #if defined(CONFIG_ANDROID_HIDL) || defined(CONFIG_MDC_HAL_AUTH)
353 	if (is_hidl_srvc)
354 		put_task_struct(cur_struct);
355 #endif
356 	return ret;
357 }
358 #endif
359 
360 #ifdef CONFIG_AUTH_HASH
361 #define UID_LEN 16
construct_hashdata(struct tc_ns_dev_file * dev_file,uint8_t * buf,uint32_t buf_len)362 static int construct_hashdata(struct tc_ns_dev_file *dev_file,
363 	uint8_t *buf, uint32_t buf_len)
364 {
365 	int ret;
366 	ret = memcpy_s(buf, buf_len, dev_file->pkg_name, dev_file->pkg_name_len);
367 	if (ret) {
368 		tloge("memcpy_s failed\n");
369 		goto error;
370 	}
371 	buf += dev_file->pkg_name_len;
372 	buf_len -= dev_file->pkg_name_len;
373 	ret = memcpy_s(buf, buf_len, dev_file->pub_key, dev_file->pub_key_len);
374 	if (ret) {
375 		tloge("memcpy_s failed\n");
376 		goto error;
377 	}
378 	return 0;
379 error:
380 	return -EFAULT;
381 }
382 
init_sdesc(struct crypto_shash * alg)383 static struct sdesc_hash *init_sdesc(struct crypto_shash *alg)
384 {
385 	struct sdesc_hash *sdesc;
386 	size_t size;
387 
388 	size = sizeof(struct shash_desc) + crypto_shash_descsize(alg);
389 	sdesc = kmalloc(size, GFP_KERNEL);
390 	if (sdesc == NULL)
391 		return ERR_PTR(-ENOMEM);
392 	sdesc->shash.tfm = alg;
393 	return sdesc;
394 }
395 
calc_hash(struct crypto_shash * alg,const unsigned char * data,unsigned int datalen,unsigned char * digest)396 static int calc_hash(struct crypto_shash *alg,
397 	const unsigned char *data, unsigned int datalen, unsigned char *digest)
398 {
399 	struct sdesc_hash *sdesc;
400 	int ret;
401 
402 	sdesc = init_sdesc(alg);
403 	if (IS_ERR(sdesc)) {
404 		pr_info("can't alloc sdesc\n");
405 		return PTR_ERR(sdesc);
406 	}
407 
408 	ret = crypto_shash_digest(&sdesc->shash, data, datalen, digest);
409 	kfree(sdesc);
410 	return ret;
411 }
412 
do_sha256(const unsigned char * data,uint32_t datalen,unsigned char * out_digest,uint8_t digest_len)413 static int do_sha256(const unsigned char *data, uint32_t datalen,
414 	unsigned char *out_digest, uint8_t digest_len)
415 {
416 	int ret;
417 	struct crypto_shash *alg;
418 	const char *hash_alg_name = "sha256";
419 	if (digest_len != SHA256_DIGEST_LENGTH) {
420 		tloge("error digest_len\n");
421 		return -1;
422 	}
423 
424 	alg = crypto_alloc_shash(hash_alg_name, 0, 0);
425 	if(IS_ERR_OR_NULL(alg)) {
426 		tloge("can't alloc alg %s, PTR_ERR alg is %ld\n", hash_alg_name, PTR_ERR(alg));
427 		return PTR_ERR(alg);
428 	}
429 	ret = calc_hash(alg, data, datalen, out_digest);
430 	if (ret != 0) {
431 		tloge("calc hash failed\n");
432 		crypto_free_shash(alg);
433 		alg = NULL;
434 		return -1;
435 	}
436 	crypto_free_shash(alg);
437 	alg = NULL;
438 	return 0;
439 }
440 
set_login_information_hash(struct tc_ns_dev_file * hash_dev_file)441 int set_login_information_hash(struct tc_ns_dev_file *hash_dev_file)
442 {
443 	int ret = 0;
444 	uint8_t *indata = NULL;
445 	if (hash_dev_file == NULL) {
446 		tloge("wrong caller info, cal hash stopped\n");
447 		return -1;
448 	}
449 	mutex_lock(&hash_dev_file->cainfo_hash_setup_lock);
450 
451 	if (!(hash_dev_file->cainfo_hash_setup)) {
452 		unsigned char digest[SHA256_DIGEST_LENGTH] = {0};
453 		uint8_t digest_len = sizeof(digest);
454 
455 		uint32_t indata_len;
456 #ifdef CONFIG_AUTH_SUPPORT_UNAME
457 		/* username using fixed length to cal hash */
458 		if (hash_dev_file->pub_key_len >= FIXED_PKG_NAME_LENGTH) {
459 			tloge("username is too loog\n");
460 			ret = -1;
461 			goto error;
462 		}
463 		indata_len = hash_dev_file->pkg_name_len + FIXED_PKG_NAME_LENGTH;
464 #else
465 		indata_len = hash_dev_file->pkg_name_len + hash_dev_file->pub_key_len;
466 #endif
467 		indata = kzalloc(indata_len, GFP_KERNEL);
468 		if (ZERO_OR_NULL_PTR((unsigned long)(uintptr_t)indata)) {
469 			tloge("indata kmalloc fail\n");
470 			ret = -1;
471 			goto error;
472 		}
473 
474 		ret = construct_hashdata(hash_dev_file, indata, indata_len);
475 		if (ret != 0) {
476 			tloge("construct hashdata failed\n");
477 			goto error;
478 		}
479 
480 		ret = do_sha256((unsigned char *)indata, indata_len, digest, digest_len);
481 		if (ret != 0) {
482 			tloge("do sha256 failed\n");
483 			goto error;
484 		}
485 
486 		ret = memcpy_s(hash_dev_file->pkg_name, MAX_PACKAGE_NAME_LEN, digest, digest_len);
487 		if (ret != 0) {
488 			tloge("memcpy_s failed\n");
489 			goto error;
490 		}
491 		hash_dev_file->pkg_name_len = SHA256_DIGEST_LENGTH;
492 		hash_dev_file->cainfo_hash_setup = true;
493 	}
494 
495 error:
496 	if (!ZERO_OR_NULL_PTR((unsigned long)(uintptr_t)indata))
497 		kfree(indata);
498 
499 	mutex_unlock(&hash_dev_file->cainfo_hash_setup_lock);
500 	return ret;
501 }
502 #endif
503 
504 #ifdef CONFIG_AUTH_SUPPORT_UNAME
505 #define PASSWD_FILE "/etc/passwd"
506 #define UID_POS	 2U
507 #define DECIMAL  10
uid_compare(uint32_t uid,const char * uid_str,uint32_t uid_len)508 static int uid_compare(uint32_t uid, const char* uid_str, uint32_t uid_len)
509 {
510 	uint32_t uid_num = 0;
511 	for (uint32_t i = 0; i < uid_len; i++) {
512 		bool is_number = uid_str[i] >= '0' && uid_str[i] <= '9';
513 		if (!is_number) {
514 			tloge("passwd info wrong format: uid missing\n");
515 			return -1;
516 		}
517 		uid_num = DECIMAL * uid_num + (uid_str[i] - '0');
518 	}
519 	return (uid_num == uid) ? 0 : -1;
520 }
521 
522 /* "username:[encrypted password]:uid:gid:[comments]:home directory:login shell" */
parse_uname(uint32_t uid,char * username,int buffer_len)523 static uint32_t parse_uname(uint32_t uid, char *username, int buffer_len)
524 {
525 	char *str = username;
526 	char *token = strsep(&str, ":");
527 	char *temp_name = token; // first tokon is username, need to check uid
528 	int index = 0;
529 	while(token != NULL && index < UID_POS) {
530 		token = strsep(&str, ":");
531 		index++;
532 	}
533 	if (token == NULL)
534 		return -1;
535 	if (uid_compare(uid, token, strlen(token)) != 0)
536 		return -1;
537 	if (strcpy_s(username, buffer_len, temp_name) != EOK)
538 		return -1;
539 	return strlen(temp_name);
540 }
read_line(char * buf,int buf_len,struct file * fp,loff_t * offset)541 static int read_line(char *buf, int buf_len, struct file *fp, loff_t *offset)
542 {
543 	if (offset == NULL) {
544 		tloge("offset is null while read file\n");
545 		return -1;
546 	}
547 	ssize_t ret = kernel_read(fp, buf, buf_len, offset);
548 	if (ret < 0)
549 		return -1;
550 	ssize_t i = 0;
551 	/* read buf_len, need to find first '\n' */
552 	while (i < ret) {
553 		if (i >= buf_len)
554 			break;
555 		if (buf[i] == '\n')
556 			break;
557 		i++;
558 	}
559 	if (i < ret)
560 		*offset -= (loff_t)(ret - i);
561 	if (i < buf_len)
562 		buf[i] = '\0';
563 	return 0;
564 }
565 
566 /* get username by uid,
567 * on linux, user info is stored in system file "/etc/passwd",
568 * each line represents a user, fields are separated by ':',
569 * formatted as such: "username:[encrypted password]:uid:gid:[comments]:home directory:login shell"
570 */
tc_ns_get_uname(uint32_t uid,char * username,int buffer_len,uint32_t * out_len)571 int tc_ns_get_uname(uint32_t uid, char *username, int buffer_len, uint32_t *out_len)
572 {
573 	if (username == NULL || out_len == NULL || buffer_len != FIXED_PKG_NAME_LENGTH) {
574 		tloge("params is null\n");
575 		return -1;
576 	}
577 	struct file *f = NULL;
578 	loff_t offset = 0;
579 	f = filp_open(PASSWD_FILE, O_RDONLY, 0);
580 	if (IS_ERR(f)) {
581 		tloge("kernel open passwd file failed\n");
582 		return -1;
583 	}
584 	while (read_line(username, buffer_len, f, &offset) == 0) {
585 		uint32_t ret = parse_uname(uid, username, buffer_len);
586 		if (ret >= 0) {
587 			*out_len = ret;
588 			filp_close(f, NULL);
589 			return 0;
590 		}
591 	}
592 	filp_close(f, NULL);
593 	return -1;
594 }
595 #endif