Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * security/tomoyo/file.c
4 *
5 * Copyright (C) 2005-2011 NTT DATA CORPORATION
6 */
7
8#include "common.h"
9#include <linux/slab.h>
10
11/*
12 * Mapping table from "enum tomoyo_path_acl_index" to "enum tomoyo_mac_index".
13 */
14static const u8 tomoyo_p2mac[TOMOYO_MAX_PATH_OPERATION] = {
15 [TOMOYO_TYPE_EXECUTE] = TOMOYO_MAC_FILE_EXECUTE,
16 [TOMOYO_TYPE_READ] = TOMOYO_MAC_FILE_OPEN,
17 [TOMOYO_TYPE_WRITE] = TOMOYO_MAC_FILE_OPEN,
18 [TOMOYO_TYPE_APPEND] = TOMOYO_MAC_FILE_OPEN,
19 [TOMOYO_TYPE_UNLINK] = TOMOYO_MAC_FILE_UNLINK,
20 [TOMOYO_TYPE_GETATTR] = TOMOYO_MAC_FILE_GETATTR,
21 [TOMOYO_TYPE_RMDIR] = TOMOYO_MAC_FILE_RMDIR,
22 [TOMOYO_TYPE_TRUNCATE] = TOMOYO_MAC_FILE_TRUNCATE,
23 [TOMOYO_TYPE_SYMLINK] = TOMOYO_MAC_FILE_SYMLINK,
24 [TOMOYO_TYPE_CHROOT] = TOMOYO_MAC_FILE_CHROOT,
25 [TOMOYO_TYPE_UMOUNT] = TOMOYO_MAC_FILE_UMOUNT,
26};
27
28/*
29 * Mapping table from "enum tomoyo_mkdev_acl_index" to "enum tomoyo_mac_index".
30 */
31const u8 tomoyo_pnnn2mac[TOMOYO_MAX_MKDEV_OPERATION] = {
32 [TOMOYO_TYPE_MKBLOCK] = TOMOYO_MAC_FILE_MKBLOCK,
33 [TOMOYO_TYPE_MKCHAR] = TOMOYO_MAC_FILE_MKCHAR,
34};
35
36/*
37 * Mapping table from "enum tomoyo_path2_acl_index" to "enum tomoyo_mac_index".
38 */
39const u8 tomoyo_pp2mac[TOMOYO_MAX_PATH2_OPERATION] = {
40 [TOMOYO_TYPE_LINK] = TOMOYO_MAC_FILE_LINK,
41 [TOMOYO_TYPE_RENAME] = TOMOYO_MAC_FILE_RENAME,
42 [TOMOYO_TYPE_PIVOT_ROOT] = TOMOYO_MAC_FILE_PIVOT_ROOT,
43};
44
45/*
46 * Mapping table from "enum tomoyo_path_number_acl_index" to
47 * "enum tomoyo_mac_index".
48 */
49const u8 tomoyo_pn2mac[TOMOYO_MAX_PATH_NUMBER_OPERATION] = {
50 [TOMOYO_TYPE_CREATE] = TOMOYO_MAC_FILE_CREATE,
51 [TOMOYO_TYPE_MKDIR] = TOMOYO_MAC_FILE_MKDIR,
52 [TOMOYO_TYPE_MKFIFO] = TOMOYO_MAC_FILE_MKFIFO,
53 [TOMOYO_TYPE_MKSOCK] = TOMOYO_MAC_FILE_MKSOCK,
54 [TOMOYO_TYPE_IOCTL] = TOMOYO_MAC_FILE_IOCTL,
55 [TOMOYO_TYPE_CHMOD] = TOMOYO_MAC_FILE_CHMOD,
56 [TOMOYO_TYPE_CHOWN] = TOMOYO_MAC_FILE_CHOWN,
57 [TOMOYO_TYPE_CHGRP] = TOMOYO_MAC_FILE_CHGRP,
58};
59
60/**
61 * tomoyo_put_name_union - Drop reference on "struct tomoyo_name_union".
62 *
63 * @ptr: Pointer to "struct tomoyo_name_union".
64 *
65 * Returns nothing.
66 */
67void tomoyo_put_name_union(struct tomoyo_name_union *ptr)
68{
69 tomoyo_put_group(ptr->group);
70 tomoyo_put_name(ptr->filename);
71}
72
73/**
74 * tomoyo_compare_name_union - Check whether a name matches "struct tomoyo_name_union" or not.
75 *
76 * @name: Pointer to "struct tomoyo_path_info".
77 * @ptr: Pointer to "struct tomoyo_name_union".
78 *
79 * Returns "struct tomoyo_path_info" if @name matches @ptr, NULL otherwise.
80 */
81const struct tomoyo_path_info *
82tomoyo_compare_name_union(const struct tomoyo_path_info *name,
83 const struct tomoyo_name_union *ptr)
84{
85 if (ptr->group)
86 return tomoyo_path_matches_group(name, ptr->group);
87 if (tomoyo_path_matches_pattern(name, ptr->filename))
88 return ptr->filename;
89 return NULL;
90}
91
92/**
93 * tomoyo_put_number_union - Drop reference on "struct tomoyo_number_union".
94 *
95 * @ptr: Pointer to "struct tomoyo_number_union".
96 *
97 * Returns nothing.
98 */
99void tomoyo_put_number_union(struct tomoyo_number_union *ptr)
100{
101 tomoyo_put_group(ptr->group);
102}
103
104/**
105 * tomoyo_compare_number_union - Check whether a value matches "struct tomoyo_number_union" or not.
106 *
107 * @value: Number to check.
108 * @ptr: Pointer to "struct tomoyo_number_union".
109 *
110 * Returns true if @value matches @ptr, false otherwise.
111 */
112bool tomoyo_compare_number_union(const unsigned long value,
113 const struct tomoyo_number_union *ptr)
114{
115 if (ptr->group)
116 return tomoyo_number_matches_group(value, value, ptr->group);
117 return value >= ptr->values[0] && value <= ptr->values[1];
118}
119
120/**
121 * tomoyo_add_slash - Add trailing '/' if needed.
122 *
123 * @buf: Pointer to "struct tomoyo_path_info".
124 *
125 * Returns nothing.
126 *
127 * @buf must be generated by tomoyo_encode() because this function does not
128 * allocate memory for adding '/'.
129 */
130static void tomoyo_add_slash(struct tomoyo_path_info *buf)
131{
132 if (buf->is_dir)
133 return;
134 /*
135 * This is OK because tomoyo_encode() reserves space for appending "/".
136 */
137 strcat((char *) buf->name, "/");
138 tomoyo_fill_path_info(buf);
139}
140
141/**
142 * tomoyo_get_realpath - Get realpath.
143 *
144 * @buf: Pointer to "struct tomoyo_path_info".
145 * @path: Pointer to "struct path".
146 *
147 * Returns true on success, false otherwise.
148 */
149static bool tomoyo_get_realpath(struct tomoyo_path_info *buf, const struct path *path)
150{
151 buf->name = tomoyo_realpath_from_path(path);
152 if (buf->name) {
153 tomoyo_fill_path_info(buf);
154 return true;
155 }
156 return false;
157}
158
159/**
160 * tomoyo_audit_path_log - Audit path request log.
161 *
162 * @r: Pointer to "struct tomoyo_request_info".
163 *
164 * Returns 0 on success, negative value otherwise.
165 */
166static int tomoyo_audit_path_log(struct tomoyo_request_info *r)
167 __must_hold_shared(&tomoyo_ss)
168{
169 return tomoyo_supervisor(r, "file %s %s\n", tomoyo_path_keyword
170 [r->param.path.operation],
171 r->param.path.filename->name);
172}
173
174/**
175 * tomoyo_audit_path2_log - Audit path/path request log.
176 *
177 * @r: Pointer to "struct tomoyo_request_info".
178 *
179 * Returns 0 on success, negative value otherwise.
180 */
181static int tomoyo_audit_path2_log(struct tomoyo_request_info *r)
182 __must_hold_shared(&tomoyo_ss)
183{
184 return tomoyo_supervisor(r, "file %s %s %s\n", tomoyo_mac_keywords
185 [tomoyo_pp2mac[r->param.path2.operation]],
186 r->param.path2.filename1->name,
187 r->param.path2.filename2->name);
188}
189
190/**
191 * tomoyo_audit_mkdev_log - Audit path/number/number/number request log.
192 *
193 * @r: Pointer to "struct tomoyo_request_info".
194 *
195 * Returns 0 on success, negative value otherwise.
196 */
197static int tomoyo_audit_mkdev_log(struct tomoyo_request_info *r)
198 __must_hold_shared(&tomoyo_ss)
199{
200 return tomoyo_supervisor(r, "file %s %s 0%o %u %u\n",
201 tomoyo_mac_keywords
202 [tomoyo_pnnn2mac[r->param.mkdev.operation]],
203 r->param.mkdev.filename->name,
204 r->param.mkdev.mode, r->param.mkdev.major,
205 r->param.mkdev.minor);
206}
207
208/**
209 * tomoyo_audit_path_number_log - Audit path/number request log.
210 *
211 * @r: Pointer to "struct tomoyo_request_info".
212 *
213 * Returns 0 on success, negative value otherwise.
214 */
215static int tomoyo_audit_path_number_log(struct tomoyo_request_info *r)
216 __must_hold_shared(&tomoyo_ss)
217{
218 const u8 type = r->param.path_number.operation;
219 u8 radix;
220 char buffer[64];
221
222 switch (type) {
223 case TOMOYO_TYPE_CREATE:
224 case TOMOYO_TYPE_MKDIR:
225 case TOMOYO_TYPE_MKFIFO:
226 case TOMOYO_TYPE_MKSOCK:
227 case TOMOYO_TYPE_CHMOD:
228 radix = TOMOYO_VALUE_TYPE_OCTAL;
229 break;
230 case TOMOYO_TYPE_IOCTL:
231 radix = TOMOYO_VALUE_TYPE_HEXADECIMAL;
232 break;
233 default:
234 radix = TOMOYO_VALUE_TYPE_DECIMAL;
235 break;
236 }
237 tomoyo_print_ulong(buffer, sizeof(buffer), r->param.path_number.number,
238 radix);
239 return tomoyo_supervisor(r, "file %s %s %s\n", tomoyo_mac_keywords
240 [tomoyo_pn2mac[type]],
241 r->param.path_number.filename->name, buffer);
242}
243
244/**
245 * tomoyo_check_path_acl - Check permission for path operation.
246 *
247 * @r: Pointer to "struct tomoyo_request_info".
248 * @ptr: Pointer to "struct tomoyo_acl_info".
249 *
250 * Returns true if granted, false otherwise.
251 *
252 * To be able to use wildcard for domain transition, this function sets
253 * matching entry on success. Since the caller holds tomoyo_read_lock(),
254 * it is safe to set matching entry.
255 */
256static bool tomoyo_check_path_acl(struct tomoyo_request_info *r,
257 const struct tomoyo_acl_info *ptr)
258{
259 const struct tomoyo_path_acl *acl = container_of(ptr, typeof(*acl),
260 head);
261
262 if (acl->perm & (1 << r->param.path.operation)) {
263 r->param.path.matched_path =
264 tomoyo_compare_name_union(r->param.path.filename,
265 &acl->name);
266 return r->param.path.matched_path != NULL;
267 }
268 return false;
269}
270
271/**
272 * tomoyo_check_path_number_acl - Check permission for path number operation.
273 *
274 * @r: Pointer to "struct tomoyo_request_info".
275 * @ptr: Pointer to "struct tomoyo_acl_info".
276 *
277 * Returns true if granted, false otherwise.
278 */
279static bool tomoyo_check_path_number_acl(struct tomoyo_request_info *r,
280 const struct tomoyo_acl_info *ptr)
281{
282 const struct tomoyo_path_number_acl *acl =
283 container_of(ptr, typeof(*acl), head);
284
285 return (acl->perm & (1 << r->param.path_number.operation)) &&
286 tomoyo_compare_number_union(r->param.path_number.number,
287 &acl->number) &&
288 tomoyo_compare_name_union(r->param.path_number.filename,
289 &acl->name);
290}
291
292/**
293 * tomoyo_check_path2_acl - Check permission for path path operation.
294 *
295 * @r: Pointer to "struct tomoyo_request_info".
296 * @ptr: Pointer to "struct tomoyo_acl_info".
297 *
298 * Returns true if granted, false otherwise.
299 */
300static bool tomoyo_check_path2_acl(struct tomoyo_request_info *r,
301 const struct tomoyo_acl_info *ptr)
302{
303 const struct tomoyo_path2_acl *acl =
304 container_of(ptr, typeof(*acl), head);
305
306 return (acl->perm & (1 << r->param.path2.operation)) &&
307 tomoyo_compare_name_union(r->param.path2.filename1, &acl->name1)
308 && tomoyo_compare_name_union(r->param.path2.filename2,
309 &acl->name2);
310}
311
312/**
313 * tomoyo_check_mkdev_acl - Check permission for path number number number operation.
314 *
315 * @r: Pointer to "struct tomoyo_request_info".
316 * @ptr: Pointer to "struct tomoyo_acl_info".
317 *
318 * Returns true if granted, false otherwise.
319 */
320static bool tomoyo_check_mkdev_acl(struct tomoyo_request_info *r,
321 const struct tomoyo_acl_info *ptr)
322{
323 const struct tomoyo_mkdev_acl *acl =
324 container_of(ptr, typeof(*acl), head);
325
326 return (acl->perm & (1 << r->param.mkdev.operation)) &&
327 tomoyo_compare_number_union(r->param.mkdev.mode,
328 &acl->mode) &&
329 tomoyo_compare_number_union(r->param.mkdev.major,
330 &acl->major) &&
331 tomoyo_compare_number_union(r->param.mkdev.minor,
332 &acl->minor) &&
333 tomoyo_compare_name_union(r->param.mkdev.filename,
334 &acl->name);
335}
336
337/**
338 * tomoyo_same_path_acl - Check for duplicated "struct tomoyo_path_acl" entry.
339 *
340 * @a: Pointer to "struct tomoyo_acl_info".
341 * @b: Pointer to "struct tomoyo_acl_info".
342 *
343 * Returns true if @a == @b except permission bits, false otherwise.
344 */
345static bool tomoyo_same_path_acl(const struct tomoyo_acl_info *a,
346 const struct tomoyo_acl_info *b)
347{
348 const struct tomoyo_path_acl *p1 = container_of(a, typeof(*p1), head);
349 const struct tomoyo_path_acl *p2 = container_of(b, typeof(*p2), head);
350
351 return tomoyo_same_name_union(&p1->name, &p2->name);
352}
353
354/**
355 * tomoyo_merge_path_acl - Merge duplicated "struct tomoyo_path_acl" entry.
356 *
357 * @a: Pointer to "struct tomoyo_acl_info".
358 * @b: Pointer to "struct tomoyo_acl_info".
359 * @is_delete: True for @a &= ~@b, false for @a |= @b.
360 *
361 * Returns true if @a is empty, false otherwise.
362 */
363static bool tomoyo_merge_path_acl(struct tomoyo_acl_info *a,
364 struct tomoyo_acl_info *b,
365 const bool is_delete)
366{
367 u16 * const a_perm = &container_of(a, struct tomoyo_path_acl, head)
368 ->perm;
369 u16 perm = READ_ONCE(*a_perm);
370 const u16 b_perm = container_of(b, struct tomoyo_path_acl, head)->perm;
371
372 if (is_delete)
373 perm &= ~b_perm;
374 else
375 perm |= b_perm;
376 WRITE_ONCE(*a_perm, perm);
377 return !perm;
378}
379
380/**
381 * tomoyo_update_path_acl - Update "struct tomoyo_path_acl" list.
382 *
383 * @perm: Permission.
384 * @param: Pointer to "struct tomoyo_acl_param".
385 *
386 * Returns 0 on success, negative value otherwise.
387 *
388 * Caller holds tomoyo_read_lock().
389 */
390static int tomoyo_update_path_acl(const u16 perm,
391 struct tomoyo_acl_param *param)
392{
393 struct tomoyo_path_acl e = {
394 .head.type = TOMOYO_TYPE_PATH_ACL,
395 .perm = perm
396 };
397 int error;
398
399 if (!tomoyo_parse_name_union(param, &e.name))
400 error = -EINVAL;
401 else
402 error = tomoyo_update_domain(&e.head, sizeof(e), param,
403 tomoyo_same_path_acl,
404 tomoyo_merge_path_acl);
405 tomoyo_put_name_union(&e.name);
406 return error;
407}
408
409/**
410 * tomoyo_same_mkdev_acl - Check for duplicated "struct tomoyo_mkdev_acl" entry.
411 *
412 * @a: Pointer to "struct tomoyo_acl_info".
413 * @b: Pointer to "struct tomoyo_acl_info".
414 *
415 * Returns true if @a == @b except permission bits, false otherwise.
416 */
417static bool tomoyo_same_mkdev_acl(const struct tomoyo_acl_info *a,
418 const struct tomoyo_acl_info *b)
419{
420 const struct tomoyo_mkdev_acl *p1 = container_of(a, typeof(*p1), head);
421 const struct tomoyo_mkdev_acl *p2 = container_of(b, typeof(*p2), head);
422
423 return tomoyo_same_name_union(&p1->name, &p2->name) &&
424 tomoyo_same_number_union(&p1->mode, &p2->mode) &&
425 tomoyo_same_number_union(&p1->major, &p2->major) &&
426 tomoyo_same_number_union(&p1->minor, &p2->minor);
427}
428
429/**
430 * tomoyo_merge_mkdev_acl - Merge duplicated "struct tomoyo_mkdev_acl" entry.
431 *
432 * @a: Pointer to "struct tomoyo_acl_info".
433 * @b: Pointer to "struct tomoyo_acl_info".
434 * @is_delete: True for @a &= ~@b, false for @a |= @b.
435 *
436 * Returns true if @a is empty, false otherwise.
437 */
438static bool tomoyo_merge_mkdev_acl(struct tomoyo_acl_info *a,
439 struct tomoyo_acl_info *b,
440 const bool is_delete)
441{
442 u8 *const a_perm = &container_of(a, struct tomoyo_mkdev_acl,
443 head)->perm;
444 u8 perm = READ_ONCE(*a_perm);
445 const u8 b_perm = container_of(b, struct tomoyo_mkdev_acl, head)
446 ->perm;
447
448 if (is_delete)
449 perm &= ~b_perm;
450 else
451 perm |= b_perm;
452 WRITE_ONCE(*a_perm, perm);
453 return !perm;
454}
455
456/**
457 * tomoyo_update_mkdev_acl - Update "struct tomoyo_mkdev_acl" list.
458 *
459 * @perm: Permission.
460 * @param: Pointer to "struct tomoyo_acl_param".
461 *
462 * Returns 0 on success, negative value otherwise.
463 *
464 * Caller holds tomoyo_read_lock().
465 */
466static int tomoyo_update_mkdev_acl(const u8 perm,
467 struct tomoyo_acl_param *param)
468{
469 struct tomoyo_mkdev_acl e = {
470 .head.type = TOMOYO_TYPE_MKDEV_ACL,
471 .perm = perm
472 };
473 int error;
474
475 if (!tomoyo_parse_name_union(param, &e.name) ||
476 !tomoyo_parse_number_union(param, &e.mode) ||
477 !tomoyo_parse_number_union(param, &e.major) ||
478 !tomoyo_parse_number_union(param, &e.minor))
479 error = -EINVAL;
480 else
481 error = tomoyo_update_domain(&e.head, sizeof(e), param,
482 tomoyo_same_mkdev_acl,
483 tomoyo_merge_mkdev_acl);
484 tomoyo_put_name_union(&e.name);
485 tomoyo_put_number_union(&e.mode);
486 tomoyo_put_number_union(&e.major);
487 tomoyo_put_number_union(&e.minor);
488 return error;
489}
490
491/**
492 * tomoyo_same_path2_acl - Check for duplicated "struct tomoyo_path2_acl" entry.
493 *
494 * @a: Pointer to "struct tomoyo_acl_info".
495 * @b: Pointer to "struct tomoyo_acl_info".
496 *
497 * Returns true if @a == @b except permission bits, false otherwise.
498 */
499static bool tomoyo_same_path2_acl(const struct tomoyo_acl_info *a,
500 const struct tomoyo_acl_info *b)
501{
502 const struct tomoyo_path2_acl *p1 = container_of(a, typeof(*p1), head);
503 const struct tomoyo_path2_acl *p2 = container_of(b, typeof(*p2), head);
504
505 return tomoyo_same_name_union(&p1->name1, &p2->name1) &&
506 tomoyo_same_name_union(&p1->name2, &p2->name2);
507}
508
509/**
510 * tomoyo_merge_path2_acl - Merge duplicated "struct tomoyo_path2_acl" entry.
511 *
512 * @a: Pointer to "struct tomoyo_acl_info".
513 * @b: Pointer to "struct tomoyo_acl_info".
514 * @is_delete: True for @a &= ~@b, false for @a |= @b.
515 *
516 * Returns true if @a is empty, false otherwise.
517 */
518static bool tomoyo_merge_path2_acl(struct tomoyo_acl_info *a,
519 struct tomoyo_acl_info *b,
520 const bool is_delete)
521{
522 u8 * const a_perm = &container_of(a, struct tomoyo_path2_acl, head)
523 ->perm;
524 u8 perm = READ_ONCE(*a_perm);
525 const u8 b_perm = container_of(b, struct tomoyo_path2_acl, head)->perm;
526
527 if (is_delete)
528 perm &= ~b_perm;
529 else
530 perm |= b_perm;
531 WRITE_ONCE(*a_perm, perm);
532 return !perm;
533}
534
535/**
536 * tomoyo_update_path2_acl - Update "struct tomoyo_path2_acl" list.
537 *
538 * @perm: Permission.
539 * @param: Pointer to "struct tomoyo_acl_param".
540 *
541 * Returns 0 on success, negative value otherwise.
542 *
543 * Caller holds tomoyo_read_lock().
544 */
545static int tomoyo_update_path2_acl(const u8 perm,
546 struct tomoyo_acl_param *param)
547{
548 struct tomoyo_path2_acl e = {
549 .head.type = TOMOYO_TYPE_PATH2_ACL,
550 .perm = perm
551 };
552 int error;
553
554 if (!tomoyo_parse_name_union(param, &e.name1) ||
555 !tomoyo_parse_name_union(param, &e.name2))
556 error = -EINVAL;
557 else
558 error = tomoyo_update_domain(&e.head, sizeof(e), param,
559 tomoyo_same_path2_acl,
560 tomoyo_merge_path2_acl);
561 tomoyo_put_name_union(&e.name1);
562 tomoyo_put_name_union(&e.name2);
563 return error;
564}
565
566/**
567 * tomoyo_path_permission - Check permission for single path operation.
568 *
569 * @r: Pointer to "struct tomoyo_request_info".
570 * @operation: Type of operation.
571 * @filename: Filename to check.
572 *
573 * Returns 0 on success, negative value otherwise.
574 *
575 * Caller holds tomoyo_read_lock().
576 */
577static int tomoyo_path_permission(struct tomoyo_request_info *r, u8 operation,
578 const struct tomoyo_path_info *filename)
579 __must_hold_shared(&tomoyo_ss)
580{
581 int error;
582
583 r->type = tomoyo_p2mac[operation];
584 r->mode = tomoyo_get_mode(r->domain->ns, r->profile, r->type);
585 if (r->mode == TOMOYO_CONFIG_DISABLED)
586 return 0;
587 r->param_type = TOMOYO_TYPE_PATH_ACL;
588 r->param.path.filename = filename;
589 r->param.path.operation = operation;
590 do {
591 tomoyo_check_acl(r, tomoyo_check_path_acl);
592 error = tomoyo_audit_path_log(r);
593 } while (error == TOMOYO_RETRY_REQUEST);
594 return error;
595}
596
597/**
598 * tomoyo_execute_permission - Check permission for execute operation.
599 *
600 * @r: Pointer to "struct tomoyo_request_info".
601 * @filename: Filename to check.
602 *
603 * Returns 0 on success, negative value otherwise.
604 *
605 * Caller holds tomoyo_read_lock().
606 */
607int tomoyo_execute_permission(struct tomoyo_request_info *r,
608 const struct tomoyo_path_info *filename)
609{
610 /*
611 * Unlike other permission checks, this check is done regardless of
612 * profile mode settings in order to check for domain transition
613 * preference.
614 */
615 r->type = TOMOYO_MAC_FILE_EXECUTE;
616 r->mode = tomoyo_get_mode(r->domain->ns, r->profile, r->type);
617 r->param_type = TOMOYO_TYPE_PATH_ACL;
618 r->param.path.filename = filename;
619 r->param.path.operation = TOMOYO_TYPE_EXECUTE;
620 tomoyo_check_acl(r, tomoyo_check_path_acl);
621 r->ee->transition = r->matched_acl && r->matched_acl->cond ?
622 r->matched_acl->cond->transit : NULL;
623 if (r->mode != TOMOYO_CONFIG_DISABLED)
624 return tomoyo_audit_path_log(r);
625 return 0;
626}
627
628/**
629 * tomoyo_same_path_number_acl - Check for duplicated "struct tomoyo_path_number_acl" entry.
630 *
631 * @a: Pointer to "struct tomoyo_acl_info".
632 * @b: Pointer to "struct tomoyo_acl_info".
633 *
634 * Returns true if @a == @b except permission bits, false otherwise.
635 */
636static bool tomoyo_same_path_number_acl(const struct tomoyo_acl_info *a,
637 const struct tomoyo_acl_info *b)
638{
639 const struct tomoyo_path_number_acl *p1 = container_of(a, typeof(*p1),
640 head);
641 const struct tomoyo_path_number_acl *p2 = container_of(b, typeof(*p2),
642 head);
643
644 return tomoyo_same_name_union(&p1->name, &p2->name) &&
645 tomoyo_same_number_union(&p1->number, &p2->number);
646}
647
648/**
649 * tomoyo_merge_path_number_acl - Merge duplicated "struct tomoyo_path_number_acl" entry.
650 *
651 * @a: Pointer to "struct tomoyo_acl_info".
652 * @b: Pointer to "struct tomoyo_acl_info".
653 * @is_delete: True for @a &= ~@b, false for @a |= @b.
654 *
655 * Returns true if @a is empty, false otherwise.
656 */
657static bool tomoyo_merge_path_number_acl(struct tomoyo_acl_info *a,
658 struct tomoyo_acl_info *b,
659 const bool is_delete)
660{
661 u8 * const a_perm = &container_of(a, struct tomoyo_path_number_acl,
662 head)->perm;
663 u8 perm = READ_ONCE(*a_perm);
664 const u8 b_perm = container_of(b, struct tomoyo_path_number_acl, head)
665 ->perm;
666
667 if (is_delete)
668 perm &= ~b_perm;
669 else
670 perm |= b_perm;
671 WRITE_ONCE(*a_perm, perm);
672 return !perm;
673}
674
675/**
676 * tomoyo_update_path_number_acl - Update ioctl/chmod/chown/chgrp ACL.
677 *
678 * @perm: Permission.
679 * @param: Pointer to "struct tomoyo_acl_param".
680 *
681 * Returns 0 on success, negative value otherwise.
682 */
683static int tomoyo_update_path_number_acl(const u8 perm,
684 struct tomoyo_acl_param *param)
685{
686 struct tomoyo_path_number_acl e = {
687 .head.type = TOMOYO_TYPE_PATH_NUMBER_ACL,
688 .perm = perm
689 };
690 int error;
691
692 if (!tomoyo_parse_name_union(param, &e.name) ||
693 !tomoyo_parse_number_union(param, &e.number))
694 error = -EINVAL;
695 else
696 error = tomoyo_update_domain(&e.head, sizeof(e), param,
697 tomoyo_same_path_number_acl,
698 tomoyo_merge_path_number_acl);
699 tomoyo_put_name_union(&e.name);
700 tomoyo_put_number_union(&e.number);
701 return error;
702}
703
704/**
705 * tomoyo_path_number_perm - Check permission for "create", "mkdir", "mkfifo", "mksock", "ioctl", "chmod", "chown", "chgrp".
706 *
707 * @type: Type of operation.
708 * @path: Pointer to "struct path".
709 * @number: Number.
710 *
711 * Returns 0 on success, negative value otherwise.
712 */
713int tomoyo_path_number_perm(const u8 type, const struct path *path,
714 unsigned long number)
715{
716 struct tomoyo_request_info r;
717 struct tomoyo_obj_info obj = {
718 .path1 = { .mnt = path->mnt, .dentry = path->dentry },
719 };
720 int error = -ENOMEM;
721 struct tomoyo_path_info buf;
722 int idx;
723
724 if (tomoyo_init_request_info(&r, NULL, tomoyo_pn2mac[type])
725 == TOMOYO_CONFIG_DISABLED)
726 return 0;
727 idx = tomoyo_read_lock();
728 if (!tomoyo_get_realpath(&buf, path))
729 goto out;
730 r.obj = &obj;
731 if (type == TOMOYO_TYPE_MKDIR)
732 tomoyo_add_slash(&buf);
733 r.param_type = TOMOYO_TYPE_PATH_NUMBER_ACL;
734 r.param.path_number.operation = type;
735 r.param.path_number.filename = &buf;
736 r.param.path_number.number = number;
737 do {
738 tomoyo_check_acl(&r, tomoyo_check_path_number_acl);
739 error = tomoyo_audit_path_number_log(&r);
740 } while (error == TOMOYO_RETRY_REQUEST);
741 kfree(buf.name);
742 out:
743 tomoyo_read_unlock(idx);
744 if (r.mode != TOMOYO_CONFIG_ENFORCING)
745 error = 0;
746 return error;
747}
748
749/**
750 * tomoyo_check_open_permission - Check permission for "read" and "write".
751 *
752 * @domain: Pointer to "struct tomoyo_domain_info".
753 * @path: Pointer to "struct path".
754 * @flag: Flags for open().
755 *
756 * Returns 0 on success, negative value otherwise.
757 */
758int tomoyo_check_open_permission(struct tomoyo_domain_info *domain,
759 const struct path *path, const int flag)
760{
761 const u8 acc_mode = ACC_MODE(flag);
762 int error = 0;
763 struct tomoyo_path_info buf;
764 struct tomoyo_request_info r;
765 struct tomoyo_obj_info obj = {
766 .path1 = { .mnt = path->mnt, .dentry = path->dentry },
767 };
768 int idx;
769
770 buf.name = NULL;
771 r.mode = TOMOYO_CONFIG_DISABLED;
772 idx = tomoyo_read_lock();
773 if (acc_mode &&
774 tomoyo_init_request_info(&r, domain, TOMOYO_MAC_FILE_OPEN)
775 != TOMOYO_CONFIG_DISABLED) {
776 if (!tomoyo_get_realpath(&buf, path)) {
777 error = -ENOMEM;
778 goto out;
779 }
780 r.obj = &obj;
781 if (acc_mode & MAY_READ)
782 error = tomoyo_path_permission(&r, TOMOYO_TYPE_READ,
783 &buf);
784 if (!error && (acc_mode & MAY_WRITE))
785 error = tomoyo_path_permission(&r, (flag & O_APPEND) ?
786 TOMOYO_TYPE_APPEND :
787 TOMOYO_TYPE_WRITE,
788 &buf);
789 }
790 out:
791 kfree(buf.name);
792 tomoyo_read_unlock(idx);
793 if (r.mode != TOMOYO_CONFIG_ENFORCING)
794 error = 0;
795 return error;
796}
797
798/**
799 * tomoyo_path_perm - Check permission for "unlink", "rmdir", "truncate", "symlink", "append", "chroot" and "unmount".
800 *
801 * @operation: Type of operation.
802 * @path: Pointer to "struct path".
803 * @target: Symlink's target if @operation is TOMOYO_TYPE_SYMLINK,
804 * NULL otherwise.
805 *
806 * Returns 0 on success, negative value otherwise.
807 */
808int tomoyo_path_perm(const u8 operation, const struct path *path, const char *target)
809{
810 struct tomoyo_request_info r;
811 struct tomoyo_obj_info obj = {
812 .path1 = { .mnt = path->mnt, .dentry = path->dentry },
813 };
814 int error;
815 struct tomoyo_path_info buf;
816 bool is_enforce;
817 struct tomoyo_path_info symlink_target;
818 int idx;
819
820 if (tomoyo_init_request_info(&r, NULL, tomoyo_p2mac[operation])
821 == TOMOYO_CONFIG_DISABLED)
822 return 0;
823 is_enforce = (r.mode == TOMOYO_CONFIG_ENFORCING);
824 error = -ENOMEM;
825 buf.name = NULL;
826 idx = tomoyo_read_lock();
827 if (!tomoyo_get_realpath(&buf, path))
828 goto out;
829 r.obj = &obj;
830 switch (operation) {
831 case TOMOYO_TYPE_RMDIR:
832 case TOMOYO_TYPE_CHROOT:
833 tomoyo_add_slash(&buf);
834 break;
835 case TOMOYO_TYPE_SYMLINK:
836 symlink_target.name = tomoyo_encode(target);
837 if (!symlink_target.name)
838 goto out;
839 tomoyo_fill_path_info(&symlink_target);
840 obj.symlink_target = &symlink_target;
841 break;
842 }
843 error = tomoyo_path_permission(&r, operation, &buf);
844 if (operation == TOMOYO_TYPE_SYMLINK)
845 kfree(symlink_target.name);
846 out:
847 kfree(buf.name);
848 tomoyo_read_unlock(idx);
849 if (!is_enforce)
850 error = 0;
851 return error;
852}
853
854/**
855 * tomoyo_mkdev_perm - Check permission for "mkblock" and "mkchar".
856 *
857 * @operation: Type of operation. (TOMOYO_TYPE_MKCHAR or TOMOYO_TYPE_MKBLOCK)
858 * @path: Pointer to "struct path".
859 * @mode: Create mode.
860 * @dev: Device number.
861 *
862 * Returns 0 on success, negative value otherwise.
863 */
864int tomoyo_mkdev_perm(const u8 operation, const struct path *path,
865 const unsigned int mode, unsigned int dev)
866{
867 struct tomoyo_request_info r;
868 struct tomoyo_obj_info obj = {
869 .path1 = { .mnt = path->mnt, .dentry = path->dentry },
870 };
871 int error = -ENOMEM;
872 struct tomoyo_path_info buf;
873 int idx;
874
875 if (tomoyo_init_request_info(&r, NULL, tomoyo_pnnn2mac[operation])
876 == TOMOYO_CONFIG_DISABLED)
877 return 0;
878 idx = tomoyo_read_lock();
879 error = -ENOMEM;
880 if (tomoyo_get_realpath(&buf, path)) {
881 r.obj = &obj;
882 dev = new_decode_dev(dev);
883 r.param_type = TOMOYO_TYPE_MKDEV_ACL;
884 r.param.mkdev.filename = &buf;
885 r.param.mkdev.operation = operation;
886 r.param.mkdev.mode = mode;
887 r.param.mkdev.major = MAJOR(dev);
888 r.param.mkdev.minor = MINOR(dev);
889 tomoyo_check_acl(&r, tomoyo_check_mkdev_acl);
890 error = tomoyo_audit_mkdev_log(&r);
891 kfree(buf.name);
892 }
893 tomoyo_read_unlock(idx);
894 if (r.mode != TOMOYO_CONFIG_ENFORCING)
895 error = 0;
896 return error;
897}
898
899/**
900 * tomoyo_path2_perm - Check permission for "rename", "link" and "pivot_root".
901 *
902 * @operation: Type of operation.
903 * @path1: Pointer to "struct path".
904 * @path2: Pointer to "struct path".
905 *
906 * Returns 0 on success, negative value otherwise.
907 */
908int tomoyo_path2_perm(const u8 operation, const struct path *path1,
909 const struct path *path2)
910{
911 int error = -ENOMEM;
912 struct tomoyo_path_info buf1;
913 struct tomoyo_path_info buf2;
914 struct tomoyo_request_info r;
915 struct tomoyo_obj_info obj = {
916 .path1 = { .mnt = path1->mnt, .dentry = path1->dentry },
917 .path2 = { .mnt = path2->mnt, .dentry = path2->dentry }
918 };
919 int idx;
920
921 if (tomoyo_init_request_info(&r, NULL, tomoyo_pp2mac[operation])
922 == TOMOYO_CONFIG_DISABLED)
923 return 0;
924 buf1.name = NULL;
925 buf2.name = NULL;
926 idx = tomoyo_read_lock();
927 if (!tomoyo_get_realpath(&buf1, path1) ||
928 !tomoyo_get_realpath(&buf2, path2))
929 goto out;
930 switch (operation) {
931 case TOMOYO_TYPE_RENAME:
932 case TOMOYO_TYPE_LINK:
933 if (!d_is_dir(path1->dentry))
934 break;
935 fallthrough;
936 case TOMOYO_TYPE_PIVOT_ROOT:
937 tomoyo_add_slash(&buf1);
938 tomoyo_add_slash(&buf2);
939 break;
940 }
941 r.obj = &obj;
942 r.param_type = TOMOYO_TYPE_PATH2_ACL;
943 r.param.path2.operation = operation;
944 r.param.path2.filename1 = &buf1;
945 r.param.path2.filename2 = &buf2;
946 do {
947 tomoyo_check_acl(&r, tomoyo_check_path2_acl);
948 error = tomoyo_audit_path2_log(&r);
949 } while (error == TOMOYO_RETRY_REQUEST);
950 out:
951 kfree(buf1.name);
952 kfree(buf2.name);
953 tomoyo_read_unlock(idx);
954 if (r.mode != TOMOYO_CONFIG_ENFORCING)
955 error = 0;
956 return error;
957}
958
959/**
960 * tomoyo_same_mount_acl - Check for duplicated "struct tomoyo_mount_acl" entry.
961 *
962 * @a: Pointer to "struct tomoyo_acl_info".
963 * @b: Pointer to "struct tomoyo_acl_info".
964 *
965 * Returns true if @a == @b, false otherwise.
966 */
967static bool tomoyo_same_mount_acl(const struct tomoyo_acl_info *a,
968 const struct tomoyo_acl_info *b)
969{
970 const struct tomoyo_mount_acl *p1 = container_of(a, typeof(*p1), head);
971 const struct tomoyo_mount_acl *p2 = container_of(b, typeof(*p2), head);
972
973 return tomoyo_same_name_union(&p1->dev_name, &p2->dev_name) &&
974 tomoyo_same_name_union(&p1->dir_name, &p2->dir_name) &&
975 tomoyo_same_name_union(&p1->fs_type, &p2->fs_type) &&
976 tomoyo_same_number_union(&p1->flags, &p2->flags);
977}
978
979/**
980 * tomoyo_update_mount_acl - Write "struct tomoyo_mount_acl" list.
981 *
982 * @param: Pointer to "struct tomoyo_acl_param".
983 *
984 * Returns 0 on success, negative value otherwise.
985 *
986 * Caller holds tomoyo_read_lock().
987 */
988static int tomoyo_update_mount_acl(struct tomoyo_acl_param *param)
989{
990 struct tomoyo_mount_acl e = { .head.type = TOMOYO_TYPE_MOUNT_ACL };
991 int error;
992
993 if (!tomoyo_parse_name_union(param, &e.dev_name) ||
994 !tomoyo_parse_name_union(param, &e.dir_name) ||
995 !tomoyo_parse_name_union(param, &e.fs_type) ||
996 !tomoyo_parse_number_union(param, &e.flags))
997 error = -EINVAL;
998 else
999 error = tomoyo_update_domain(&e.head, sizeof(e), param,
1000 tomoyo_same_mount_acl, NULL);
1001 tomoyo_put_name_union(&e.dev_name);
1002 tomoyo_put_name_union(&e.dir_name);
1003 tomoyo_put_name_union(&e.fs_type);
1004 tomoyo_put_number_union(&e.flags);
1005 return error;
1006}
1007
1008/**
1009 * tomoyo_write_file - Update file related list.
1010 *
1011 * @param: Pointer to "struct tomoyo_acl_param".
1012 *
1013 * Returns 0 on success, negative value otherwise.
1014 *
1015 * Caller holds tomoyo_read_lock().
1016 */
1017int tomoyo_write_file(struct tomoyo_acl_param *param)
1018{
1019 u16 perm = 0;
1020 u8 type;
1021 const char *operation = tomoyo_read_token(param);
1022
1023 for (type = 0; type < TOMOYO_MAX_PATH_OPERATION; type++)
1024 if (tomoyo_permstr(operation, tomoyo_path_keyword[type]))
1025 perm |= 1 << type;
1026 if (perm)
1027 return tomoyo_update_path_acl(perm, param);
1028 for (type = 0; type < TOMOYO_MAX_PATH2_OPERATION; type++)
1029 if (tomoyo_permstr(operation,
1030 tomoyo_mac_keywords[tomoyo_pp2mac[type]]))
1031 perm |= 1 << type;
1032 if (perm)
1033 return tomoyo_update_path2_acl(perm, param);
1034 for (type = 0; type < TOMOYO_MAX_PATH_NUMBER_OPERATION; type++)
1035 if (tomoyo_permstr(operation,
1036 tomoyo_mac_keywords[tomoyo_pn2mac[type]]))
1037 perm |= 1 << type;
1038 if (perm)
1039 return tomoyo_update_path_number_acl(perm, param);
1040 for (type = 0; type < TOMOYO_MAX_MKDEV_OPERATION; type++)
1041 if (tomoyo_permstr(operation,
1042 tomoyo_mac_keywords[tomoyo_pnnn2mac[type]]))
1043 perm |= 1 << type;
1044 if (perm)
1045 return tomoyo_update_mkdev_acl(perm, param);
1046 if (tomoyo_permstr(operation,
1047 tomoyo_mac_keywords[TOMOYO_MAC_FILE_MOUNT]))
1048 return tomoyo_update_mount_acl(param);
1049 return -EINVAL;
1050}