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
45struct 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
53static 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
78static 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
103const 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
114static 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
145struct get_code_info {
146	unsigned long code_start;
147	unsigned long code_end;
148	unsigned long code_size;
149};
150static 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 */
207static 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
259static 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
301int 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
362static 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;
379error:
380	return -EFAULT;
381}
382
383static 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
396static 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
413static 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
441int 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
495error:
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
508static 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" */
523static 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}
541static 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*/
571int 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