1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * access_tokenid.c
4 *
5 * Copyright (C) 2022 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/sched.h>
16 #include "access_tokenid.h"
17
access_tokenid_get_tokenid(struct file * file,void __user * uarg)18 int access_tokenid_get_tokenid(struct file *file, void __user *uarg)
19 {
20 return copy_to_user(uarg, ¤t->token,
21 sizeof(current->token)) ? -EFAULT : 0;
22 }
23
check_permission_for_set_tokenid(struct file * file)24 static bool check_permission_for_set_tokenid(struct file *file)
25 {
26 kuid_t uid = current_uid();
27 struct inode *inode = file->f_inode;
28
29 if (inode == NULL) {
30 pr_err("%s: file inode is null\n", __func__);
31 return false;
32 }
33
34 if (uid_eq(uid, GLOBAL_ROOT_UID) ||
35 uid_eq(uid, inode->i_uid)) {
36 return true;
37 }
38
39 return false;
40 }
41
access_tokenid_set_tokenid(struct file * file,void __user * uarg)42 int access_tokenid_set_tokenid(struct file *file, void __user *uarg)
43 {
44 unsigned long long tmp = 0;
45
46 if (!check_permission_for_set_tokenid(file))
47 return -EPERM;
48
49 if (copy_from_user(&tmp, uarg, sizeof(tmp)))
50 return -EFAULT;
51
52 current->token = tmp;
53 return 0;
54 }
55
check_permission_for_ftokenid(struct file * file)56 static bool check_permission_for_ftokenid(struct file *file)
57 {
58 int i;
59 struct group_info *group_info;
60 kuid_t uid = current_uid();
61 struct inode *inode = file->f_inode;
62
63 if (inode == NULL) {
64 pr_err("%s: file inode is null\n", __func__);
65 return false;
66 }
67
68 if (uid_eq(uid, GLOBAL_ROOT_UID))
69 return true;
70
71 group_info = get_current_groups();
72 for (i = 0; i < group_info->ngroups; i++) {
73 kgid_t gid = group_info->gid[i];
74
75 if (gid_eq(gid, inode->i_gid)) {
76 put_group_info(group_info);
77 return true;
78 }
79 }
80
81 put_group_info(group_info);
82 return false;
83 }
84
access_tokenid_get_ftokenid(struct file * file,void __user * uarg)85 int access_tokenid_get_ftokenid(struct file *file, void __user *uarg)
86 {
87 if (!check_permission_for_ftokenid(file))
88 return -EPERM;
89
90 return copy_to_user(uarg, ¤t->ftoken,
91 sizeof(current->ftoken)) ? -EFAULT : 0;
92 }
93
access_tokenid_set_ftokenid(struct file * file,void __user * uarg)94 int access_tokenid_set_ftokenid(struct file *file, void __user *uarg)
95 {
96 unsigned long long tmp = 0;
97
98 if (!check_permission_for_ftokenid(file))
99 return -EPERM;
100
101 if (copy_from_user(&tmp, uarg, sizeof(tmp)))
102 return -EFAULT;
103
104 current->ftoken = tmp;
105 return 0;
106 }
107
108 typedef int (*access_token_id_func)(struct file *file, void __user *arg);
109
110 static access_token_id_func g_func_array[ACCESS_TOKENID_MAX_NR] = {
111 NULL, /* reserved */
112 access_tokenid_get_tokenid,
113 access_tokenid_set_tokenid,
114 access_tokenid_get_ftokenid,
115 access_tokenid_set_ftokenid,
116 };
117
access_tokenid_ioctl(struct file * file,unsigned int cmd,unsigned long arg)118 static long access_tokenid_ioctl(struct file *file, unsigned int cmd,
119 unsigned long arg)
120 {
121 void __user *uarg = (void __user *)arg;
122 unsigned int func_cmd = _IOC_NR(cmd);
123
124 if (uarg == NULL) {
125 pr_err("%s: invalid user uarg\n", __func__);
126 return -EINVAL;
127 }
128
129 if (_IOC_TYPE(cmd) != ACCESS_TOKEN_ID_IOCTL_BASE) {
130 pr_err("%s: access tokenid magic fail, TYPE=%d\n",
131 __func__, _IOC_TYPE(cmd));
132 return -EINVAL;
133 }
134
135 if (func_cmd >= ACCESS_TOKENID_MAX_NR) {
136 pr_err("%s: access tokenid cmd error, cmd:%d\n",
137 __func__, func_cmd);
138 return -EINVAL;
139 }
140
141 if (g_func_array[func_cmd])
142 return (*g_func_array[func_cmd])(file, uarg);
143
144 return -EINVAL;
145 }
146
147 static const struct file_operations access_tokenid_fops = {
148 .owner = THIS_MODULE,
149 .unlocked_ioctl = access_tokenid_ioctl,
150 .compat_ioctl = access_tokenid_ioctl,
151 };
152
153 static struct miscdevice access_tokenid_device = {
154 .minor = MISC_DYNAMIC_MINOR,
155 .name = "access_token_id",
156 .fops = &access_tokenid_fops,
157 };
158
access_tokenid_init_module(void)159 static int access_tokenid_init_module(void)
160 {
161 int err;
162
163 err = misc_register(&access_tokenid_device);
164 if (err < 0) {
165 pr_err("access_tokenid register failed\n");
166 return err;
167 }
168
169 pr_info("access_tokenid init success\n");
170 return 0;
171 }
172
access_tokenid_exit_module(void)173 static void access_tokenid_exit_module(void)
174 {
175 misc_deregister(&access_tokenid_device);
176 }
177
178 /* module entry points */
179 module_init(access_tokenid_init_module);
180 module_exit(access_tokenid_exit_module);
181