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_permission(void)122 static bool check_permission_for_set_token_permission(void)
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 struct token_perm_node *target_node = NULL;
166 struct token_perm_node *parent_node = NULL;
167 find_node_by_token(root_node, node->perm_data.token, &target_node, &parent_node);
168 if (target_node != NULL) {
169 target_node->perm_data = node->perm_data;
170 return 0;
171 }
172 if (g_total_node_num >= MAX_NODE_NUM) {
173 pr_err("%s: the number of token nodes is exceeded.\n", __func__);
174 return -EDQUOT;
175 }
176 if (parent_node == NULL) {
177 g_token_perm_root = node;
178 } else if (parent_node->perm_data.token > node->perm_data.token) {
179 parent_node->left = node;
180 } else {
181 parent_node->right = node;
182 }
183 g_total_node_num++;
184 return 1;
185 }
186
remove_node_by_token(struct token_perm_node *root_node, uint32_t token)187 static struct token_perm_node *remove_node_by_token(struct token_perm_node *root_node, uint32_t token)
188 {
189 struct token_perm_node *target_node = NULL;
190 struct token_perm_node *parent_node = NULL;
191 find_node_by_token(root_node, token, &target_node, &parent_node);
192 if (target_node == NULL) {
193 pr_err("%s: target token to be removed not found.\n", __func__);
194 return NULL;
195 }
196
197 struct token_perm_node **new_node_addr = NULL;
198 if (parent_node == NULL) {
199 new_node_addr = &root_node;
200 } else if (parent_node->perm_data.token > token) {
201 new_node_addr = &(parent_node->left);
202 } else {
203 new_node_addr = &(parent_node->right);
204 }
205 if (target_node->right != NULL) {
206 *new_node_addr = target_node->right;
207 add_node_to_left_tree_tail(target_node->right, target_node->left);
208 } else {
209 *new_node_addr = target_node->left;
210 }
211 g_total_node_num--;
212 return target_node;
213 }
214
access_tokenid_add_permission(struct file *file, void __user *uarg)215 int access_tokenid_add_permission(struct file *file, void __user *uarg)
216 {
217 if (!check_permission_for_set_token_permission())
218 return -EPERM;
219
220 struct token_perm_node *node = kmem_cache_zalloc(g_cache, GFP_KERNEL);
221 if (node == NULL)
222 return -ENOMEM;
223 if (copy_from_user(&(node->perm_data), uarg, sizeof(ioctl_add_perm_data))) {
224 kmem_cache_free(g_cache, node);
225 return -EFAULT;
226 }
227
228 write_lock(&token_rwlock);
229 int ret = add_node_to_tree(g_token_perm_root, node);
230 write_unlock(&token_rwlock);
231 if (ret <= 0) {
232 kmem_cache_free(g_cache, node);
233 return ret;
234 }
235 return 0;
236 }
237
access_tokenid_remove_permission(struct file *file, void __user *uarg)238 int access_tokenid_remove_permission(struct file *file, void __user *uarg)
239 {
240 if (!check_permission_for_set_token_permission())
241 return -EPERM;
242
243 uint32_t token = 0;
244 if (copy_from_user(&token, uarg, sizeof(token)))
245 return -EFAULT;
246
247 write_lock(&token_rwlock);
248 struct token_perm_node *target_node = remove_node_by_token(g_token_perm_root, token);
249 write_unlock(&token_rwlock);
250
251 if (target_node != NULL)
252 kmem_cache_free(g_cache, target_node);
253
254 return 0;
255 }
256
access_tokenid_set_permission(struct file *file, void __user *uarg)257 int access_tokenid_set_permission(struct file *file, void __user *uarg)
258 {
259 if (!check_permission_for_set_token_permission())
260 return -EPERM;
261
262 ioctl_set_get_perm_data set_perm_data;
263 if (copy_from_user(&set_perm_data, uarg, sizeof(set_perm_data)))
264 return -EFAULT;
265
266 uint32_t idx = set_perm_data.op_code / UINT32_T_BITS;
267 if (idx >= MAX_PERM_GROUP_NUM) {
268 pr_err("%s: invalid op_code.\n", __func__);
269 return -EINVAL;
270 }
271
272 struct token_perm_node *target_node = NULL;
273 struct token_perm_node *parent_node = NULL;
274 write_lock(&token_rwlock);
275 find_node_by_token(g_token_perm_root, set_perm_data.token, &target_node, &parent_node);
276 if (target_node == NULL) {
277 write_unlock(&token_rwlock);
278 pr_err("%s: token not found.\n", __func__);
279 return -ENODATA;
280 }
281 uint32_t bit_idx = set_perm_data.op_code % UINT32_T_BITS;
282 if (set_perm_data.is_granted) {
283 target_node->perm_data.perm[idx] |= (uint32_t)0x01 << bit_idx;
284 } else {
285 target_node->perm_data.perm[idx] &= ~((uint32_t)0x01 << bit_idx);
286 }
287 write_unlock(&token_rwlock);
288 return 0;
289 }
290
access_tokenid_get_permission(struct file *file, void __user *uarg)291 int access_tokenid_get_permission(struct file *file, void __user *uarg)
292 {
293 ioctl_set_get_perm_data get_perm_data;
294 if (copy_from_user(&get_perm_data, uarg, sizeof(get_perm_data)))
295 return -EFAULT;
296
297 uint32_t idx = get_perm_data.op_code / UINT32_T_BITS;
298 if (idx >= MAX_PERM_GROUP_NUM) {
299 pr_err("%s: invalid op_code.\n", __func__);
300 return -EINVAL;
301 }
302
303 struct token_perm_node *target_node = NULL;
304 struct token_perm_node *parent_node = NULL;
305 read_lock(&token_rwlock);
306 find_node_by_token(g_token_perm_root, get_perm_data.token, &target_node, &parent_node);
307 read_unlock(&token_rwlock);
308 if (target_node == NULL)
309 return -ENODATA;
310
311 uint32_t bit_idx = get_perm_data.op_code % UINT32_T_BITS;
312 return (target_node->perm_data.perm[idx] & ((uint32_t)0x01 << bit_idx)) >> bit_idx;
313 }
314
315 typedef int (*access_token_id_func)(struct file *file, void __user *arg);
316
317 static access_token_id_func g_func_array[ACCESS_TOKENID_MAX_NR] = {
318 NULL, /* reserved */
319 access_tokenid_get_tokenid,
320 access_tokenid_set_tokenid,
321 access_tokenid_get_ftokenid,
322 access_tokenid_set_ftokenid,
323 access_tokenid_add_permission,
324 access_tokenid_remove_permission,
325 access_tokenid_get_permission,
326 access_tokenid_set_permission,
327 };
328
access_tokenid_ioctl(struct file *file, unsigned int cmd, unsigned long arg)329 static long access_tokenid_ioctl(struct file *file, unsigned int cmd,
330 unsigned long arg)
331 {
332 void __user *uarg = (void __user *)arg;
333 unsigned int func_cmd = _IOC_NR(cmd);
334
335 if (uarg == NULL) {
336 pr_err("%s: invalid user uarg\n", __func__);
337 return -EINVAL;
338 }
339
340 if (_IOC_TYPE(cmd) != ACCESS_TOKEN_ID_IOCTL_BASE) {
341 pr_err("%s: access tokenid magic fail, TYPE=%d\n",
342 __func__, _IOC_TYPE(cmd));
343 return -EINVAL;
344 }
345
346 if (func_cmd >= ACCESS_TOKENID_MAX_NR) {
347 pr_err("%s: access tokenid cmd error, cmd:%d\n",
348 __func__, func_cmd);
349 return -EINVAL;
350 }
351
352 if (g_func_array[func_cmd])
353 return (*g_func_array[func_cmd])(file, uarg);
354
355 return -EINVAL;
356 }
357
358 static const struct file_operations access_tokenid_fops = {
359 .owner = THIS_MODULE,
360 .unlocked_ioctl = access_tokenid_ioctl,
361 .compat_ioctl = access_tokenid_ioctl,
362 };
363
364 static struct miscdevice access_tokenid_device = {
365 .minor = MISC_DYNAMIC_MINOR,
366 .name = "access_token_id",
367 .fops = &access_tokenid_fops,
368 };
369
access_tokenid_init_module(void)370 static int access_tokenid_init_module(void)
371 {
372 int err;
373
374 err = misc_register(&access_tokenid_device);
375 if (err < 0) {
376 pr_err("access_tokenid register failed\n");
377 return err;
378 }
379
380 g_cache = kmem_cache_create("access_token_node", sizeof(struct token_perm_node), 0, SLAB_HWCACHE_ALIGN, NULL);
381 if (g_cache == NULL) {
382 pr_err("access_tokenid kmem_cache create failed\n");
383 return -ENOMEM;
384 }
385 pr_info("access_tokenid init success\n");
386 return 0;
387 }
388
access_tokenid_exit_module(void)389 static void access_tokenid_exit_module(void)
390 {
391 kmem_cache_destroy(g_cache);
392 misc_deregister(&access_tokenid_device);
393 }
394
395 /* module entry points */
396 module_init(access_tokenid_init_module);
397 module_exit(access_tokenid_exit_module);
398