diff options
author | James Morris <jmorris@namei.org> | 2009-06-18 18:20:55 -0400 |
---|---|---|
committer | James Morris <jmorris@namei.org> | 2009-06-18 18:20:55 -0400 |
commit | d905163c5b23f6d8511971e06081a1b525e8a0bd (patch) | |
tree | f76918c1be802ec068d37763466f5518efdb690e /security/tomoyo | |
parent | 44c2d9bdd7022ca7d240d5adc009296fc1c6ce08 (diff) | |
parent | 0732f87761dbe417cb6e084b712d07e879e876ef (diff) |
Merge branch 'master' into next
Diffstat (limited to 'security/tomoyo')
-rw-r--r-- | security/tomoyo/common.c | 119 | ||||
-rw-r--r-- | security/tomoyo/common.h | 134 | ||||
-rw-r--r-- | security/tomoyo/domain.c | 240 | ||||
-rw-r--r-- | security/tomoyo/file.c | 156 | ||||
-rw-r--r-- | security/tomoyo/realpath.c | 23 | ||||
-rw-r--r-- | security/tomoyo/tomoyo.c | 4 | ||||
-rw-r--r-- | security/tomoyo/tomoyo.h | 13 |
7 files changed, 549 insertions, 140 deletions
diff --git a/security/tomoyo/common.c b/security/tomoyo/common.c index ddfb9cccf468..fdd1f4b8c448 100644 --- a/security/tomoyo/common.c +++ b/security/tomoyo/common.c | |||
@@ -28,7 +28,13 @@ static const char *tomoyo_mode_2[4] = { | |||
28 | "disabled", "enabled", "enabled", "enabled" | 28 | "disabled", "enabled", "enabled", "enabled" |
29 | }; | 29 | }; |
30 | 30 | ||
31 | /* Table for profile. */ | 31 | /* |
32 | * tomoyo_control_array is a static data which contains | ||
33 | * | ||
34 | * (1) functionality name used by /sys/kernel/security/tomoyo/profile . | ||
35 | * (2) initial values for "struct tomoyo_profile". | ||
36 | * (3) max values for "struct tomoyo_profile". | ||
37 | */ | ||
32 | static struct { | 38 | static struct { |
33 | const char *keyword; | 39 | const char *keyword; |
34 | unsigned int current_value; | 40 | unsigned int current_value; |
@@ -39,7 +45,13 @@ static struct { | |||
39 | [TOMOYO_VERBOSE] = { "TOMOYO_VERBOSE", 1, 1 }, | 45 | [TOMOYO_VERBOSE] = { "TOMOYO_VERBOSE", 1, 1 }, |
40 | }; | 46 | }; |
41 | 47 | ||
42 | /* Profile table. Memory is allocated as needed. */ | 48 | /* |
49 | * tomoyo_profile is a structure which is used for holding the mode of access | ||
50 | * controls. TOMOYO has 4 modes: disabled, learning, permissive, enforcing. | ||
51 | * An administrator can define up to 256 profiles. | ||
52 | * The ->profile of "struct tomoyo_domain_info" is used for remembering | ||
53 | * the profile's number (0 - 255) assigned to that domain. | ||
54 | */ | ||
43 | static struct tomoyo_profile { | 55 | static struct tomoyo_profile { |
44 | unsigned int value[TOMOYO_MAX_CONTROL_INDEX]; | 56 | unsigned int value[TOMOYO_MAX_CONTROL_INDEX]; |
45 | const struct tomoyo_path_info *comment; | 57 | const struct tomoyo_path_info *comment; |
@@ -428,7 +440,6 @@ void tomoyo_fill_path_info(struct tomoyo_path_info *ptr) | |||
428 | const char *name = ptr->name; | 440 | const char *name = ptr->name; |
429 | const int len = strlen(name); | 441 | const int len = strlen(name); |
430 | 442 | ||
431 | ptr->total_len = len; | ||
432 | ptr->const_len = tomoyo_const_part_length(name); | 443 | ptr->const_len = tomoyo_const_part_length(name); |
433 | ptr->is_dir = len && (name[len - 1] == '/'); | 444 | ptr->is_dir = len && (name[len - 1] == '/'); |
434 | ptr->is_patterned = (ptr->const_len < len); | 445 | ptr->is_patterned = (ptr->const_len < len); |
@@ -866,7 +877,6 @@ static struct tomoyo_profile *tomoyo_find_or_assign_new_profile(const unsigned | |||
866 | 877 | ||
867 | if (profile >= TOMOYO_MAX_PROFILES) | 878 | if (profile >= TOMOYO_MAX_PROFILES) |
868 | return NULL; | 879 | return NULL; |
869 | /***** EXCLUSIVE SECTION START *****/ | ||
870 | mutex_lock(&lock); | 880 | mutex_lock(&lock); |
871 | ptr = tomoyo_profile_ptr[profile]; | 881 | ptr = tomoyo_profile_ptr[profile]; |
872 | if (ptr) | 882 | if (ptr) |
@@ -880,7 +890,6 @@ static struct tomoyo_profile *tomoyo_find_or_assign_new_profile(const unsigned | |||
880 | tomoyo_profile_ptr[profile] = ptr; | 890 | tomoyo_profile_ptr[profile] = ptr; |
881 | ok: | 891 | ok: |
882 | mutex_unlock(&lock); | 892 | mutex_unlock(&lock); |
883 | /***** EXCLUSIVE SECTION END *****/ | ||
884 | return ptr; | 893 | return ptr; |
885 | } | 894 | } |
886 | 895 | ||
@@ -1009,7 +1018,19 @@ static int tomoyo_read_profile(struct tomoyo_io_buffer *head) | |||
1009 | return 0; | 1018 | return 0; |
1010 | } | 1019 | } |
1011 | 1020 | ||
1012 | /* Structure for policy manager. */ | 1021 | /* |
1022 | * tomoyo_policy_manager_entry is a structure which is used for holding list of | ||
1023 | * domainnames or programs which are permitted to modify configuration via | ||
1024 | * /sys/kernel/security/tomoyo/ interface. | ||
1025 | * It has following fields. | ||
1026 | * | ||
1027 | * (1) "list" which is linked to tomoyo_policy_manager_list . | ||
1028 | * (2) "manager" is a domainname or a program's pathname. | ||
1029 | * (3) "is_domain" is a bool which is true if "manager" is a domainname, false | ||
1030 | * otherwise. | ||
1031 | * (4) "is_deleted" is a bool which is true if marked as deleted, false | ||
1032 | * otherwise. | ||
1033 | */ | ||
1013 | struct tomoyo_policy_manager_entry { | 1034 | struct tomoyo_policy_manager_entry { |
1014 | struct list_head list; | 1035 | struct list_head list; |
1015 | /* A path to program or a domainname. */ | 1036 | /* A path to program or a domainname. */ |
@@ -1018,7 +1039,36 @@ struct tomoyo_policy_manager_entry { | |||
1018 | bool is_deleted; /* True if this entry is deleted. */ | 1039 | bool is_deleted; /* True if this entry is deleted. */ |
1019 | }; | 1040 | }; |
1020 | 1041 | ||
1021 | /* The list for "struct tomoyo_policy_manager_entry". */ | 1042 | /* |
1043 | * tomoyo_policy_manager_list is used for holding list of domainnames or | ||
1044 | * programs which are permitted to modify configuration via | ||
1045 | * /sys/kernel/security/tomoyo/ interface. | ||
1046 | * | ||
1047 | * An entry is added by | ||
1048 | * | ||
1049 | * # echo '<kernel> /sbin/mingetty /bin/login /bin/bash' > \ | ||
1050 | * /sys/kernel/security/tomoyo/manager | ||
1051 | * (if you want to specify by a domainname) | ||
1052 | * | ||
1053 | * or | ||
1054 | * | ||
1055 | * # echo '/usr/lib/ccs/editpolicy' > /sys/kernel/security/tomoyo/manager | ||
1056 | * (if you want to specify by a program's location) | ||
1057 | * | ||
1058 | * and is deleted by | ||
1059 | * | ||
1060 | * # echo 'delete <kernel> /sbin/mingetty /bin/login /bin/bash' > \ | ||
1061 | * /sys/kernel/security/tomoyo/manager | ||
1062 | * | ||
1063 | * or | ||
1064 | * | ||
1065 | * # echo 'delete /usr/lib/ccs/editpolicy' > \ | ||
1066 | * /sys/kernel/security/tomoyo/manager | ||
1067 | * | ||
1068 | * and all entries are retrieved by | ||
1069 | * | ||
1070 | * # cat /sys/kernel/security/tomoyo/manager | ||
1071 | */ | ||
1022 | static LIST_HEAD(tomoyo_policy_manager_list); | 1072 | static LIST_HEAD(tomoyo_policy_manager_list); |
1023 | static DECLARE_RWSEM(tomoyo_policy_manager_list_lock); | 1073 | static DECLARE_RWSEM(tomoyo_policy_manager_list_lock); |
1024 | 1074 | ||
@@ -1050,7 +1100,6 @@ static int tomoyo_update_manager_entry(const char *manager, | |||
1050 | saved_manager = tomoyo_save_name(manager); | 1100 | saved_manager = tomoyo_save_name(manager); |
1051 | if (!saved_manager) | 1101 | if (!saved_manager) |
1052 | return -ENOMEM; | 1102 | return -ENOMEM; |
1053 | /***** EXCLUSIVE SECTION START *****/ | ||
1054 | down_write(&tomoyo_policy_manager_list_lock); | 1103 | down_write(&tomoyo_policy_manager_list_lock); |
1055 | list_for_each_entry(ptr, &tomoyo_policy_manager_list, list) { | 1104 | list_for_each_entry(ptr, &tomoyo_policy_manager_list, list) { |
1056 | if (ptr->manager != saved_manager) | 1105 | if (ptr->manager != saved_manager) |
@@ -1072,7 +1121,6 @@ static int tomoyo_update_manager_entry(const char *manager, | |||
1072 | error = 0; | 1121 | error = 0; |
1073 | out: | 1122 | out: |
1074 | up_write(&tomoyo_policy_manager_list_lock); | 1123 | up_write(&tomoyo_policy_manager_list_lock); |
1075 | /***** EXCLUSIVE SECTION END *****/ | ||
1076 | return error; | 1124 | return error; |
1077 | } | 1125 | } |
1078 | 1126 | ||
@@ -1117,10 +1165,9 @@ static int tomoyo_read_manager_policy(struct tomoyo_io_buffer *head) | |||
1117 | list); | 1165 | list); |
1118 | if (ptr->is_deleted) | 1166 | if (ptr->is_deleted) |
1119 | continue; | 1167 | continue; |
1120 | if (!tomoyo_io_printf(head, "%s\n", ptr->manager->name)) { | 1168 | done = tomoyo_io_printf(head, "%s\n", ptr->manager->name); |
1121 | done = false; | 1169 | if (!done) |
1122 | break; | 1170 | break; |
1123 | } | ||
1124 | } | 1171 | } |
1125 | up_read(&tomoyo_policy_manager_list_lock); | 1172 | up_read(&tomoyo_policy_manager_list_lock); |
1126 | head->read_eof = done; | 1173 | head->read_eof = done; |
@@ -1197,13 +1244,11 @@ static bool tomoyo_is_select_one(struct tomoyo_io_buffer *head, | |||
1197 | 1244 | ||
1198 | if (sscanf(data, "pid=%u", &pid) == 1) { | 1245 | if (sscanf(data, "pid=%u", &pid) == 1) { |
1199 | struct task_struct *p; | 1246 | struct task_struct *p; |
1200 | /***** CRITICAL SECTION START *****/ | ||
1201 | read_lock(&tasklist_lock); | 1247 | read_lock(&tasklist_lock); |
1202 | p = find_task_by_vpid(pid); | 1248 | p = find_task_by_vpid(pid); |
1203 | if (p) | 1249 | if (p) |
1204 | domain = tomoyo_real_domain(p); | 1250 | domain = tomoyo_real_domain(p); |
1205 | read_unlock(&tasklist_lock); | 1251 | read_unlock(&tasklist_lock); |
1206 | /***** CRITICAL SECTION END *****/ | ||
1207 | } else if (!strncmp(data, "domain=", 7)) { | 1252 | } else if (!strncmp(data, "domain=", 7)) { |
1208 | if (tomoyo_is_domain_def(data + 7)) { | 1253 | if (tomoyo_is_domain_def(data + 7)) { |
1209 | down_read(&tomoyo_domain_list_lock); | 1254 | down_read(&tomoyo_domain_list_lock); |
@@ -1447,15 +1492,14 @@ static int tomoyo_read_domain_policy(struct tomoyo_io_buffer *head) | |||
1447 | TOMOYO_DOMAIN_FLAGS_IGNORE_GLOBAL_ALLOW_READ) | 1492 | TOMOYO_DOMAIN_FLAGS_IGNORE_GLOBAL_ALLOW_READ) |
1448 | ignore_global_allow_read | 1493 | ignore_global_allow_read |
1449 | = TOMOYO_KEYWORD_IGNORE_GLOBAL_ALLOW_READ "\n"; | 1494 | = TOMOYO_KEYWORD_IGNORE_GLOBAL_ALLOW_READ "\n"; |
1450 | if (!tomoyo_io_printf(head, | 1495 | done = tomoyo_io_printf(head, "%s\n" TOMOYO_KEYWORD_USE_PROFILE |
1451 | "%s\n" TOMOYO_KEYWORD_USE_PROFILE "%u\n" | 1496 | "%u\n%s%s%s\n", |
1452 | "%s%s%s\n", domain->domainname->name, | 1497 | domain->domainname->name, |
1453 | domain->profile, quota_exceeded, | 1498 | domain->profile, quota_exceeded, |
1454 | transition_failed, | 1499 | transition_failed, |
1455 | ignore_global_allow_read)) { | 1500 | ignore_global_allow_read); |
1456 | done = false; | 1501 | if (!done) |
1457 | break; | 1502 | break; |
1458 | } | ||
1459 | head->read_step = 2; | 1503 | head->read_step = 2; |
1460 | acl_loop: | 1504 | acl_loop: |
1461 | if (head->read_step == 3) | 1505 | if (head->read_step == 3) |
@@ -1463,24 +1507,22 @@ acl_loop: | |||
1463 | /* Print ACL entries in the domain. */ | 1507 | /* Print ACL entries in the domain. */ |
1464 | down_read(&tomoyo_domain_acl_info_list_lock); | 1508 | down_read(&tomoyo_domain_acl_info_list_lock); |
1465 | list_for_each_cookie(apos, head->read_var2, | 1509 | list_for_each_cookie(apos, head->read_var2, |
1466 | &domain->acl_info_list) { | 1510 | &domain->acl_info_list) { |
1467 | struct tomoyo_acl_info *ptr | 1511 | struct tomoyo_acl_info *ptr |
1468 | = list_entry(apos, struct tomoyo_acl_info, | 1512 | = list_entry(apos, struct tomoyo_acl_info, |
1469 | list); | 1513 | list); |
1470 | if (!tomoyo_print_entry(head, ptr)) { | 1514 | done = tomoyo_print_entry(head, ptr); |
1471 | done = false; | 1515 | if (!done) |
1472 | break; | 1516 | break; |
1473 | } | ||
1474 | } | 1517 | } |
1475 | up_read(&tomoyo_domain_acl_info_list_lock); | 1518 | up_read(&tomoyo_domain_acl_info_list_lock); |
1476 | if (!done) | 1519 | if (!done) |
1477 | break; | 1520 | break; |
1478 | head->read_step = 3; | 1521 | head->read_step = 3; |
1479 | tail_mark: | 1522 | tail_mark: |
1480 | if (!tomoyo_io_printf(head, "\n")) { | 1523 | done = tomoyo_io_printf(head, "\n"); |
1481 | done = false; | 1524 | if (!done) |
1482 | break; | 1525 | break; |
1483 | } | ||
1484 | head->read_step = 1; | 1526 | head->read_step = 1; |
1485 | if (head->read_single_domain) | 1527 | if (head->read_single_domain) |
1486 | break; | 1528 | break; |
@@ -1550,11 +1592,10 @@ static int tomoyo_read_domain_profile(struct tomoyo_io_buffer *head) | |||
1550 | domain = list_entry(pos, struct tomoyo_domain_info, list); | 1592 | domain = list_entry(pos, struct tomoyo_domain_info, list); |
1551 | if (domain->is_deleted) | 1593 | if (domain->is_deleted) |
1552 | continue; | 1594 | continue; |
1553 | if (!tomoyo_io_printf(head, "%u %s\n", domain->profile, | 1595 | done = tomoyo_io_printf(head, "%u %s\n", domain->profile, |
1554 | domain->domainname->name)) { | 1596 | domain->domainname->name); |
1555 | done = false; | 1597 | if (!done) |
1556 | break; | 1598 | break; |
1557 | } | ||
1558 | } | 1599 | } |
1559 | up_read(&tomoyo_domain_list_lock); | 1600 | up_read(&tomoyo_domain_list_lock); |
1560 | head->read_eof = done; | 1601 | head->read_eof = done; |
@@ -1594,13 +1635,11 @@ static int tomoyo_read_pid(struct tomoyo_io_buffer *head) | |||
1594 | const int pid = head->read_step; | 1635 | const int pid = head->read_step; |
1595 | struct task_struct *p; | 1636 | struct task_struct *p; |
1596 | struct tomoyo_domain_info *domain = NULL; | 1637 | struct tomoyo_domain_info *domain = NULL; |
1597 | /***** CRITICAL SECTION START *****/ | ||
1598 | read_lock(&tasklist_lock); | 1638 | read_lock(&tasklist_lock); |
1599 | p = find_task_by_vpid(pid); | 1639 | p = find_task_by_vpid(pid); |
1600 | if (p) | 1640 | if (p) |
1601 | domain = tomoyo_real_domain(p); | 1641 | domain = tomoyo_real_domain(p); |
1602 | read_unlock(&tasklist_lock); | 1642 | read_unlock(&tasklist_lock); |
1603 | /***** CRITICAL SECTION END *****/ | ||
1604 | if (domain) | 1643 | if (domain) |
1605 | tomoyo_io_printf(head, "%d %u %s", pid, domain->profile, | 1644 | tomoyo_io_printf(head, "%d %u %s", pid, domain->profile, |
1606 | domain->domainname->name); | 1645 | domain->domainname->name); |
@@ -2138,7 +2177,13 @@ static ssize_t tomoyo_write(struct file *file, const char __user *buf, | |||
2138 | return tomoyo_write_control(file, buf, count); | 2177 | return tomoyo_write_control(file, buf, count); |
2139 | } | 2178 | } |
2140 | 2179 | ||
2141 | /* Operations for /sys/kernel/security/tomoyo/ interface. */ | 2180 | /* |
2181 | * tomoyo_operations is a "struct file_operations" which is used for handling | ||
2182 | * /sys/kernel/security/tomoyo/ interface. | ||
2183 | * | ||
2184 | * Some files under /sys/kernel/security/tomoyo/ directory accept open(O_RDWR). | ||
2185 | * See tomoyo_io_buffer for internals. | ||
2186 | */ | ||
2142 | static const struct file_operations tomoyo_operations = { | 2187 | static const struct file_operations tomoyo_operations = { |
2143 | .open = tomoyo_open, | 2188 | .open = tomoyo_open, |
2144 | .release = tomoyo_release, | 2189 | .release = tomoyo_release, |
diff --git a/security/tomoyo/common.h b/security/tomoyo/common.h index 678f4ff16aa4..6d6ba09af457 100644 --- a/security/tomoyo/common.h +++ b/security/tomoyo/common.h | |||
@@ -26,16 +26,43 @@ | |||
26 | struct dentry; | 26 | struct dentry; |
27 | struct vfsmount; | 27 | struct vfsmount; |
28 | 28 | ||
29 | /* Temporary buffer for holding pathnames. */ | 29 | /* |
30 | * tomoyo_page_buffer is a structure which is used for holding a pathname | ||
31 | * obtained from "struct dentry" and "struct vfsmount" pair. | ||
32 | * As of now, it is 4096 bytes. If users complain that 4096 bytes is too small | ||
33 | * (because TOMOYO escapes non ASCII printable characters using \ooo format), | ||
34 | * we will make the buffer larger. | ||
35 | */ | ||
30 | struct tomoyo_page_buffer { | 36 | struct tomoyo_page_buffer { |
31 | char buffer[4096]; | 37 | char buffer[4096]; |
32 | }; | 38 | }; |
33 | 39 | ||
34 | /* Structure for holding a token. */ | 40 | /* |
41 | * tomoyo_path_info is a structure which is used for holding a string data | ||
42 | * used by TOMOYO. | ||
43 | * This structure has several fields for supporting pattern matching. | ||
44 | * | ||
45 | * (1) "name" is the '\0' terminated string data. | ||
46 | * (2) "hash" is full_name_hash(name, strlen(name)). | ||
47 | * This allows tomoyo_pathcmp() to compare by hash before actually compare | ||
48 | * using strcmp(). | ||
49 | * (3) "const_len" is the length of the initial segment of "name" which | ||
50 | * consists entirely of non wildcard characters. In other words, the length | ||
51 | * which we can compare two strings using strncmp(). | ||
52 | * (4) "is_dir" is a bool which is true if "name" ends with "/", | ||
53 | * false otherwise. | ||
54 | * TOMOYO distinguishes directory and non-directory. A directory ends with | ||
55 | * "/" and non-directory does not end with "/". | ||
56 | * (5) "is_patterned" is a bool which is true if "name" contains wildcard | ||
57 | * characters, false otherwise. This allows TOMOYO to use "hash" and | ||
58 | * strcmp() for string comparison if "is_patterned" is false. | ||
59 | * (6) "depth" is calculated using the number of "/" characters in "name". | ||
60 | * This allows TOMOYO to avoid comparing two pathnames which never match | ||
61 | * (e.g. whether "/var/www/html/index.html" matches "/tmp/sh-thd-\$"). | ||
62 | */ | ||
35 | struct tomoyo_path_info { | 63 | struct tomoyo_path_info { |
36 | const char *name; | 64 | const char *name; |
37 | u32 hash; /* = full_name_hash(name, strlen(name)) */ | 65 | u32 hash; /* = full_name_hash(name, strlen(name)) */ |
38 | u16 total_len; /* = strlen(name) */ | ||
39 | u16 const_len; /* = tomoyo_const_part_length(name) */ | 66 | u16 const_len; /* = tomoyo_const_part_length(name) */ |
40 | bool is_dir; /* = tomoyo_strendswith(name, "/") */ | 67 | bool is_dir; /* = tomoyo_strendswith(name, "/") */ |
41 | bool is_patterned; /* = tomoyo_path_contains_pattern(name) */ | 68 | bool is_patterned; /* = tomoyo_path_contains_pattern(name) */ |
@@ -51,7 +78,20 @@ struct tomoyo_path_info { | |||
51 | */ | 78 | */ |
52 | #define TOMOYO_MAX_PATHNAME_LEN 4000 | 79 | #define TOMOYO_MAX_PATHNAME_LEN 4000 |
53 | 80 | ||
54 | /* Structure for holding requested pathname. */ | 81 | /* |
82 | * tomoyo_path_info_with_data is a structure which is used for holding a | ||
83 | * pathname obtained from "struct dentry" and "struct vfsmount" pair. | ||
84 | * | ||
85 | * "struct tomoyo_path_info_with_data" consists of "struct tomoyo_path_info" | ||
86 | * and buffer for the pathname, while "struct tomoyo_page_buffer" consists of | ||
87 | * buffer for the pathname only. | ||
88 | * | ||
89 | * "struct tomoyo_path_info_with_data" is intended to allow TOMOYO to release | ||
90 | * both "struct tomoyo_path_info" and buffer for the pathname by single kfree() | ||
91 | * so that we don't need to return two pointers to the caller. If the caller | ||
92 | * puts "struct tomoyo_path_info" on stack memory, we will be able to remove | ||
93 | * "struct tomoyo_path_info_with_data". | ||
94 | */ | ||
55 | struct tomoyo_path_info_with_data { | 95 | struct tomoyo_path_info_with_data { |
56 | /* Keep "head" first, for this pointer is passed to tomoyo_free(). */ | 96 | /* Keep "head" first, for this pointer is passed to tomoyo_free(). */ |
57 | struct tomoyo_path_info head; | 97 | struct tomoyo_path_info head; |
@@ -61,7 +101,15 @@ struct tomoyo_path_info_with_data { | |||
61 | }; | 101 | }; |
62 | 102 | ||
63 | /* | 103 | /* |
64 | * Common header for holding ACL entries. | 104 | * tomoyo_acl_info is a structure which is used for holding |
105 | * | ||
106 | * (1) "list" which is linked to the ->acl_info_list of | ||
107 | * "struct tomoyo_domain_info" | ||
108 | * (2) "type" which tells | ||
109 | * (a) type & 0x7F : type of the entry (either | ||
110 | * "struct tomoyo_single_path_acl_record" or | ||
111 | * "struct tomoyo_double_path_acl_record") | ||
112 | * (b) type & 0x80 : whether the entry is marked as "deleted". | ||
65 | * | 113 | * |
66 | * Packing "struct tomoyo_acl_info" allows | 114 | * Packing "struct tomoyo_acl_info" allows |
67 | * "struct tomoyo_single_path_acl_record" to embed "u16" and | 115 | * "struct tomoyo_single_path_acl_record" to embed "u16" and |
@@ -81,7 +129,28 @@ struct tomoyo_acl_info { | |||
81 | /* This ACL entry is deleted. */ | 129 | /* This ACL entry is deleted. */ |
82 | #define TOMOYO_ACL_DELETED 0x80 | 130 | #define TOMOYO_ACL_DELETED 0x80 |
83 | 131 | ||
84 | /* Structure for domain information. */ | 132 | /* |
133 | * tomoyo_domain_info is a structure which is used for holding permissions | ||
134 | * (e.g. "allow_read /lib/libc-2.5.so") given to each domain. | ||
135 | * It has following fields. | ||
136 | * | ||
137 | * (1) "list" which is linked to tomoyo_domain_list . | ||
138 | * (2) "acl_info_list" which is linked to "struct tomoyo_acl_info". | ||
139 | * (3) "domainname" which holds the name of the domain. | ||
140 | * (4) "profile" which remembers profile number assigned to this domain. | ||
141 | * (5) "is_deleted" is a bool which is true if this domain is marked as | ||
142 | * "deleted", false otherwise. | ||
143 | * (6) "quota_warned" is a bool which is used for suppressing warning message | ||
144 | * when learning mode learned too much entries. | ||
145 | * (7) "flags" which remembers this domain's attributes. | ||
146 | * | ||
147 | * A domain's lifecycle is an analogy of files on / directory. | ||
148 | * Multiple domains with the same domainname cannot be created (as with | ||
149 | * creating files with the same filename fails with -EEXIST). | ||
150 | * If a process reached a domain, that process can reside in that domain after | ||
151 | * that domain is marked as "deleted" (as with a process can access an already | ||
152 | * open()ed file after that file was unlink()ed). | ||
153 | */ | ||
85 | struct tomoyo_domain_info { | 154 | struct tomoyo_domain_info { |
86 | struct list_head list; | 155 | struct list_head list; |
87 | struct list_head acl_info_list; | 156 | struct list_head acl_info_list; |
@@ -108,10 +177,18 @@ struct tomoyo_domain_info { | |||
108 | #define TOMOYO_DOMAIN_FLAGS_TRANSITION_FAILED 2 | 177 | #define TOMOYO_DOMAIN_FLAGS_TRANSITION_FAILED 2 |
109 | 178 | ||
110 | /* | 179 | /* |
111 | * Structure for "allow_read/write", "allow_execute", "allow_read", | 180 | * tomoyo_single_path_acl_record is a structure which is used for holding an |
112 | * "allow_write", "allow_create", "allow_unlink", "allow_mkdir", "allow_rmdir", | 181 | * entry with one pathname operation (e.g. open(), mkdir()). |
113 | * "allow_mkfifo", "allow_mksock", "allow_mkblock", "allow_mkchar", | 182 | * It has following fields. |
114 | * "allow_truncate", "allow_symlink" and "allow_rewrite" directive. | 183 | * |
184 | * (1) "head" which is a "struct tomoyo_acl_info". | ||
185 | * (2) "perm" which is a bitmask of permitted operations. | ||
186 | * (3) "filename" is the pathname. | ||
187 | * | ||
188 | * Directives held by this structure are "allow_read/write", "allow_execute", | ||
189 | * "allow_read", "allow_write", "allow_create", "allow_unlink", "allow_mkdir", | ||
190 | * "allow_rmdir", "allow_mkfifo", "allow_mksock", "allow_mkblock", | ||
191 | * "allow_mkchar", "allow_truncate", "allow_symlink" and "allow_rewrite". | ||
115 | */ | 192 | */ |
116 | struct tomoyo_single_path_acl_record { | 193 | struct tomoyo_single_path_acl_record { |
117 | struct tomoyo_acl_info head; /* type = TOMOYO_TYPE_SINGLE_PATH_ACL */ | 194 | struct tomoyo_acl_info head; /* type = TOMOYO_TYPE_SINGLE_PATH_ACL */ |
@@ -120,7 +197,18 @@ struct tomoyo_single_path_acl_record { | |||
120 | const struct tomoyo_path_info *filename; | 197 | const struct tomoyo_path_info *filename; |
121 | }; | 198 | }; |
122 | 199 | ||
123 | /* Structure for "allow_rename" and "allow_link" directive. */ | 200 | /* |
201 | * tomoyo_double_path_acl_record is a structure which is used for holding an | ||
202 | * entry with two pathnames operation (i.e. link() and rename()). | ||
203 | * It has following fields. | ||
204 | * | ||
205 | * (1) "head" which is a "struct tomoyo_acl_info". | ||
206 | * (2) "perm" which is a bitmask of permitted operations. | ||
207 | * (3) "filename1" is the source/old pathname. | ||
208 | * (4) "filename2" is the destination/new pathname. | ||
209 | * | ||
210 | * Directives held by this structure are "allow_rename" and "allow_link". | ||
211 | */ | ||
124 | struct tomoyo_double_path_acl_record { | 212 | struct tomoyo_double_path_acl_record { |
125 | struct tomoyo_acl_info head; /* type = TOMOYO_TYPE_DOUBLE_PATH_ACL */ | 213 | struct tomoyo_acl_info head; /* type = TOMOYO_TYPE_DOUBLE_PATH_ACL */ |
126 | u8 perm; | 214 | u8 perm; |
@@ -153,7 +241,29 @@ struct tomoyo_double_path_acl_record { | |||
153 | #define TOMOYO_VERBOSE 2 | 241 | #define TOMOYO_VERBOSE 2 |
154 | #define TOMOYO_MAX_CONTROL_INDEX 3 | 242 | #define TOMOYO_MAX_CONTROL_INDEX 3 |
155 | 243 | ||
156 | /* Structure for reading/writing policy via securityfs interfaces. */ | 244 | /* |
245 | * tomoyo_io_buffer is a structure which is used for reading and modifying | ||
246 | * configuration via /sys/kernel/security/tomoyo/ interface. | ||
247 | * It has many fields. ->read_var1 , ->read_var2 , ->write_var1 are used as | ||
248 | * cursors. | ||
249 | * | ||
250 | * Since the content of /sys/kernel/security/tomoyo/domain_policy is a list of | ||
251 | * "struct tomoyo_domain_info" entries and each "struct tomoyo_domain_info" | ||
252 | * entry has a list of "struct tomoyo_acl_info", we need two cursors when | ||
253 | * reading (one is for traversing tomoyo_domain_list and the other is for | ||
254 | * traversing "struct tomoyo_acl_info"->acl_info_list ). | ||
255 | * | ||
256 | * If a line written to /sys/kernel/security/tomoyo/domain_policy starts with | ||
257 | * "select ", TOMOYO seeks the cursor ->read_var1 and ->write_var1 to the | ||
258 | * domain with the domainname specified by the rest of that line (NULL is set | ||
259 | * if seek failed). | ||
260 | * If a line written to /sys/kernel/security/tomoyo/domain_policy starts with | ||
261 | * "delete ", TOMOYO deletes an entry or a domain specified by the rest of that | ||
262 | * line (->write_var1 is set to NULL if a domain was deleted). | ||
263 | * If a line written to /sys/kernel/security/tomoyo/domain_policy starts with | ||
264 | * neither "select " nor "delete ", an entry or a domain specified by that line | ||
265 | * is appended. | ||
266 | */ | ||
157 | struct tomoyo_io_buffer { | 267 | struct tomoyo_io_buffer { |
158 | int (*read) (struct tomoyo_io_buffer *); | 268 | int (*read) (struct tomoyo_io_buffer *); |
159 | int (*write) (struct tomoyo_io_buffer *); | 269 | int (*write) (struct tomoyo_io_buffer *); |
diff --git a/security/tomoyo/domain.c b/security/tomoyo/domain.c index 2d6748741a26..1d8b16960576 100644 --- a/security/tomoyo/domain.c +++ b/security/tomoyo/domain.c | |||
@@ -19,11 +19,63 @@ | |||
19 | /* The initial domain. */ | 19 | /* The initial domain. */ |
20 | struct tomoyo_domain_info tomoyo_kernel_domain; | 20 | struct tomoyo_domain_info tomoyo_kernel_domain; |
21 | 21 | ||
22 | /* The list for "struct tomoyo_domain_info". */ | 22 | /* |
23 | * tomoyo_domain_list is used for holding list of domains. | ||
24 | * The ->acl_info_list of "struct tomoyo_domain_info" is used for holding | ||
25 | * permissions (e.g. "allow_read /lib/libc-2.5.so") given to each domain. | ||
26 | * | ||
27 | * An entry is added by | ||
28 | * | ||
29 | * # ( echo "<kernel>"; echo "allow_execute /sbin/init" ) > \ | ||
30 | * /sys/kernel/security/tomoyo/domain_policy | ||
31 | * | ||
32 | * and is deleted by | ||
33 | * | ||
34 | * # ( echo "<kernel>"; echo "delete allow_execute /sbin/init" ) > \ | ||
35 | * /sys/kernel/security/tomoyo/domain_policy | ||
36 | * | ||
37 | * and all entries are retrieved by | ||
38 | * | ||
39 | * # cat /sys/kernel/security/tomoyo/domain_policy | ||
40 | * | ||
41 | * A domain is added by | ||
42 | * | ||
43 | * # echo "<kernel>" > /sys/kernel/security/tomoyo/domain_policy | ||
44 | * | ||
45 | * and is deleted by | ||
46 | * | ||
47 | * # echo "delete <kernel>" > /sys/kernel/security/tomoyo/domain_policy | ||
48 | * | ||
49 | * and all domains are retrieved by | ||
50 | * | ||
51 | * # grep '^<kernel>' /sys/kernel/security/tomoyo/domain_policy | ||
52 | * | ||
53 | * Normally, a domainname is monotonically getting longer because a domainname | ||
54 | * which the process will belong to if an execve() operation succeeds is | ||
55 | * defined as a concatenation of "current domainname" + "pathname passed to | ||
56 | * execve()". | ||
57 | * See tomoyo_domain_initializer_list and tomoyo_domain_keeper_list for | ||
58 | * exceptions. | ||
59 | */ | ||
23 | LIST_HEAD(tomoyo_domain_list); | 60 | LIST_HEAD(tomoyo_domain_list); |
24 | DECLARE_RWSEM(tomoyo_domain_list_lock); | 61 | DECLARE_RWSEM(tomoyo_domain_list_lock); |
25 | 62 | ||
26 | /* Structure for "initialize_domain" and "no_initialize_domain" keyword. */ | 63 | /* |
64 | * tomoyo_domain_initializer_entry is a structure which is used for holding | ||
65 | * "initialize_domain" and "no_initialize_domain" entries. | ||
66 | * It has following fields. | ||
67 | * | ||
68 | * (1) "list" which is linked to tomoyo_domain_initializer_list . | ||
69 | * (2) "domainname" which is "a domainname" or "the last component of a | ||
70 | * domainname". This field is NULL if "from" clause is not specified. | ||
71 | * (3) "program" which is a program's pathname. | ||
72 | * (4) "is_deleted" is a bool which is true if marked as deleted, false | ||
73 | * otherwise. | ||
74 | * (5) "is_not" is a bool which is true if "no_initialize_domain", false | ||
75 | * otherwise. | ||
76 | * (6) "is_last_name" is a bool which is true if "domainname" is "the last | ||
77 | * component of a domainname", false otherwise. | ||
78 | */ | ||
27 | struct tomoyo_domain_initializer_entry { | 79 | struct tomoyo_domain_initializer_entry { |
28 | struct list_head list; | 80 | struct list_head list; |
29 | const struct tomoyo_path_info *domainname; /* This may be NULL */ | 81 | const struct tomoyo_path_info *domainname; /* This may be NULL */ |
@@ -34,7 +86,23 @@ struct tomoyo_domain_initializer_entry { | |||
34 | bool is_last_name; | 86 | bool is_last_name; |
35 | }; | 87 | }; |
36 | 88 | ||
37 | /* Structure for "keep_domain" and "no_keep_domain" keyword. */ | 89 | /* |
90 | * tomoyo_domain_keeper_entry is a structure which is used for holding | ||
91 | * "keep_domain" and "no_keep_domain" entries. | ||
92 | * It has following fields. | ||
93 | * | ||
94 | * (1) "list" which is linked to tomoyo_domain_keeper_list . | ||
95 | * (2) "domainname" which is "a domainname" or "the last component of a | ||
96 | * domainname". | ||
97 | * (3) "program" which is a program's pathname. | ||
98 | * This field is NULL if "from" clause is not specified. | ||
99 | * (4) "is_deleted" is a bool which is true if marked as deleted, false | ||
100 | * otherwise. | ||
101 | * (5) "is_not" is a bool which is true if "no_initialize_domain", false | ||
102 | * otherwise. | ||
103 | * (6) "is_last_name" is a bool which is true if "domainname" is "the last | ||
104 | * component of a domainname", false otherwise. | ||
105 | */ | ||
38 | struct tomoyo_domain_keeper_entry { | 106 | struct tomoyo_domain_keeper_entry { |
39 | struct list_head list; | 107 | struct list_head list; |
40 | const struct tomoyo_path_info *domainname; | 108 | const struct tomoyo_path_info *domainname; |
@@ -45,7 +113,16 @@ struct tomoyo_domain_keeper_entry { | |||
45 | bool is_last_name; | 113 | bool is_last_name; |
46 | }; | 114 | }; |
47 | 115 | ||
48 | /* Structure for "alias" keyword. */ | 116 | /* |
117 | * tomoyo_alias_entry is a structure which is used for holding "alias" entries. | ||
118 | * It has following fields. | ||
119 | * | ||
120 | * (1) "list" which is linked to tomoyo_alias_list . | ||
121 | * (2) "original_name" which is a dereferenced pathname. | ||
122 | * (3) "aliased_name" which is a symlink's pathname. | ||
123 | * (4) "is_deleted" is a bool which is true if marked as deleted, false | ||
124 | * otherwise. | ||
125 | */ | ||
49 | struct tomoyo_alias_entry { | 126 | struct tomoyo_alias_entry { |
50 | struct list_head list; | 127 | struct list_head list; |
51 | const struct tomoyo_path_info *original_name; | 128 | const struct tomoyo_path_info *original_name; |
@@ -67,14 +144,12 @@ void tomoyo_set_domain_flag(struct tomoyo_domain_info *domain, | |||
67 | { | 144 | { |
68 | /* We need to serialize because this is bitfield operation. */ | 145 | /* We need to serialize because this is bitfield operation. */ |
69 | static DEFINE_SPINLOCK(lock); | 146 | static DEFINE_SPINLOCK(lock); |
70 | /***** CRITICAL SECTION START *****/ | ||
71 | spin_lock(&lock); | 147 | spin_lock(&lock); |
72 | if (!is_delete) | 148 | if (!is_delete) |
73 | domain->flags |= flags; | 149 | domain->flags |= flags; |
74 | else | 150 | else |
75 | domain->flags &= ~flags; | 151 | domain->flags &= ~flags; |
76 | spin_unlock(&lock); | 152 | spin_unlock(&lock); |
77 | /***** CRITICAL SECTION END *****/ | ||
78 | } | 153 | } |
79 | 154 | ||
80 | /** | 155 | /** |
@@ -94,7 +169,42 @@ const char *tomoyo_get_last_name(const struct tomoyo_domain_info *domain) | |||
94 | return cp0; | 169 | return cp0; |
95 | } | 170 | } |
96 | 171 | ||
97 | /* The list for "struct tomoyo_domain_initializer_entry". */ | 172 | /* |
173 | * tomoyo_domain_initializer_list is used for holding list of programs which | ||
174 | * triggers reinitialization of domainname. Normally, a domainname is | ||
175 | * monotonically getting longer. But sometimes, we restart daemon programs. | ||
176 | * It would be convenient for us that "a daemon started upon system boot" and | ||
177 | * "the daemon restarted from console" belong to the same domain. Thus, TOMOYO | ||
178 | * provides a way to shorten domainnames. | ||
179 | * | ||
180 | * An entry is added by | ||
181 | * | ||
182 | * # echo 'initialize_domain /usr/sbin/httpd' > \ | ||
183 | * /sys/kernel/security/tomoyo/exception_policy | ||
184 | * | ||
185 | * and is deleted by | ||
186 | * | ||
187 | * # echo 'delete initialize_domain /usr/sbin/httpd' > \ | ||
188 | * /sys/kernel/security/tomoyo/exception_policy | ||
189 | * | ||
190 | * and all entries are retrieved by | ||
191 | * | ||
192 | * # grep ^initialize_domain /sys/kernel/security/tomoyo/exception_policy | ||
193 | * | ||
194 | * In the example above, /usr/sbin/httpd will belong to | ||
195 | * "<kernel> /usr/sbin/httpd" domain. | ||
196 | * | ||
197 | * You may specify a domainname using "from" keyword. | ||
198 | * "initialize_domain /usr/sbin/httpd from <kernel> /etc/rc.d/init.d/httpd" | ||
199 | * will cause "/usr/sbin/httpd" executed from "<kernel> /etc/rc.d/init.d/httpd" | ||
200 | * domain to belong to "<kernel> /usr/sbin/httpd" domain. | ||
201 | * | ||
202 | * You may add "no_" prefix to "initialize_domain". | ||
203 | * "initialize_domain /usr/sbin/httpd" and | ||
204 | * "no_initialize_domain /usr/sbin/httpd from <kernel> /etc/rc.d/init.d/httpd" | ||
205 | * will cause "/usr/sbin/httpd" to belong to "<kernel> /usr/sbin/httpd" domain | ||
206 | * unless executed from "<kernel> /etc/rc.d/init.d/httpd" domain. | ||
207 | */ | ||
98 | static LIST_HEAD(tomoyo_domain_initializer_list); | 208 | static LIST_HEAD(tomoyo_domain_initializer_list); |
99 | static DECLARE_RWSEM(tomoyo_domain_initializer_list_lock); | 209 | static DECLARE_RWSEM(tomoyo_domain_initializer_list_lock); |
100 | 210 | ||
@@ -135,7 +245,6 @@ static int tomoyo_update_domain_initializer_entry(const char *domainname, | |||
135 | saved_program = tomoyo_save_name(program); | 245 | saved_program = tomoyo_save_name(program); |
136 | if (!saved_program) | 246 | if (!saved_program) |
137 | return -ENOMEM; | 247 | return -ENOMEM; |
138 | /***** EXCLUSIVE SECTION START *****/ | ||
139 | down_write(&tomoyo_domain_initializer_list_lock); | 248 | down_write(&tomoyo_domain_initializer_list_lock); |
140 | list_for_each_entry(ptr, &tomoyo_domain_initializer_list, list) { | 249 | list_for_each_entry(ptr, &tomoyo_domain_initializer_list, list) { |
141 | if (ptr->is_not != is_not || | 250 | if (ptr->is_not != is_not || |
@@ -161,7 +270,6 @@ static int tomoyo_update_domain_initializer_entry(const char *domainname, | |||
161 | error = 0; | 270 | error = 0; |
162 | out: | 271 | out: |
163 | up_write(&tomoyo_domain_initializer_list_lock); | 272 | up_write(&tomoyo_domain_initializer_list_lock); |
164 | /***** EXCLUSIVE SECTION END *****/ | ||
165 | return error; | 273 | return error; |
166 | } | 274 | } |
167 | 275 | ||
@@ -193,13 +301,12 @@ bool tomoyo_read_domain_initializer_policy(struct tomoyo_io_buffer *head) | |||
193 | from = " from "; | 301 | from = " from "; |
194 | domain = ptr->domainname->name; | 302 | domain = ptr->domainname->name; |
195 | } | 303 | } |
196 | if (!tomoyo_io_printf(head, | 304 | done = tomoyo_io_printf(head, |
197 | "%s" TOMOYO_KEYWORD_INITIALIZE_DOMAIN | 305 | "%s" TOMOYO_KEYWORD_INITIALIZE_DOMAIN |
198 | "%s%s%s\n", no, ptr->program->name, from, | 306 | "%s%s%s\n", no, ptr->program->name, |
199 | domain)) { | 307 | from, domain); |
200 | done = false; | 308 | if (!done) |
201 | break; | 309 | break; |
202 | } | ||
203 | } | 310 | } |
204 | up_read(&tomoyo_domain_initializer_list_lock); | 311 | up_read(&tomoyo_domain_initializer_list_lock); |
205 | return done; | 312 | return done; |
@@ -273,7 +380,44 @@ static bool tomoyo_is_domain_initializer(const struct tomoyo_path_info * | |||
273 | return flag; | 380 | return flag; |
274 | } | 381 | } |
275 | 382 | ||
276 | /* The list for "struct tomoyo_domain_keeper_entry". */ | 383 | /* |
384 | * tomoyo_domain_keeper_list is used for holding list of domainnames which | ||
385 | * suppresses domain transition. Normally, a domainname is monotonically | ||
386 | * getting longer. But sometimes, we want to suppress domain transition. | ||
387 | * It would be convenient for us that programs executed from a login session | ||
388 | * belong to the same domain. Thus, TOMOYO provides a way to suppress domain | ||
389 | * transition. | ||
390 | * | ||
391 | * An entry is added by | ||
392 | * | ||
393 | * # echo 'keep_domain <kernel> /usr/sbin/sshd /bin/bash' > \ | ||
394 | * /sys/kernel/security/tomoyo/exception_policy | ||
395 | * | ||
396 | * and is deleted by | ||
397 | * | ||
398 | * # echo 'delete keep_domain <kernel> /usr/sbin/sshd /bin/bash' > \ | ||
399 | * /sys/kernel/security/tomoyo/exception_policy | ||
400 | * | ||
401 | * and all entries are retrieved by | ||
402 | * | ||
403 | * # grep ^keep_domain /sys/kernel/security/tomoyo/exception_policy | ||
404 | * | ||
405 | * In the example above, any process which belongs to | ||
406 | * "<kernel> /usr/sbin/sshd /bin/bash" domain will remain in that domain, | ||
407 | * unless explicitly specified by "initialize_domain" or "no_keep_domain". | ||
408 | * | ||
409 | * You may specify a program using "from" keyword. | ||
410 | * "keep_domain /bin/pwd from <kernel> /usr/sbin/sshd /bin/bash" | ||
411 | * will cause "/bin/pwd" executed from "<kernel> /usr/sbin/sshd /bin/bash" | ||
412 | * domain to remain in "<kernel> /usr/sbin/sshd /bin/bash" domain. | ||
413 | * | ||
414 | * You may add "no_" prefix to "keep_domain". | ||
415 | * "keep_domain <kernel> /usr/sbin/sshd /bin/bash" and | ||
416 | * "no_keep_domain /usr/bin/passwd from <kernel> /usr/sbin/sshd /bin/bash" will | ||
417 | * cause "/usr/bin/passwd" to belong to | ||
418 | * "<kernel> /usr/sbin/sshd /bin/bash /usr/bin/passwd" domain, unless | ||
419 | * explicitly specified by "initialize_domain". | ||
420 | */ | ||
277 | static LIST_HEAD(tomoyo_domain_keeper_list); | 421 | static LIST_HEAD(tomoyo_domain_keeper_list); |
278 | static DECLARE_RWSEM(tomoyo_domain_keeper_list_lock); | 422 | static DECLARE_RWSEM(tomoyo_domain_keeper_list_lock); |
279 | 423 | ||
@@ -296,7 +440,6 @@ static int tomoyo_update_domain_keeper_entry(const char *domainname, | |||
296 | struct tomoyo_domain_keeper_entry *ptr; | 440 | struct tomoyo_domain_keeper_entry *ptr; |
297 | const struct tomoyo_path_info *saved_domainname; | 441 | const struct tomoyo_path_info *saved_domainname; |
298 | const struct tomoyo_path_info *saved_program = NULL; | 442 | const struct tomoyo_path_info *saved_program = NULL; |
299 | static DEFINE_MUTEX(lock); | ||
300 | int error = -ENOMEM; | 443 | int error = -ENOMEM; |
301 | bool is_last_name = false; | 444 | bool is_last_name = false; |
302 | 445 | ||
@@ -315,7 +458,6 @@ static int tomoyo_update_domain_keeper_entry(const char *domainname, | |||
315 | saved_domainname = tomoyo_save_name(domainname); | 458 | saved_domainname = tomoyo_save_name(domainname); |
316 | if (!saved_domainname) | 459 | if (!saved_domainname) |
317 | return -ENOMEM; | 460 | return -ENOMEM; |
318 | /***** EXCLUSIVE SECTION START *****/ | ||
319 | down_write(&tomoyo_domain_keeper_list_lock); | 461 | down_write(&tomoyo_domain_keeper_list_lock); |
320 | list_for_each_entry(ptr, &tomoyo_domain_keeper_list, list) { | 462 | list_for_each_entry(ptr, &tomoyo_domain_keeper_list, list) { |
321 | if (ptr->is_not != is_not || | 463 | if (ptr->is_not != is_not || |
@@ -341,7 +483,6 @@ static int tomoyo_update_domain_keeper_entry(const char *domainname, | |||
341 | error = 0; | 483 | error = 0; |
342 | out: | 484 | out: |
343 | up_write(&tomoyo_domain_keeper_list_lock); | 485 | up_write(&tomoyo_domain_keeper_list_lock); |
344 | /***** EXCLUSIVE SECTION END *****/ | ||
345 | return error; | 486 | return error; |
346 | } | 487 | } |
347 | 488 | ||
@@ -394,13 +535,12 @@ bool tomoyo_read_domain_keeper_policy(struct tomoyo_io_buffer *head) | |||
394 | from = " from "; | 535 | from = " from "; |
395 | program = ptr->program->name; | 536 | program = ptr->program->name; |
396 | } | 537 | } |
397 | if (!tomoyo_io_printf(head, | 538 | done = tomoyo_io_printf(head, |
398 | "%s" TOMOYO_KEYWORD_KEEP_DOMAIN | 539 | "%s" TOMOYO_KEYWORD_KEEP_DOMAIN |
399 | "%s%s%s\n", no, program, from, | 540 | "%s%s%s\n", no, program, from, |
400 | ptr->domainname->name)) { | 541 | ptr->domainname->name); |
401 | done = false; | 542 | if (!done) |
402 | break; | 543 | break; |
403 | } | ||
404 | } | 544 | } |
405 | up_read(&tomoyo_domain_keeper_list_lock); | 545 | up_read(&tomoyo_domain_keeper_list_lock); |
406 | return done; | 546 | return done; |
@@ -446,7 +586,36 @@ static bool tomoyo_is_domain_keeper(const struct tomoyo_path_info *domainname, | |||
446 | return flag; | 586 | return flag; |
447 | } | 587 | } |
448 | 588 | ||
449 | /* The list for "struct tomoyo_alias_entry". */ | 589 | /* |
590 | * tomoyo_alias_list is used for holding list of symlink's pathnames which are | ||
591 | * allowed to be passed to an execve() request. Normally, the domainname which | ||
592 | * the current process will belong to after execve() succeeds is calculated | ||
593 | * using dereferenced pathnames. But some programs behave differently depending | ||
594 | * on the name passed to argv[0]. For busybox, calculating domainname using | ||
595 | * dereferenced pathnames will cause all programs in the busybox to belong to | ||
596 | * the same domain. Thus, TOMOYO provides a way to allow use of symlink's | ||
597 | * pathname for checking execve()'s permission and calculating domainname which | ||
598 | * the current process will belong to after execve() succeeds. | ||
599 | * | ||
600 | * An entry is added by | ||
601 | * | ||
602 | * # echo 'alias /bin/busybox /bin/cat' > \ | ||
603 | * /sys/kernel/security/tomoyo/exception_policy | ||
604 | * | ||
605 | * and is deleted by | ||
606 | * | ||
607 | * # echo 'delete alias /bin/busybox /bin/cat' > \ | ||
608 | * /sys/kernel/security/tomoyo/exception_policy | ||
609 | * | ||
610 | * and all entries are retrieved by | ||
611 | * | ||
612 | * # grep ^alias /sys/kernel/security/tomoyo/exception_policy | ||
613 | * | ||
614 | * In the example above, if /bin/cat is a symlink to /bin/busybox and execution | ||
615 | * of /bin/cat is requested, permission is checked for /bin/cat rather than | ||
616 | * /bin/busybox and domainname which the current process will belong to after | ||
617 | * execve() succeeds is calculated using /bin/cat rather than /bin/busybox . | ||
618 | */ | ||
450 | static LIST_HEAD(tomoyo_alias_list); | 619 | static LIST_HEAD(tomoyo_alias_list); |
451 | static DECLARE_RWSEM(tomoyo_alias_list_lock); | 620 | static DECLARE_RWSEM(tomoyo_alias_list_lock); |
452 | 621 | ||
@@ -476,7 +645,6 @@ static int tomoyo_update_alias_entry(const char *original_name, | |||
476 | saved_aliased_name = tomoyo_save_name(aliased_name); | 645 | saved_aliased_name = tomoyo_save_name(aliased_name); |
477 | if (!saved_original_name || !saved_aliased_name) | 646 | if (!saved_original_name || !saved_aliased_name) |
478 | return -ENOMEM; | 647 | return -ENOMEM; |
479 | /***** EXCLUSIVE SECTION START *****/ | ||
480 | down_write(&tomoyo_alias_list_lock); | 648 | down_write(&tomoyo_alias_list_lock); |
481 | list_for_each_entry(ptr, &tomoyo_alias_list, list) { | 649 | list_for_each_entry(ptr, &tomoyo_alias_list, list) { |
482 | if (ptr->original_name != saved_original_name || | 650 | if (ptr->original_name != saved_original_name || |
@@ -499,7 +667,6 @@ static int tomoyo_update_alias_entry(const char *original_name, | |||
499 | error = 0; | 667 | error = 0; |
500 | out: | 668 | out: |
501 | up_write(&tomoyo_alias_list_lock); | 669 | up_write(&tomoyo_alias_list_lock); |
502 | /***** EXCLUSIVE SECTION END *****/ | ||
503 | return error; | 670 | return error; |
504 | } | 671 | } |
505 | 672 | ||
@@ -522,12 +689,11 @@ bool tomoyo_read_alias_policy(struct tomoyo_io_buffer *head) | |||
522 | ptr = list_entry(pos, struct tomoyo_alias_entry, list); | 689 | ptr = list_entry(pos, struct tomoyo_alias_entry, list); |
523 | if (ptr->is_deleted) | 690 | if (ptr->is_deleted) |
524 | continue; | 691 | continue; |
525 | if (!tomoyo_io_printf(head, TOMOYO_KEYWORD_ALIAS "%s %s\n", | 692 | done = tomoyo_io_printf(head, TOMOYO_KEYWORD_ALIAS "%s %s\n", |
526 | ptr->original_name->name, | 693 | ptr->original_name->name, |
527 | ptr->aliased_name->name)) { | 694 | ptr->aliased_name->name); |
528 | done = false; | 695 | if (!done) |
529 | break; | 696 | break; |
530 | } | ||
531 | } | 697 | } |
532 | up_read(&tomoyo_alias_list_lock); | 698 | up_read(&tomoyo_alias_list_lock); |
533 | return done; | 699 | return done; |
@@ -567,7 +733,6 @@ int tomoyo_delete_domain(char *domainname) | |||
567 | 733 | ||
568 | name.name = domainname; | 734 | name.name = domainname; |
569 | tomoyo_fill_path_info(&name); | 735 | tomoyo_fill_path_info(&name); |
570 | /***** EXCLUSIVE SECTION START *****/ | ||
571 | down_write(&tomoyo_domain_list_lock); | 736 | down_write(&tomoyo_domain_list_lock); |
572 | /* Is there an active domain? */ | 737 | /* Is there an active domain? */ |
573 | list_for_each_entry(domain, &tomoyo_domain_list, list) { | 738 | list_for_each_entry(domain, &tomoyo_domain_list, list) { |
@@ -581,7 +746,6 @@ int tomoyo_delete_domain(char *domainname) | |||
581 | break; | 746 | break; |
582 | } | 747 | } |
583 | up_write(&tomoyo_domain_list_lock); | 748 | up_write(&tomoyo_domain_list_lock); |
584 | /***** EXCLUSIVE SECTION END *****/ | ||
585 | return 0; | 749 | return 0; |
586 | } | 750 | } |
587 | 751 | ||
@@ -600,7 +764,6 @@ struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char * | |||
600 | struct tomoyo_domain_info *domain = NULL; | 764 | struct tomoyo_domain_info *domain = NULL; |
601 | const struct tomoyo_path_info *saved_domainname; | 765 | const struct tomoyo_path_info *saved_domainname; |
602 | 766 | ||
603 | /***** EXCLUSIVE SECTION START *****/ | ||
604 | down_write(&tomoyo_domain_list_lock); | 767 | down_write(&tomoyo_domain_list_lock); |
605 | domain = tomoyo_find_domain(domainname); | 768 | domain = tomoyo_find_domain(domainname); |
606 | if (domain) | 769 | if (domain) |
@@ -619,7 +782,6 @@ struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char * | |||
619 | domain->domainname != saved_domainname) | 782 | domain->domainname != saved_domainname) |
620 | continue; | 783 | continue; |
621 | flag = false; | 784 | flag = false; |
622 | /***** CRITICAL SECTION START *****/ | ||
623 | read_lock(&tasklist_lock); | 785 | read_lock(&tasklist_lock); |
624 | for_each_process(p) { | 786 | for_each_process(p) { |
625 | if (tomoyo_real_domain(p) != domain) | 787 | if (tomoyo_real_domain(p) != domain) |
@@ -628,7 +790,6 @@ struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char * | |||
628 | break; | 790 | break; |
629 | } | 791 | } |
630 | read_unlock(&tasklist_lock); | 792 | read_unlock(&tasklist_lock); |
631 | /***** CRITICAL SECTION END *****/ | ||
632 | if (flag) | 793 | if (flag) |
633 | continue; | 794 | continue; |
634 | list_for_each_entry(ptr, &domain->acl_info_list, list) { | 795 | list_for_each_entry(ptr, &domain->acl_info_list, list) { |
@@ -651,7 +812,6 @@ struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char * | |||
651 | } | 812 | } |
652 | out: | 813 | out: |
653 | up_write(&tomoyo_domain_list_lock); | 814 | up_write(&tomoyo_domain_list_lock); |
654 | /***** EXCLUSIVE SECTION END *****/ | ||
655 | return domain; | 815 | return domain; |
656 | } | 816 | } |
657 | 817 | ||
@@ -739,7 +899,7 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm, | |||
739 | } | 899 | } |
740 | 900 | ||
741 | /* Check execute permission. */ | 901 | /* Check execute permission. */ |
742 | retval = tomoyo_check_exec_perm(old_domain, &r, tmp); | 902 | retval = tomoyo_check_exec_perm(old_domain, &r); |
743 | if (retval < 0) | 903 | if (retval < 0) |
744 | goto out; | 904 | goto out; |
745 | 905 | ||
diff --git a/security/tomoyo/file.c b/security/tomoyo/file.c index 2316da8ec5bc..5ae3a571559f 100644 --- a/security/tomoyo/file.c +++ b/security/tomoyo/file.c | |||
@@ -14,21 +14,50 @@ | |||
14 | #include "realpath.h" | 14 | #include "realpath.h" |
15 | #define ACC_MODE(x) ("\000\004\002\006"[(x)&O_ACCMODE]) | 15 | #define ACC_MODE(x) ("\000\004\002\006"[(x)&O_ACCMODE]) |
16 | 16 | ||
17 | /* Structure for "allow_read" keyword. */ | 17 | /* |
18 | * tomoyo_globally_readable_file_entry is a structure which is used for holding | ||
19 | * "allow_read" entries. | ||
20 | * It has following fields. | ||
21 | * | ||
22 | * (1) "list" which is linked to tomoyo_globally_readable_list . | ||
23 | * (2) "filename" is a pathname which is allowed to open(O_RDONLY). | ||
24 | * (3) "is_deleted" is a bool which is true if marked as deleted, false | ||
25 | * otherwise. | ||
26 | */ | ||
18 | struct tomoyo_globally_readable_file_entry { | 27 | struct tomoyo_globally_readable_file_entry { |
19 | struct list_head list; | 28 | struct list_head list; |
20 | const struct tomoyo_path_info *filename; | 29 | const struct tomoyo_path_info *filename; |
21 | bool is_deleted; | 30 | bool is_deleted; |
22 | }; | 31 | }; |
23 | 32 | ||
24 | /* Structure for "file_pattern" keyword. */ | 33 | /* |
34 | * tomoyo_pattern_entry is a structure which is used for holding | ||
35 | * "tomoyo_pattern_list" entries. | ||
36 | * It has following fields. | ||
37 | * | ||
38 | * (1) "list" which is linked to tomoyo_pattern_list . | ||
39 | * (2) "pattern" is a pathname pattern which is used for converting pathnames | ||
40 | * to pathname patterns during learning mode. | ||
41 | * (3) "is_deleted" is a bool which is true if marked as deleted, false | ||
42 | * otherwise. | ||
43 | */ | ||
25 | struct tomoyo_pattern_entry { | 44 | struct tomoyo_pattern_entry { |
26 | struct list_head list; | 45 | struct list_head list; |
27 | const struct tomoyo_path_info *pattern; | 46 | const struct tomoyo_path_info *pattern; |
28 | bool is_deleted; | 47 | bool is_deleted; |
29 | }; | 48 | }; |
30 | 49 | ||
31 | /* Structure for "deny_rewrite" keyword. */ | 50 | /* |
51 | * tomoyo_no_rewrite_entry is a structure which is used for holding | ||
52 | * "deny_rewrite" entries. | ||
53 | * It has following fields. | ||
54 | * | ||
55 | * (1) "list" which is linked to tomoyo_no_rewrite_list . | ||
56 | * (2) "pattern" is a pathname which is by default not permitted to modify | ||
57 | * already existing content. | ||
58 | * (3) "is_deleted" is a bool which is true if marked as deleted, false | ||
59 | * otherwise. | ||
60 | */ | ||
32 | struct tomoyo_no_rewrite_entry { | 61 | struct tomoyo_no_rewrite_entry { |
33 | struct list_head list; | 62 | struct list_head list; |
34 | const struct tomoyo_path_info *pattern; | 63 | const struct tomoyo_path_info *pattern; |
@@ -141,7 +170,31 @@ static int tomoyo_update_single_path_acl(const u8 type, const char *filename, | |||
141 | struct tomoyo_domain_info * | 170 | struct tomoyo_domain_info * |
142 | const domain, const bool is_delete); | 171 | const domain, const bool is_delete); |
143 | 172 | ||
144 | /* The list for "struct tomoyo_globally_readable_file_entry". */ | 173 | /* |
174 | * tomoyo_globally_readable_list is used for holding list of pathnames which | ||
175 | * are by default allowed to be open()ed for reading by any process. | ||
176 | * | ||
177 | * An entry is added by | ||
178 | * | ||
179 | * # echo 'allow_read /lib/libc-2.5.so' > \ | ||
180 | * /sys/kernel/security/tomoyo/exception_policy | ||
181 | * | ||
182 | * and is deleted by | ||
183 | * | ||
184 | * # echo 'delete allow_read /lib/libc-2.5.so' > \ | ||
185 | * /sys/kernel/security/tomoyo/exception_policy | ||
186 | * | ||
187 | * and all entries are retrieved by | ||
188 | * | ||
189 | * # grep ^allow_read /sys/kernel/security/tomoyo/exception_policy | ||
190 | * | ||
191 | * In the example above, any process is allowed to | ||
192 | * open("/lib/libc-2.5.so", O_RDONLY). | ||
193 | * One exception is, if the domain which current process belongs to is marked | ||
194 | * as "ignore_global_allow_read", current process can't do so unless explicitly | ||
195 | * given "allow_read /lib/libc-2.5.so" to the domain which current process | ||
196 | * belongs to. | ||
197 | */ | ||
145 | static LIST_HEAD(tomoyo_globally_readable_list); | 198 | static LIST_HEAD(tomoyo_globally_readable_list); |
146 | static DECLARE_RWSEM(tomoyo_globally_readable_list_lock); | 199 | static DECLARE_RWSEM(tomoyo_globally_readable_list_lock); |
147 | 200 | ||
@@ -166,7 +219,6 @@ static int tomoyo_update_globally_readable_entry(const char *filename, | |||
166 | saved_filename = tomoyo_save_name(filename); | 219 | saved_filename = tomoyo_save_name(filename); |
167 | if (!saved_filename) | 220 | if (!saved_filename) |
168 | return -ENOMEM; | 221 | return -ENOMEM; |
169 | /***** EXCLUSIVE SECTION START *****/ | ||
170 | down_write(&tomoyo_globally_readable_list_lock); | 222 | down_write(&tomoyo_globally_readable_list_lock); |
171 | list_for_each_entry(ptr, &tomoyo_globally_readable_list, list) { | 223 | list_for_each_entry(ptr, &tomoyo_globally_readable_list, list) { |
172 | if (ptr->filename != saved_filename) | 224 | if (ptr->filename != saved_filename) |
@@ -187,7 +239,6 @@ static int tomoyo_update_globally_readable_entry(const char *filename, | |||
187 | error = 0; | 239 | error = 0; |
188 | out: | 240 | out: |
189 | up_write(&tomoyo_globally_readable_list_lock); | 241 | up_write(&tomoyo_globally_readable_list_lock); |
190 | /***** EXCLUSIVE SECTION END *****/ | ||
191 | return error; | 242 | return error; |
192 | } | 243 | } |
193 | 244 | ||
@@ -249,17 +300,44 @@ bool tomoyo_read_globally_readable_policy(struct tomoyo_io_buffer *head) | |||
249 | list); | 300 | list); |
250 | if (ptr->is_deleted) | 301 | if (ptr->is_deleted) |
251 | continue; | 302 | continue; |
252 | if (!tomoyo_io_printf(head, TOMOYO_KEYWORD_ALLOW_READ "%s\n", | 303 | done = tomoyo_io_printf(head, TOMOYO_KEYWORD_ALLOW_READ "%s\n", |
253 | ptr->filename->name)) { | 304 | ptr->filename->name); |
254 | done = false; | 305 | if (!done) |
255 | break; | 306 | break; |
256 | } | ||
257 | } | 307 | } |
258 | up_read(&tomoyo_globally_readable_list_lock); | 308 | up_read(&tomoyo_globally_readable_list_lock); |
259 | return done; | 309 | return done; |
260 | } | 310 | } |
261 | 311 | ||
262 | /* The list for "struct tomoyo_pattern_entry". */ | 312 | /* tomoyo_pattern_list is used for holding list of pathnames which are used for |
313 | * converting pathnames to pathname patterns during learning mode. | ||
314 | * | ||
315 | * An entry is added by | ||
316 | * | ||
317 | * # echo 'file_pattern /proc/\$/mounts' > \ | ||
318 | * /sys/kernel/security/tomoyo/exception_policy | ||
319 | * | ||
320 | * and is deleted by | ||
321 | * | ||
322 | * # echo 'delete file_pattern /proc/\$/mounts' > \ | ||
323 | * /sys/kernel/security/tomoyo/exception_policy | ||
324 | * | ||
325 | * and all entries are retrieved by | ||
326 | * | ||
327 | * # grep ^file_pattern /sys/kernel/security/tomoyo/exception_policy | ||
328 | * | ||
329 | * In the example above, if a process which belongs to a domain which is in | ||
330 | * learning mode requested open("/proc/1/mounts", O_RDONLY), | ||
331 | * "allow_read /proc/\$/mounts" is automatically added to the domain which that | ||
332 | * process belongs to. | ||
333 | * | ||
334 | * It is not a desirable behavior that we have to use /proc/\$/ instead of | ||
335 | * /proc/self/ when current process needs to access only current process's | ||
336 | * information. As of now, LSM version of TOMOYO is using __d_path() for | ||
337 | * calculating pathname. Non LSM version of TOMOYO is using its own function | ||
338 | * which pretends as if /proc/self/ is not a symlink; so that we can forbid | ||
339 | * current process from accessing other process's information. | ||
340 | */ | ||
263 | static LIST_HEAD(tomoyo_pattern_list); | 341 | static LIST_HEAD(tomoyo_pattern_list); |
264 | static DECLARE_RWSEM(tomoyo_pattern_list_lock); | 342 | static DECLARE_RWSEM(tomoyo_pattern_list_lock); |
265 | 343 | ||
@@ -284,7 +362,6 @@ static int tomoyo_update_file_pattern_entry(const char *pattern, | |||
284 | saved_pattern = tomoyo_save_name(pattern); | 362 | saved_pattern = tomoyo_save_name(pattern); |
285 | if (!saved_pattern) | 363 | if (!saved_pattern) |
286 | return -ENOMEM; | 364 | return -ENOMEM; |
287 | /***** EXCLUSIVE SECTION START *****/ | ||
288 | down_write(&tomoyo_pattern_list_lock); | 365 | down_write(&tomoyo_pattern_list_lock); |
289 | list_for_each_entry(ptr, &tomoyo_pattern_list, list) { | 366 | list_for_each_entry(ptr, &tomoyo_pattern_list, list) { |
290 | if (saved_pattern != ptr->pattern) | 367 | if (saved_pattern != ptr->pattern) |
@@ -305,7 +382,6 @@ static int tomoyo_update_file_pattern_entry(const char *pattern, | |||
305 | error = 0; | 382 | error = 0; |
306 | out: | 383 | out: |
307 | up_write(&tomoyo_pattern_list_lock); | 384 | up_write(&tomoyo_pattern_list_lock); |
308 | /***** EXCLUSIVE SECTION END *****/ | ||
309 | return error; | 385 | return error; |
310 | } | 386 | } |
311 | 387 | ||
@@ -373,17 +449,44 @@ bool tomoyo_read_file_pattern(struct tomoyo_io_buffer *head) | |||
373 | ptr = list_entry(pos, struct tomoyo_pattern_entry, list); | 449 | ptr = list_entry(pos, struct tomoyo_pattern_entry, list); |
374 | if (ptr->is_deleted) | 450 | if (ptr->is_deleted) |
375 | continue; | 451 | continue; |
376 | if (!tomoyo_io_printf(head, TOMOYO_KEYWORD_FILE_PATTERN "%s\n", | 452 | done = tomoyo_io_printf(head, TOMOYO_KEYWORD_FILE_PATTERN |
377 | ptr->pattern->name)) { | 453 | "%s\n", ptr->pattern->name); |
378 | done = false; | 454 | if (!done) |
379 | break; | 455 | break; |
380 | } | ||
381 | } | 456 | } |
382 | up_read(&tomoyo_pattern_list_lock); | 457 | up_read(&tomoyo_pattern_list_lock); |
383 | return done; | 458 | return done; |
384 | } | 459 | } |
385 | 460 | ||
386 | /* The list for "struct tomoyo_no_rewrite_entry". */ | 461 | /* |
462 | * tomoyo_no_rewrite_list is used for holding list of pathnames which are by | ||
463 | * default forbidden to modify already written content of a file. | ||
464 | * | ||
465 | * An entry is added by | ||
466 | * | ||
467 | * # echo 'deny_rewrite /var/log/messages' > \ | ||
468 | * /sys/kernel/security/tomoyo/exception_policy | ||
469 | * | ||
470 | * and is deleted by | ||
471 | * | ||
472 | * # echo 'delete deny_rewrite /var/log/messages' > \ | ||
473 | * /sys/kernel/security/tomoyo/exception_policy | ||
474 | * | ||
475 | * and all entries are retrieved by | ||
476 | * | ||
477 | * # grep ^deny_rewrite /sys/kernel/security/tomoyo/exception_policy | ||
478 | * | ||
479 | * In the example above, if a process requested to rewrite /var/log/messages , | ||
480 | * the process can't rewrite unless the domain which that process belongs to | ||
481 | * has "allow_rewrite /var/log/messages" entry. | ||
482 | * | ||
483 | * It is not a desirable behavior that we have to add "\040(deleted)" suffix | ||
484 | * when we want to allow rewriting already unlink()ed file. As of now, | ||
485 | * LSM version of TOMOYO is using __d_path() for calculating pathname. | ||
486 | * Non LSM version of TOMOYO is using its own function which doesn't append | ||
487 | * " (deleted)" suffix if the file is already unlink()ed; so that we don't | ||
488 | * need to worry whether the file is already unlink()ed or not. | ||
489 | */ | ||
387 | static LIST_HEAD(tomoyo_no_rewrite_list); | 490 | static LIST_HEAD(tomoyo_no_rewrite_list); |
388 | static DECLARE_RWSEM(tomoyo_no_rewrite_list_lock); | 491 | static DECLARE_RWSEM(tomoyo_no_rewrite_list_lock); |
389 | 492 | ||
@@ -407,7 +510,6 @@ static int tomoyo_update_no_rewrite_entry(const char *pattern, | |||
407 | saved_pattern = tomoyo_save_name(pattern); | 510 | saved_pattern = tomoyo_save_name(pattern); |
408 | if (!saved_pattern) | 511 | if (!saved_pattern) |
409 | return -ENOMEM; | 512 | return -ENOMEM; |
410 | /***** EXCLUSIVE SECTION START *****/ | ||
411 | down_write(&tomoyo_no_rewrite_list_lock); | 513 | down_write(&tomoyo_no_rewrite_list_lock); |
412 | list_for_each_entry(ptr, &tomoyo_no_rewrite_list, list) { | 514 | list_for_each_entry(ptr, &tomoyo_no_rewrite_list, list) { |
413 | if (ptr->pattern != saved_pattern) | 515 | if (ptr->pattern != saved_pattern) |
@@ -428,7 +530,6 @@ static int tomoyo_update_no_rewrite_entry(const char *pattern, | |||
428 | error = 0; | 530 | error = 0; |
429 | out: | 531 | out: |
430 | up_write(&tomoyo_no_rewrite_list_lock); | 532 | up_write(&tomoyo_no_rewrite_list_lock); |
431 | /***** EXCLUSIVE SECTION END *****/ | ||
432 | return error; | 533 | return error; |
433 | } | 534 | } |
434 | 535 | ||
@@ -489,11 +590,10 @@ bool tomoyo_read_no_rewrite_policy(struct tomoyo_io_buffer *head) | |||
489 | ptr = list_entry(pos, struct tomoyo_no_rewrite_entry, list); | 590 | ptr = list_entry(pos, struct tomoyo_no_rewrite_entry, list); |
490 | if (ptr->is_deleted) | 591 | if (ptr->is_deleted) |
491 | continue; | 592 | continue; |
492 | if (!tomoyo_io_printf(head, TOMOYO_KEYWORD_DENY_REWRITE "%s\n", | 593 | done = tomoyo_io_printf(head, TOMOYO_KEYWORD_DENY_REWRITE |
493 | ptr->pattern->name)) { | 594 | "%s\n", ptr->pattern->name); |
494 | done = false; | 595 | if (!done) |
495 | break; | 596 | break; |
496 | } | ||
497 | } | 597 | } |
498 | up_read(&tomoyo_no_rewrite_list_lock); | 598 | up_read(&tomoyo_no_rewrite_list_lock); |
499 | return done; | 599 | return done; |
@@ -745,7 +845,6 @@ static int tomoyo_update_single_path_acl(const u8 type, const char *filename, | |||
745 | saved_filename = tomoyo_save_name(filename); | 845 | saved_filename = tomoyo_save_name(filename); |
746 | if (!saved_filename) | 846 | if (!saved_filename) |
747 | return -ENOMEM; | 847 | return -ENOMEM; |
748 | /***** EXCLUSIVE SECTION START *****/ | ||
749 | down_write(&tomoyo_domain_acl_info_list_lock); | 848 | down_write(&tomoyo_domain_acl_info_list_lock); |
750 | if (is_delete) | 849 | if (is_delete) |
751 | goto delete; | 850 | goto delete; |
@@ -800,7 +899,6 @@ static int tomoyo_update_single_path_acl(const u8 type, const char *filename, | |||
800 | } | 899 | } |
801 | out: | 900 | out: |
802 | up_write(&tomoyo_domain_acl_info_list_lock); | 901 | up_write(&tomoyo_domain_acl_info_list_lock); |
803 | /***** EXCLUSIVE SECTION END *****/ | ||
804 | return error; | 902 | return error; |
805 | } | 903 | } |
806 | 904 | ||
@@ -836,7 +934,6 @@ static int tomoyo_update_double_path_acl(const u8 type, const char *filename1, | |||
836 | saved_filename2 = tomoyo_save_name(filename2); | 934 | saved_filename2 = tomoyo_save_name(filename2); |
837 | if (!saved_filename1 || !saved_filename2) | 935 | if (!saved_filename1 || !saved_filename2) |
838 | return -ENOMEM; | 936 | return -ENOMEM; |
839 | /***** EXCLUSIVE SECTION START *****/ | ||
840 | down_write(&tomoyo_domain_acl_info_list_lock); | 937 | down_write(&tomoyo_domain_acl_info_list_lock); |
841 | if (is_delete) | 938 | if (is_delete) |
842 | goto delete; | 939 | goto delete; |
@@ -884,7 +981,6 @@ static int tomoyo_update_double_path_acl(const u8 type, const char *filename1, | |||
884 | } | 981 | } |
885 | out: | 982 | out: |
886 | up_write(&tomoyo_domain_acl_info_list_lock); | 983 | up_write(&tomoyo_domain_acl_info_list_lock); |
887 | /***** EXCLUSIVE SECTION END *****/ | ||
888 | return error; | 984 | return error; |
889 | } | 985 | } |
890 | 986 | ||
@@ -1025,13 +1121,11 @@ int tomoyo_check_file_perm(struct tomoyo_domain_info *domain, | |||
1025 | * | 1121 | * |
1026 | * @domain: Pointer to "struct tomoyo_domain_info". | 1122 | * @domain: Pointer to "struct tomoyo_domain_info". |
1027 | * @filename: Check permission for "execute". | 1123 | * @filename: Check permission for "execute". |
1028 | * @tmp: Buffer for temporary use. | ||
1029 | * | 1124 | * |
1030 | * Returns 0 on success, negativevalue otherwise. | 1125 | * Returns 0 on success, negativevalue otherwise. |
1031 | */ | 1126 | */ |
1032 | int tomoyo_check_exec_perm(struct tomoyo_domain_info *domain, | 1127 | int tomoyo_check_exec_perm(struct tomoyo_domain_info *domain, |
1033 | const struct tomoyo_path_info *filename, | 1128 | const struct tomoyo_path_info *filename) |
1034 | struct tomoyo_page_buffer *tmp) | ||
1035 | { | 1129 | { |
1036 | const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE); | 1130 | const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE); |
1037 | 1131 | ||
diff --git a/security/tomoyo/realpath.c b/security/tomoyo/realpath.c index 40927a84cb6e..5f2e33263371 100644 --- a/security/tomoyo/realpath.c +++ b/security/tomoyo/realpath.c | |||
@@ -220,7 +220,6 @@ void *tomoyo_alloc_element(const unsigned int size) | |||
220 | = roundup(size, max(sizeof(void *), sizeof(long))); | 220 | = roundup(size, max(sizeof(void *), sizeof(long))); |
221 | if (word_aligned_size > PATH_MAX) | 221 | if (word_aligned_size > PATH_MAX) |
222 | return NULL; | 222 | return NULL; |
223 | /***** EXCLUSIVE SECTION START *****/ | ||
224 | mutex_lock(&lock); | 223 | mutex_lock(&lock); |
225 | if (buf_used_len + word_aligned_size > PATH_MAX) { | 224 | if (buf_used_len + word_aligned_size > PATH_MAX) { |
226 | if (!tomoyo_quota_for_elements || | 225 | if (!tomoyo_quota_for_elements || |
@@ -251,7 +250,6 @@ void *tomoyo_alloc_element(const unsigned int size) | |||
251 | } | 250 | } |
252 | } | 251 | } |
253 | mutex_unlock(&lock); | 252 | mutex_unlock(&lock); |
254 | /***** EXCLUSIVE SECTION END *****/ | ||
255 | return ptr; | 253 | return ptr; |
256 | } | 254 | } |
257 | 255 | ||
@@ -267,7 +265,16 @@ static unsigned int tomoyo_quota_for_savename; | |||
267 | */ | 265 | */ |
268 | #define TOMOYO_MAX_HASH 256 | 266 | #define TOMOYO_MAX_HASH 256 |
269 | 267 | ||
270 | /* Structure for string data. */ | 268 | /* |
269 | * tomoyo_name_entry is a structure which is used for linking | ||
270 | * "struct tomoyo_path_info" into tomoyo_name_list . | ||
271 | * | ||
272 | * Since tomoyo_name_list manages a list of strings which are shared by | ||
273 | * multiple processes (whereas "struct tomoyo_path_info" inside | ||
274 | * "struct tomoyo_path_info_with_data" is not shared), a reference counter will | ||
275 | * be added to "struct tomoyo_name_entry" rather than "struct tomoyo_path_info" | ||
276 | * when TOMOYO starts supporting garbage collector. | ||
277 | */ | ||
271 | struct tomoyo_name_entry { | 278 | struct tomoyo_name_entry { |
272 | struct list_head list; | 279 | struct list_head list; |
273 | struct tomoyo_path_info entry; | 280 | struct tomoyo_path_info entry; |
@@ -281,10 +288,10 @@ struct tomoyo_free_memory_block_list { | |||
281 | }; | 288 | }; |
282 | 289 | ||
283 | /* | 290 | /* |
284 | * The list for "struct tomoyo_name_entry". | 291 | * tomoyo_name_list is used for holding string data used by TOMOYO. |
285 | * | 292 | * Since same string data is likely used for multiple times (e.g. |
286 | * This list is updated only inside tomoyo_save_name(), thus | 293 | * "/lib/libc-2.5.so"), TOMOYO shares string data in the form of |
287 | * no global mutex exists. | 294 | * "const struct tomoyo_path_info *". |
288 | */ | 295 | */ |
289 | static struct list_head tomoyo_name_list[TOMOYO_MAX_HASH]; | 296 | static struct list_head tomoyo_name_list[TOMOYO_MAX_HASH]; |
290 | 297 | ||
@@ -318,7 +325,6 @@ const struct tomoyo_path_info *tomoyo_save_name(const char *name) | |||
318 | return NULL; | 325 | return NULL; |
319 | } | 326 | } |
320 | hash = full_name_hash((const unsigned char *) name, len - 1); | 327 | hash = full_name_hash((const unsigned char *) name, len - 1); |
321 | /***** EXCLUSIVE SECTION START *****/ | ||
322 | mutex_lock(&lock); | 328 | mutex_lock(&lock); |
323 | list_for_each_entry(ptr, &tomoyo_name_list[hash % TOMOYO_MAX_HASH], | 329 | list_for_each_entry(ptr, &tomoyo_name_list[hash % TOMOYO_MAX_HASH], |
324 | list) { | 330 | list) { |
@@ -366,7 +372,6 @@ const struct tomoyo_path_info *tomoyo_save_name(const char *name) | |||
366 | } | 372 | } |
367 | out: | 373 | out: |
368 | mutex_unlock(&lock); | 374 | mutex_unlock(&lock); |
369 | /***** EXCLUSIVE SECTION END *****/ | ||
370 | return ptr ? &ptr->entry : NULL; | 375 | return ptr ? &ptr->entry : NULL; |
371 | } | 376 | } |
372 | 377 | ||
diff --git a/security/tomoyo/tomoyo.c b/security/tomoyo/tomoyo.c index e42be5c4f055..3194d09fe0f4 100644 --- a/security/tomoyo/tomoyo.c +++ b/security/tomoyo/tomoyo.c | |||
@@ -262,6 +262,10 @@ static int tomoyo_dentry_open(struct file *f, const struct cred *cred) | |||
262 | return tomoyo_check_open_permission(tomoyo_domain(), &f->f_path, flags); | 262 | return tomoyo_check_open_permission(tomoyo_domain(), &f->f_path, flags); |
263 | } | 263 | } |
264 | 264 | ||
265 | /* | ||
266 | * tomoyo_security_ops is a "struct security_operations" which is used for | ||
267 | * registering TOMOYO. | ||
268 | */ | ||
265 | static struct security_operations tomoyo_security_ops = { | 269 | static struct security_operations tomoyo_security_ops = { |
266 | .name = "tomoyo", | 270 | .name = "tomoyo", |
267 | .cred_prepare = tomoyo_cred_prepare, | 271 | .cred_prepare = tomoyo_cred_prepare, |
diff --git a/security/tomoyo/tomoyo.h b/security/tomoyo/tomoyo.h index 41c6ebafb9c5..0fd588a629cf 100644 --- a/security/tomoyo/tomoyo.h +++ b/security/tomoyo/tomoyo.h | |||
@@ -17,13 +17,11 @@ struct path; | |||
17 | struct inode; | 17 | struct inode; |
18 | struct linux_binprm; | 18 | struct linux_binprm; |
19 | struct pt_regs; | 19 | struct pt_regs; |
20 | struct tomoyo_page_buffer; | ||
21 | 20 | ||
22 | int tomoyo_check_file_perm(struct tomoyo_domain_info *domain, | 21 | int tomoyo_check_file_perm(struct tomoyo_domain_info *domain, |
23 | const char *filename, const u8 perm); | 22 | const char *filename, const u8 perm); |
24 | int tomoyo_check_exec_perm(struct tomoyo_domain_info *domain, | 23 | int tomoyo_check_exec_perm(struct tomoyo_domain_info *domain, |
25 | const struct tomoyo_path_info *filename, | 24 | const struct tomoyo_path_info *filename); |
26 | struct tomoyo_page_buffer *buf); | ||
27 | int tomoyo_check_open_permission(struct tomoyo_domain_info *domain, | 25 | int tomoyo_check_open_permission(struct tomoyo_domain_info *domain, |
28 | struct path *path, const int flag); | 26 | struct path *path, const int flag); |
29 | int tomoyo_check_1path_perm(struct tomoyo_domain_info *domain, | 27 | int tomoyo_check_1path_perm(struct tomoyo_domain_info *domain, |
@@ -90,17 +88,10 @@ static inline struct tomoyo_domain_info *tomoyo_domain(void) | |||
90 | return current_cred()->security; | 88 | return current_cred()->security; |
91 | } | 89 | } |
92 | 90 | ||
93 | /* Caller holds tasklist_lock spinlock. */ | ||
94 | static inline struct tomoyo_domain_info *tomoyo_real_domain(struct task_struct | 91 | static inline struct tomoyo_domain_info *tomoyo_real_domain(struct task_struct |
95 | *task) | 92 | *task) |
96 | { | 93 | { |
97 | /***** CRITICAL SECTION START *****/ | 94 | return task_cred_xxx(task, security); |
98 | const struct cred *cred = get_task_cred(task); | ||
99 | struct tomoyo_domain_info *domain = cred->security; | ||
100 | |||
101 | put_cred(cred); | ||
102 | return domain; | ||
103 | /***** CRITICAL SECTION END *****/ | ||
104 | } | 95 | } |
105 | 96 | ||
106 | #endif /* !defined(_SECURITY_TOMOYO_TOMOYO_H) */ | 97 | #endif /* !defined(_SECURITY_TOMOYO_TOMOYO_H) */ |