diff options
Diffstat (limited to 'security/tomoyo/common.c')
-rw-r--r-- | security/tomoyo/common.c | 157 |
1 files changed, 113 insertions, 44 deletions
diff --git a/security/tomoyo/common.c b/security/tomoyo/common.c index 975c45d88baa..b5dbdc9ff73c 100644 --- a/security/tomoyo/common.c +++ b/security/tomoyo/common.c | |||
@@ -76,6 +76,49 @@ static int tomoyo_write_control(struct file *file, const char __user *buffer, | |||
76 | const int buffer_len); | 76 | const int buffer_len); |
77 | 77 | ||
78 | /** | 78 | /** |
79 | * tomoyo_parse_name_union - Parse a tomoyo_name_union. | ||
80 | * | ||
81 | * @filename: Name or name group. | ||
82 | * @ptr: Pointer to "struct tomoyo_name_union". | ||
83 | * | ||
84 | * Returns true on success, false otherwise. | ||
85 | */ | ||
86 | bool tomoyo_parse_name_union(const char *filename, | ||
87 | struct tomoyo_name_union *ptr) | ||
88 | { | ||
89 | if (!tomoyo_is_correct_path(filename, 0, 0, 0)) | ||
90 | return false; | ||
91 | if (filename[0] == '@') { | ||
92 | ptr->group = tomoyo_get_path_group(filename + 1); | ||
93 | ptr->is_group = true; | ||
94 | return ptr->group != NULL; | ||
95 | } | ||
96 | ptr->filename = tomoyo_get_name(filename); | ||
97 | ptr->is_group = false; | ||
98 | return ptr->filename != NULL; | ||
99 | } | ||
100 | |||
101 | /** | ||
102 | * tomoyo_print_name_union - Print a tomoyo_name_union. | ||
103 | * | ||
104 | * @head: Pointer to "struct tomoyo_io_buffer". | ||
105 | * @ptr: Pointer to "struct tomoyo_name_union". | ||
106 | * | ||
107 | * Returns true on success, false otherwise. | ||
108 | */ | ||
109 | static bool tomoyo_print_name_union(struct tomoyo_io_buffer *head, | ||
110 | const struct tomoyo_name_union *ptr) | ||
111 | { | ||
112 | int pos = head->read_avail; | ||
113 | if (pos && head->read_buf[pos - 1] == ' ') | ||
114 | head->read_avail--; | ||
115 | if (ptr->is_group) | ||
116 | return tomoyo_io_printf(head, " @%s", | ||
117 | ptr->group->group_name->name); | ||
118 | return tomoyo_io_printf(head, " %s", ptr->filename->name); | ||
119 | } | ||
120 | |||
121 | /** | ||
79 | * tomoyo_is_byte_range - Check whether the string isa \ooo style octal value. | 122 | * tomoyo_is_byte_range - Check whether the string isa \ooo style octal value. |
80 | * | 123 | * |
81 | * @str: Pointer to the string. | 124 | * @str: Pointer to the string. |
@@ -172,6 +215,33 @@ static void tomoyo_normalize_line(unsigned char *buffer) | |||
172 | } | 215 | } |
173 | 216 | ||
174 | /** | 217 | /** |
218 | * tomoyo_tokenize - Tokenize string. | ||
219 | * | ||
220 | * @buffer: The line to tokenize. | ||
221 | * @w: Pointer to "char *". | ||
222 | * @size: Sizeof @w . | ||
223 | * | ||
224 | * Returns true on success, false otherwise. | ||
225 | */ | ||
226 | bool tomoyo_tokenize(char *buffer, char *w[], size_t size) | ||
227 | { | ||
228 | int count = size / sizeof(char *); | ||
229 | int i; | ||
230 | for (i = 0; i < count; i++) | ||
231 | w[i] = ""; | ||
232 | for (i = 0; i < count; i++) { | ||
233 | char *cp = strchr(buffer, ' '); | ||
234 | if (cp) | ||
235 | *cp = '\0'; | ||
236 | w[i] = buffer; | ||
237 | if (!cp) | ||
238 | break; | ||
239 | buffer = cp + 1; | ||
240 | } | ||
241 | return i < count || !*buffer; | ||
242 | } | ||
243 | |||
244 | /** | ||
175 | * tomoyo_is_correct_path - Validate a pathname. | 245 | * tomoyo_is_correct_path - Validate a pathname. |
176 | * @filename: The pathname to check. | 246 | * @filename: The pathname to check. |
177 | * @start_type: Should the pathname start with '/'? | 247 | * @start_type: Should the pathname start with '/'? |
@@ -874,17 +944,17 @@ bool tomoyo_domain_quota_is_ok(struct tomoyo_domain_info * const domain) | |||
874 | static struct tomoyo_profile *tomoyo_find_or_assign_new_profile(const unsigned | 944 | static struct tomoyo_profile *tomoyo_find_or_assign_new_profile(const unsigned |
875 | int profile) | 945 | int profile) |
876 | { | 946 | { |
877 | static DEFINE_MUTEX(lock); | ||
878 | struct tomoyo_profile *ptr = NULL; | 947 | struct tomoyo_profile *ptr = NULL; |
879 | int i; | 948 | int i; |
880 | 949 | ||
881 | if (profile >= TOMOYO_MAX_PROFILES) | 950 | if (profile >= TOMOYO_MAX_PROFILES) |
882 | return NULL; | 951 | return NULL; |
883 | mutex_lock(&lock); | 952 | if (mutex_lock_interruptible(&tomoyo_policy_lock)) |
953 | return NULL; | ||
884 | ptr = tomoyo_profile_ptr[profile]; | 954 | ptr = tomoyo_profile_ptr[profile]; |
885 | if (ptr) | 955 | if (ptr) |
886 | goto ok; | 956 | goto ok; |
887 | ptr = kmalloc(sizeof(*ptr), GFP_KERNEL); | 957 | ptr = kmalloc(sizeof(*ptr), GFP_NOFS); |
888 | if (!tomoyo_memory_ok(ptr)) { | 958 | if (!tomoyo_memory_ok(ptr)) { |
889 | kfree(ptr); | 959 | kfree(ptr); |
890 | ptr = NULL; | 960 | ptr = NULL; |
@@ -895,7 +965,7 @@ static struct tomoyo_profile *tomoyo_find_or_assign_new_profile(const unsigned | |||
895 | mb(); /* Avoid out-of-order execution. */ | 965 | mb(); /* Avoid out-of-order execution. */ |
896 | tomoyo_profile_ptr[profile] = ptr; | 966 | tomoyo_profile_ptr[profile] = ptr; |
897 | ok: | 967 | ok: |
898 | mutex_unlock(&lock); | 968 | mutex_unlock(&tomoyo_policy_lock); |
899 | return ptr; | 969 | return ptr; |
900 | } | 970 | } |
901 | 971 | ||
@@ -1071,44 +1141,42 @@ LIST_HEAD(tomoyo_policy_manager_list); | |||
1071 | static int tomoyo_update_manager_entry(const char *manager, | 1141 | static int tomoyo_update_manager_entry(const char *manager, |
1072 | const bool is_delete) | 1142 | const bool is_delete) |
1073 | { | 1143 | { |
1074 | struct tomoyo_policy_manager_entry *entry = NULL; | ||
1075 | struct tomoyo_policy_manager_entry *ptr; | 1144 | struct tomoyo_policy_manager_entry *ptr; |
1076 | const struct tomoyo_path_info *saved_manager; | 1145 | struct tomoyo_policy_manager_entry e = { }; |
1077 | int error = is_delete ? -ENOENT : -ENOMEM; | 1146 | int error = is_delete ? -ENOENT : -ENOMEM; |
1078 | bool is_domain = false; | ||
1079 | 1147 | ||
1080 | if (tomoyo_is_domain_def(manager)) { | 1148 | if (tomoyo_is_domain_def(manager)) { |
1081 | if (!tomoyo_is_correct_domain(manager)) | 1149 | if (!tomoyo_is_correct_domain(manager)) |
1082 | return -EINVAL; | 1150 | return -EINVAL; |
1083 | is_domain = true; | 1151 | e.is_domain = true; |
1084 | } else { | 1152 | } else { |
1085 | if (!tomoyo_is_correct_path(manager, 1, -1, -1)) | 1153 | if (!tomoyo_is_correct_path(manager, 1, -1, -1)) |
1086 | return -EINVAL; | 1154 | return -EINVAL; |
1087 | } | 1155 | } |
1088 | saved_manager = tomoyo_get_name(manager); | 1156 | e.manager = tomoyo_get_name(manager); |
1089 | if (!saved_manager) | 1157 | if (!e.manager) |
1090 | return -ENOMEM; | 1158 | return -ENOMEM; |
1091 | if (!is_delete) | 1159 | if (mutex_lock_interruptible(&tomoyo_policy_lock)) |
1092 | entry = kmalloc(sizeof(*entry), GFP_KERNEL); | 1160 | goto out; |
1093 | mutex_lock(&tomoyo_policy_lock); | ||
1094 | list_for_each_entry_rcu(ptr, &tomoyo_policy_manager_list, list) { | 1161 | list_for_each_entry_rcu(ptr, &tomoyo_policy_manager_list, list) { |
1095 | if (ptr->manager != saved_manager) | 1162 | if (ptr->manager != e.manager) |
1096 | continue; | 1163 | continue; |
1097 | ptr->is_deleted = is_delete; | 1164 | ptr->is_deleted = is_delete; |
1098 | error = 0; | 1165 | error = 0; |
1099 | break; | 1166 | break; |
1100 | } | 1167 | } |
1101 | if (!is_delete && error && tomoyo_memory_ok(entry)) { | 1168 | if (!is_delete && error) { |
1102 | entry->manager = saved_manager; | 1169 | struct tomoyo_policy_manager_entry *entry = |
1103 | saved_manager = NULL; | 1170 | tomoyo_commit_ok(&e, sizeof(e)); |
1104 | entry->is_domain = is_domain; | 1171 | if (entry) { |
1105 | list_add_tail_rcu(&entry->list, &tomoyo_policy_manager_list); | 1172 | list_add_tail_rcu(&entry->list, |
1106 | entry = NULL; | 1173 | &tomoyo_policy_manager_list); |
1107 | error = 0; | 1174 | error = 0; |
1175 | } | ||
1108 | } | 1176 | } |
1109 | mutex_unlock(&tomoyo_policy_lock); | 1177 | mutex_unlock(&tomoyo_policy_lock); |
1110 | tomoyo_put_name(saved_manager); | 1178 | out: |
1111 | kfree(entry); | 1179 | tomoyo_put_name(e.manager); |
1112 | return error; | 1180 | return error; |
1113 | } | 1181 | } |
1114 | 1182 | ||
@@ -1287,7 +1355,8 @@ static int tomoyo_delete_domain(char *domainname) | |||
1287 | 1355 | ||
1288 | name.name = domainname; | 1356 | name.name = domainname; |
1289 | tomoyo_fill_path_info(&name); | 1357 | tomoyo_fill_path_info(&name); |
1290 | mutex_lock(&tomoyo_policy_lock); | 1358 | if (mutex_lock_interruptible(&tomoyo_policy_lock)) |
1359 | return 0; | ||
1291 | /* Is there an active domain? */ | 1360 | /* Is there an active domain? */ |
1292 | list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) { | 1361 | list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) { |
1293 | /* Never delete tomoyo_kernel_domain */ | 1362 | /* Never delete tomoyo_kernel_domain */ |
@@ -1369,23 +1438,20 @@ static bool tomoyo_print_path_acl(struct tomoyo_io_buffer *head, | |||
1369 | { | 1438 | { |
1370 | int pos; | 1439 | int pos; |
1371 | u8 bit; | 1440 | u8 bit; |
1372 | const char *atmark = ""; | ||
1373 | const char *filename; | ||
1374 | const u32 perm = ptr->perm | (((u32) ptr->perm_high) << 16); | 1441 | const u32 perm = ptr->perm | (((u32) ptr->perm_high) << 16); |
1375 | 1442 | ||
1376 | filename = ptr->filename->name; | ||
1377 | for (bit = head->read_bit; bit < TOMOYO_MAX_PATH_OPERATION; bit++) { | 1443 | for (bit = head->read_bit; bit < TOMOYO_MAX_PATH_OPERATION; bit++) { |
1378 | const char *msg; | ||
1379 | if (!(perm & (1 << bit))) | 1444 | if (!(perm & (1 << bit))) |
1380 | continue; | 1445 | continue; |
1381 | /* Print "read/write" instead of "read" and "write". */ | 1446 | /* Print "read/write" instead of "read" and "write". */ |
1382 | if ((bit == TOMOYO_TYPE_READ || bit == TOMOYO_TYPE_WRITE) | 1447 | if ((bit == TOMOYO_TYPE_READ || bit == TOMOYO_TYPE_WRITE) |
1383 | && (perm & (1 << TOMOYO_TYPE_READ_WRITE))) | 1448 | && (perm & (1 << TOMOYO_TYPE_READ_WRITE))) |
1384 | continue; | 1449 | continue; |
1385 | msg = tomoyo_path2keyword(bit); | ||
1386 | pos = head->read_avail; | 1450 | pos = head->read_avail; |
1387 | if (!tomoyo_io_printf(head, "allow_%s %s%s\n", msg, | 1451 | if (!tomoyo_io_printf(head, "allow_%s ", |
1388 | atmark, filename)) | 1452 | tomoyo_path2keyword(bit)) || |
1453 | !tomoyo_print_name_union(head, &ptr->name) || | ||
1454 | !tomoyo_io_printf(head, "\n")) | ||
1389 | goto out; | 1455 | goto out; |
1390 | } | 1456 | } |
1391 | head->read_bit = 0; | 1457 | head->read_bit = 0; |
@@ -1408,23 +1474,18 @@ static bool tomoyo_print_path2_acl(struct tomoyo_io_buffer *head, | |||
1408 | struct tomoyo_path2_acl *ptr) | 1474 | struct tomoyo_path2_acl *ptr) |
1409 | { | 1475 | { |
1410 | int pos; | 1476 | int pos; |
1411 | const char *atmark1 = ""; | ||
1412 | const char *atmark2 = ""; | ||
1413 | const char *filename1; | ||
1414 | const char *filename2; | ||
1415 | const u8 perm = ptr->perm; | 1477 | const u8 perm = ptr->perm; |
1416 | u8 bit; | 1478 | u8 bit; |
1417 | 1479 | ||
1418 | filename1 = ptr->filename1->name; | ||
1419 | filename2 = ptr->filename2->name; | ||
1420 | for (bit = head->read_bit; bit < TOMOYO_MAX_PATH2_OPERATION; bit++) { | 1480 | for (bit = head->read_bit; bit < TOMOYO_MAX_PATH2_OPERATION; bit++) { |
1421 | const char *msg; | ||
1422 | if (!(perm & (1 << bit))) | 1481 | if (!(perm & (1 << bit))) |
1423 | continue; | 1482 | continue; |
1424 | msg = tomoyo_path22keyword(bit); | ||
1425 | pos = head->read_avail; | 1483 | pos = head->read_avail; |
1426 | if (!tomoyo_io_printf(head, "allow_%s %s%s %s%s\n", msg, | 1484 | if (!tomoyo_io_printf(head, "allow_%s ", |
1427 | atmark1, filename1, atmark2, filename2)) | 1485 | tomoyo_path22keyword(bit)) || |
1486 | !tomoyo_print_name_union(head, &ptr->name1) || | ||
1487 | !tomoyo_print_name_union(head, &ptr->name2) || | ||
1488 | !tomoyo_io_printf(head, "\n")) | ||
1428 | goto out; | 1489 | goto out; |
1429 | } | 1490 | } |
1430 | head->read_bit = 0; | 1491 | head->read_bit = 0; |
@@ -1687,6 +1748,8 @@ static int tomoyo_write_exception_policy(struct tomoyo_io_buffer *head) | |||
1687 | return tomoyo_write_pattern_policy(data, is_delete); | 1748 | return tomoyo_write_pattern_policy(data, is_delete); |
1688 | if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_DENY_REWRITE)) | 1749 | if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_DENY_REWRITE)) |
1689 | return tomoyo_write_no_rewrite_policy(data, is_delete); | 1750 | return tomoyo_write_no_rewrite_policy(data, is_delete); |
1751 | if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_PATH_GROUP)) | ||
1752 | return tomoyo_write_path_group_policy(data, is_delete); | ||
1690 | return -EINVAL; | 1753 | return -EINVAL; |
1691 | } | 1754 | } |
1692 | 1755 | ||
@@ -1743,6 +1806,12 @@ static int tomoyo_read_exception_policy(struct tomoyo_io_buffer *head) | |||
1743 | head->read_var2 = NULL; | 1806 | head->read_var2 = NULL; |
1744 | head->read_step = 9; | 1807 | head->read_step = 9; |
1745 | case 9: | 1808 | case 9: |
1809 | if (!tomoyo_read_path_group_policy(head)) | ||
1810 | break; | ||
1811 | head->read_var1 = NULL; | ||
1812 | head->read_var2 = NULL; | ||
1813 | head->read_step = 10; | ||
1814 | case 10: | ||
1746 | head->read_eof = true; | 1815 | head->read_eof = true; |
1747 | break; | 1816 | break; |
1748 | default: | 1817 | default: |
@@ -1886,7 +1955,7 @@ static int tomoyo_read_self_domain(struct tomoyo_io_buffer *head) | |||
1886 | */ | 1955 | */ |
1887 | static int tomoyo_open_control(const u8 type, struct file *file) | 1956 | static int tomoyo_open_control(const u8 type, struct file *file) |
1888 | { | 1957 | { |
1889 | struct tomoyo_io_buffer *head = kzalloc(sizeof(*head), GFP_KERNEL); | 1958 | struct tomoyo_io_buffer *head = kzalloc(sizeof(*head), GFP_NOFS); |
1890 | 1959 | ||
1891 | if (!head) | 1960 | if (!head) |
1892 | return -ENOMEM; | 1961 | return -ENOMEM; |
@@ -1947,7 +2016,7 @@ static int tomoyo_open_control(const u8 type, struct file *file) | |||
1947 | } else { | 2016 | } else { |
1948 | if (!head->readbuf_size) | 2017 | if (!head->readbuf_size) |
1949 | head->readbuf_size = 4096 * 2; | 2018 | head->readbuf_size = 4096 * 2; |
1950 | head->read_buf = kzalloc(head->readbuf_size, GFP_KERNEL); | 2019 | head->read_buf = kzalloc(head->readbuf_size, GFP_NOFS); |
1951 | if (!head->read_buf) { | 2020 | if (!head->read_buf) { |
1952 | kfree(head); | 2021 | kfree(head); |
1953 | return -ENOMEM; | 2022 | return -ENOMEM; |
@@ -1961,7 +2030,7 @@ static int tomoyo_open_control(const u8 type, struct file *file) | |||
1961 | head->write = NULL; | 2030 | head->write = NULL; |
1962 | } else if (head->write) { | 2031 | } else if (head->write) { |
1963 | head->writebuf_size = 4096 * 2; | 2032 | head->writebuf_size = 4096 * 2; |
1964 | head->write_buf = kzalloc(head->writebuf_size, GFP_KERNEL); | 2033 | head->write_buf = kzalloc(head->writebuf_size, GFP_NOFS); |
1965 | if (!head->write_buf) { | 2034 | if (!head->write_buf) { |
1966 | kfree(head->read_buf); | 2035 | kfree(head->read_buf); |
1967 | kfree(head); | 2036 | kfree(head); |