1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * security/tomoyo/securityfs_if.c |
4 | * |
5 | * Copyright (C) 2005-2011 NTT DATA CORPORATION |
6 | */ |
7 | |
8 | #include <linux/security.h> |
9 | #include "common.h" |
10 | |
11 | /** |
12 | * tomoyo_check_task_acl - Check permission for task operation. |
13 | * |
14 | * @r: Pointer to "struct tomoyo_request_info". |
15 | * @ptr: Pointer to "struct tomoyo_acl_info". |
16 | * |
17 | * Returns true if granted, false otherwise. |
18 | */ |
19 | static bool tomoyo_check_task_acl(struct tomoyo_request_info *r, |
20 | const struct tomoyo_acl_info *ptr) |
21 | { |
22 | const struct tomoyo_task_acl *acl = container_of(ptr, typeof(*acl), |
23 | head); |
24 | |
25 | return !tomoyo_pathcmp(a: r->param.task.domainname, b: acl->domainname); |
26 | } |
27 | |
28 | /** |
29 | * tomoyo_write_self - write() for /sys/kernel/security/tomoyo/self_domain interface. |
30 | * |
31 | * @file: Pointer to "struct file". |
32 | * @buf: Domainname to transit to. |
33 | * @count: Size of @buf. |
34 | * @ppos: Unused. |
35 | * |
36 | * Returns @count on success, negative value otherwise. |
37 | * |
38 | * If domain transition was permitted but the domain transition failed, this |
39 | * function returns error rather than terminating current thread with SIGKILL. |
40 | */ |
41 | static ssize_t tomoyo_write_self(struct file *file, const char __user *buf, |
42 | size_t count, loff_t *ppos) |
43 | { |
44 | char *data; |
45 | int error; |
46 | |
47 | if (!count || count >= TOMOYO_EXEC_TMPSIZE - 10) |
48 | return -ENOMEM; |
49 | data = memdup_user_nul(buf, count); |
50 | if (IS_ERR(ptr: data)) |
51 | return PTR_ERR(ptr: data); |
52 | tomoyo_normalize_line(buffer: data); |
53 | if (tomoyo_correct_domain(domainname: data)) { |
54 | const int idx = tomoyo_read_lock(); |
55 | struct tomoyo_path_info name; |
56 | struct tomoyo_request_info r; |
57 | |
58 | name.name = data; |
59 | tomoyo_fill_path_info(ptr: &name); |
60 | /* Check "task manual_domain_transition" permission. */ |
61 | tomoyo_init_request_info(r: &r, NULL, index: TOMOYO_MAC_FILE_EXECUTE); |
62 | r.param_type = TOMOYO_TYPE_MANUAL_TASK_ACL; |
63 | r.param.task.domainname = &name; |
64 | tomoyo_check_acl(r: &r, check_entry: tomoyo_check_task_acl); |
65 | if (!r.granted) |
66 | error = -EPERM; |
67 | else { |
68 | struct tomoyo_domain_info *new_domain = |
69 | tomoyo_assign_domain(domainname: data, transit: true); |
70 | if (!new_domain) { |
71 | error = -ENOENT; |
72 | } else { |
73 | struct tomoyo_task *s = tomoyo_task(current); |
74 | struct tomoyo_domain_info *old_domain = |
75 | s->domain_info; |
76 | |
77 | s->domain_info = new_domain; |
78 | atomic_inc(v: &new_domain->users); |
79 | atomic_dec(v: &old_domain->users); |
80 | error = 0; |
81 | } |
82 | } |
83 | tomoyo_read_unlock(idx); |
84 | } else |
85 | error = -EINVAL; |
86 | kfree(objp: data); |
87 | return error ? error : count; |
88 | } |
89 | |
90 | /** |
91 | * tomoyo_read_self - read() for /sys/kernel/security/tomoyo/self_domain interface. |
92 | * |
93 | * @file: Pointer to "struct file". |
94 | * @buf: Domainname which current thread belongs to. |
95 | * @count: Size of @buf. |
96 | * @ppos: Bytes read by now. |
97 | * |
98 | * Returns read size on success, negative value otherwise. |
99 | */ |
100 | static ssize_t tomoyo_read_self(struct file *file, char __user *buf, |
101 | size_t count, loff_t *ppos) |
102 | { |
103 | const char *domain = tomoyo_domain()->domainname->name; |
104 | loff_t len = strlen(domain); |
105 | loff_t pos = *ppos; |
106 | |
107 | if (pos >= len || !count) |
108 | return 0; |
109 | len -= pos; |
110 | if (count < len) |
111 | len = count; |
112 | if (copy_to_user(to: buf, from: domain + pos, n: len)) |
113 | return -EFAULT; |
114 | *ppos += len; |
115 | return len; |
116 | } |
117 | |
118 | /* Operations for /sys/kernel/security/tomoyo/self_domain interface. */ |
119 | static const struct file_operations tomoyo_self_operations = { |
120 | .write = tomoyo_write_self, |
121 | .read = tomoyo_read_self, |
122 | }; |
123 | |
124 | /** |
125 | * tomoyo_open - open() for /sys/kernel/security/tomoyo/ interface. |
126 | * |
127 | * @inode: Pointer to "struct inode". |
128 | * @file: Pointer to "struct file". |
129 | * |
130 | * Returns 0 on success, negative value otherwise. |
131 | */ |
132 | static int tomoyo_open(struct inode *inode, struct file *file) |
133 | { |
134 | const u8 key = (uintptr_t) file_inode(f: file)->i_private; |
135 | |
136 | return tomoyo_open_control(type: key, file); |
137 | } |
138 | |
139 | /** |
140 | * tomoyo_release - close() for /sys/kernel/security/tomoyo/ interface. |
141 | * |
142 | * @inode: Pointer to "struct inode". |
143 | * @file: Pointer to "struct file". |
144 | * |
145 | */ |
146 | static int tomoyo_release(struct inode *inode, struct file *file) |
147 | { |
148 | tomoyo_close_control(head: file->private_data); |
149 | return 0; |
150 | } |
151 | |
152 | /** |
153 | * tomoyo_poll - poll() for /sys/kernel/security/tomoyo/ interface. |
154 | * |
155 | * @file: Pointer to "struct file". |
156 | * @wait: Pointer to "poll_table". Maybe NULL. |
157 | * |
158 | * Returns EPOLLIN | EPOLLRDNORM | EPOLLOUT | EPOLLWRNORM if ready to read/write, |
159 | * EPOLLOUT | EPOLLWRNORM otherwise. |
160 | */ |
161 | static __poll_t tomoyo_poll(struct file *file, poll_table *wait) |
162 | { |
163 | return tomoyo_poll_control(file, wait); |
164 | } |
165 | |
166 | /** |
167 | * tomoyo_read - read() for /sys/kernel/security/tomoyo/ interface. |
168 | * |
169 | * @file: Pointer to "struct file". |
170 | * @buf: Pointer to buffer. |
171 | * @count: Size of @buf. |
172 | * @ppos: Unused. |
173 | * |
174 | * Returns bytes read on success, negative value otherwise. |
175 | */ |
176 | static ssize_t tomoyo_read(struct file *file, char __user *buf, size_t count, |
177 | loff_t *ppos) |
178 | { |
179 | return tomoyo_read_control(head: file->private_data, buffer: buf, buffer_len: count); |
180 | } |
181 | |
182 | /** |
183 | * tomoyo_write - write() for /sys/kernel/security/tomoyo/ interface. |
184 | * |
185 | * @file: Pointer to "struct file". |
186 | * @buf: Pointer to buffer. |
187 | * @count: Size of @buf. |
188 | * @ppos: Unused. |
189 | * |
190 | * Returns @count on success, negative value otherwise. |
191 | */ |
192 | static ssize_t tomoyo_write(struct file *file, const char __user *buf, |
193 | size_t count, loff_t *ppos) |
194 | { |
195 | return tomoyo_write_control(head: file->private_data, buffer: buf, buffer_len: count); |
196 | } |
197 | |
198 | /* |
199 | * tomoyo_operations is a "struct file_operations" which is used for handling |
200 | * /sys/kernel/security/tomoyo/ interface. |
201 | * |
202 | * Some files under /sys/kernel/security/tomoyo/ directory accept open(O_RDWR). |
203 | * See tomoyo_io_buffer for internals. |
204 | */ |
205 | static const struct file_operations tomoyo_operations = { |
206 | .open = tomoyo_open, |
207 | .release = tomoyo_release, |
208 | .poll = tomoyo_poll, |
209 | .read = tomoyo_read, |
210 | .write = tomoyo_write, |
211 | .llseek = noop_llseek, |
212 | }; |
213 | |
214 | /** |
215 | * tomoyo_create_entry - Create interface files under /sys/kernel/security/tomoyo/ directory. |
216 | * |
217 | * @name: The name of the interface file. |
218 | * @mode: The permission of the interface file. |
219 | * @parent: The parent directory. |
220 | * @key: Type of interface. |
221 | * |
222 | * Returns nothing. |
223 | */ |
224 | static void __init tomoyo_create_entry(const char *name, const umode_t mode, |
225 | struct dentry *parent, const u8 key) |
226 | { |
227 | securityfs_create_file(name, mode, parent, data: (void *) (uintptr_t) key, |
228 | fops: &tomoyo_operations); |
229 | } |
230 | |
231 | /** |
232 | * tomoyo_initerface_init - Initialize /sys/kernel/security/tomoyo/ interface. |
233 | * |
234 | * Returns 0. |
235 | */ |
236 | static int __init tomoyo_initerface_init(void) |
237 | { |
238 | struct tomoyo_domain_info *domain; |
239 | struct dentry *tomoyo_dir; |
240 | |
241 | if (!tomoyo_enabled) |
242 | return 0; |
243 | domain = tomoyo_domain(); |
244 | /* Don't create securityfs entries unless registered. */ |
245 | if (domain != &tomoyo_kernel_domain) |
246 | return 0; |
247 | |
248 | tomoyo_dir = securityfs_create_dir(name: "tomoyo" , NULL); |
249 | tomoyo_create_entry(name: "query" , mode: 0600, parent: tomoyo_dir, |
250 | key: TOMOYO_QUERY); |
251 | tomoyo_create_entry(name: "domain_policy" , mode: 0600, parent: tomoyo_dir, |
252 | key: TOMOYO_DOMAINPOLICY); |
253 | tomoyo_create_entry(name: "exception_policy" , mode: 0600, parent: tomoyo_dir, |
254 | key: TOMOYO_EXCEPTIONPOLICY); |
255 | tomoyo_create_entry(name: "audit" , mode: 0400, parent: tomoyo_dir, |
256 | key: TOMOYO_AUDIT); |
257 | tomoyo_create_entry(name: ".process_status" , mode: 0600, parent: tomoyo_dir, |
258 | key: TOMOYO_PROCESS_STATUS); |
259 | tomoyo_create_entry(name: "stat" , mode: 0644, parent: tomoyo_dir, |
260 | key: TOMOYO_STAT); |
261 | tomoyo_create_entry(name: "profile" , mode: 0600, parent: tomoyo_dir, |
262 | key: TOMOYO_PROFILE); |
263 | tomoyo_create_entry(name: "manager" , mode: 0600, parent: tomoyo_dir, |
264 | key: TOMOYO_MANAGER); |
265 | tomoyo_create_entry(name: "version" , mode: 0400, parent: tomoyo_dir, |
266 | key: TOMOYO_VERSION); |
267 | securityfs_create_file(name: "self_domain" , mode: 0666, parent: tomoyo_dir, NULL, |
268 | fops: &tomoyo_self_operations); |
269 | tomoyo_load_builtin_policy(); |
270 | return 0; |
271 | } |
272 | |
273 | fs_initcall(tomoyo_initerface_init); |
274 | |