diff options
author | Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp> | 2010-05-16 21:10:31 -0400 |
---|---|---|
committer | James Morris <jmorris@namei.org> | 2010-08-02 01:33:37 -0400 |
commit | 2106ccd972dcd9fda7df9b181505fac1741b3508 (patch) | |
tree | 4361f9498c303cabc20abc85c1b5ee0afa677b0f /security/tomoyo | |
parent | a1f9bb6a375a8dbf7797ffbd6739c46b338a77f7 (diff) |
TOMOYO: Add mount restriction.
mount(2) has three string and one numeric parameters.
Split mount restriction code from security/tomoyo/file.c .
Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
Signed-off-by: James Morris <jmorris@namei.org>
Diffstat (limited to 'security/tomoyo')
-rw-r--r-- | security/tomoyo/Makefile | 2 | ||||
-rw-r--r-- | security/tomoyo/common.c | 35 | ||||
-rw-r--r-- | security/tomoyo/common.h | 56 | ||||
-rw-r--r-- | security/tomoyo/file.c | 9 | ||||
-rw-r--r-- | security/tomoyo/gc.c | 10 | ||||
-rw-r--r-- | security/tomoyo/mount.c | 366 | ||||
-rw-r--r-- | security/tomoyo/tomoyo.c | 2 |
7 files changed, 469 insertions, 11 deletions
diff --git a/security/tomoyo/Makefile b/security/tomoyo/Makefile index 4d1b5af4f1f7..d7befab40eff 100644 --- a/security/tomoyo/Makefile +++ b/security/tomoyo/Makefile | |||
@@ -1 +1 @@ | |||
obj-y = common.o realpath.o tomoyo.o domain.o file.o gc.o path_group.o number_group.o | obj-y = common.o realpath.o tomoyo.o domain.o file.o gc.o path_group.o number_group.o mount.o | ||
diff --git a/security/tomoyo/common.c b/security/tomoyo/common.c index 0706b175fdb1..0c6f9a5c37a5 100644 --- a/security/tomoyo/common.c +++ b/security/tomoyo/common.c | |||
@@ -1075,6 +1075,10 @@ bool tomoyo_domain_quota_is_ok(struct tomoyo_request_info *r) | |||
1075 | if (perm & (1 << i)) | 1075 | if (perm & (1 << i)) |
1076 | count++; | 1076 | count++; |
1077 | break; | 1077 | break; |
1078 | case TOMOYO_TYPE_MOUNT_ACL: | ||
1079 | if (!container_of(ptr, struct tomoyo_mount_acl, head)-> | ||
1080 | is_deleted) | ||
1081 | count++; | ||
1078 | } | 1082 | } |
1079 | } | 1083 | } |
1080 | if (count < tomoyo_check_flags(domain, TOMOYO_MAX_ACCEPT_ENTRY)) | 1084 | if (count < tomoyo_check_flags(domain, TOMOYO_MAX_ACCEPT_ENTRY)) |
@@ -1576,6 +1580,8 @@ static int tomoyo_write_domain_policy(struct tomoyo_io_buffer *head) | |||
1576 | domain->ignore_global_allow_read = !is_delete; | 1580 | domain->ignore_global_allow_read = !is_delete; |
1577 | return 0; | 1581 | return 0; |
1578 | } | 1582 | } |
1583 | if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_ALLOW_MOUNT)) | ||
1584 | return tomoyo_write_mount_policy(data, domain, is_delete); | ||
1579 | return tomoyo_write_file_policy(data, domain, is_delete); | 1585 | return tomoyo_write_file_policy(data, domain, is_delete); |
1580 | } | 1586 | } |
1581 | 1587 | ||
@@ -1721,6 +1727,30 @@ static bool tomoyo_print_path_number3_acl(struct tomoyo_io_buffer *head, | |||
1721 | } | 1727 | } |
1722 | 1728 | ||
1723 | /** | 1729 | /** |
1730 | * tomoyo_print_mount_acl - Print a mount ACL entry. | ||
1731 | * | ||
1732 | * @head: Pointer to "struct tomoyo_io_buffer". | ||
1733 | * @ptr: Pointer to "struct tomoyo_mount_acl". | ||
1734 | * | ||
1735 | * Returns true on success, false otherwise. | ||
1736 | */ | ||
1737 | static bool tomoyo_print_mount_acl(struct tomoyo_io_buffer *head, | ||
1738 | struct tomoyo_mount_acl *ptr) | ||
1739 | { | ||
1740 | const int pos = head->read_avail; | ||
1741 | if (!tomoyo_io_printf(head, TOMOYO_KEYWORD_ALLOW_MOUNT) || | ||
1742 | !tomoyo_print_name_union(head, &ptr->dev_name) || | ||
1743 | !tomoyo_print_name_union(head, &ptr->dir_name) || | ||
1744 | !tomoyo_print_name_union(head, &ptr->fs_type) || | ||
1745 | !tomoyo_print_number_union(head, &ptr->flags) || | ||
1746 | !tomoyo_io_printf(head, "\n")) { | ||
1747 | head->read_avail = pos; | ||
1748 | return false; | ||
1749 | } | ||
1750 | return true; | ||
1751 | } | ||
1752 | |||
1753 | /** | ||
1724 | * tomoyo_print_entry - Print an ACL entry. | 1754 | * tomoyo_print_entry - Print an ACL entry. |
1725 | * | 1755 | * |
1726 | * @head: Pointer to "struct tomoyo_io_buffer". | 1756 | * @head: Pointer to "struct tomoyo_io_buffer". |
@@ -1755,6 +1785,11 @@ static bool tomoyo_print_entry(struct tomoyo_io_buffer *head, | |||
1755 | head); | 1785 | head); |
1756 | return tomoyo_print_path_number3_acl(head, acl); | 1786 | return tomoyo_print_path_number3_acl(head, acl); |
1757 | } | 1787 | } |
1788 | if (acl_type == TOMOYO_TYPE_MOUNT_ACL) { | ||
1789 | struct tomoyo_mount_acl *acl | ||
1790 | = container_of(ptr, struct tomoyo_mount_acl, head); | ||
1791 | return tomoyo_print_mount_acl(head, acl); | ||
1792 | } | ||
1758 | BUG(); /* This must not happen. */ | 1793 | BUG(); /* This must not happen. */ |
1759 | return false; | 1794 | return false; |
1760 | } | 1795 | } |
diff --git a/security/tomoyo/common.h b/security/tomoyo/common.h index 565a1c11da53..3d819b139165 100644 --- a/security/tomoyo/common.h +++ b/security/tomoyo/common.h | |||
@@ -53,6 +53,7 @@ enum tomoyo_mode_index { | |||
53 | 53 | ||
54 | /* Keywords for ACLs. */ | 54 | /* Keywords for ACLs. */ |
55 | #define TOMOYO_KEYWORD_ALIAS "alias " | 55 | #define TOMOYO_KEYWORD_ALIAS "alias " |
56 | #define TOMOYO_KEYWORD_ALLOW_MOUNT "allow_mount " | ||
56 | #define TOMOYO_KEYWORD_ALLOW_READ "allow_read " | 57 | #define TOMOYO_KEYWORD_ALLOW_READ "allow_read " |
57 | #define TOMOYO_KEYWORD_DELETE "delete " | 58 | #define TOMOYO_KEYWORD_DELETE "delete " |
58 | #define TOMOYO_KEYWORD_DENY_REWRITE "deny_rewrite " | 59 | #define TOMOYO_KEYWORD_DENY_REWRITE "deny_rewrite " |
@@ -90,6 +91,7 @@ enum tomoyo_acl_entry_type_index { | |||
90 | TOMOYO_TYPE_PATH2_ACL, | 91 | TOMOYO_TYPE_PATH2_ACL, |
91 | TOMOYO_TYPE_PATH_NUMBER_ACL, | 92 | TOMOYO_TYPE_PATH_NUMBER_ACL, |
92 | TOMOYO_TYPE_PATH_NUMBER3_ACL, | 93 | TOMOYO_TYPE_PATH_NUMBER3_ACL, |
94 | TOMOYO_TYPE_MOUNT_ACL, | ||
93 | }; | 95 | }; |
94 | 96 | ||
95 | /* Index numbers for File Controls. */ | 97 | /* Index numbers for File Controls. */ |
@@ -116,7 +118,6 @@ enum tomoyo_path_acl_index { | |||
116 | TOMOYO_TYPE_SYMLINK, | 118 | TOMOYO_TYPE_SYMLINK, |
117 | TOMOYO_TYPE_REWRITE, | 119 | TOMOYO_TYPE_REWRITE, |
118 | TOMOYO_TYPE_CHROOT, | 120 | TOMOYO_TYPE_CHROOT, |
119 | TOMOYO_TYPE_MOUNT, | ||
120 | TOMOYO_TYPE_UMOUNT, | 121 | TOMOYO_TYPE_UMOUNT, |
121 | TOMOYO_MAX_PATH_OPERATION | 122 | TOMOYO_MAX_PATH_OPERATION |
122 | }; | 123 | }; |
@@ -360,8 +361,8 @@ struct tomoyo_domain_info { | |||
360 | * | 361 | * |
361 | * Directives held by this structure are "allow_read/write", "allow_execute", | 362 | * Directives held by this structure are "allow_read/write", "allow_execute", |
362 | * "allow_read", "allow_write", "allow_unlink", "allow_rmdir", | 363 | * "allow_read", "allow_write", "allow_unlink", "allow_rmdir", |
363 | * "allow_truncate", "allow_symlink", "allow_rewrite", "allow_chroot", | 364 | * "allow_truncate", "allow_symlink", "allow_rewrite", "allow_chroot" and |
364 | * "allow_mount" and "allow_unmount". | 365 | * "allow_unmount". |
365 | */ | 366 | */ |
366 | struct tomoyo_path_acl { | 367 | struct tomoyo_path_acl { |
367 | struct tomoyo_acl_info head; /* type = TOMOYO_TYPE_PATH_ACL */ | 368 | struct tomoyo_acl_info head; /* type = TOMOYO_TYPE_PATH_ACL */ |
@@ -435,6 +436,29 @@ struct tomoyo_path2_acl { | |||
435 | }; | 436 | }; |
436 | 437 | ||
437 | /* | 438 | /* |
439 | * tomoyo_mount_acl is a structure which is used for holding an | ||
440 | * entry for mount operation. | ||
441 | * It has following fields. | ||
442 | * | ||
443 | * (1) "head" which is a "struct tomoyo_acl_info". | ||
444 | * (2) "is_deleted" is boolean. | ||
445 | * (3) "dev_name" is the device name. | ||
446 | * (4) "dir_name" is the mount point. | ||
447 | * (5) "flags" is the mount flags. | ||
448 | * | ||
449 | * Directives held by this structure are "allow_rename", "allow_link" and | ||
450 | * "allow_pivot_root". | ||
451 | */ | ||
452 | struct tomoyo_mount_acl { | ||
453 | struct tomoyo_acl_info head; /* type = TOMOYO_TYPE_MOUNT_ACL */ | ||
454 | bool is_deleted; | ||
455 | struct tomoyo_name_union dev_name; | ||
456 | struct tomoyo_name_union dir_name; | ||
457 | struct tomoyo_name_union fs_type; | ||
458 | struct tomoyo_number_union flags; | ||
459 | }; | ||
460 | |||
461 | /* | ||
438 | * tomoyo_io_buffer is a structure which is used for reading and modifying | 462 | * tomoyo_io_buffer is a structure which is used for reading and modifying |
439 | * configuration via /sys/kernel/security/tomoyo/ interface. | 463 | * configuration via /sys/kernel/security/tomoyo/ interface. |
440 | * It has many fields. ->read_var1 , ->read_var2 , ->write_var1 are used as | 464 | * It has many fields. ->read_var1 , ->read_var2 , ->write_var1 are used as |
@@ -638,6 +662,9 @@ struct tomoyo_policy_manager_entry { | |||
638 | /* Check whether the given name matches the given name_union. */ | 662 | /* Check whether the given name matches the given name_union. */ |
639 | bool tomoyo_compare_name_union(const struct tomoyo_path_info *name, | 663 | bool tomoyo_compare_name_union(const struct tomoyo_path_info *name, |
640 | const struct tomoyo_name_union *ptr); | 664 | const struct tomoyo_name_union *ptr); |
665 | /* Check whether the given number matches the given number_union. */ | ||
666 | bool tomoyo_compare_number_union(const unsigned long value, | ||
667 | const struct tomoyo_number_union *ptr); | ||
641 | /* Check whether the domain has too many ACL entries to hold. */ | 668 | /* Check whether the domain has too many ACL entries to hold. */ |
642 | bool tomoyo_domain_quota_is_ok(struct tomoyo_request_info *r); | 669 | bool tomoyo_domain_quota_is_ok(struct tomoyo_request_info *r); |
643 | /* Transactional sprintf() for policy dump. */ | 670 | /* Transactional sprintf() for policy dump. */ |
@@ -699,6 +726,12 @@ const char *tomoyo_path_number32keyword(const u8 operation); | |||
699 | const char *tomoyo_get_last_name(const struct tomoyo_domain_info *domain); | 726 | const char *tomoyo_get_last_name(const struct tomoyo_domain_info *domain); |
700 | /* Convert single path operation to operation name. */ | 727 | /* Convert single path operation to operation name. */ |
701 | const char *tomoyo_path2keyword(const u8 operation); | 728 | const char *tomoyo_path2keyword(const u8 operation); |
729 | /* Fill "struct tomoyo_request_info". */ | ||
730 | int tomoyo_init_request_info(struct tomoyo_request_info *r, | ||
731 | struct tomoyo_domain_info *domain); | ||
732 | /* Check permission for mount operation. */ | ||
733 | int tomoyo_mount_permission(char *dev_name, struct path *path, char *type, | ||
734 | unsigned long flags, void *data_page); | ||
702 | /* Create "alias" entry in exception policy. */ | 735 | /* Create "alias" entry in exception policy. */ |
703 | int tomoyo_write_alias_policy(char *data, const bool is_delete); | 736 | int tomoyo_write_alias_policy(char *data, const bool is_delete); |
704 | /* | 737 | /* |
@@ -721,6 +754,9 @@ int tomoyo_write_file_policy(char *data, struct tomoyo_domain_info *domain, | |||
721 | const bool is_delete); | 754 | const bool is_delete); |
722 | /* Create "allow_read" entry in exception policy. */ | 755 | /* Create "allow_read" entry in exception policy. */ |
723 | int tomoyo_write_globally_readable_policy(char *data, const bool is_delete); | 756 | int tomoyo_write_globally_readable_policy(char *data, const bool is_delete); |
757 | /* Create "allow_mount" entry in domain policy. */ | ||
758 | int tomoyo_write_mount_policy(char *data, struct tomoyo_domain_info *domain, | ||
759 | const bool is_delete); | ||
724 | /* Create "deny_rewrite" entry in exception policy. */ | 760 | /* Create "deny_rewrite" entry in exception policy. */ |
725 | int tomoyo_write_no_rewrite_policy(char *data, const bool is_delete); | 761 | int tomoyo_write_no_rewrite_policy(char *data, const bool is_delete); |
726 | /* Create "file_pattern" entry in exception policy. */ | 762 | /* Create "file_pattern" entry in exception policy. */ |
@@ -735,7 +771,9 @@ struct tomoyo_domain_info *tomoyo_find_domain(const char *domainname); | |||
735 | struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char * | 771 | struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char * |
736 | domainname, | 772 | domainname, |
737 | const u8 profile); | 773 | const u8 profile); |
738 | 774 | /* Get patterned pathname. */ | |
775 | const struct tomoyo_path_info * | ||
776 | tomoyo_get_file_pattern(const struct tomoyo_path_info *filename); | ||
739 | /* Allocate memory for "struct tomoyo_path_group". */ | 777 | /* Allocate memory for "struct tomoyo_path_group". */ |
740 | struct tomoyo_path_group *tomoyo_get_path_group(const char *group_name); | 778 | struct tomoyo_path_group *tomoyo_get_path_group(const char *group_name); |
741 | struct tomoyo_number_group *tomoyo_get_number_group(const char *group_name); | 779 | struct tomoyo_number_group *tomoyo_get_number_group(const char *group_name); |
@@ -972,6 +1010,16 @@ static inline bool tomoyo_is_same_path_number_acl | |||
972 | && tomoyo_is_same_number_union(&p1->number, &p2->number); | 1010 | && tomoyo_is_same_number_union(&p1->number, &p2->number); |
973 | } | 1011 | } |
974 | 1012 | ||
1013 | static inline bool tomoyo_is_same_mount_acl(const struct tomoyo_mount_acl *p1, | ||
1014 | const struct tomoyo_mount_acl *p2) | ||
1015 | { | ||
1016 | return tomoyo_is_same_acl_head(&p1->head, &p2->head) && | ||
1017 | tomoyo_is_same_name_union(&p1->dev_name, &p2->dev_name) && | ||
1018 | tomoyo_is_same_name_union(&p1->dir_name, &p2->dir_name) && | ||
1019 | tomoyo_is_same_name_union(&p1->fs_type, &p2->fs_type) && | ||
1020 | tomoyo_is_same_number_union(&p1->flags, &p2->flags); | ||
1021 | } | ||
1022 | |||
975 | static inline bool tomoyo_is_same_domain_initializer_entry | 1023 | static inline bool tomoyo_is_same_domain_initializer_entry |
976 | (const struct tomoyo_domain_initializer_entry *p1, | 1024 | (const struct tomoyo_domain_initializer_entry *p1, |
977 | const struct tomoyo_domain_initializer_entry *p2) | 1025 | const struct tomoyo_domain_initializer_entry *p2) |
diff --git a/security/tomoyo/file.c b/security/tomoyo/file.c index 727cc723f87d..ae32cab8ec7e 100644 --- a/security/tomoyo/file.c +++ b/security/tomoyo/file.c | |||
@@ -24,7 +24,6 @@ static const char *tomoyo_path_keyword[TOMOYO_MAX_PATH_OPERATION] = { | |||
24 | [TOMOYO_TYPE_SYMLINK] = "symlink", | 24 | [TOMOYO_TYPE_SYMLINK] = "symlink", |
25 | [TOMOYO_TYPE_REWRITE] = "rewrite", | 25 | [TOMOYO_TYPE_REWRITE] = "rewrite", |
26 | [TOMOYO_TYPE_CHROOT] = "chroot", | 26 | [TOMOYO_TYPE_CHROOT] = "chroot", |
27 | [TOMOYO_TYPE_MOUNT] = "mount", | ||
28 | [TOMOYO_TYPE_UMOUNT] = "unmount", | 27 | [TOMOYO_TYPE_UMOUNT] = "unmount", |
29 | }; | 28 | }; |
30 | 29 | ||
@@ -108,8 +107,8 @@ bool tomoyo_compare_number_union(const unsigned long value, | |||
108 | * | 107 | * |
109 | * Returns mode. | 108 | * Returns mode. |
110 | */ | 109 | */ |
111 | static int tomoyo_init_request_info(struct tomoyo_request_info *r, | 110 | int tomoyo_init_request_info(struct tomoyo_request_info *r, |
112 | struct tomoyo_domain_info *domain) | 111 | struct tomoyo_domain_info *domain) |
113 | { | 112 | { |
114 | memset(r, 0, sizeof(*r)); | 113 | memset(r, 0, sizeof(*r)); |
115 | if (!domain) | 114 | if (!domain) |
@@ -487,7 +486,7 @@ static int tomoyo_update_file_pattern_entry(const char *pattern, | |||
487 | * | 486 | * |
488 | * Caller holds tomoyo_read_lock(). | 487 | * Caller holds tomoyo_read_lock(). |
489 | */ | 488 | */ |
490 | static const struct tomoyo_path_info * | 489 | const struct tomoyo_path_info * |
491 | tomoyo_get_file_pattern(const struct tomoyo_path_info *filename) | 490 | tomoyo_get_file_pattern(const struct tomoyo_path_info *filename) |
492 | { | 491 | { |
493 | struct tomoyo_pattern_entry *ptr; | 492 | struct tomoyo_pattern_entry *ptr; |
@@ -1418,7 +1417,7 @@ int tomoyo_check_open_permission(struct tomoyo_domain_info *domain, | |||
1418 | } | 1417 | } |
1419 | 1418 | ||
1420 | /** | 1419 | /** |
1421 | * tomoyo_path_perm - Check permission for "unlink", "rmdir", "truncate", "symlink", "rewrite", "chroot", "mount" and "unmount". | 1420 | * tomoyo_path_perm - Check permission for "unlink", "rmdir", "truncate", "symlink", "rewrite", "chroot" and "unmount". |
1422 | * | 1421 | * |
1423 | * @operation: Type of operation. | 1422 | * @operation: Type of operation. |
1424 | * @path: Pointer to "struct path". | 1423 | * @path: Pointer to "struct path". |
diff --git a/security/tomoyo/gc.c b/security/tomoyo/gc.c index 78100180d23d..be2d3b935533 100644 --- a/security/tomoyo/gc.c +++ b/security/tomoyo/gc.c | |||
@@ -124,6 +124,16 @@ static void tomoyo_del_acl(struct tomoyo_acl_info *acl) | |||
124 | tomoyo_put_number_union(&entry->minor); | 124 | tomoyo_put_number_union(&entry->minor); |
125 | } | 125 | } |
126 | break; | 126 | break; |
127 | case TOMOYO_TYPE_MOUNT_ACL: | ||
128 | { | ||
129 | struct tomoyo_mount_acl *entry | ||
130 | = container_of(acl, typeof(*entry), head); | ||
131 | tomoyo_put_name_union(&entry->dev_name); | ||
132 | tomoyo_put_name_union(&entry->dir_name); | ||
133 | tomoyo_put_name_union(&entry->fs_type); | ||
134 | tomoyo_put_number_union(&entry->flags); | ||
135 | } | ||
136 | break; | ||
127 | default: | 137 | default: |
128 | printk(KERN_WARNING "Unknown type\n"); | 138 | printk(KERN_WARNING "Unknown type\n"); |
129 | break; | 139 | break; |
diff --git a/security/tomoyo/mount.c b/security/tomoyo/mount.c new file mode 100644 index 000000000000..507be09e93a9 --- /dev/null +++ b/security/tomoyo/mount.c | |||
@@ -0,0 +1,366 @@ | |||
1 | /* | ||
2 | * security/tomoyo/mount.c | ||
3 | * | ||
4 | * Copyright (C) 2005-2010 NTT DATA CORPORATION | ||
5 | */ | ||
6 | |||
7 | #include <linux/slab.h> | ||
8 | #include "common.h" | ||
9 | |||
10 | /* Keywords for mount restrictions. */ | ||
11 | |||
12 | /* Allow to call 'mount --bind /source_dir /dest_dir' */ | ||
13 | #define TOMOYO_MOUNT_BIND_KEYWORD "--bind" | ||
14 | /* Allow to call 'mount --move /old_dir /new_dir ' */ | ||
15 | #define TOMOYO_MOUNT_MOVE_KEYWORD "--move" | ||
16 | /* Allow to call 'mount -o remount /dir ' */ | ||
17 | #define TOMOYO_MOUNT_REMOUNT_KEYWORD "--remount" | ||
18 | /* Allow to call 'mount --make-unbindable /dir' */ | ||
19 | #define TOMOYO_MOUNT_MAKE_UNBINDABLE_KEYWORD "--make-unbindable" | ||
20 | /* Allow to call 'mount --make-private /dir' */ | ||
21 | #define TOMOYO_MOUNT_MAKE_PRIVATE_KEYWORD "--make-private" | ||
22 | /* Allow to call 'mount --make-slave /dir' */ | ||
23 | #define TOMOYO_MOUNT_MAKE_SLAVE_KEYWORD "--make-slave" | ||
24 | /* Allow to call 'mount --make-shared /dir' */ | ||
25 | #define TOMOYO_MOUNT_MAKE_SHARED_KEYWORD "--make-shared" | ||
26 | |||
27 | /** | ||
28 | * tomoyo_encode2: Encode binary string to ascii string. | ||
29 | * | ||
30 | * @str: String in binary format. | ||
31 | * | ||
32 | * Returns pointer to @str in ascii format on success, NULL otherwise. | ||
33 | * | ||
34 | * This function uses kzalloc(), so caller must kfree() if this function | ||
35 | * didn't return NULL. | ||
36 | */ | ||
37 | static char *tomoyo_encode2(const char *str) | ||
38 | { | ||
39 | int len = 0; | ||
40 | const char *p = str; | ||
41 | char *cp; | ||
42 | char *cp0; | ||
43 | if (!p) | ||
44 | return NULL; | ||
45 | while (*p) { | ||
46 | const unsigned char c = *p++; | ||
47 | if (c == '\\') | ||
48 | len += 2; | ||
49 | else if (c > ' ' && c < 127) | ||
50 | len++; | ||
51 | else | ||
52 | len += 4; | ||
53 | } | ||
54 | len++; | ||
55 | /* Reserve space for appending "/". */ | ||
56 | cp = kzalloc(len + 10, GFP_NOFS); | ||
57 | if (!cp) | ||
58 | return NULL; | ||
59 | cp0 = cp; | ||
60 | p = str; | ||
61 | while (*p) { | ||
62 | const unsigned char c = *p++; | ||
63 | if (c == '\\') { | ||
64 | *cp++ = '\\'; | ||
65 | *cp++ = '\\'; | ||
66 | } else if (c > ' ' && c < 127) { | ||
67 | *cp++ = c; | ||
68 | } else { | ||
69 | *cp++ = '\\'; | ||
70 | *cp++ = (c >> 6) + '0'; | ||
71 | *cp++ = ((c >> 3) & 7) + '0'; | ||
72 | *cp++ = (c & 7) + '0'; | ||
73 | } | ||
74 | } | ||
75 | return cp0; | ||
76 | } | ||
77 | |||
78 | /** | ||
79 | * tomoyo_mount_acl2 - Check permission for mount() operation. | ||
80 | * | ||
81 | * @r: Pointer to "struct tomoyo_request_info". | ||
82 | * @dev_name: Name of device file. | ||
83 | * @dir: Pointer to "struct path". | ||
84 | * @type: Name of filesystem type. | ||
85 | * @flags: Mount options. | ||
86 | * | ||
87 | * Returns 0 on success, negative value otherwise. | ||
88 | * | ||
89 | * Caller holds tomoyo_read_lock(). | ||
90 | */ | ||
91 | static int tomoyo_mount_acl2(struct tomoyo_request_info *r, char *dev_name, | ||
92 | struct path *dir, char *type, unsigned long flags) | ||
93 | { | ||
94 | struct path path; | ||
95 | struct tomoyo_acl_info *ptr; | ||
96 | struct file_system_type *fstype = NULL; | ||
97 | const char *requested_type = NULL; | ||
98 | const char *requested_dir_name = NULL; | ||
99 | const char *requested_dev_name = NULL; | ||
100 | struct tomoyo_path_info rtype; | ||
101 | struct tomoyo_path_info rdev; | ||
102 | struct tomoyo_path_info rdir; | ||
103 | int need_dev = 0; | ||
104 | int error = -ENOMEM; | ||
105 | |||
106 | /* Get fstype. */ | ||
107 | requested_type = tomoyo_encode2(type); | ||
108 | if (!requested_type) | ||
109 | goto out; | ||
110 | rtype.name = requested_type; | ||
111 | tomoyo_fill_path_info(&rtype); | ||
112 | |||
113 | /* Get mount point. */ | ||
114 | requested_dir_name = tomoyo_realpath_from_path(dir); | ||
115 | if (!requested_dir_name) { | ||
116 | error = -ENOMEM; | ||
117 | goto out; | ||
118 | } | ||
119 | rdir.name = requested_dir_name; | ||
120 | tomoyo_fill_path_info(&rdir); | ||
121 | |||
122 | /* Compare fs name. */ | ||
123 | if (!strcmp(type, TOMOYO_MOUNT_REMOUNT_KEYWORD)) { | ||
124 | /* dev_name is ignored. */ | ||
125 | } else if (!strcmp(type, TOMOYO_MOUNT_MAKE_UNBINDABLE_KEYWORD) || | ||
126 | !strcmp(type, TOMOYO_MOUNT_MAKE_PRIVATE_KEYWORD) || | ||
127 | !strcmp(type, TOMOYO_MOUNT_MAKE_SLAVE_KEYWORD) || | ||
128 | !strcmp(type, TOMOYO_MOUNT_MAKE_SHARED_KEYWORD)) { | ||
129 | /* dev_name is ignored. */ | ||
130 | } else if (!strcmp(type, TOMOYO_MOUNT_BIND_KEYWORD) || | ||
131 | !strcmp(type, TOMOYO_MOUNT_MOVE_KEYWORD)) { | ||
132 | need_dev = -1; /* dev_name is a directory */ | ||
133 | } else { | ||
134 | fstype = get_fs_type(type); | ||
135 | if (!fstype) { | ||
136 | error = -ENODEV; | ||
137 | goto out; | ||
138 | } | ||
139 | if (fstype->fs_flags & FS_REQUIRES_DEV) | ||
140 | /* dev_name is a block device file. */ | ||
141 | need_dev = 1; | ||
142 | } | ||
143 | if (need_dev) { | ||
144 | /* Get mount point or device file. */ | ||
145 | if (kern_path(dev_name, LOOKUP_FOLLOW, &path)) { | ||
146 | error = -ENOENT; | ||
147 | goto out; | ||
148 | } | ||
149 | requested_dev_name = tomoyo_realpath_from_path(&path); | ||
150 | if (!requested_dev_name) { | ||
151 | error = -ENOENT; | ||
152 | goto out; | ||
153 | } | ||
154 | } else { | ||
155 | /* Map dev_name to "<NULL>" if no dev_name given. */ | ||
156 | if (!dev_name) | ||
157 | dev_name = "<NULL>"; | ||
158 | requested_dev_name = tomoyo_encode2(dev_name); | ||
159 | if (!requested_dev_name) { | ||
160 | error = -ENOMEM; | ||
161 | goto out; | ||
162 | } | ||
163 | } | ||
164 | rdev.name = requested_dev_name; | ||
165 | tomoyo_fill_path_info(&rdev); | ||
166 | list_for_each_entry_rcu(ptr, &r->domain->acl_info_list, list) { | ||
167 | struct tomoyo_mount_acl *acl; | ||
168 | if (ptr->type != TOMOYO_TYPE_MOUNT_ACL) | ||
169 | continue; | ||
170 | acl = container_of(ptr, struct tomoyo_mount_acl, head); | ||
171 | if (acl->is_deleted || | ||
172 | !tomoyo_compare_number_union(flags, &acl->flags) || | ||
173 | !tomoyo_compare_name_union(&rtype, &acl->fs_type) || | ||
174 | !tomoyo_compare_name_union(&rdir, &acl->dir_name) || | ||
175 | (need_dev && | ||
176 | !tomoyo_compare_name_union(&rdev, &acl->dev_name))) | ||
177 | continue; | ||
178 | error = 0; | ||
179 | break; | ||
180 | } | ||
181 | if (error) { | ||
182 | const char *dev = tomoyo_get_file_pattern(&rdev)->name; | ||
183 | const char *dir = tomoyo_get_file_pattern(&rdir)->name; | ||
184 | int len = strlen(dev) + strlen(dir) + strlen(requested_type) | ||
185 | + 64; | ||
186 | char *buf = kzalloc(len, GFP_NOFS); | ||
187 | if (buf) { | ||
188 | snprintf(buf, len - 1, "%s %s %s 0x%lX", | ||
189 | dev, dir, requested_type, flags); | ||
190 | tomoyo_write_mount_policy(buf, r->domain, false); | ||
191 | kfree(buf); | ||
192 | } | ||
193 | } | ||
194 | out: | ||
195 | kfree(requested_dev_name); | ||
196 | kfree(requested_dir_name); | ||
197 | if (fstype) | ||
198 | put_filesystem(fstype); | ||
199 | kfree(requested_type); | ||
200 | return error; | ||
201 | } | ||
202 | |||
203 | /** | ||
204 | * tomoyo_mount_acl - Check permission for mount() operation. | ||
205 | * | ||
206 | * @r: Pointer to "struct tomoyo_request_info". | ||
207 | * @dev_name: Name of device file. | ||
208 | * @dir: Pointer to "struct path". | ||
209 | * @type: Name of filesystem type. | ||
210 | * @flags: Mount options. | ||
211 | * | ||
212 | * Returns 0 on success, negative value otherwise. | ||
213 | * | ||
214 | * Caller holds tomoyo_read_lock(). | ||
215 | */ | ||
216 | static int tomoyo_mount_acl(struct tomoyo_request_info *r, char *dev_name, | ||
217 | struct path *dir, char *type, unsigned long flags) | ||
218 | { | ||
219 | int error; | ||
220 | error = -EPERM; | ||
221 | if ((flags & MS_MGC_MSK) == MS_MGC_VAL) | ||
222 | flags &= ~MS_MGC_MSK; | ||
223 | switch (flags & (MS_REMOUNT | MS_MOVE | MS_BIND)) { | ||
224 | case MS_REMOUNT: | ||
225 | case MS_MOVE: | ||
226 | case MS_BIND: | ||
227 | case 0: | ||
228 | break; | ||
229 | default: | ||
230 | printk(KERN_WARNING "ERROR: " | ||
231 | "%s%s%sare given for single mount operation.\n", | ||
232 | flags & MS_REMOUNT ? "'remount' " : "", | ||
233 | flags & MS_MOVE ? "'move' " : "", | ||
234 | flags & MS_BIND ? "'bind' " : ""); | ||
235 | return -EINVAL; | ||
236 | } | ||
237 | switch (flags & (MS_UNBINDABLE | MS_PRIVATE | MS_SLAVE | MS_SHARED)) { | ||
238 | case MS_UNBINDABLE: | ||
239 | case MS_PRIVATE: | ||
240 | case MS_SLAVE: | ||
241 | case MS_SHARED: | ||
242 | case 0: | ||
243 | break; | ||
244 | default: | ||
245 | printk(KERN_WARNING "ERROR: " | ||
246 | "%s%s%s%sare given for single mount operation.\n", | ||
247 | flags & MS_UNBINDABLE ? "'unbindable' " : "", | ||
248 | flags & MS_PRIVATE ? "'private' " : "", | ||
249 | flags & MS_SLAVE ? "'slave' " : "", | ||
250 | flags & MS_SHARED ? "'shared' " : ""); | ||
251 | return -EINVAL; | ||
252 | } | ||
253 | if (flags & MS_REMOUNT) | ||
254 | error = tomoyo_mount_acl(r, dev_name, dir, | ||
255 | TOMOYO_MOUNT_REMOUNT_KEYWORD, | ||
256 | flags & ~MS_REMOUNT); | ||
257 | else if (flags & MS_MOVE) | ||
258 | error = tomoyo_mount_acl(r, dev_name, dir, | ||
259 | TOMOYO_MOUNT_MOVE_KEYWORD, | ||
260 | flags & ~MS_MOVE); | ||
261 | else if (flags & MS_BIND) | ||
262 | error = tomoyo_mount_acl(r, dev_name, dir, | ||
263 | TOMOYO_MOUNT_BIND_KEYWORD, | ||
264 | flags & ~MS_BIND); | ||
265 | else if (flags & MS_UNBINDABLE) | ||
266 | error = tomoyo_mount_acl(r, dev_name, dir, | ||
267 | TOMOYO_MOUNT_MAKE_UNBINDABLE_KEYWORD, | ||
268 | flags & ~MS_UNBINDABLE); | ||
269 | else if (flags & MS_PRIVATE) | ||
270 | error = tomoyo_mount_acl(r, dev_name, dir, | ||
271 | TOMOYO_MOUNT_MAKE_PRIVATE_KEYWORD, | ||
272 | flags & ~MS_PRIVATE); | ||
273 | else if (flags & MS_SLAVE) | ||
274 | error = tomoyo_mount_acl(r, dev_name, dir, | ||
275 | TOMOYO_MOUNT_MAKE_SLAVE_KEYWORD, | ||
276 | flags & ~MS_SLAVE); | ||
277 | else if (flags & MS_SHARED) | ||
278 | error = tomoyo_mount_acl(r, dev_name, dir, | ||
279 | TOMOYO_MOUNT_MAKE_SHARED_KEYWORD, | ||
280 | flags & ~MS_SHARED); | ||
281 | else | ||
282 | error = tomoyo_mount_acl2(r, dev_name, dir, type, flags); | ||
283 | if (r->mode != TOMOYO_CONFIG_ENFORCING) | ||
284 | error = 0; | ||
285 | return error; | ||
286 | } | ||
287 | |||
288 | /** | ||
289 | * tomoyo_mount_permission - Check permission for mount() operation. | ||
290 | * | ||
291 | * @dev_name: Name of device file. | ||
292 | * @path: Pointer to "struct path". | ||
293 | * @type: Name of filesystem type. May be NULL. | ||
294 | * @flags: Mount options. | ||
295 | * @data_page: Optional data. May be NULL. | ||
296 | * | ||
297 | * Returns 0 on success, negative value otherwise. | ||
298 | */ | ||
299 | int tomoyo_mount_permission(char *dev_name, struct path *path, char *type, | ||
300 | unsigned long flags, void *data_page) | ||
301 | { | ||
302 | struct tomoyo_request_info r; | ||
303 | int error; | ||
304 | int idx; | ||
305 | |||
306 | if (tomoyo_init_request_info(&r, NULL) == TOMOYO_CONFIG_DISABLED) | ||
307 | return 0; | ||
308 | if (!type) | ||
309 | type = "<NULL>"; | ||
310 | idx = tomoyo_read_lock(); | ||
311 | error = tomoyo_mount_acl(&r, dev_name, path, type, flags); | ||
312 | tomoyo_read_unlock(idx); | ||
313 | return error; | ||
314 | } | ||
315 | |||
316 | /** | ||
317 | * tomoyo_write_mount_policy - Write "struct tomoyo_mount_acl" list. | ||
318 | * | ||
319 | * @data: String to parse. | ||
320 | * @domain: Pointer to "struct tomoyo_domain_info". | ||
321 | * @is_delete: True if it is a delete request. | ||
322 | * | ||
323 | * Returns 0 on success, negative value otherwise. | ||
324 | */ | ||
325 | int tomoyo_write_mount_policy(char *data, struct tomoyo_domain_info *domain, | ||
326 | const bool is_delete) | ||
327 | { | ||
328 | struct tomoyo_acl_info *ptr; | ||
329 | struct tomoyo_mount_acl e = { .head.type = TOMOYO_TYPE_MOUNT_ACL }; | ||
330 | int error = is_delete ? -ENOENT : -ENOMEM; | ||
331 | char *w[4]; | ||
332 | if (!tomoyo_tokenize(data, w, sizeof(w)) || !w[3][0]) | ||
333 | return -EINVAL; | ||
334 | if (!tomoyo_parse_name_union(w[0], &e.dev_name) || | ||
335 | !tomoyo_parse_name_union(w[1], &e.dir_name) || | ||
336 | !tomoyo_parse_name_union(w[2], &e.fs_type) || | ||
337 | !tomoyo_parse_number_union(w[3], &e.flags)) | ||
338 | goto out; | ||
339 | if (mutex_lock_interruptible(&tomoyo_policy_lock)) | ||
340 | goto out; | ||
341 | list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { | ||
342 | struct tomoyo_mount_acl *acl = | ||
343 | container_of(ptr, struct tomoyo_mount_acl, head); | ||
344 | if (!tomoyo_is_same_mount_acl(acl, &e)) | ||
345 | continue; | ||
346 | acl->is_deleted = is_delete; | ||
347 | error = 0; | ||
348 | break; | ||
349 | } | ||
350 | if (!is_delete && error) { | ||
351 | struct tomoyo_mount_acl *entry = | ||
352 | tomoyo_commit_ok(&e, sizeof(e)); | ||
353 | if (entry) { | ||
354 | list_add_tail_rcu(&entry->head.list, | ||
355 | &domain->acl_info_list); | ||
356 | error = 0; | ||
357 | } | ||
358 | } | ||
359 | mutex_unlock(&tomoyo_policy_lock); | ||
360 | out: | ||
361 | tomoyo_put_name_union(&e.dev_name); | ||
362 | tomoyo_put_name_union(&e.dir_name); | ||
363 | tomoyo_put_name_union(&e.fs_type); | ||
364 | tomoyo_put_number_union(&e.flags); | ||
365 | return error; | ||
366 | } | ||
diff --git a/security/tomoyo/tomoyo.c b/security/tomoyo/tomoyo.c index bbe00429b3f5..5d64d409b112 100644 --- a/security/tomoyo/tomoyo.c +++ b/security/tomoyo/tomoyo.c | |||
@@ -226,7 +226,7 @@ static int tomoyo_path_chroot(struct path *path) | |||
226 | static int tomoyo_sb_mount(char *dev_name, struct path *path, | 226 | static int tomoyo_sb_mount(char *dev_name, struct path *path, |
227 | char *type, unsigned long flags, void *data) | 227 | char *type, unsigned long flags, void *data) |
228 | { | 228 | { |
229 | return tomoyo_path_perm(TOMOYO_TYPE_MOUNT, path); | 229 | return tomoyo_mount_permission(dev_name, path, type, flags, data); |
230 | } | 230 | } |
231 | 231 | ||
232 | static int tomoyo_sb_umount(struct vfsmount *mnt, int flags) | 232 | static int tomoyo_sb_umount(struct vfsmount *mnt, int flags) |