• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * auth_base_impl.c
3  *
4  * function for base hash operation
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 "auth_base_impl.h"
18 #include <linux/string.h>
19 #include <linux/mutex.h>
20 #include <linux/types.h>
21 #include <linux/rwsem.h>
22 #include <linux/path.h>
23 #include <linux/file.h>
24 #include <linux/fs.h>
25 
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 #if (KERNEL_VERSION(4, 14, 0) <= LINUX_VERSION_CODE)
33 #include <linux/sched/mm.h>
34 #endif
35 #if defined (CONFIG_SELINUX_AUTH_ENABLE) && defined (CONFIG_SECURITY_SELINUX)
36 #include <linux/security.h>
37 #endif
38 #include <securec.h>
39 #include "tc_ns_log.h"
40 #include "tc_ns_client.h"
41 #include "agent.h" /* for get_proc_dpath */
42 #include "ko_adapt.h"
43 
44 /* for crypto */
45 struct crypto_shash *g_shash_handle;
46 bool g_shash_handle_state = false;
47 struct mutex g_shash_handle_lock;
48 
init_crypto_hash_lock(void)49 void init_crypto_hash_lock(void)
50 {
51 	mutex_init(&g_shash_handle_lock);
52 }
53 
mutex_crypto_hash_lock(void)54 void mutex_crypto_hash_lock(void)
55 {
56 	mutex_lock(&g_shash_handle_lock);
57 }
58 
mutex_crypto_hash_unlock(void)59 void mutex_crypto_hash_unlock(void)
60 {
61 	mutex_unlock(&g_shash_handle_lock);
62 }
63 
64 /* begin: prepare crypto context */
get_shash_handle(void)65 struct crypto_shash *get_shash_handle(void)
66 {
67 	return g_shash_handle;
68 }
69 
free_shash_handle(void)70 void free_shash_handle(void)
71 {
72 	if (g_shash_handle) {
73 		crypto_free_shash(g_shash_handle);
74 		g_shash_handle_state = false;
75 		g_shash_handle = NULL;
76 	}
77 }
78 
tee_init_shash_handle(char * hash_type)79 int tee_init_shash_handle(char *hash_type)
80 {
81 	long rc;
82 
83 	if (!hash_type) {
84 		tloge("tee init crypto: error input parameter\n");
85 		return -EFAULT;
86 	}
87 
88 	mutex_crypto_hash_lock();
89 	if (g_shash_handle_state) {
90 		mutex_crypto_hash_unlock();
91 		return 0;
92 	}
93 
94 	g_shash_handle = crypto_alloc_shash(hash_type, 0, 0);
95 	if (IS_ERR_OR_NULL(g_shash_handle)) {
96 		rc = PTR_ERR(g_shash_handle);
97 		tloge("Can not allocate %s reason: %ld\n", hash_type, rc);
98 		mutex_crypto_hash_unlock();
99 		return rc;
100 	}
101 	g_shash_handle_state = true;
102 
103 	mutex_crypto_hash_unlock();
104 	return 0;
105 }
106 /* end: prepare crypto context */
107 
108 /* begin: Calculate the SHA256 file digest */
prepare_desc(struct sdesc ** desc)109 static int prepare_desc(struct sdesc **desc)
110 {
111 	size_t size;
112 	size_t shash_size;
113 
114 	shash_size = crypto_shash_descsize(g_shash_handle);
115 	size = sizeof((*desc)->shash) + shash_size;
116 	if (size < sizeof((*desc)->shash) || size < shash_size) {
117 		tloge("size flow\n");
118 		return -ENOMEM;
119 	}
120 
121 	*desc = kzalloc(size, GFP_KERNEL);
122 	if (ZERO_OR_NULL_PTR((unsigned long)(uintptr_t)(*desc))) {
123 		tloge("alloc desc failed\n");
124 		return -ENOMEM;
125 	}
126 
127 	return EOK;
128 }
129 
130 #define PINED_PAGE_NUMBER 1
get_proc_user_pages(struct mm_struct * mm,unsigned long start_code,struct page ** ptr_page,struct task_struct * cur_struct)131 static int get_proc_user_pages(struct mm_struct *mm, unsigned long start_code,
132 	struct page **ptr_page, struct task_struct *cur_struct)
133 {
134 #if (KERNEL_VERSION(5, 10, 0) <= LINUX_VERSION_CODE)
135 	(void)cur_struct;
136 	return get_user_pages_remote(mm, start_code,
137 		(unsigned long)PINED_PAGE_NUMBER, FOLL_FORCE, ptr_page, NULL, NULL);
138 #elif (KERNEL_VERSION(4, 9, 0) <= LINUX_VERSION_CODE)
139 	return get_user_pages_remote(cur_struct, mm, start_code,
140 		(unsigned long)PINED_PAGE_NUMBER, FOLL_FORCE, ptr_page, NULL, NULL);
141 #elif (KERNEL_VERSION(4, 4, 197) == LINUX_VERSION_CODE)
142 	return get_user_pages_locked(cur_struct, mm, start_code,
143 		(unsigned long)PINED_PAGE_NUMBER, FOLL_FORCE, ptr_page, NULL);
144 #else
145 	return get_user_pages_locked(cur_struct, mm, start_code,
146 		(unsigned long)PINED_PAGE_NUMBER, 0, 1, ptr_page, NULL);
147 #endif
148 }
149 
update_task_hash(struct mm_struct * mm,struct task_struct * cur_struct,struct shash_desc * shash)150 static int update_task_hash(struct mm_struct *mm,
151 	struct task_struct *cur_struct, struct shash_desc *shash)
152 {
153 	int rc = -1;
154 	unsigned long in_size;
155 	struct page *ptr_page = NULL;
156 	void *ptr_base = NULL;
157 
158 	unsigned long start_code = mm->start_code;
159 	unsigned long end_code = mm->end_code;
160 	unsigned long code_size = end_code - start_code;
161 	if (code_size == 0) {
162 		tloge("bad code size\n");
163 		return -EINVAL;
164 	}
165 
166 	while (start_code < end_code) {
167 		/* Get a handle of the page we want to read */
168 		rc = get_proc_user_pages(mm, start_code, &ptr_page, cur_struct);
169 		if (rc != PINED_PAGE_NUMBER) {
170 			tloge("get user pages error[0x%x]\n", rc);
171 			rc = -EFAULT;
172 			break;
173 		}
174 
175 		ptr_base = kmap_atomic(ptr_page);
176 		if (!ptr_base) {
177 			rc = -EFAULT;
178 			put_page(ptr_page);
179 			break;
180 		}
181 
182 		in_size = (code_size > PAGE_SIZE) ? PAGE_SIZE : code_size;
183 		rc = crypto_shash_update(shash, ptr_base, in_size);
184 		if (rc) {
185 			kunmap_atomic(ptr_base);
186 			put_page(ptr_page);
187 			break;
188 		}
189 
190 		kunmap_atomic(ptr_base);
191 		put_page(ptr_page);
192 		start_code += in_size;
193 		code_size = end_code - start_code;
194 	}
195 	return rc;
196 }
197 
calc_task_hash(unsigned char * digest,uint32_t dig_len,struct task_struct * cur_struct,uint32_t pub_key_len)198 int calc_task_hash(unsigned char *digest, uint32_t dig_len,
199 	struct task_struct *cur_struct, uint32_t pub_key_len)
200 {
201 	struct mm_struct *mm = NULL;
202 	struct sdesc *desc = NULL;
203 	bool check_value = false;
204 	int rc;
205 
206 	check_value = (!cur_struct || !digest ||
207 		dig_len != SHA256_DIGEST_LENTH);
208 	if (check_value) {
209 		tloge("tee hash: input param is error\n");
210 		return -EFAULT;
211 	}
212 
213 	mm = get_task_mm(cur_struct);
214 	if (!mm) {
215 		if (memset_s(digest, dig_len, 0, MAX_SHA_256_SZ))
216 			return -EFAULT;
217 		tloge("kernel proc need not check\n");
218 		return EOK;
219 	}
220 
221 	if (pub_key_len != sizeof(uint32_t)) {
222 		tloge("apk need not check\n");
223 		mmput(mm);
224 		return EOK;
225 	}
226 
227 	if (prepare_desc(&desc) != EOK) {
228 		mmput(mm);
229 		tloge("prepare desc failed\n");
230 		return -ENOMEM;
231 	}
232 
233 	desc->shash.tfm = g_shash_handle;
234 	if (crypto_shash_init(&desc->shash)) {
235 		tloge("shash init failed\n");
236 		rc = -ENOMEM;
237 		goto free_res;
238 	}
239 
240 	down_read(&mm_sem_lock(mm));
241 	if (update_task_hash(mm, cur_struct, &desc->shash)) {
242 		up_read(&mm_sem_lock(mm));
243 		rc = -ENOMEM;
244 		goto free_res;
245 	}
246 	up_read(&mm_sem_lock(mm));
247 
248 	rc = crypto_shash_final(&desc->shash, digest);
249 free_res:
250 	mmput(mm);
251 	kfree(desc);
252 	return rc;
253 }
254 /* end: Calculate the SHA256 file digest */
255 
256 #if defined(CONFIG_SELINUX_AUTH_ENABLE) && defined (CONFIG_SECURITY_SELINUX)
check_proc_selinux_access(const char * s_ctx)257 static int check_proc_selinux_access(const char * s_ctx)
258 {
259 	if (s_ctx == NULL) {
260 		tloge("bad params\n");
261 		return CHECK_ACCESS_FAIL;
262 	}
263 
264 	int rc;
265 	u32 sid;
266 	u32 tid;
267 	u32 s_ctx_len = strnlen(s_ctx, MAX_SCTX_LEN);
268 	if (s_ctx_len == 0 || s_ctx_len >= MAX_SCTX_LEN) {
269 		tloge("invalid selinux ctx\n");
270 		return CHECK_ACCESS_FAIL;
271 	}
272 
273 	security_task_getsecid(current, &sid);
274 	rc = security_secctx_to_secid(s_ctx, s_ctx_len, &tid);
275 	if (rc != 0) {
276 		tloge("secctx to sid failed, rc %d", rc);
277 		return CHECK_ACCESS_FAIL;
278 	}
279 	if (sid != tid) {
280 		tloge("check selinux label failed\n");
281 		return CHECK_ACCESS_FAIL;
282 	}
283 
284 	return EOK;
285 }
286 #else
check_proc_selinux_access(const char * s_ctx)287 static int check_proc_selinux_access(const char * s_ctx)
288 {
289 	(void)s_ctx;
290 	return 0;
291 }
292 #endif
293 
get_proc_uid(uid_t * proc_uid)294 static int get_proc_uid(uid_t *proc_uid)
295 {
296 #ifdef CONFIG_LIBLINUX
297 	if (current->cred == NULL) {
298 		tloge("cred is NULL\n");
299 		return CHECK_ACCESS_FAIL;
300 	}
301 	*proc_uid = current->cred->uid.val;
302 #else
303 	const struct cred *cred = NULL;
304 	get_task_struct(current);
305 	cred = koadpt_get_task_cred(current);
306 	if (cred == NULL) {
307 		tloge("cred is NULL\n");
308 		put_task_struct(current);
309 		return CHECK_ACCESS_FAIL;
310 	}
311 
312 	*proc_uid = cred->uid.val;
313 	put_cred(cred);
314 	put_task_struct(current);
315 #endif
316 	return CHECK_ACCESS_SUCC;
317 }
318 
check_proc_uid_path(const char * auth_ctx)319 static int check_proc_uid_path(const char *auth_ctx)
320 {
321 	int ret = 0;
322 	char str_path_uid[MAX_PATH_SIZE] = { 0 };
323 	char *pro_dpath = NULL;
324 	char *k_path = NULL;
325 	u32 auth_ctx_len;
326 	uid_t proc_uid;
327 
328 	if (auth_ctx == NULL) {
329 		tloge("bad params\n");
330 		return CHECK_ACCESS_FAIL;
331 	}
332 
333 	auth_ctx_len = (u32)strnlen(auth_ctx, MAX_PATH_SIZE);
334 	if (auth_ctx_len == 0 || auth_ctx_len >= MAX_PATH_SIZE) {
335 		tloge("invalid uid path\n");
336 		return CHECK_ACCESS_FAIL;
337 	}
338 
339 	k_path = kmalloc(MAX_PATH_SIZE, GFP_KERNEL);
340 	if (ZERO_OR_NULL_PTR((unsigned long)(uintptr_t)k_path)) {
341 		tloge("path kmalloc fail\n");
342 		return CHECK_ACCESS_FAIL;
343 	}
344 
345 	pro_dpath = get_proc_dpath(k_path, MAX_PATH_SIZE);
346 	if (IS_ERR_OR_NULL(pro_dpath)) {
347 		kfree(k_path);
348 		return CHECK_ACCESS_FAIL;
349 	}
350 
351 	ret = get_proc_uid(&proc_uid);
352 	if (ret != CHECK_ACCESS_SUCC) {
353 		tloge("get proc uid failed\n");
354 		goto clean;
355 	}
356 
357 	if (snprintf_s(str_path_uid, MAX_PATH_SIZE, MAX_PATH_SIZE - 1, "%s:%u",
358 		pro_dpath, (unsigned int)proc_uid) < 0) {
359 		tloge("snprintf_s path uid failed, ret %d\n", ret);
360 		ret = CHECK_ACCESS_FAIL;
361 		goto clean;
362 	}
363 
364 	if (strnlen(str_path_uid, MAX_PATH_SIZE) != auth_ctx_len || strncmp(str_path_uid, auth_ctx, auth_ctx_len) != 0)
365 		ret = ENTER_BYPASS_CHANNEL;
366 	else
367 		ret = CHECK_ACCESS_SUCC;
368 
369 clean:
370 	kfree(k_path);
371 	return ret;
372 }
373 
374 #ifdef CONFIG_CADAEMON_AUTH
check_cadaemon_auth(void)375 int check_cadaemon_auth(void)
376 {
377 	int ret = check_proc_uid_path(CADAEMON_PATH_UID_AUTH_CTX);
378 	if (ret != 0) {
379 		tloge("check cadaemon path failed, ret %d\n", ret);
380 		return ret;
381 	}
382 	ret = check_proc_selinux_access(SELINUX_CADAEMON_LABEL);
383 	if (ret != 0) {
384 		tloge("check cadaemon selinux label failed!, ret %d\n", ret);
385 		return -EACCES;
386 	}
387 	return 0;
388 }
389 #endif
390 
check_hidl_auth(void)391 int check_hidl_auth(void)
392 {
393 	int ret = check_proc_uid_path(CA_HIDL_PATH_UID_AUTH_CTX);
394 	if (ret != CHECK_ACCESS_SUCC)
395 		return ret;
396 
397 #if defined(CONFIG_SELINUX_AUTH_ENABLE) && defined (CONFIG_SECURITY_SELINUX)
398 	ret = check_proc_selinux_access(SELINUX_CA_HIDL_LABEL);
399 	if (ret != EOK) {
400 		tloge("check hidl selinux label failed, ret %d\n", ret);
401 		return CHECK_SECLABEL_FAIL;
402 	}
403 #endif
404 
405 	return CHECK_ACCESS_SUCC;
406 }
407 
408 #ifdef CONFIG_TEECD_AUTH
check_teecd_auth(void)409 int check_teecd_auth(void)
410 {
411 	int ret = check_proc_uid_path(TEECD_PATH_UID_AUTH_CTX);
412 	if (ret != 0) {
413 		tloge("check teecd path failed, ret %d\n", ret);
414 		return ret;
415 	}
416 
417 #if defined(CONFIG_SELINUX_AUTH_ENABLE) && defined (CONFIG_SECURITY_SELINUX)
418 	ret = check_proc_selinux_access(SELINUX_TEECD_LABEL);
419 	if (ret != 0) {
420 		tloge("check teecd selinux label failed!, ret %d\n", ret);
421 		return -EACCES;
422 	}
423 #endif
424 	return CHECK_ACCESS_SUCC;
425 }
426 #endif