18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * access_tokenid.c 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2022-2023 Huawei Technologies Co., Ltd. All rights reserved. 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#define pr_fmt(fmt) "access_token_id: " fmt 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include <linux/errno.h> 128c2ecf20Sopenharmony_ci#include <linux/fs.h> 138c2ecf20Sopenharmony_ci#include <linux/miscdevice.h> 148c2ecf20Sopenharmony_ci#include <linux/module.h> 158c2ecf20Sopenharmony_ci#include <linux/rwlock.h> 168c2ecf20Sopenharmony_ci#include <linux/sched.h> 178c2ecf20Sopenharmony_ci#include <linux/slab.h> 188c2ecf20Sopenharmony_ci#include "access_tokenid.h" 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ciDEFINE_RWLOCK(token_rwlock); 218c2ecf20Sopenharmony_ci#define ACCESS_TOKEN_UID KUIDT_INIT(3020) 228c2ecf20Sopenharmony_ci#define MAX_NODE_NUM 500 238c2ecf20Sopenharmony_ci#define UINT32_T_BITS 32 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_cistatic struct kmem_cache *g_cache = NULL; 268c2ecf20Sopenharmony_cistatic struct token_perm_node *g_token_perm_root = NULL; 278c2ecf20Sopenharmony_cistatic size_t g_total_node_num = 0; 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ciint access_tokenid_get_tokenid(struct file *file, void __user *uarg) 308c2ecf20Sopenharmony_ci{ 318c2ecf20Sopenharmony_ci return copy_to_user(uarg, ¤t->token, 328c2ecf20Sopenharmony_ci sizeof(current->token)) ? -EFAULT : 0; 338c2ecf20Sopenharmony_ci} 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_cistatic bool check_permission_for_set_tokenid(struct file *file, unsigned long long tokenid) 368c2ecf20Sopenharmony_ci{ 378c2ecf20Sopenharmony_ci kuid_t uid = current_uid(); 388c2ecf20Sopenharmony_ci struct inode *inode = file->f_inode; 398c2ecf20Sopenharmony_ci access_tokenid_inner *tokenid_inner = (access_tokenid_inner *)&tokenid; 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci if (inode == NULL) { 428c2ecf20Sopenharmony_ci pr_err("%s: file inode is null\n", __func__); 438c2ecf20Sopenharmony_ci return false; 448c2ecf20Sopenharmony_ci } 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci if (uid_eq(uid, GLOBAL_ROOT_UID) || 478c2ecf20Sopenharmony_ci uid_eq(uid, inode->i_uid)) { 488c2ecf20Sopenharmony_ci return true; 498c2ecf20Sopenharmony_ci } else if (uid_eq(uid, NWEBSPAWN_UID) && (tokenid_inner->render_flag == 1)) { 508c2ecf20Sopenharmony_ci return true; 518c2ecf20Sopenharmony_ci } 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci return false; 548c2ecf20Sopenharmony_ci} 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ciint access_tokenid_set_tokenid(struct file *file, void __user *uarg) 578c2ecf20Sopenharmony_ci{ 588c2ecf20Sopenharmony_ci unsigned long long tmp = 0; 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci if (copy_from_user(&tmp, uarg, sizeof(tmp))) 618c2ecf20Sopenharmony_ci return -EFAULT; 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci if (!check_permission_for_set_tokenid(file, tmp)) 648c2ecf20Sopenharmony_ci return -EPERM; 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci current->token = tmp; 678c2ecf20Sopenharmony_ci return 0; 688c2ecf20Sopenharmony_ci} 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_cistatic bool check_permission_for_ftokenid(struct file *file) 718c2ecf20Sopenharmony_ci{ 728c2ecf20Sopenharmony_ci int i; 738c2ecf20Sopenharmony_ci struct group_info *group_info; 748c2ecf20Sopenharmony_ci kuid_t uid = current_uid(); 758c2ecf20Sopenharmony_ci struct inode *inode = file->f_inode; 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci if (inode == NULL) { 788c2ecf20Sopenharmony_ci pr_err("%s: file inode is null\n", __func__); 798c2ecf20Sopenharmony_ci return false; 808c2ecf20Sopenharmony_ci } 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci if (uid_eq(uid, GLOBAL_ROOT_UID)) 838c2ecf20Sopenharmony_ci return true; 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci group_info = get_current_groups(); 868c2ecf20Sopenharmony_ci for (i = 0; i < group_info->ngroups; i++) { 878c2ecf20Sopenharmony_ci kgid_t gid = group_info->gid[i]; 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci if (gid_eq(gid, inode->i_gid)) { 908c2ecf20Sopenharmony_ci put_group_info(group_info); 918c2ecf20Sopenharmony_ci return true; 928c2ecf20Sopenharmony_ci } 938c2ecf20Sopenharmony_ci } 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci put_group_info(group_info); 968c2ecf20Sopenharmony_ci return false; 978c2ecf20Sopenharmony_ci} 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ciint access_tokenid_get_ftokenid(struct file *file, void __user *uarg) 1008c2ecf20Sopenharmony_ci{ 1018c2ecf20Sopenharmony_ci if (!check_permission_for_ftokenid(file)) 1028c2ecf20Sopenharmony_ci return -EPERM; 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci return copy_to_user(uarg, ¤t->ftoken, 1058c2ecf20Sopenharmony_ci sizeof(current->ftoken)) ? -EFAULT : 0; 1068c2ecf20Sopenharmony_ci} 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ciint access_tokenid_set_ftokenid(struct file *file, void __user *uarg) 1098c2ecf20Sopenharmony_ci{ 1108c2ecf20Sopenharmony_ci unsigned long long tmp = 0; 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci if (!check_permission_for_ftokenid(file)) 1138c2ecf20Sopenharmony_ci return -EPERM; 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci if (copy_from_user(&tmp, uarg, sizeof(tmp))) 1168c2ecf20Sopenharmony_ci return -EFAULT; 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci current->ftoken = tmp; 1198c2ecf20Sopenharmony_ci return 0; 1208c2ecf20Sopenharmony_ci} 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_cistatic bool check_permission_for_set_token_permission() 1238c2ecf20Sopenharmony_ci{ 1248c2ecf20Sopenharmony_ci kuid_t uid = current_uid(); 1258c2ecf20Sopenharmony_ci return uid_eq(uid, ACCESS_TOKEN_UID); 1268c2ecf20Sopenharmony_ci} 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_cistatic void add_node_to_left_tree_tail(struct token_perm_node *root_node, struct token_perm_node *node) 1298c2ecf20Sopenharmony_ci{ 1308c2ecf20Sopenharmony_ci if ((root_node == NULL) || (node == NULL)) 1318c2ecf20Sopenharmony_ci return; 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci struct token_perm_node *current_node = root_node; 1348c2ecf20Sopenharmony_ci while (true) { 1358c2ecf20Sopenharmony_ci if (current_node->left == NULL) { 1368c2ecf20Sopenharmony_ci current_node->left = node; 1378c2ecf20Sopenharmony_ci break; 1388c2ecf20Sopenharmony_ci } 1398c2ecf20Sopenharmony_ci current_node = current_node->left; 1408c2ecf20Sopenharmony_ci } 1418c2ecf20Sopenharmony_ci} 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_cistatic void find_node_by_token(struct token_perm_node *root_node, uint32_t token, 1448c2ecf20Sopenharmony_ci struct token_perm_node **target_node, struct token_perm_node **parent_node) 1458c2ecf20Sopenharmony_ci{ 1468c2ecf20Sopenharmony_ci *target_node = NULL; 1478c2ecf20Sopenharmony_ci *parent_node = NULL; 1488c2ecf20Sopenharmony_ci struct token_perm_node *current_node = root_node; 1498c2ecf20Sopenharmony_ci while (current_node != NULL) { 1508c2ecf20Sopenharmony_ci if (current_node->perm_data.token == token) { 1518c2ecf20Sopenharmony_ci *target_node = current_node; 1528c2ecf20Sopenharmony_ci break; 1538c2ecf20Sopenharmony_ci } 1548c2ecf20Sopenharmony_ci *parent_node = current_node; 1558c2ecf20Sopenharmony_ci if (current_node->perm_data.token > token) { 1568c2ecf20Sopenharmony_ci current_node = current_node->left; 1578c2ecf20Sopenharmony_ci } else { 1588c2ecf20Sopenharmony_ci current_node = current_node->right; 1598c2ecf20Sopenharmony_ci } 1608c2ecf20Sopenharmony_ci } 1618c2ecf20Sopenharmony_ci} 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_cistatic int add_node_to_tree(struct token_perm_node **root_node, struct token_perm_node *node) 1648c2ecf20Sopenharmony_ci{ 1658c2ecf20Sopenharmony_ci if (root_node == NULL) { 1668c2ecf20Sopenharmony_ci pr_err("%s: invalid root_node.\n", __func__); 1678c2ecf20Sopenharmony_ci return -EINVAL; 1688c2ecf20Sopenharmony_ci } 1698c2ecf20Sopenharmony_ci struct token_perm_node *target_node = NULL; 1708c2ecf20Sopenharmony_ci struct token_perm_node *parent_node = NULL; 1718c2ecf20Sopenharmony_ci find_node_by_token(*root_node, node->perm_data.token, &target_node, &parent_node); 1728c2ecf20Sopenharmony_ci if (target_node != NULL) { 1738c2ecf20Sopenharmony_ci target_node->perm_data = node->perm_data; 1748c2ecf20Sopenharmony_ci return 0; 1758c2ecf20Sopenharmony_ci } 1768c2ecf20Sopenharmony_ci if (g_total_node_num >= MAX_NODE_NUM) { 1778c2ecf20Sopenharmony_ci pr_err("%s: the number of token nodes is exceeded.\n", __func__); 1788c2ecf20Sopenharmony_ci return -EDQUOT; 1798c2ecf20Sopenharmony_ci } 1808c2ecf20Sopenharmony_ci if (parent_node == NULL) { 1818c2ecf20Sopenharmony_ci *root_node = node; 1828c2ecf20Sopenharmony_ci } else if (parent_node->perm_data.token > node->perm_data.token) { 1838c2ecf20Sopenharmony_ci parent_node->left = node; 1848c2ecf20Sopenharmony_ci } else { 1858c2ecf20Sopenharmony_ci parent_node->right = node; 1868c2ecf20Sopenharmony_ci } 1878c2ecf20Sopenharmony_ci g_total_node_num++; 1888c2ecf20Sopenharmony_ci return 1; 1898c2ecf20Sopenharmony_ci} 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_cistatic struct token_perm_node *remove_node_by_token(struct token_perm_node **root_node, uint32_t token) 1928c2ecf20Sopenharmony_ci{ 1938c2ecf20Sopenharmony_ci if (root_node == NULL) { 1948c2ecf20Sopenharmony_ci pr_err("%s: invalid root_node.\n", __func__); 1958c2ecf20Sopenharmony_ci return NULL; 1968c2ecf20Sopenharmony_ci } 1978c2ecf20Sopenharmony_ci struct token_perm_node *target_node = NULL; 1988c2ecf20Sopenharmony_ci struct token_perm_node *parent_node = NULL; 1998c2ecf20Sopenharmony_ci find_node_by_token(*root_node, token, &target_node, &parent_node); 2008c2ecf20Sopenharmony_ci if (target_node == NULL) { 2018c2ecf20Sopenharmony_ci pr_err("%s: target token to be removed not found.\n", __func__); 2028c2ecf20Sopenharmony_ci return NULL; 2038c2ecf20Sopenharmony_ci } 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci struct token_perm_node **new_node_addr = NULL; 2068c2ecf20Sopenharmony_ci if (parent_node == NULL) { 2078c2ecf20Sopenharmony_ci new_node_addr = root_node; 2088c2ecf20Sopenharmony_ci } else if (parent_node->perm_data.token > token) { 2098c2ecf20Sopenharmony_ci new_node_addr = &(parent_node->left); 2108c2ecf20Sopenharmony_ci } else { 2118c2ecf20Sopenharmony_ci new_node_addr = &(parent_node->right); 2128c2ecf20Sopenharmony_ci } 2138c2ecf20Sopenharmony_ci if (target_node->right != NULL) { 2148c2ecf20Sopenharmony_ci *new_node_addr = target_node->right; 2158c2ecf20Sopenharmony_ci add_node_to_left_tree_tail(target_node->right, target_node->left); 2168c2ecf20Sopenharmony_ci } else { 2178c2ecf20Sopenharmony_ci *new_node_addr = target_node->left; 2188c2ecf20Sopenharmony_ci } 2198c2ecf20Sopenharmony_ci g_total_node_num--; 2208c2ecf20Sopenharmony_ci return target_node; 2218c2ecf20Sopenharmony_ci} 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ciint access_tokenid_add_permission(struct file *file, void __user *uarg) 2248c2ecf20Sopenharmony_ci{ 2258c2ecf20Sopenharmony_ci if (!check_permission_for_set_token_permission()) 2268c2ecf20Sopenharmony_ci return -EPERM; 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci struct token_perm_node *node = kmem_cache_zalloc(g_cache, GFP_KERNEL); 2298c2ecf20Sopenharmony_ci if (node == NULL) 2308c2ecf20Sopenharmony_ci return -ENOMEM; 2318c2ecf20Sopenharmony_ci if (copy_from_user(&(node->perm_data), uarg, sizeof(ioctl_add_perm_data))) { 2328c2ecf20Sopenharmony_ci kmem_cache_free(g_cache, node); 2338c2ecf20Sopenharmony_ci return -EFAULT; 2348c2ecf20Sopenharmony_ci } 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci write_lock(&token_rwlock); 2378c2ecf20Sopenharmony_ci int ret = add_node_to_tree(&g_token_perm_root, node); 2388c2ecf20Sopenharmony_ci write_unlock(&token_rwlock); 2398c2ecf20Sopenharmony_ci if (ret <= 0) { 2408c2ecf20Sopenharmony_ci kmem_cache_free(g_cache, node); 2418c2ecf20Sopenharmony_ci return ret; 2428c2ecf20Sopenharmony_ci } 2438c2ecf20Sopenharmony_ci return 0; 2448c2ecf20Sopenharmony_ci} 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ciint access_tokenid_remove_permission(struct file *file, void __user *uarg) 2478c2ecf20Sopenharmony_ci{ 2488c2ecf20Sopenharmony_ci if (!check_permission_for_set_token_permission()) 2498c2ecf20Sopenharmony_ci return -EPERM; 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci uint32_t token = 0; 2528c2ecf20Sopenharmony_ci if (copy_from_user(&token, uarg, sizeof(token))) 2538c2ecf20Sopenharmony_ci return -EFAULT; 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci write_lock(&token_rwlock); 2568c2ecf20Sopenharmony_ci struct token_perm_node *target_node = remove_node_by_token(&g_token_perm_root, token); 2578c2ecf20Sopenharmony_ci if (target_node != NULL) 2588c2ecf20Sopenharmony_ci kmem_cache_free(g_cache, target_node); 2598c2ecf20Sopenharmony_ci write_unlock(&token_rwlock); 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci return 0; 2628c2ecf20Sopenharmony_ci} 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ciint access_tokenid_set_permission(struct file *file, void __user *uarg) 2658c2ecf20Sopenharmony_ci{ 2668c2ecf20Sopenharmony_ci if (!check_permission_for_set_token_permission()) 2678c2ecf20Sopenharmony_ci return -EPERM; 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci ioctl_set_get_perm_data set_perm_data; 2708c2ecf20Sopenharmony_ci if (copy_from_user(&set_perm_data, uarg, sizeof(set_perm_data))) 2718c2ecf20Sopenharmony_ci return -EFAULT; 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci uint32_t idx = set_perm_data.op_code / UINT32_T_BITS; 2748c2ecf20Sopenharmony_ci if (idx >= MAX_PERM_GROUP_NUM) { 2758c2ecf20Sopenharmony_ci pr_err("%s: invalid op_code.\n", __func__); 2768c2ecf20Sopenharmony_ci return -EINVAL; 2778c2ecf20Sopenharmony_ci } 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci struct token_perm_node *target_node = NULL; 2808c2ecf20Sopenharmony_ci struct token_perm_node *parent_node = NULL; 2818c2ecf20Sopenharmony_ci write_lock(&token_rwlock); 2828c2ecf20Sopenharmony_ci find_node_by_token(g_token_perm_root, set_perm_data.token, &target_node, &parent_node); 2838c2ecf20Sopenharmony_ci if (target_node == NULL) { 2848c2ecf20Sopenharmony_ci write_unlock(&token_rwlock); 2858c2ecf20Sopenharmony_ci pr_err("%s: token not found.\n", __func__); 2868c2ecf20Sopenharmony_ci return -ENODATA; 2878c2ecf20Sopenharmony_ci } 2888c2ecf20Sopenharmony_ci uint32_t bit_idx = set_perm_data.op_code % UINT32_T_BITS; 2898c2ecf20Sopenharmony_ci if (set_perm_data.is_granted) { 2908c2ecf20Sopenharmony_ci target_node->perm_data.perm[idx] |= (uint32_t)0x01 << bit_idx; 2918c2ecf20Sopenharmony_ci } else { 2928c2ecf20Sopenharmony_ci target_node->perm_data.perm[idx] &= ~((uint32_t)0x01 << bit_idx); 2938c2ecf20Sopenharmony_ci } 2948c2ecf20Sopenharmony_ci write_unlock(&token_rwlock); 2958c2ecf20Sopenharmony_ci return 0; 2968c2ecf20Sopenharmony_ci} 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ciint access_tokenid_get_permission(struct file *file, void __user *uarg) 2998c2ecf20Sopenharmony_ci{ 3008c2ecf20Sopenharmony_ci ioctl_set_get_perm_data get_perm_data; 3018c2ecf20Sopenharmony_ci if (copy_from_user(&get_perm_data, uarg, sizeof(get_perm_data))) 3028c2ecf20Sopenharmony_ci return -EFAULT; 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci uint32_t idx = get_perm_data.op_code / UINT32_T_BITS; 3058c2ecf20Sopenharmony_ci if (idx >= MAX_PERM_GROUP_NUM) { 3068c2ecf20Sopenharmony_ci pr_err("%s: invalid op_code.\n", __func__); 3078c2ecf20Sopenharmony_ci return -EINVAL; 3088c2ecf20Sopenharmony_ci } 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci struct token_perm_node *target_node = NULL; 3118c2ecf20Sopenharmony_ci struct token_perm_node *parent_node = NULL; 3128c2ecf20Sopenharmony_ci read_lock(&token_rwlock); 3138c2ecf20Sopenharmony_ci find_node_by_token(g_token_perm_root, get_perm_data.token, &target_node, &parent_node); 3148c2ecf20Sopenharmony_ci if (target_node == NULL) { 3158c2ecf20Sopenharmony_ci read_unlock(&token_rwlock); 3168c2ecf20Sopenharmony_ci return -ENODATA; 3178c2ecf20Sopenharmony_ci } 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci uint32_t bit_idx = get_perm_data.op_code % UINT32_T_BITS; 3208c2ecf20Sopenharmony_ci int ret = (target_node->perm_data.perm[idx] & ((uint32_t)0x01 << bit_idx)) >> bit_idx; 3218c2ecf20Sopenharmony_ci read_unlock(&token_rwlock); 3228c2ecf20Sopenharmony_ci return ret; 3238c2ecf20Sopenharmony_ci} 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_citypedef int (*access_token_id_func)(struct file *file, void __user *arg); 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_cistatic access_token_id_func g_func_array[ACCESS_TOKENID_MAX_NR] = { 3288c2ecf20Sopenharmony_ci NULL, /* reserved */ 3298c2ecf20Sopenharmony_ci access_tokenid_get_tokenid, 3308c2ecf20Sopenharmony_ci access_tokenid_set_tokenid, 3318c2ecf20Sopenharmony_ci access_tokenid_get_ftokenid, 3328c2ecf20Sopenharmony_ci access_tokenid_set_ftokenid, 3338c2ecf20Sopenharmony_ci access_tokenid_add_permission, 3348c2ecf20Sopenharmony_ci access_tokenid_remove_permission, 3358c2ecf20Sopenharmony_ci access_tokenid_get_permission, 3368c2ecf20Sopenharmony_ci access_tokenid_set_permission, 3378c2ecf20Sopenharmony_ci}; 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_cistatic long access_tokenid_ioctl(struct file *file, unsigned int cmd, 3408c2ecf20Sopenharmony_ci unsigned long arg) 3418c2ecf20Sopenharmony_ci{ 3428c2ecf20Sopenharmony_ci void __user *uarg = (void __user *)arg; 3438c2ecf20Sopenharmony_ci unsigned int func_cmd = _IOC_NR(cmd); 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci if (uarg == NULL) { 3468c2ecf20Sopenharmony_ci pr_err("%s: invalid user uarg\n", __func__); 3478c2ecf20Sopenharmony_ci return -EINVAL; 3488c2ecf20Sopenharmony_ci } 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci if (_IOC_TYPE(cmd) != ACCESS_TOKEN_ID_IOCTL_BASE) { 3518c2ecf20Sopenharmony_ci pr_err("%s: access tokenid magic fail, TYPE=%d\n", 3528c2ecf20Sopenharmony_ci __func__, _IOC_TYPE(cmd)); 3538c2ecf20Sopenharmony_ci return -EINVAL; 3548c2ecf20Sopenharmony_ci } 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci if (func_cmd >= ACCESS_TOKENID_MAX_NR) { 3578c2ecf20Sopenharmony_ci pr_err("%s: access tokenid cmd error, cmd:%d\n", 3588c2ecf20Sopenharmony_ci __func__, func_cmd); 3598c2ecf20Sopenharmony_ci return -EINVAL; 3608c2ecf20Sopenharmony_ci } 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci if (g_func_array[func_cmd]) 3638c2ecf20Sopenharmony_ci return (*g_func_array[func_cmd])(file, uarg); 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci return -EINVAL; 3668c2ecf20Sopenharmony_ci} 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_cistatic const struct file_operations access_tokenid_fops = { 3698c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 3708c2ecf20Sopenharmony_ci .unlocked_ioctl = access_tokenid_ioctl, 3718c2ecf20Sopenharmony_ci .compat_ioctl = access_tokenid_ioctl, 3728c2ecf20Sopenharmony_ci}; 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_cistatic struct miscdevice access_tokenid_device = { 3758c2ecf20Sopenharmony_ci .minor = MISC_DYNAMIC_MINOR, 3768c2ecf20Sopenharmony_ci .name = "access_token_id", 3778c2ecf20Sopenharmony_ci .fops = &access_tokenid_fops, 3788c2ecf20Sopenharmony_ci}; 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_cistatic int access_tokenid_init_module(void) 3818c2ecf20Sopenharmony_ci{ 3828c2ecf20Sopenharmony_ci int err; 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci err = misc_register(&access_tokenid_device); 3858c2ecf20Sopenharmony_ci if (err < 0) { 3868c2ecf20Sopenharmony_ci pr_err("access_tokenid register failed\n"); 3878c2ecf20Sopenharmony_ci return err; 3888c2ecf20Sopenharmony_ci } 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_ci g_cache = kmem_cache_create("access_token_node", sizeof(struct token_perm_node), 0, SLAB_HWCACHE_ALIGN, NULL); 3918c2ecf20Sopenharmony_ci if (g_cache == NULL) { 3928c2ecf20Sopenharmony_ci pr_err("access_tokenid kmem_cache create failed\n"); 3938c2ecf20Sopenharmony_ci return -ENOMEM; 3948c2ecf20Sopenharmony_ci } 3958c2ecf20Sopenharmony_ci pr_info("access_tokenid init success\n"); 3968c2ecf20Sopenharmony_ci return 0; 3978c2ecf20Sopenharmony_ci} 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_cistatic void access_tokenid_exit_module(void) 4008c2ecf20Sopenharmony_ci{ 4018c2ecf20Sopenharmony_ci kmem_cache_destroy(g_cache); 4028c2ecf20Sopenharmony_ci misc_deregister(&access_tokenid_device); 4038c2ecf20Sopenharmony_ci} 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci/* module entry points */ 4068c2ecf20Sopenharmony_cimodule_init(access_tokenid_init_module); 4078c2ecf20Sopenharmony_cimodule_exit(access_tokenid_exit_module); 408