Merge branch 'master' of /pub/scm/linux/kernel/git/torvalds/linux-2.6
[linux-2.6/linux-acpi-2.6/ibm-acpi-2.6.git] / security / tomoyo / file.c
blob2316da8ec5bcaf13485aca9f93bdd0e01b171107
1 /*
2 * security/tomoyo/file.c
4 * Implementation of the Domain-Based Mandatory Access Control.
6 * Copyright (C) 2005-2009 NTT DATA CORPORATION
8 * Version: 2.2.0 2009/04/01
12 #include "common.h"
13 #include "tomoyo.h"
14 #include "realpath.h"
15 #define ACC_MODE(x) ("\000\004\002\006"[(x)&O_ACCMODE])
17 /* Structure for "allow_read" keyword. */
18 struct tomoyo_globally_readable_file_entry {
19 struct list_head list;
20 const struct tomoyo_path_info *filename;
21 bool is_deleted;
24 /* Structure for "file_pattern" keyword. */
25 struct tomoyo_pattern_entry {
26 struct list_head list;
27 const struct tomoyo_path_info *pattern;
28 bool is_deleted;
31 /* Structure for "deny_rewrite" keyword. */
32 struct tomoyo_no_rewrite_entry {
33 struct list_head list;
34 const struct tomoyo_path_info *pattern;
35 bool is_deleted;
38 /* Keyword array for single path operations. */
39 static const char *tomoyo_sp_keyword[TOMOYO_MAX_SINGLE_PATH_OPERATION] = {
40 [TOMOYO_TYPE_READ_WRITE_ACL] = "read/write",
41 [TOMOYO_TYPE_EXECUTE_ACL] = "execute",
42 [TOMOYO_TYPE_READ_ACL] = "read",
43 [TOMOYO_TYPE_WRITE_ACL] = "write",
44 [TOMOYO_TYPE_CREATE_ACL] = "create",
45 [TOMOYO_TYPE_UNLINK_ACL] = "unlink",
46 [TOMOYO_TYPE_MKDIR_ACL] = "mkdir",
47 [TOMOYO_TYPE_RMDIR_ACL] = "rmdir",
48 [TOMOYO_TYPE_MKFIFO_ACL] = "mkfifo",
49 [TOMOYO_TYPE_MKSOCK_ACL] = "mksock",
50 [TOMOYO_TYPE_MKBLOCK_ACL] = "mkblock",
51 [TOMOYO_TYPE_MKCHAR_ACL] = "mkchar",
52 [TOMOYO_TYPE_TRUNCATE_ACL] = "truncate",
53 [TOMOYO_TYPE_SYMLINK_ACL] = "symlink",
54 [TOMOYO_TYPE_REWRITE_ACL] = "rewrite",
57 /* Keyword array for double path operations. */
58 static const char *tomoyo_dp_keyword[TOMOYO_MAX_DOUBLE_PATH_OPERATION] = {
59 [TOMOYO_TYPE_LINK_ACL] = "link",
60 [TOMOYO_TYPE_RENAME_ACL] = "rename",
63 /**
64 * tomoyo_sp2keyword - Get the name of single path operation.
66 * @operation: Type of operation.
68 * Returns the name of single path operation.
70 const char *tomoyo_sp2keyword(const u8 operation)
72 return (operation < TOMOYO_MAX_SINGLE_PATH_OPERATION)
73 ? tomoyo_sp_keyword[operation] : NULL;
76 /**
77 * tomoyo_dp2keyword - Get the name of double path operation.
79 * @operation: Type of operation.
81 * Returns the name of double path operation.
83 const char *tomoyo_dp2keyword(const u8 operation)
85 return (operation < TOMOYO_MAX_DOUBLE_PATH_OPERATION)
86 ? tomoyo_dp_keyword[operation] : NULL;
89 /**
90 * tomoyo_strendswith - Check whether the token ends with the given token.
92 * @name: The token to check.
93 * @tail: The token to find.
95 * Returns true if @name ends with @tail, false otherwise.
97 static bool tomoyo_strendswith(const char *name, const char *tail)
99 int len;
101 if (!name || !tail)
102 return false;
103 len = strlen(name) - strlen(tail);
104 return len >= 0 && !strcmp(name + len, tail);
108 * tomoyo_get_path - Get realpath.
110 * @path: Pointer to "struct path".
112 * Returns pointer to "struct tomoyo_path_info" on success, NULL otherwise.
114 static struct tomoyo_path_info *tomoyo_get_path(struct path *path)
116 int error;
117 struct tomoyo_path_info_with_data *buf = tomoyo_alloc(sizeof(*buf));
119 if (!buf)
120 return NULL;
121 /* Reserve one byte for appending "/". */
122 error = tomoyo_realpath_from_path2(path, buf->body,
123 sizeof(buf->body) - 2);
124 if (!error) {
125 buf->head.name = buf->body;
126 tomoyo_fill_path_info(&buf->head);
127 return &buf->head;
129 tomoyo_free(buf);
130 return NULL;
133 /* Lock for domain->acl_info_list. */
134 DECLARE_RWSEM(tomoyo_domain_acl_info_list_lock);
136 static int tomoyo_update_double_path_acl(const u8 type, const char *filename1,
137 const char *filename2,
138 struct tomoyo_domain_info *
139 const domain, const bool is_delete);
140 static int tomoyo_update_single_path_acl(const u8 type, const char *filename,
141 struct tomoyo_domain_info *
142 const domain, const bool is_delete);
144 /* The list for "struct tomoyo_globally_readable_file_entry". */
145 static LIST_HEAD(tomoyo_globally_readable_list);
146 static DECLARE_RWSEM(tomoyo_globally_readable_list_lock);
149 * tomoyo_update_globally_readable_entry - Update "struct tomoyo_globally_readable_file_entry" list.
151 * @filename: Filename unconditionally permitted to open() for reading.
152 * @is_delete: True if it is a delete request.
154 * Returns 0 on success, negative value otherwise.
156 static int tomoyo_update_globally_readable_entry(const char *filename,
157 const bool is_delete)
159 struct tomoyo_globally_readable_file_entry *new_entry;
160 struct tomoyo_globally_readable_file_entry *ptr;
161 const struct tomoyo_path_info *saved_filename;
162 int error = -ENOMEM;
164 if (!tomoyo_is_correct_path(filename, 1, 0, -1, __func__))
165 return -EINVAL;
166 saved_filename = tomoyo_save_name(filename);
167 if (!saved_filename)
168 return -ENOMEM;
169 /***** EXCLUSIVE SECTION START *****/
170 down_write(&tomoyo_globally_readable_list_lock);
171 list_for_each_entry(ptr, &tomoyo_globally_readable_list, list) {
172 if (ptr->filename != saved_filename)
173 continue;
174 ptr->is_deleted = is_delete;
175 error = 0;
176 goto out;
178 if (is_delete) {
179 error = -ENOENT;
180 goto out;
182 new_entry = tomoyo_alloc_element(sizeof(*new_entry));
183 if (!new_entry)
184 goto out;
185 new_entry->filename = saved_filename;
186 list_add_tail(&new_entry->list, &tomoyo_globally_readable_list);
187 error = 0;
188 out:
189 up_write(&tomoyo_globally_readable_list_lock);
190 /***** EXCLUSIVE SECTION END *****/
191 return error;
195 * tomoyo_is_globally_readable_file - Check if the file is unconditionnaly permitted to be open()ed for reading.
197 * @filename: The filename to check.
199 * Returns true if any domain can open @filename for reading, false otherwise.
201 static bool tomoyo_is_globally_readable_file(const struct tomoyo_path_info *
202 filename)
204 struct tomoyo_globally_readable_file_entry *ptr;
205 bool found = false;
206 down_read(&tomoyo_globally_readable_list_lock);
207 list_for_each_entry(ptr, &tomoyo_globally_readable_list, list) {
208 if (!ptr->is_deleted &&
209 tomoyo_path_matches_pattern(filename, ptr->filename)) {
210 found = true;
211 break;
214 up_read(&tomoyo_globally_readable_list_lock);
215 return found;
219 * tomoyo_write_globally_readable_policy - Write "struct tomoyo_globally_readable_file_entry" list.
221 * @data: String to parse.
222 * @is_delete: True if it is a delete request.
224 * Returns 0 on success, negative value otherwise.
226 int tomoyo_write_globally_readable_policy(char *data, const bool is_delete)
228 return tomoyo_update_globally_readable_entry(data, is_delete);
232 * tomoyo_read_globally_readable_policy - Read "struct tomoyo_globally_readable_file_entry" list.
234 * @head: Pointer to "struct tomoyo_io_buffer".
236 * Returns true on success, false otherwise.
238 bool tomoyo_read_globally_readable_policy(struct tomoyo_io_buffer *head)
240 struct list_head *pos;
241 bool done = true;
243 down_read(&tomoyo_globally_readable_list_lock);
244 list_for_each_cookie(pos, head->read_var2,
245 &tomoyo_globally_readable_list) {
246 struct tomoyo_globally_readable_file_entry *ptr;
247 ptr = list_entry(pos,
248 struct tomoyo_globally_readable_file_entry,
249 list);
250 if (ptr->is_deleted)
251 continue;
252 if (!tomoyo_io_printf(head, TOMOYO_KEYWORD_ALLOW_READ "%s\n",
253 ptr->filename->name)) {
254 done = false;
255 break;
258 up_read(&tomoyo_globally_readable_list_lock);
259 return done;
262 /* The list for "struct tomoyo_pattern_entry". */
263 static LIST_HEAD(tomoyo_pattern_list);
264 static DECLARE_RWSEM(tomoyo_pattern_list_lock);
267 * tomoyo_update_file_pattern_entry - Update "struct tomoyo_pattern_entry" list.
269 * @pattern: Pathname pattern.
270 * @is_delete: True if it is a delete request.
272 * Returns 0 on success, negative value otherwise.
274 static int tomoyo_update_file_pattern_entry(const char *pattern,
275 const bool is_delete)
277 struct tomoyo_pattern_entry *new_entry;
278 struct tomoyo_pattern_entry *ptr;
279 const struct tomoyo_path_info *saved_pattern;
280 int error = -ENOMEM;
282 if (!tomoyo_is_correct_path(pattern, 0, 1, 0, __func__))
283 return -EINVAL;
284 saved_pattern = tomoyo_save_name(pattern);
285 if (!saved_pattern)
286 return -ENOMEM;
287 /***** EXCLUSIVE SECTION START *****/
288 down_write(&tomoyo_pattern_list_lock);
289 list_for_each_entry(ptr, &tomoyo_pattern_list, list) {
290 if (saved_pattern != ptr->pattern)
291 continue;
292 ptr->is_deleted = is_delete;
293 error = 0;
294 goto out;
296 if (is_delete) {
297 error = -ENOENT;
298 goto out;
300 new_entry = tomoyo_alloc_element(sizeof(*new_entry));
301 if (!new_entry)
302 goto out;
303 new_entry->pattern = saved_pattern;
304 list_add_tail(&new_entry->list, &tomoyo_pattern_list);
305 error = 0;
306 out:
307 up_write(&tomoyo_pattern_list_lock);
308 /***** EXCLUSIVE SECTION END *****/
309 return error;
313 * tomoyo_get_file_pattern - Get patterned pathname.
315 * @filename: The filename to find patterned pathname.
317 * Returns pointer to pathname pattern if matched, @filename otherwise.
319 static const struct tomoyo_path_info *
320 tomoyo_get_file_pattern(const struct tomoyo_path_info *filename)
322 struct tomoyo_pattern_entry *ptr;
323 const struct tomoyo_path_info *pattern = NULL;
325 down_read(&tomoyo_pattern_list_lock);
326 list_for_each_entry(ptr, &tomoyo_pattern_list, list) {
327 if (ptr->is_deleted)
328 continue;
329 if (!tomoyo_path_matches_pattern(filename, ptr->pattern))
330 continue;
331 pattern = ptr->pattern;
332 if (tomoyo_strendswith(pattern->name, "/\\*")) {
333 /* Do nothing. Try to find the better match. */
334 } else {
335 /* This would be the better match. Use this. */
336 break;
339 up_read(&tomoyo_pattern_list_lock);
340 if (pattern)
341 filename = pattern;
342 return filename;
346 * tomoyo_write_pattern_policy - Write "struct tomoyo_pattern_entry" list.
348 * @data: String to parse.
349 * @is_delete: True if it is a delete request.
351 * Returns 0 on success, negative value otherwise.
353 int tomoyo_write_pattern_policy(char *data, const bool is_delete)
355 return tomoyo_update_file_pattern_entry(data, is_delete);
359 * tomoyo_read_file_pattern - Read "struct tomoyo_pattern_entry" list.
361 * @head: Pointer to "struct tomoyo_io_buffer".
363 * Returns true on success, false otherwise.
365 bool tomoyo_read_file_pattern(struct tomoyo_io_buffer *head)
367 struct list_head *pos;
368 bool done = true;
370 down_read(&tomoyo_pattern_list_lock);
371 list_for_each_cookie(pos, head->read_var2, &tomoyo_pattern_list) {
372 struct tomoyo_pattern_entry *ptr;
373 ptr = list_entry(pos, struct tomoyo_pattern_entry, list);
374 if (ptr->is_deleted)
375 continue;
376 if (!tomoyo_io_printf(head, TOMOYO_KEYWORD_FILE_PATTERN "%s\n",
377 ptr->pattern->name)) {
378 done = false;
379 break;
382 up_read(&tomoyo_pattern_list_lock);
383 return done;
386 /* The list for "struct tomoyo_no_rewrite_entry". */
387 static LIST_HEAD(tomoyo_no_rewrite_list);
388 static DECLARE_RWSEM(tomoyo_no_rewrite_list_lock);
391 * tomoyo_update_no_rewrite_entry - Update "struct tomoyo_no_rewrite_entry" list.
393 * @pattern: Pathname pattern that are not rewritable by default.
394 * @is_delete: True if it is a delete request.
396 * Returns 0 on success, negative value otherwise.
398 static int tomoyo_update_no_rewrite_entry(const char *pattern,
399 const bool is_delete)
401 struct tomoyo_no_rewrite_entry *new_entry, *ptr;
402 const struct tomoyo_path_info *saved_pattern;
403 int error = -ENOMEM;
405 if (!tomoyo_is_correct_path(pattern, 0, 0, 0, __func__))
406 return -EINVAL;
407 saved_pattern = tomoyo_save_name(pattern);
408 if (!saved_pattern)
409 return -ENOMEM;
410 /***** EXCLUSIVE SECTION START *****/
411 down_write(&tomoyo_no_rewrite_list_lock);
412 list_for_each_entry(ptr, &tomoyo_no_rewrite_list, list) {
413 if (ptr->pattern != saved_pattern)
414 continue;
415 ptr->is_deleted = is_delete;
416 error = 0;
417 goto out;
419 if (is_delete) {
420 error = -ENOENT;
421 goto out;
423 new_entry = tomoyo_alloc_element(sizeof(*new_entry));
424 if (!new_entry)
425 goto out;
426 new_entry->pattern = saved_pattern;
427 list_add_tail(&new_entry->list, &tomoyo_no_rewrite_list);
428 error = 0;
429 out:
430 up_write(&tomoyo_no_rewrite_list_lock);
431 /***** EXCLUSIVE SECTION END *****/
432 return error;
436 * tomoyo_is_no_rewrite_file - Check if the given pathname is not permitted to be rewrited.
438 * @filename: Filename to check.
440 * Returns true if @filename is specified by "deny_rewrite" directive,
441 * false otherwise.
443 static bool tomoyo_is_no_rewrite_file(const struct tomoyo_path_info *filename)
445 struct tomoyo_no_rewrite_entry *ptr;
446 bool found = false;
448 down_read(&tomoyo_no_rewrite_list_lock);
449 list_for_each_entry(ptr, &tomoyo_no_rewrite_list, list) {
450 if (ptr->is_deleted)
451 continue;
452 if (!tomoyo_path_matches_pattern(filename, ptr->pattern))
453 continue;
454 found = true;
455 break;
457 up_read(&tomoyo_no_rewrite_list_lock);
458 return found;
462 * tomoyo_write_no_rewrite_policy - Write "struct tomoyo_no_rewrite_entry" list.
464 * @data: String to parse.
465 * @is_delete: True if it is a delete request.
467 * Returns 0 on success, negative value otherwise.
469 int tomoyo_write_no_rewrite_policy(char *data, const bool is_delete)
471 return tomoyo_update_no_rewrite_entry(data, is_delete);
475 * tomoyo_read_no_rewrite_policy - Read "struct tomoyo_no_rewrite_entry" list.
477 * @head: Pointer to "struct tomoyo_io_buffer".
479 * Returns true on success, false otherwise.
481 bool tomoyo_read_no_rewrite_policy(struct tomoyo_io_buffer *head)
483 struct list_head *pos;
484 bool done = true;
486 down_read(&tomoyo_no_rewrite_list_lock);
487 list_for_each_cookie(pos, head->read_var2, &tomoyo_no_rewrite_list) {
488 struct tomoyo_no_rewrite_entry *ptr;
489 ptr = list_entry(pos, struct tomoyo_no_rewrite_entry, list);
490 if (ptr->is_deleted)
491 continue;
492 if (!tomoyo_io_printf(head, TOMOYO_KEYWORD_DENY_REWRITE "%s\n",
493 ptr->pattern->name)) {
494 done = false;
495 break;
498 up_read(&tomoyo_no_rewrite_list_lock);
499 return done;
503 * tomoyo_update_file_acl - Update file's read/write/execute ACL.
505 * @filename: Filename.
506 * @perm: Permission (between 1 to 7).
507 * @domain: Pointer to "struct tomoyo_domain_info".
508 * @is_delete: True if it is a delete request.
510 * Returns 0 on success, negative value otherwise.
512 * This is legacy support interface for older policy syntax.
513 * Current policy syntax uses "allow_read/write" instead of "6",
514 * "allow_read" instead of "4", "allow_write" instead of "2",
515 * "allow_execute" instead of "1".
517 static int tomoyo_update_file_acl(const char *filename, u8 perm,
518 struct tomoyo_domain_info * const domain,
519 const bool is_delete)
521 if (perm > 7 || !perm) {
522 printk(KERN_DEBUG "%s: Invalid permission '%d %s'\n",
523 __func__, perm, filename);
524 return -EINVAL;
526 if (filename[0] != '@' && tomoyo_strendswith(filename, "/"))
528 * Only 'allow_mkdir' and 'allow_rmdir' are valid for
529 * directory permissions.
531 return 0;
532 if (perm & 4)
533 tomoyo_update_single_path_acl(TOMOYO_TYPE_READ_ACL, filename,
534 domain, is_delete);
535 if (perm & 2)
536 tomoyo_update_single_path_acl(TOMOYO_TYPE_WRITE_ACL, filename,
537 domain, is_delete);
538 if (perm & 1)
539 tomoyo_update_single_path_acl(TOMOYO_TYPE_EXECUTE_ACL,
540 filename, domain, is_delete);
541 return 0;
545 * tomoyo_check_single_path_acl2 - Check permission for single path operation.
547 * @domain: Pointer to "struct tomoyo_domain_info".
548 * @filename: Filename to check.
549 * @perm: Permission.
550 * @may_use_pattern: True if patterned ACL is permitted.
552 * Returns 0 on success, -EPERM otherwise.
554 static int tomoyo_check_single_path_acl2(const struct tomoyo_domain_info *
555 domain,
556 const struct tomoyo_path_info *
557 filename,
558 const u16 perm,
559 const bool may_use_pattern)
561 struct tomoyo_acl_info *ptr;
562 int error = -EPERM;
564 down_read(&tomoyo_domain_acl_info_list_lock);
565 list_for_each_entry(ptr, &domain->acl_info_list, list) {
566 struct tomoyo_single_path_acl_record *acl;
567 if (tomoyo_acl_type2(ptr) != TOMOYO_TYPE_SINGLE_PATH_ACL)
568 continue;
569 acl = container_of(ptr, struct tomoyo_single_path_acl_record,
570 head);
571 if (!(acl->perm & perm))
572 continue;
573 if (may_use_pattern || !acl->filename->is_patterned) {
574 if (!tomoyo_path_matches_pattern(filename,
575 acl->filename))
576 continue;
577 } else {
578 continue;
580 error = 0;
581 break;
583 up_read(&tomoyo_domain_acl_info_list_lock);
584 return error;
588 * tomoyo_check_file_acl - Check permission for opening files.
590 * @domain: Pointer to "struct tomoyo_domain_info".
591 * @filename: Filename to check.
592 * @operation: Mode ("read" or "write" or "read/write" or "execute").
594 * Returns 0 on success, -EPERM otherwise.
596 static int tomoyo_check_file_acl(const struct tomoyo_domain_info *domain,
597 const struct tomoyo_path_info *filename,
598 const u8 operation)
600 u16 perm = 0;
602 if (!tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE))
603 return 0;
604 if (operation == 6)
605 perm = 1 << TOMOYO_TYPE_READ_WRITE_ACL;
606 else if (operation == 4)
607 perm = 1 << TOMOYO_TYPE_READ_ACL;
608 else if (operation == 2)
609 perm = 1 << TOMOYO_TYPE_WRITE_ACL;
610 else if (operation == 1)
611 perm = 1 << TOMOYO_TYPE_EXECUTE_ACL;
612 else
613 BUG();
614 return tomoyo_check_single_path_acl2(domain, filename, perm,
615 operation != 1);
619 * tomoyo_check_file_perm2 - Check permission for opening files.
621 * @domain: Pointer to "struct tomoyo_domain_info".
622 * @filename: Filename to check.
623 * @perm: Mode ("read" or "write" or "read/write" or "execute").
624 * @operation: Operation name passed used for verbose mode.
625 * @mode: Access control mode.
627 * Returns 0 on success, negative value otherwise.
629 static int tomoyo_check_file_perm2(struct tomoyo_domain_info * const domain,
630 const struct tomoyo_path_info *filename,
631 const u8 perm, const char *operation,
632 const u8 mode)
634 const bool is_enforce = (mode == 3);
635 const char *msg = "<unknown>";
636 int error = 0;
638 if (!filename)
639 return 0;
640 error = tomoyo_check_file_acl(domain, filename, perm);
641 if (error && perm == 4 &&
642 (domain->flags & TOMOYO_DOMAIN_FLAGS_IGNORE_GLOBAL_ALLOW_READ) == 0
643 && tomoyo_is_globally_readable_file(filename))
644 error = 0;
645 if (perm == 6)
646 msg = tomoyo_sp2keyword(TOMOYO_TYPE_READ_WRITE_ACL);
647 else if (perm == 4)
648 msg = tomoyo_sp2keyword(TOMOYO_TYPE_READ_ACL);
649 else if (perm == 2)
650 msg = tomoyo_sp2keyword(TOMOYO_TYPE_WRITE_ACL);
651 else if (perm == 1)
652 msg = tomoyo_sp2keyword(TOMOYO_TYPE_EXECUTE_ACL);
653 else
654 BUG();
655 if (!error)
656 return 0;
657 if (tomoyo_verbose_mode(domain))
658 printk(KERN_WARNING "TOMOYO-%s: Access '%s(%s) %s' denied "
659 "for %s\n", tomoyo_get_msg(is_enforce), msg, operation,
660 filename->name, tomoyo_get_last_name(domain));
661 if (is_enforce)
662 return error;
663 if (mode == 1 && tomoyo_domain_quota_is_ok(domain)) {
664 /* Don't use patterns for execute permission. */
665 const struct tomoyo_path_info *patterned_file = (perm != 1) ?
666 tomoyo_get_file_pattern(filename) : filename;
667 tomoyo_update_file_acl(patterned_file->name, perm,
668 domain, false);
670 return 0;
674 * tomoyo_write_file_policy - Update file related list.
676 * @data: String to parse.
677 * @domain: Pointer to "struct tomoyo_domain_info".
678 * @is_delete: True if it is a delete request.
680 * Returns 0 on success, negative value otherwise.
682 int tomoyo_write_file_policy(char *data, struct tomoyo_domain_info *domain,
683 const bool is_delete)
685 char *filename = strchr(data, ' ');
686 char *filename2;
687 unsigned int perm;
688 u8 type;
690 if (!filename)
691 return -EINVAL;
692 *filename++ = '\0';
693 if (sscanf(data, "%u", &perm) == 1)
694 return tomoyo_update_file_acl(filename, (u8) perm, domain,
695 is_delete);
696 if (strncmp(data, "allow_", 6))
697 goto out;
698 data += 6;
699 for (type = 0; type < TOMOYO_MAX_SINGLE_PATH_OPERATION; type++) {
700 if (strcmp(data, tomoyo_sp_keyword[type]))
701 continue;
702 return tomoyo_update_single_path_acl(type, filename,
703 domain, is_delete);
705 filename2 = strchr(filename, ' ');
706 if (!filename2)
707 goto out;
708 *filename2++ = '\0';
709 for (type = 0; type < TOMOYO_MAX_DOUBLE_PATH_OPERATION; type++) {
710 if (strcmp(data, tomoyo_dp_keyword[type]))
711 continue;
712 return tomoyo_update_double_path_acl(type, filename, filename2,
713 domain, is_delete);
715 out:
716 return -EINVAL;
720 * tomoyo_update_single_path_acl - Update "struct tomoyo_single_path_acl_record" list.
722 * @type: Type of operation.
723 * @filename: Filename.
724 * @domain: Pointer to "struct tomoyo_domain_info".
725 * @is_delete: True if it is a delete request.
727 * Returns 0 on success, negative value otherwise.
729 static int tomoyo_update_single_path_acl(const u8 type, const char *filename,
730 struct tomoyo_domain_info *
731 const domain, const bool is_delete)
733 static const u16 rw_mask =
734 (1 << TOMOYO_TYPE_READ_ACL) | (1 << TOMOYO_TYPE_WRITE_ACL);
735 const struct tomoyo_path_info *saved_filename;
736 struct tomoyo_acl_info *ptr;
737 struct tomoyo_single_path_acl_record *acl;
738 int error = -ENOMEM;
739 const u16 perm = 1 << type;
741 if (!domain)
742 return -EINVAL;
743 if (!tomoyo_is_correct_path(filename, 0, 0, 0, __func__))
744 return -EINVAL;
745 saved_filename = tomoyo_save_name(filename);
746 if (!saved_filename)
747 return -ENOMEM;
748 /***** EXCLUSIVE SECTION START *****/
749 down_write(&tomoyo_domain_acl_info_list_lock);
750 if (is_delete)
751 goto delete;
752 list_for_each_entry(ptr, &domain->acl_info_list, list) {
753 if (tomoyo_acl_type1(ptr) != TOMOYO_TYPE_SINGLE_PATH_ACL)
754 continue;
755 acl = container_of(ptr, struct tomoyo_single_path_acl_record,
756 head);
757 if (acl->filename != saved_filename)
758 continue;
759 /* Special case. Clear all bits if marked as deleted. */
760 if (ptr->type & TOMOYO_ACL_DELETED)
761 acl->perm = 0;
762 acl->perm |= perm;
763 if ((acl->perm & rw_mask) == rw_mask)
764 acl->perm |= 1 << TOMOYO_TYPE_READ_WRITE_ACL;
765 else if (acl->perm & (1 << TOMOYO_TYPE_READ_WRITE_ACL))
766 acl->perm |= rw_mask;
767 ptr->type &= ~TOMOYO_ACL_DELETED;
768 error = 0;
769 goto out;
771 /* Not found. Append it to the tail. */
772 acl = tomoyo_alloc_acl_element(TOMOYO_TYPE_SINGLE_PATH_ACL);
773 if (!acl)
774 goto out;
775 acl->perm = perm;
776 if (perm == (1 << TOMOYO_TYPE_READ_WRITE_ACL))
777 acl->perm |= rw_mask;
778 acl->filename = saved_filename;
779 list_add_tail(&acl->head.list, &domain->acl_info_list);
780 error = 0;
781 goto out;
782 delete:
783 error = -ENOENT;
784 list_for_each_entry(ptr, &domain->acl_info_list, list) {
785 if (tomoyo_acl_type2(ptr) != TOMOYO_TYPE_SINGLE_PATH_ACL)
786 continue;
787 acl = container_of(ptr, struct tomoyo_single_path_acl_record,
788 head);
789 if (acl->filename != saved_filename)
790 continue;
791 acl->perm &= ~perm;
792 if ((acl->perm & rw_mask) != rw_mask)
793 acl->perm &= ~(1 << TOMOYO_TYPE_READ_WRITE_ACL);
794 else if (!(acl->perm & (1 << TOMOYO_TYPE_READ_WRITE_ACL)))
795 acl->perm &= ~rw_mask;
796 if (!acl->perm)
797 ptr->type |= TOMOYO_ACL_DELETED;
798 error = 0;
799 break;
801 out:
802 up_write(&tomoyo_domain_acl_info_list_lock);
803 /***** EXCLUSIVE SECTION END *****/
804 return error;
808 * tomoyo_update_double_path_acl - Update "struct tomoyo_double_path_acl_record" list.
810 * @type: Type of operation.
811 * @filename1: First filename.
812 * @filename2: Second filename.
813 * @domain: Pointer to "struct tomoyo_domain_info".
814 * @is_delete: True if it is a delete request.
816 * Returns 0 on success, negative value otherwise.
818 static int tomoyo_update_double_path_acl(const u8 type, const char *filename1,
819 const char *filename2,
820 struct tomoyo_domain_info *
821 const domain, const bool is_delete)
823 const struct tomoyo_path_info *saved_filename1;
824 const struct tomoyo_path_info *saved_filename2;
825 struct tomoyo_acl_info *ptr;
826 struct tomoyo_double_path_acl_record *acl;
827 int error = -ENOMEM;
828 const u8 perm = 1 << type;
830 if (!domain)
831 return -EINVAL;
832 if (!tomoyo_is_correct_path(filename1, 0, 0, 0, __func__) ||
833 !tomoyo_is_correct_path(filename2, 0, 0, 0, __func__))
834 return -EINVAL;
835 saved_filename1 = tomoyo_save_name(filename1);
836 saved_filename2 = tomoyo_save_name(filename2);
837 if (!saved_filename1 || !saved_filename2)
838 return -ENOMEM;
839 /***** EXCLUSIVE SECTION START *****/
840 down_write(&tomoyo_domain_acl_info_list_lock);
841 if (is_delete)
842 goto delete;
843 list_for_each_entry(ptr, &domain->acl_info_list, list) {
844 if (tomoyo_acl_type1(ptr) != TOMOYO_TYPE_DOUBLE_PATH_ACL)
845 continue;
846 acl = container_of(ptr, struct tomoyo_double_path_acl_record,
847 head);
848 if (acl->filename1 != saved_filename1 ||
849 acl->filename2 != saved_filename2)
850 continue;
851 /* Special case. Clear all bits if marked as deleted. */
852 if (ptr->type & TOMOYO_ACL_DELETED)
853 acl->perm = 0;
854 acl->perm |= perm;
855 ptr->type &= ~TOMOYO_ACL_DELETED;
856 error = 0;
857 goto out;
859 /* Not found. Append it to the tail. */
860 acl = tomoyo_alloc_acl_element(TOMOYO_TYPE_DOUBLE_PATH_ACL);
861 if (!acl)
862 goto out;
863 acl->perm = perm;
864 acl->filename1 = saved_filename1;
865 acl->filename2 = saved_filename2;
866 list_add_tail(&acl->head.list, &domain->acl_info_list);
867 error = 0;
868 goto out;
869 delete:
870 error = -ENOENT;
871 list_for_each_entry(ptr, &domain->acl_info_list, list) {
872 if (tomoyo_acl_type2(ptr) != TOMOYO_TYPE_DOUBLE_PATH_ACL)
873 continue;
874 acl = container_of(ptr, struct tomoyo_double_path_acl_record,
875 head);
876 if (acl->filename1 != saved_filename1 ||
877 acl->filename2 != saved_filename2)
878 continue;
879 acl->perm &= ~perm;
880 if (!acl->perm)
881 ptr->type |= TOMOYO_ACL_DELETED;
882 error = 0;
883 break;
885 out:
886 up_write(&tomoyo_domain_acl_info_list_lock);
887 /***** EXCLUSIVE SECTION END *****/
888 return error;
892 * tomoyo_check_single_path_acl - Check permission for single path operation.
894 * @domain: Pointer to "struct tomoyo_domain_info".
895 * @type: Type of operation.
896 * @filename: Filename to check.
898 * Returns 0 on success, negative value otherwise.
900 static int tomoyo_check_single_path_acl(struct tomoyo_domain_info *domain,
901 const u8 type,
902 const struct tomoyo_path_info *filename)
904 if (!tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE))
905 return 0;
906 return tomoyo_check_single_path_acl2(domain, filename, 1 << type, 1);
910 * tomoyo_check_double_path_acl - Check permission for double path operation.
912 * @domain: Pointer to "struct tomoyo_domain_info".
913 * @type: Type of operation.
914 * @filename1: First filename to check.
915 * @filename2: Second filename to check.
917 * Returns 0 on success, -EPERM otherwise.
919 static int tomoyo_check_double_path_acl(const struct tomoyo_domain_info *domain,
920 const u8 type,
921 const struct tomoyo_path_info *
922 filename1,
923 const struct tomoyo_path_info *
924 filename2)
926 struct tomoyo_acl_info *ptr;
927 const u8 perm = 1 << type;
928 int error = -EPERM;
930 if (!tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE))
931 return 0;
932 down_read(&tomoyo_domain_acl_info_list_lock);
933 list_for_each_entry(ptr, &domain->acl_info_list, list) {
934 struct tomoyo_double_path_acl_record *acl;
935 if (tomoyo_acl_type2(ptr) != TOMOYO_TYPE_DOUBLE_PATH_ACL)
936 continue;
937 acl = container_of(ptr, struct tomoyo_double_path_acl_record,
938 head);
939 if (!(acl->perm & perm))
940 continue;
941 if (!tomoyo_path_matches_pattern(filename1, acl->filename1))
942 continue;
943 if (!tomoyo_path_matches_pattern(filename2, acl->filename2))
944 continue;
945 error = 0;
946 break;
948 up_read(&tomoyo_domain_acl_info_list_lock);
949 return error;
953 * tomoyo_check_single_path_permission2 - Check permission for single path operation.
955 * @domain: Pointer to "struct tomoyo_domain_info".
956 * @operation: Type of operation.
957 * @filename: Filename to check.
958 * @mode: Access control mode.
960 * Returns 0 on success, negative value otherwise.
962 static int tomoyo_check_single_path_permission2(struct tomoyo_domain_info *
963 const domain, u8 operation,
964 const struct tomoyo_path_info *
965 filename, const u8 mode)
967 const char *msg;
968 int error;
969 const bool is_enforce = (mode == 3);
971 if (!mode)
972 return 0;
973 next:
974 error = tomoyo_check_single_path_acl(domain, operation, filename);
975 msg = tomoyo_sp2keyword(operation);
976 if (!error)
977 goto ok;
978 if (tomoyo_verbose_mode(domain))
979 printk(KERN_WARNING "TOMOYO-%s: Access '%s %s' denied for %s\n",
980 tomoyo_get_msg(is_enforce), msg, filename->name,
981 tomoyo_get_last_name(domain));
982 if (mode == 1 && tomoyo_domain_quota_is_ok(domain)) {
983 const char *name = tomoyo_get_file_pattern(filename)->name;
984 tomoyo_update_single_path_acl(operation, name, domain, false);
986 if (!is_enforce)
987 error = 0;
990 * Since "allow_truncate" doesn't imply "allow_rewrite" permission,
991 * we need to check "allow_rewrite" permission if the filename is
992 * specified by "deny_rewrite" keyword.
994 if (!error && operation == TOMOYO_TYPE_TRUNCATE_ACL &&
995 tomoyo_is_no_rewrite_file(filename)) {
996 operation = TOMOYO_TYPE_REWRITE_ACL;
997 goto next;
999 return error;
1003 * tomoyo_check_file_perm - Check permission for sysctl()'s "read" and "write".
1005 * @domain: Pointer to "struct tomoyo_domain_info".
1006 * @filename: Filename to check.
1007 * @perm: Mode ("read" or "write" or "read/write").
1008 * Returns 0 on success, negative value otherwise.
1010 int tomoyo_check_file_perm(struct tomoyo_domain_info *domain,
1011 const char *filename, const u8 perm)
1013 struct tomoyo_path_info name;
1014 const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE);
1016 if (!mode)
1017 return 0;
1018 name.name = filename;
1019 tomoyo_fill_path_info(&name);
1020 return tomoyo_check_file_perm2(domain, &name, perm, "sysctl", mode);
1024 * tomoyo_check_exec_perm - Check permission for "execute".
1026 * @domain: Pointer to "struct tomoyo_domain_info".
1027 * @filename: Check permission for "execute".
1028 * @tmp: Buffer for temporary use.
1030 * Returns 0 on success, negativevalue otherwise.
1032 int tomoyo_check_exec_perm(struct tomoyo_domain_info *domain,
1033 const struct tomoyo_path_info *filename,
1034 struct tomoyo_page_buffer *tmp)
1036 const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE);
1038 if (!mode)
1039 return 0;
1040 return tomoyo_check_file_perm2(domain, filename, 1, "do_execve", mode);
1044 * tomoyo_check_open_permission - Check permission for "read" and "write".
1046 * @domain: Pointer to "struct tomoyo_domain_info".
1047 * @path: Pointer to "struct path".
1048 * @flag: Flags for open().
1050 * Returns 0 on success, negative value otherwise.
1052 int tomoyo_check_open_permission(struct tomoyo_domain_info *domain,
1053 struct path *path, const int flag)
1055 const u8 acc_mode = ACC_MODE(flag);
1056 int error = -ENOMEM;
1057 struct tomoyo_path_info *buf;
1058 const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE);
1059 const bool is_enforce = (mode == 3);
1061 if (!mode || !path->mnt)
1062 return 0;
1063 if (acc_mode == 0)
1064 return 0;
1065 if (path->dentry->d_inode && S_ISDIR(path->dentry->d_inode->i_mode))
1067 * I don't check directories here because mkdir() and rmdir()
1068 * don't call me.
1070 return 0;
1071 buf = tomoyo_get_path(path);
1072 if (!buf)
1073 goto out;
1074 error = 0;
1076 * If the filename is specified by "deny_rewrite" keyword,
1077 * we need to check "allow_rewrite" permission when the filename is not
1078 * opened for append mode or the filename is truncated at open time.
1080 if ((acc_mode & MAY_WRITE) &&
1081 ((flag & O_TRUNC) || !(flag & O_APPEND)) &&
1082 (tomoyo_is_no_rewrite_file(buf))) {
1083 error = tomoyo_check_single_path_permission2(domain,
1084 TOMOYO_TYPE_REWRITE_ACL,
1085 buf, mode);
1087 if (!error)
1088 error = tomoyo_check_file_perm2(domain, buf, acc_mode, "open",
1089 mode);
1090 if (!error && (flag & O_TRUNC))
1091 error = tomoyo_check_single_path_permission2(domain,
1092 TOMOYO_TYPE_TRUNCATE_ACL,
1093 buf, mode);
1094 out:
1095 tomoyo_free(buf);
1096 if (!is_enforce)
1097 error = 0;
1098 return error;
1102 * tomoyo_check_1path_perm - Check permission for "create", "unlink", "mkdir", "rmdir", "mkfifo", "mksock", "mkblock", "mkchar", "truncate" and "symlink".
1104 * @domain: Pointer to "struct tomoyo_domain_info".
1105 * @operation: Type of operation.
1106 * @path: Pointer to "struct path".
1108 * Returns 0 on success, negative value otherwise.
1110 int tomoyo_check_1path_perm(struct tomoyo_domain_info *domain,
1111 const u8 operation, struct path *path)
1113 int error = -ENOMEM;
1114 struct tomoyo_path_info *buf;
1115 const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE);
1116 const bool is_enforce = (mode == 3);
1118 if (!mode || !path->mnt)
1119 return 0;
1120 buf = tomoyo_get_path(path);
1121 if (!buf)
1122 goto out;
1123 switch (operation) {
1124 case TOMOYO_TYPE_MKDIR_ACL:
1125 case TOMOYO_TYPE_RMDIR_ACL:
1126 if (!buf->is_dir) {
1128 * tomoyo_get_path() reserves space for appending "/."
1130 strcat((char *) buf->name, "/");
1131 tomoyo_fill_path_info(buf);
1134 error = tomoyo_check_single_path_permission2(domain, operation, buf,
1135 mode);
1136 out:
1137 tomoyo_free(buf);
1138 if (!is_enforce)
1139 error = 0;
1140 return error;
1144 * tomoyo_check_rewrite_permission - Check permission for "rewrite".
1146 * @domain: Pointer to "struct tomoyo_domain_info".
1147 * @filp: Pointer to "struct file".
1149 * Returns 0 on success, negative value otherwise.
1151 int tomoyo_check_rewrite_permission(struct tomoyo_domain_info *domain,
1152 struct file *filp)
1154 int error = -ENOMEM;
1155 const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE);
1156 const bool is_enforce = (mode == 3);
1157 struct tomoyo_path_info *buf;
1159 if (!mode || !filp->f_path.mnt)
1160 return 0;
1161 buf = tomoyo_get_path(&filp->f_path);
1162 if (!buf)
1163 goto out;
1164 if (!tomoyo_is_no_rewrite_file(buf)) {
1165 error = 0;
1166 goto out;
1168 error = tomoyo_check_single_path_permission2(domain,
1169 TOMOYO_TYPE_REWRITE_ACL,
1170 buf, mode);
1171 out:
1172 tomoyo_free(buf);
1173 if (!is_enforce)
1174 error = 0;
1175 return error;
1179 * tomoyo_check_2path_perm - Check permission for "rename" and "link".
1181 * @domain: Pointer to "struct tomoyo_domain_info".
1182 * @operation: Type of operation.
1183 * @path1: Pointer to "struct path".
1184 * @path2: Pointer to "struct path".
1186 * Returns 0 on success, negative value otherwise.
1188 int tomoyo_check_2path_perm(struct tomoyo_domain_info * const domain,
1189 const u8 operation, struct path *path1,
1190 struct path *path2)
1192 int error = -ENOMEM;
1193 struct tomoyo_path_info *buf1, *buf2;
1194 const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE);
1195 const bool is_enforce = (mode == 3);
1196 const char *msg;
1198 if (!mode || !path1->mnt || !path2->mnt)
1199 return 0;
1200 buf1 = tomoyo_get_path(path1);
1201 buf2 = tomoyo_get_path(path2);
1202 if (!buf1 || !buf2)
1203 goto out;
1205 struct dentry *dentry = path1->dentry;
1206 if (dentry->d_inode && S_ISDIR(dentry->d_inode->i_mode)) {
1208 * tomoyo_get_path() reserves space for appending "/."
1210 if (!buf1->is_dir) {
1211 strcat((char *) buf1->name, "/");
1212 tomoyo_fill_path_info(buf1);
1214 if (!buf2->is_dir) {
1215 strcat((char *) buf2->name, "/");
1216 tomoyo_fill_path_info(buf2);
1220 error = tomoyo_check_double_path_acl(domain, operation, buf1, buf2);
1221 msg = tomoyo_dp2keyword(operation);
1222 if (!error)
1223 goto out;
1224 if (tomoyo_verbose_mode(domain))
1225 printk(KERN_WARNING "TOMOYO-%s: Access '%s %s %s' "
1226 "denied for %s\n", tomoyo_get_msg(is_enforce),
1227 msg, buf1->name, buf2->name,
1228 tomoyo_get_last_name(domain));
1229 if (mode == 1 && tomoyo_domain_quota_is_ok(domain)) {
1230 const char *name1 = tomoyo_get_file_pattern(buf1)->name;
1231 const char *name2 = tomoyo_get_file_pattern(buf2)->name;
1232 tomoyo_update_double_path_acl(operation, name1, name2, domain,
1233 false);
1235 out:
1236 tomoyo_free(buf1);
1237 tomoyo_free(buf2);
1238 if (!is_enforce)
1239 error = 0;
1240 return error;