1// SPDX-License-Identifier: GPL-2.0
2/*
3 * access_tokenid.c
4 *
5 * Copyright (C) 2022-2023 Huawei Technologies Co., Ltd. All rights reserved.
6 *
7 */
8
9#define pr_fmt(fmt) "access_token_id: " fmt
10
11#include <linux/errno.h>
12#include <linux/fs.h>
13#include <linux/miscdevice.h>
14#include <linux/module.h>
15#include <linux/rwlock.h>
16#include <linux/sched.h>
17#include <linux/slab.h>
18#include "access_tokenid.h"
19
20DEFINE_RWLOCK(token_rwlock);
21#define ACCESS_TOKEN_UID KUIDT_INIT(3020)
22#define MAX_NODE_NUM 500
23#define UINT32_T_BITS 32
24
25static struct kmem_cache *g_cache = NULL;
26static struct token_perm_node *g_token_perm_root = NULL;
27static size_t g_total_node_num = 0;
28
29int access_tokenid_get_tokenid(struct file *file, void __user *uarg)
30{
31	return copy_to_user(uarg, &current->token,
32			    sizeof(current->token)) ? -EFAULT : 0;
33}
34
35static bool check_permission_for_set_tokenid(struct file *file, unsigned long long tokenid)
36{
37	kuid_t uid = current_uid();
38	struct inode *inode = file->f_inode;
39	access_tokenid_inner *tokenid_inner = (access_tokenid_inner *)&tokenid;
40
41	if (inode == NULL) {
42		pr_err("%s: file inode is null\n", __func__);
43		return false;
44	}
45
46	if (uid_eq(uid, GLOBAL_ROOT_UID) ||
47	    uid_eq(uid, inode->i_uid)) {
48		return true;
49	} else if (uid_eq(uid, NWEBSPAWN_UID) && (tokenid_inner->render_flag == 1)) {
50		return true;
51	}
52
53	return false;
54}
55
56int access_tokenid_set_tokenid(struct file *file, void __user *uarg)
57{
58	unsigned long long tmp = 0;
59
60	if (copy_from_user(&tmp, uarg, sizeof(tmp)))
61		return -EFAULT;
62
63	if (!check_permission_for_set_tokenid(file, tmp))
64		return -EPERM;
65
66	current->token = tmp;
67	return 0;
68}
69
70static bool check_permission_for_ftokenid(struct file *file)
71{
72	int i;
73	struct group_info *group_info;
74	kuid_t uid = current_uid();
75	struct inode *inode = file->f_inode;
76
77	if (inode == NULL) {
78		pr_err("%s: file inode is null\n", __func__);
79		return false;
80	}
81
82	if (uid_eq(uid, GLOBAL_ROOT_UID))
83		return true;
84
85	group_info = get_current_groups();
86	for (i = 0; i < group_info->ngroups; i++) {
87		kgid_t gid = group_info->gid[i];
88
89		if (gid_eq(gid, inode->i_gid)) {
90			put_group_info(group_info);
91			return true;
92		}
93	}
94
95	put_group_info(group_info);
96	return false;
97}
98
99int access_tokenid_get_ftokenid(struct file *file, void __user *uarg)
100{
101	if (!check_permission_for_ftokenid(file))
102		return -EPERM;
103
104	return copy_to_user(uarg, &current->ftoken,
105			    sizeof(current->ftoken)) ? -EFAULT : 0;
106}
107
108int access_tokenid_set_ftokenid(struct file *file, void __user *uarg)
109{
110	unsigned long long tmp = 0;
111
112	if (!check_permission_for_ftokenid(file))
113		return -EPERM;
114
115	if (copy_from_user(&tmp, uarg, sizeof(tmp)))
116		return -EFAULT;
117
118	current->ftoken = tmp;
119	return 0;
120}
121
122static bool check_permission_for_set_token_permission()
123{
124	kuid_t uid = current_uid();
125	return uid_eq(uid, ACCESS_TOKEN_UID);
126}
127
128static void add_node_to_left_tree_tail(struct token_perm_node *root_node, struct token_perm_node *node)
129{
130	if ((root_node == NULL) || (node == NULL))
131		return;
132
133	struct token_perm_node *current_node = root_node;
134	while (true) {
135		if (current_node->left == NULL) {
136			current_node->left = node;
137			break;
138		}
139		current_node = current_node->left;
140	}
141}
142
143static void find_node_by_token(struct token_perm_node *root_node, uint32_t token,
144	struct token_perm_node **target_node, struct token_perm_node **parent_node)
145{
146	*target_node = NULL;
147	*parent_node = NULL;
148	struct token_perm_node *current_node = root_node;
149	while (current_node != NULL) {
150		if (current_node->perm_data.token == token) {
151			*target_node = current_node;
152			break;
153		}
154		*parent_node = current_node;
155		if (current_node->perm_data.token > token) {
156			current_node = current_node->left;
157		} else {
158			current_node = current_node->right;
159		}
160	}
161}
162
163static int add_node_to_tree(struct token_perm_node **root_node, struct token_perm_node *node)
164{
165	if (root_node == NULL) {
166		pr_err("%s: invalid root_node.\n", __func__);
167		return -EINVAL;
168	}
169	struct token_perm_node *target_node = NULL;
170	struct token_perm_node *parent_node = NULL;
171	find_node_by_token(*root_node, node->perm_data.token, &target_node, &parent_node);
172	if (target_node != NULL) {
173		target_node->perm_data = node->perm_data;
174		return 0;
175	}
176	if (g_total_node_num >= MAX_NODE_NUM) {
177		pr_err("%s: the number of token nodes is exceeded.\n", __func__);
178		return -EDQUOT;
179	}
180	if (parent_node == NULL) {
181		*root_node = node;
182	} else if (parent_node->perm_data.token > node->perm_data.token) {
183		parent_node->left = node;
184	} else {
185		parent_node->right = node;
186	}
187	g_total_node_num++;
188	return 1;
189}
190
191static struct token_perm_node *remove_node_by_token(struct token_perm_node **root_node, uint32_t token)
192{
193	if (root_node == NULL) {
194		pr_err("%s: invalid root_node.\n", __func__);
195		return NULL;
196	}
197	struct token_perm_node *target_node = NULL;
198	struct token_perm_node *parent_node = NULL;
199	find_node_by_token(*root_node, token, &target_node, &parent_node);
200	if (target_node == NULL) {
201		pr_err("%s: target token to be removed not found.\n", __func__);
202		return NULL;
203	}
204
205	struct token_perm_node **new_node_addr = NULL;
206	if (parent_node == NULL) {
207		new_node_addr = root_node;
208	} else if (parent_node->perm_data.token > token) {
209		new_node_addr = &(parent_node->left);
210	} else {
211		new_node_addr = &(parent_node->right);
212	}
213	if (target_node->right != NULL) {
214		*new_node_addr = target_node->right;
215		add_node_to_left_tree_tail(target_node->right, target_node->left);
216	} else {
217		*new_node_addr = target_node->left;
218	}
219	g_total_node_num--;
220	return target_node;
221}
222
223int access_tokenid_add_permission(struct file *file, void __user *uarg)
224{
225	if (!check_permission_for_set_token_permission())
226		return -EPERM;
227
228	struct token_perm_node *node = kmem_cache_zalloc(g_cache, GFP_KERNEL);
229	if (node == NULL)
230		return -ENOMEM;
231	if (copy_from_user(&(node->perm_data), uarg, sizeof(ioctl_add_perm_data))) {
232		kmem_cache_free(g_cache, node);
233		return -EFAULT;
234	}
235
236	write_lock(&token_rwlock);
237	int ret = add_node_to_tree(&g_token_perm_root, node);
238	write_unlock(&token_rwlock);
239	if (ret <= 0) {
240		kmem_cache_free(g_cache, node);
241		return ret;
242	}
243	return 0;
244}
245
246int access_tokenid_remove_permission(struct file *file, void __user *uarg)
247{
248	if (!check_permission_for_set_token_permission())
249		return -EPERM;
250
251	uint32_t token = 0;
252	if (copy_from_user(&token, uarg, sizeof(token)))
253		return -EFAULT;
254
255	write_lock(&token_rwlock);
256	struct token_perm_node *target_node = remove_node_by_token(&g_token_perm_root, token);
257	if (target_node != NULL)
258		kmem_cache_free(g_cache, target_node);
259	write_unlock(&token_rwlock);
260
261	return 0;
262}
263
264int access_tokenid_set_permission(struct file *file, void __user *uarg)
265{
266	if (!check_permission_for_set_token_permission())
267		return -EPERM;
268
269	ioctl_set_get_perm_data set_perm_data;
270	if (copy_from_user(&set_perm_data, uarg, sizeof(set_perm_data)))
271		return -EFAULT;
272
273	uint32_t idx = set_perm_data.op_code / UINT32_T_BITS;
274	if (idx >= MAX_PERM_GROUP_NUM) {
275		pr_err("%s: invalid op_code.\n", __func__);
276		return -EINVAL;
277	}
278
279	struct token_perm_node *target_node = NULL;
280	struct token_perm_node *parent_node = NULL;
281	write_lock(&token_rwlock);
282	find_node_by_token(g_token_perm_root, set_perm_data.token, &target_node, &parent_node);
283	if (target_node == NULL) {
284		write_unlock(&token_rwlock);
285		pr_err("%s: token not found.\n", __func__);
286		return -ENODATA;
287	}
288	uint32_t bit_idx = set_perm_data.op_code % UINT32_T_BITS;
289	if (set_perm_data.is_granted) {
290		target_node->perm_data.perm[idx] |= (uint32_t)0x01 << bit_idx;
291	} else {
292		target_node->perm_data.perm[idx] &= ~((uint32_t)0x01 << bit_idx);
293	}
294	write_unlock(&token_rwlock);
295	return 0;
296}
297
298int access_tokenid_get_permission(struct file *file, void __user *uarg)
299{
300	ioctl_set_get_perm_data get_perm_data;
301	if (copy_from_user(&get_perm_data, uarg, sizeof(get_perm_data)))
302		return -EFAULT;
303
304	uint32_t idx = get_perm_data.op_code / UINT32_T_BITS;
305	if (idx >= MAX_PERM_GROUP_NUM) {
306		pr_err("%s: invalid op_code.\n", __func__);
307		return -EINVAL;
308	}
309
310	struct token_perm_node *target_node = NULL;
311	struct token_perm_node *parent_node = NULL;
312	read_lock(&token_rwlock);
313	find_node_by_token(g_token_perm_root, get_perm_data.token, &target_node, &parent_node);
314	if (target_node == NULL) {
315		read_unlock(&token_rwlock);
316		return -ENODATA;
317	}
318
319	uint32_t bit_idx = get_perm_data.op_code % UINT32_T_BITS;
320	int ret = (target_node->perm_data.perm[idx] & ((uint32_t)0x01 << bit_idx)) >> bit_idx;
321	read_unlock(&token_rwlock);
322	return ret;
323}
324
325typedef int (*access_token_id_func)(struct file *file, void __user *arg);
326
327static access_token_id_func g_func_array[ACCESS_TOKENID_MAX_NR] = {
328	NULL, /* reserved */
329	access_tokenid_get_tokenid,
330	access_tokenid_set_tokenid,
331	access_tokenid_get_ftokenid,
332	access_tokenid_set_ftokenid,
333	access_tokenid_add_permission,
334	access_tokenid_remove_permission,
335	access_tokenid_get_permission,
336	access_tokenid_set_permission,
337};
338
339static long access_tokenid_ioctl(struct file *file, unsigned int cmd,
340				 unsigned long arg)
341{
342	void __user *uarg = (void __user *)arg;
343	unsigned int func_cmd = _IOC_NR(cmd);
344
345	if (uarg == NULL) {
346		pr_err("%s: invalid user uarg\n", __func__);
347		return -EINVAL;
348	}
349
350	if (_IOC_TYPE(cmd) != ACCESS_TOKEN_ID_IOCTL_BASE) {
351		pr_err("%s: access tokenid magic fail, TYPE=%d\n",
352		       __func__, _IOC_TYPE(cmd));
353		return -EINVAL;
354	}
355
356	if (func_cmd >= ACCESS_TOKENID_MAX_NR) {
357		pr_err("%s: access tokenid cmd error, cmd:%d\n",
358			__func__, func_cmd);
359		return -EINVAL;
360	}
361
362	if (g_func_array[func_cmd])
363		return (*g_func_array[func_cmd])(file, uarg);
364
365	return -EINVAL;
366}
367
368static const struct file_operations access_tokenid_fops = {
369	.owner		= THIS_MODULE,
370	.unlocked_ioctl	= access_tokenid_ioctl,
371	.compat_ioctl	= access_tokenid_ioctl,
372};
373
374static struct miscdevice access_tokenid_device = {
375	.minor	= MISC_DYNAMIC_MINOR,
376	.name	= "access_token_id",
377	.fops	= &access_tokenid_fops,
378};
379
380static int access_tokenid_init_module(void)
381{
382	int err;
383
384	err = misc_register(&access_tokenid_device);
385	if (err < 0) {
386		pr_err("access_tokenid register failed\n");
387		return err;
388	}
389
390	g_cache = kmem_cache_create("access_token_node", sizeof(struct token_perm_node), 0, SLAB_HWCACHE_ALIGN, NULL);
391	if (g_cache == NULL) {
392		pr_err("access_tokenid kmem_cache create failed\n");
393		return -ENOMEM;
394	}
395	pr_info("access_tokenid init success\n");
396	return 0;
397}
398
399static void access_tokenid_exit_module(void)
400{
401	kmem_cache_destroy(g_cache);
402	misc_deregister(&access_tokenid_device);
403}
404
405/* module entry points */
406module_init(access_tokenid_init_module);
407module_exit(access_tokenid_exit_module);
408