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
20 DEFINE_RWLOCK(token_rwlock);
21 #define ACCESS_TOKEN_UID KUIDT_INIT(3020)
22 #define MAX_NODE_NUM 500
23 #define UINT32_T_BITS 32
24
25 static struct kmem_cache *g_cache = NULL;
26 static struct token_perm_node *g_token_perm_root = NULL;
27 static size_t g_total_node_num = 0;
28
access_tokenid_get_tokenid(struct file *file, void __user *uarg)29 int access_tokenid_get_tokenid(struct file *file, void __user *uarg)
30 {
31 return copy_to_user(uarg, ¤t->token,
32 sizeof(current->token)) ? -EFAULT : 0;
33 }
34
check_permission_for_set_tokenid(struct file *file, unsigned long long tokenid)35 static 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
access_tokenid_set_tokenid(struct file *file, void __user *uarg)56 int 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
check_permission_for_ftokenid(struct file *file)70 static 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
access_tokenid_get_ftokenid(struct file *file, void __user *uarg)99 int 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, ¤t->ftoken,
105 sizeof(current->ftoken)) ? -EFAULT : 0;
106 }
107
access_tokenid_set_ftokenid(struct file *file, void __user *uarg)108 int 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
check_permission_for_set_token_permissionnull122 static bool check_permission_for_set_token_permission()
123 {
124 kuid_t uid = current_uid();
125 return uid_eq(uid, ACCESS_TOKEN_UID);
126 }
127
add_node_to_left_tree_tail(struct token_perm_node *root_node, struct token_perm_node *node)128 static 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
find_node_by_token(struct token_perm_node *root_node, uint32_t token, struct token_perm_node **target_node, struct token_perm_node **parent_node)143 static 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
add_node_to_tree(struct token_perm_node **root_node, struct token_perm_node *node)163 static 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
remove_node_by_token(struct token_perm_node **root_node, uint32_t token)191 static 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
access_tokenid_add_permission(struct file *file, void __user *uarg)223 int 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
access_tokenid_remove_permission(struct file *file, void __user *uarg)246 int 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
access_tokenid_set_permission(struct file *file, void __user *uarg)264 int 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
access_tokenid_get_permission(struct file *file, void __user *uarg)298 int 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
325 typedef int (*access_token_id_func)(struct file *file, void __user *arg);
326
327 static 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
access_tokenid_ioctl(struct file *file, unsigned int cmd, unsigned long arg)339 static 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
368 static 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
374 static struct miscdevice access_tokenid_device = {
375 .minor = MISC_DYNAMIC_MINOR,
376 .name = "access_token_id",
377 .fops = &access_tokenid_fops,
378 };
379
access_tokenid_init_module(void)380 static 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
access_tokenid_exit_module(void)399 static 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 */
406 module_init(access_tokenid_init_module);
407 module_exit(access_tokenid_exit_module);
408