diff options
Diffstat (limited to 'security/tomoyo')
-rw-r--r-- | security/tomoyo/common.c | 55 | ||||
-rw-r--r-- | security/tomoyo/common.h | 64 | ||||
-rw-r--r-- | security/tomoyo/domain.c | 316 | ||||
-rw-r--r-- | security/tomoyo/gc.c | 19 | ||||
-rw-r--r-- | security/tomoyo/memory.c | 8 | ||||
-rw-r--r-- | security/tomoyo/util.c | 2 |
6 files changed, 159 insertions, 305 deletions
diff --git a/security/tomoyo/common.c b/security/tomoyo/common.c index 0e6b1b598b86..6568ef18112b 100644 --- a/security/tomoyo/common.c +++ b/security/tomoyo/common.c | |||
@@ -1150,6 +1150,15 @@ static void tomoyo_read_pid(struct tomoyo_io_buffer *head) | |||
1150 | } | 1150 | } |
1151 | } | 1151 | } |
1152 | 1152 | ||
1153 | static const char *tomoyo_transition_type[TOMOYO_MAX_TRANSITION_TYPE] = { | ||
1154 | [TOMOYO_TRANSITION_CONTROL_NO_INITIALIZE] | ||
1155 | = TOMOYO_KEYWORD_NO_INITIALIZE_DOMAIN, | ||
1156 | [TOMOYO_TRANSITION_CONTROL_INITIALIZE] | ||
1157 | = TOMOYO_KEYWORD_INITIALIZE_DOMAIN, | ||
1158 | [TOMOYO_TRANSITION_CONTROL_NO_KEEP] = TOMOYO_KEYWORD_NO_KEEP_DOMAIN, | ||
1159 | [TOMOYO_TRANSITION_CONTROL_KEEP] = TOMOYO_KEYWORD_KEEP_DOMAIN | ||
1160 | }; | ||
1161 | |||
1153 | /** | 1162 | /** |
1154 | * tomoyo_write_exception_policy - Write exception policy. | 1163 | * tomoyo_write_exception_policy - Write exception policy. |
1155 | * | 1164 | * |
@@ -1163,18 +1172,13 @@ static int tomoyo_write_exception_policy(struct tomoyo_io_buffer *head) | |||
1163 | { | 1172 | { |
1164 | char *data = head->write_buf; | 1173 | char *data = head->write_buf; |
1165 | bool is_delete = tomoyo_str_starts(&data, TOMOYO_KEYWORD_DELETE); | 1174 | bool is_delete = tomoyo_str_starts(&data, TOMOYO_KEYWORD_DELETE); |
1175 | u8 i; | ||
1166 | 1176 | ||
1167 | if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_KEEP_DOMAIN)) | 1177 | for (i = 0; i < TOMOYO_MAX_TRANSITION_TYPE; i++) { |
1168 | return tomoyo_write_domain_keeper_policy(data, false, | 1178 | if (tomoyo_str_starts(&data, tomoyo_transition_type[i])) |
1169 | is_delete); | 1179 | return tomoyo_write_transition_control(data, is_delete, |
1170 | if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_NO_KEEP_DOMAIN)) | 1180 | i); |
1171 | return tomoyo_write_domain_keeper_policy(data, true, is_delete); | 1181 | } |
1172 | if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_INITIALIZE_DOMAIN)) | ||
1173 | return tomoyo_write_domain_initializer_policy(data, false, | ||
1174 | is_delete); | ||
1175 | if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_NO_INITIALIZE_DOMAIN)) | ||
1176 | return tomoyo_write_domain_initializer_policy(data, true, | ||
1177 | is_delete); | ||
1178 | if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_AGGREGATOR)) | 1182 | if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_AGGREGATOR)) |
1179 | return tomoyo_write_aggregator_policy(data, is_delete); | 1183 | return tomoyo_write_aggregator_policy(data, is_delete); |
1180 | if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_ALLOW_READ)) | 1184 | if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_ALLOW_READ)) |
@@ -1296,32 +1300,17 @@ static bool tomoyo_read_policy(struct tomoyo_io_buffer *head, const int idx) | |||
1296 | if (acl->is_deleted) | 1300 | if (acl->is_deleted) |
1297 | continue; | 1301 | continue; |
1298 | switch (idx) { | 1302 | switch (idx) { |
1299 | case TOMOYO_ID_DOMAIN_KEEPER: | 1303 | case TOMOYO_ID_TRANSITION_CONTROL: |
1300 | { | 1304 | { |
1301 | struct tomoyo_domain_keeper_entry *ptr = | 1305 | struct tomoyo_transition_control *ptr = |
1302 | container_of(acl, typeof(*ptr), head); | 1306 | container_of(acl, typeof(*ptr), head); |
1303 | w[0] = ptr->is_not ? | 1307 | w[0] = tomoyo_transition_type[ptr->type]; |
1304 | TOMOYO_KEYWORD_NO_KEEP_DOMAIN : | 1308 | if (ptr->program) |
1305 | TOMOYO_KEYWORD_KEEP_DOMAIN; | ||
1306 | if (ptr->program) { | ||
1307 | w[1] = ptr->program->name; | 1309 | w[1] = ptr->program->name; |
1308 | w[2] = " from "; | 1310 | if (ptr->domainname) |
1309 | } | ||
1310 | w[3] = ptr->domainname->name; | ||
1311 | } | ||
1312 | break; | ||
1313 | case TOMOYO_ID_DOMAIN_INITIALIZER: | ||
1314 | { | ||
1315 | struct tomoyo_domain_initializer_entry *ptr = | ||
1316 | container_of(acl, typeof(*ptr), head); | ||
1317 | w[0] = ptr->is_not ? | ||
1318 | TOMOYO_KEYWORD_NO_INITIALIZE_DOMAIN : | ||
1319 | TOMOYO_KEYWORD_INITIALIZE_DOMAIN; | ||
1320 | w[1] = ptr->program->name; | ||
1321 | if (ptr->domainname) { | ||
1322 | w[2] = " from "; | ||
1323 | w[3] = ptr->domainname->name; | 1311 | w[3] = ptr->domainname->name; |
1324 | } | 1312 | if (w[1][0] && w[3][0]) |
1313 | w[2] = " from "; | ||
1325 | } | 1314 | } |
1326 | break; | 1315 | break; |
1327 | case TOMOYO_ID_GLOBALLY_READABLE: | 1316 | case TOMOYO_ID_GLOBALLY_READABLE: |
diff --git a/security/tomoyo/common.h b/security/tomoyo/common.h index 12b0c5c46c8d..1277724edae4 100644 --- a/security/tomoyo/common.h +++ b/security/tomoyo/common.h | |||
@@ -50,8 +50,7 @@ enum tomoyo_policy_id { | |||
50 | TOMOYO_ID_GROUP, | 50 | TOMOYO_ID_GROUP, |
51 | TOMOYO_ID_PATH_GROUP, | 51 | TOMOYO_ID_PATH_GROUP, |
52 | TOMOYO_ID_NUMBER_GROUP, | 52 | TOMOYO_ID_NUMBER_GROUP, |
53 | TOMOYO_ID_DOMAIN_INITIALIZER, | 53 | TOMOYO_ID_TRANSITION_CONTROL, |
54 | TOMOYO_ID_DOMAIN_KEEPER, | ||
55 | TOMOYO_ID_AGGREGATOR, | 54 | TOMOYO_ID_AGGREGATOR, |
56 | TOMOYO_ID_GLOBALLY_READABLE, | 55 | TOMOYO_ID_GLOBALLY_READABLE, |
57 | TOMOYO_ID_PATTERN, | 56 | TOMOYO_ID_PATTERN, |
@@ -97,6 +96,15 @@ enum tomoyo_group_id { | |||
97 | #define TOMOYO_VALUE_TYPE_OCTAL 2 | 96 | #define TOMOYO_VALUE_TYPE_OCTAL 2 |
98 | #define TOMOYO_VALUE_TYPE_HEXADECIMAL 3 | 97 | #define TOMOYO_VALUE_TYPE_HEXADECIMAL 3 |
99 | 98 | ||
99 | enum tomoyo_transition_type { | ||
100 | /* Do not change this order, */ | ||
101 | TOMOYO_TRANSITION_CONTROL_NO_INITIALIZE, | ||
102 | TOMOYO_TRANSITION_CONTROL_INITIALIZE, | ||
103 | TOMOYO_TRANSITION_CONTROL_NO_KEEP, | ||
104 | TOMOYO_TRANSITION_CONTROL_KEEP, | ||
105 | TOMOYO_MAX_TRANSITION_TYPE | ||
106 | }; | ||
107 | |||
100 | /* Index numbers for Access Controls. */ | 108 | /* Index numbers for Access Controls. */ |
101 | enum tomoyo_acl_entry_type_index { | 109 | enum tomoyo_acl_entry_type_index { |
102 | TOMOYO_TYPE_PATH_ACL, | 110 | TOMOYO_TYPE_PATH_ACL, |
@@ -619,50 +627,26 @@ struct tomoyo_no_rewrite_entry { | |||
619 | }; | 627 | }; |
620 | 628 | ||
621 | /* | 629 | /* |
622 | * tomoyo_domain_initializer_entry is a structure which is used for holding | 630 | * tomoyo_transition_control is a structure which is used for holding |
623 | * "initialize_domain" and "no_initialize_domain" entries. | 631 | * "initialize_domain"/"no_initialize_domain"/"keep_domain"/"no_keep_domain" |
632 | * entries. | ||
624 | * It has following fields. | 633 | * It has following fields. |
625 | * | 634 | * |
626 | * (1) "head" is "struct tomoyo_acl_head". | 635 | * (1) "head" is "struct tomoyo_acl_head". |
627 | * (2) "is_not" is a bool which is true if "no_initialize_domain", false | 636 | * (2) "type" is type of this entry. |
628 | * otherwise. | ||
629 | * (3) "is_last_name" is a bool which is true if "domainname" is "the last | ||
630 | * component of a domainname", false otherwise. | ||
631 | * (4) "domainname" which is "a domainname" or "the last component of a | ||
632 | * domainname". This field is NULL if "from" clause is not specified. | ||
633 | * (5) "program" which is a program's pathname. | ||
634 | */ | ||
635 | struct tomoyo_domain_initializer_entry { | ||
636 | struct tomoyo_acl_head head; | ||
637 | bool is_not; /* True if this entry is "no_initialize_domain". */ | ||
638 | /* True if the domainname is tomoyo_get_last_name(). */ | ||
639 | bool is_last_name; | ||
640 | const struct tomoyo_path_info *domainname; /* This may be NULL */ | ||
641 | const struct tomoyo_path_info *program; | ||
642 | }; | ||
643 | |||
644 | /* | ||
645 | * tomoyo_domain_keeper_entry is a structure which is used for holding | ||
646 | * "keep_domain" and "no_keep_domain" entries. | ||
647 | * It has following fields. | ||
648 | * | ||
649 | * (1) "head" is "struct tomoyo_acl_head". | ||
650 | * (2) "is_not" is a bool which is true if "no_initialize_domain", false | ||
651 | * otherwise. | ||
652 | * (3) "is_last_name" is a bool which is true if "domainname" is "the last | 637 | * (3) "is_last_name" is a bool which is true if "domainname" is "the last |
653 | * component of a domainname", false otherwise. | 638 | * component of a domainname", false otherwise. |
654 | * (4) "domainname" which is "a domainname" or "the last component of a | 639 | * (4) "domainname" which is "a domainname" or "the last component of a |
655 | * domainname". | 640 | * domainname". |
656 | * (5) "program" which is a program's pathname. | 641 | * (5) "program" which is a program's pathname. |
657 | * This field is NULL if "from" clause is not specified. | ||
658 | */ | 642 | */ |
659 | struct tomoyo_domain_keeper_entry { | 643 | struct tomoyo_transition_control { |
660 | struct tomoyo_acl_head head; | 644 | struct tomoyo_acl_head head; |
661 | bool is_not; /* True if this entry is "no_keep_domain". */ | 645 | u8 type; /* One of values in "enum tomoyo_transition_type". */ |
662 | /* True if the domainname is tomoyo_get_last_name(). */ | 646 | /* True if the domainname is tomoyo_get_last_name(). */ |
663 | bool is_last_name; | 647 | bool is_last_name; |
664 | const struct tomoyo_path_info *domainname; | 648 | const struct tomoyo_path_info *domainname; /* Maybe NULL */ |
665 | const struct tomoyo_path_info *program; /* This may be NULL */ | 649 | const struct tomoyo_path_info *program; /* Maybe NULL */ |
666 | }; | 650 | }; |
667 | 651 | ||
668 | /* | 652 | /* |
@@ -793,15 +777,8 @@ int tomoyo_mount_permission(char *dev_name, struct path *path, char *type, | |||
793 | unsigned long flags, void *data_page); | 777 | unsigned long flags, void *data_page); |
794 | /* Create "aggregator" entry in exception policy. */ | 778 | /* Create "aggregator" entry in exception policy. */ |
795 | int tomoyo_write_aggregator_policy(char *data, const bool is_delete); | 779 | int tomoyo_write_aggregator_policy(char *data, const bool is_delete); |
796 | /* | 780 | int tomoyo_write_transition_control(char *data, const bool is_delete, |
797 | * Create "initialize_domain" and "no_initialize_domain" entry | 781 | const u8 type); |
798 | * in exception policy. | ||
799 | */ | ||
800 | int tomoyo_write_domain_initializer_policy(char *data, const bool is_not, | ||
801 | const bool is_delete); | ||
802 | /* Create "keep_domain" and "no_keep_domain" entry in exception policy. */ | ||
803 | int tomoyo_write_domain_keeper_policy(char *data, const bool is_not, | ||
804 | const bool is_delete); | ||
805 | /* | 782 | /* |
806 | * Create "allow_read/write", "allow_execute", "allow_read", "allow_write", | 783 | * Create "allow_read/write", "allow_execute", "allow_read", "allow_write", |
807 | * "allow_create", "allow_unlink", "allow_mkdir", "allow_rmdir", | 784 | * "allow_create", "allow_unlink", "allow_mkdir", "allow_rmdir", |
@@ -922,6 +899,7 @@ int tomoyo_update_policy(struct tomoyo_acl_head *new_entry, const int size, | |||
922 | void tomoyo_check_acl(struct tomoyo_request_info *r, | 899 | void tomoyo_check_acl(struct tomoyo_request_info *r, |
923 | bool (*check_entry) (const struct tomoyo_request_info *, | 900 | bool (*check_entry) (const struct tomoyo_request_info *, |
924 | const struct tomoyo_acl_info *)); | 901 | const struct tomoyo_acl_info *)); |
902 | const char *tomoyo_last_word(const char *name); | ||
925 | 903 | ||
926 | /********** External variable definitions. **********/ | 904 | /********** External variable definitions. **********/ |
927 | 905 | ||
diff --git a/security/tomoyo/domain.c b/security/tomoyo/domain.c index 273e670acf0c..05450b17c57f 100644 --- a/security/tomoyo/domain.c +++ b/security/tomoyo/domain.c | |||
@@ -150,59 +150,60 @@ const char *tomoyo_get_last_name(const struct tomoyo_domain_info *domain) | |||
150 | return cp0; | 150 | return cp0; |
151 | } | 151 | } |
152 | 152 | ||
153 | static bool tomoyo_same_domain_initializer_entry(const struct tomoyo_acl_head * | 153 | static bool tomoyo_same_transition_control_entry(const struct tomoyo_acl_head * |
154 | a, | 154 | a, |
155 | const struct tomoyo_acl_head * | 155 | const struct tomoyo_acl_head * |
156 | b) | 156 | b) |
157 | { | 157 | { |
158 | const struct tomoyo_domain_initializer_entry *p1 = | 158 | const struct tomoyo_transition_control *p1 = container_of(a, |
159 | container_of(a, typeof(*p1), head); | 159 | typeof(*p1), |
160 | const struct tomoyo_domain_initializer_entry *p2 = | 160 | head); |
161 | container_of(b, typeof(*p2), head); | 161 | const struct tomoyo_transition_control *p2 = container_of(b, |
162 | return p1->is_not == p2->is_not && p1->is_last_name == p2->is_last_name | 162 | typeof(*p2), |
163 | head); | ||
164 | return p1->type == p2->type && p1->is_last_name == p2->is_last_name | ||
163 | && p1->domainname == p2->domainname | 165 | && p1->domainname == p2->domainname |
164 | && p1->program == p2->program; | 166 | && p1->program == p2->program; |
165 | } | 167 | } |
166 | 168 | ||
167 | /** | 169 | /** |
168 | * tomoyo_update_domain_initializer_entry - Update "struct tomoyo_domain_initializer_entry" list. | 170 | * tomoyo_update_transition_control_entry - Update "struct tomoyo_transition_control" list. |
169 | * | 171 | * |
170 | * @domainname: The name of domain. May be NULL. | 172 | * @domainname: The name of domain. Maybe NULL. |
171 | * @program: The name of program. | 173 | * @program: The name of program. Maybe NULL. |
172 | * @is_not: True if it is "no_initialize_domain" entry. | 174 | * @type: Type of transition. |
173 | * @is_delete: True if it is a delete request. | 175 | * @is_delete: True if it is a delete request. |
174 | * | 176 | * |
175 | * Returns 0 on success, negative value otherwise. | 177 | * Returns 0 on success, negative value otherwise. |
176 | * | ||
177 | * Caller holds tomoyo_read_lock(). | ||
178 | */ | 178 | */ |
179 | static int tomoyo_update_domain_initializer_entry(const char *domainname, | 179 | static int tomoyo_update_transition_control_entry(const char *domainname, |
180 | const char *program, | 180 | const char *program, |
181 | const bool is_not, | 181 | const u8 type, |
182 | const bool is_delete) | 182 | const bool is_delete) |
183 | { | 183 | { |
184 | struct tomoyo_domain_initializer_entry e = { .is_not = is_not }; | 184 | struct tomoyo_transition_control e = { .type = type }; |
185 | int error = is_delete ? -ENOENT : -ENOMEM; | 185 | int error = is_delete ? -ENOENT : -ENOMEM; |
186 | 186 | if (program) { | |
187 | if (!tomoyo_correct_path(program)) | 187 | if (!tomoyo_correct_path(program)) |
188 | return -EINVAL; | 188 | return -EINVAL; |
189 | e.program = tomoyo_get_name(program); | ||
190 | if (!e.program) | ||
191 | goto out; | ||
192 | } | ||
189 | if (domainname) { | 193 | if (domainname) { |
190 | if (!tomoyo_domain_def(domainname) && | 194 | if (!tomoyo_correct_domain(domainname)) { |
191 | tomoyo_correct_path(domainname)) | 195 | if (!tomoyo_correct_path(domainname)) |
196 | goto out; | ||
192 | e.is_last_name = true; | 197 | e.is_last_name = true; |
193 | else if (!tomoyo_correct_domain(domainname)) | 198 | } |
194 | return -EINVAL; | ||
195 | e.domainname = tomoyo_get_name(domainname); | 199 | e.domainname = tomoyo_get_name(domainname); |
196 | if (!e.domainname) | 200 | if (!e.domainname) |
197 | goto out; | 201 | goto out; |
198 | } | 202 | } |
199 | e.program = tomoyo_get_name(program); | ||
200 | if (!e.program) | ||
201 | goto out; | ||
202 | error = tomoyo_update_policy(&e.head, sizeof(e), is_delete, | 203 | error = tomoyo_update_policy(&e.head, sizeof(e), is_delete, |
203 | &tomoyo_policy_list | 204 | &tomoyo_policy_list |
204 | [TOMOYO_ID_DOMAIN_INITIALIZER], | 205 | [TOMOYO_ID_TRANSITION_CONTROL], |
205 | tomoyo_same_domain_initializer_entry); | 206 | tomoyo_same_transition_control_entry); |
206 | out: | 207 | out: |
207 | tomoyo_put_name(e.domainname); | 208 | tomoyo_put_name(e.domainname); |
208 | tomoyo_put_name(e.program); | 209 | tomoyo_put_name(e.program); |
@@ -210,195 +211,85 @@ static int tomoyo_update_domain_initializer_entry(const char *domainname, | |||
210 | } | 211 | } |
211 | 212 | ||
212 | /** | 213 | /** |
213 | * tomoyo_write_domain_initializer_policy - Write "struct tomoyo_domain_initializer_entry" list. | 214 | * tomoyo_write_transition_control - Write "struct tomoyo_transition_control" list. |
214 | * | 215 | * |
215 | * @data: String to parse. | 216 | * @data: String to parse. |
216 | * @is_not: True if it is "no_initialize_domain" entry. | ||
217 | * @is_delete: True if it is a delete request. | 217 | * @is_delete: True if it is a delete request. |
218 | * @type: Type of this entry. | ||
218 | * | 219 | * |
219 | * Returns 0 on success, negative value otherwise. | 220 | * Returns 0 on success, negative value otherwise. |
220 | * | ||
221 | * Caller holds tomoyo_read_lock(). | ||
222 | */ | 221 | */ |
223 | int tomoyo_write_domain_initializer_policy(char *data, const bool is_not, | 222 | int tomoyo_write_transition_control(char *data, const bool is_delete, |
224 | const bool is_delete) | 223 | const u8 type) |
225 | { | 224 | { |
226 | char *cp = strstr(data, " from "); | 225 | char *domainname = strstr(data, " from "); |
227 | 226 | if (domainname) { | |
228 | if (cp) { | 227 | *domainname = '\0'; |
229 | *cp = '\0'; | 228 | domainname += 6; |
230 | return tomoyo_update_domain_initializer_entry(cp + 6, data, | 229 | } else if (type == TOMOYO_TRANSITION_CONTROL_NO_KEEP || |
231 | is_not, | 230 | type == TOMOYO_TRANSITION_CONTROL_KEEP) { |
232 | is_delete); | 231 | domainname = data; |
232 | data = NULL; | ||
233 | } | 233 | } |
234 | return tomoyo_update_domain_initializer_entry(NULL, data, is_not, | 234 | return tomoyo_update_transition_control_entry(domainname, data, type, |
235 | is_delete); | 235 | is_delete); |
236 | } | 236 | } |
237 | 237 | ||
238 | /** | 238 | /** |
239 | * tomoyo_domain_initializer - Check whether the given program causes domainname reinitialization. | 239 | * tomoyo_transition_type - Get domain transition type. |
240 | * | 240 | * |
241 | * @domainname: The name of domain. | 241 | * @domainname: The name of domain. |
242 | * @program: The name of program. | 242 | * @program: The name of program. |
243 | * @last_name: The last component of @domainname. | ||
244 | * | 243 | * |
245 | * Returns true if executing @program reinitializes domain transition, | 244 | * Returns TOMOYO_TRANSITION_CONTROL_INITIALIZE if executing @program |
246 | * false otherwise. | 245 | * reinitializes domain transition, TOMOYO_TRANSITION_CONTROL_KEEP if executing |
246 | * @program suppresses domain transition, others otherwise. | ||
247 | * | 247 | * |
248 | * Caller holds tomoyo_read_lock(). | 248 | * Caller holds tomoyo_read_lock(). |
249 | */ | 249 | */ |
250 | static bool tomoyo_domain_initializer(const struct tomoyo_path_info * | 250 | static u8 tomoyo_transition_type(const struct tomoyo_path_info *domainname, |
251 | domainname, | 251 | const struct tomoyo_path_info *program) |
252 | const struct tomoyo_path_info *program, | ||
253 | const struct tomoyo_path_info * | ||
254 | last_name) | ||
255 | { | 252 | { |
256 | struct tomoyo_domain_initializer_entry *ptr; | 253 | const struct tomoyo_transition_control *ptr; |
257 | bool flag = false; | 254 | const char *last_name = tomoyo_last_word(domainname->name); |
258 | 255 | u8 type; | |
259 | list_for_each_entry_rcu(ptr, &tomoyo_policy_list | 256 | for (type = 0; type < TOMOYO_MAX_TRANSITION_TYPE; type++) { |
260 | [TOMOYO_ID_DOMAIN_INITIALIZER], head.list) { | 257 | next: |
261 | if (ptr->head.is_deleted) | 258 | list_for_each_entry_rcu(ptr, &tomoyo_policy_list |
262 | continue; | 259 | [TOMOYO_ID_TRANSITION_CONTROL], |
263 | if (ptr->domainname) { | 260 | head.list) { |
264 | if (!ptr->is_last_name) { | 261 | if (ptr->head.is_deleted || ptr->type != type) |
265 | if (ptr->domainname != domainname) | ||
266 | continue; | ||
267 | } else { | ||
268 | if (tomoyo_pathcmp(ptr->domainname, last_name)) | ||
269 | continue; | ||
270 | } | ||
271 | } | ||
272 | if (tomoyo_pathcmp(ptr->program, program)) | ||
273 | continue; | ||
274 | if (ptr->is_not) { | ||
275 | flag = false; | ||
276 | break; | ||
277 | } | ||
278 | flag = true; | ||
279 | } | ||
280 | return flag; | ||
281 | } | ||
282 | |||
283 | static bool tomoyo_same_domain_keeper_entry(const struct tomoyo_acl_head *a, | ||
284 | const struct tomoyo_acl_head *b) | ||
285 | { | ||
286 | const struct tomoyo_domain_keeper_entry *p1 = | ||
287 | container_of(a, typeof(*p1), head); | ||
288 | const struct tomoyo_domain_keeper_entry *p2 = | ||
289 | container_of(b, typeof(*p2), head); | ||
290 | return p1->is_not == p2->is_not && p1->is_last_name == p2->is_last_name | ||
291 | && p1->domainname == p2->domainname | ||
292 | && p1->program == p2->program; | ||
293 | } | ||
294 | |||
295 | /** | ||
296 | * tomoyo_update_domain_keeper_entry - Update "struct tomoyo_domain_keeper_entry" list. | ||
297 | * | ||
298 | * @domainname: The name of domain. | ||
299 | * @program: The name of program. May be NULL. | ||
300 | * @is_not: True if it is "no_keep_domain" entry. | ||
301 | * @is_delete: True if it is a delete request. | ||
302 | * | ||
303 | * Returns 0 on success, negative value otherwise. | ||
304 | * | ||
305 | * Caller holds tomoyo_read_lock(). | ||
306 | */ | ||
307 | static int tomoyo_update_domain_keeper_entry(const char *domainname, | ||
308 | const char *program, | ||
309 | const bool is_not, | ||
310 | const bool is_delete) | ||
311 | { | ||
312 | struct tomoyo_domain_keeper_entry e = { .is_not = is_not }; | ||
313 | int error = is_delete ? -ENOENT : -ENOMEM; | ||
314 | |||
315 | if (!tomoyo_domain_def(domainname) && | ||
316 | tomoyo_correct_path(domainname)) | ||
317 | e.is_last_name = true; | ||
318 | else if (!tomoyo_correct_domain(domainname)) | ||
319 | return -EINVAL; | ||
320 | if (program) { | ||
321 | if (!tomoyo_correct_path(program)) | ||
322 | return -EINVAL; | ||
323 | e.program = tomoyo_get_name(program); | ||
324 | if (!e.program) | ||
325 | goto out; | ||
326 | } | ||
327 | e.domainname = tomoyo_get_name(domainname); | ||
328 | if (!e.domainname) | ||
329 | goto out; | ||
330 | error = tomoyo_update_policy(&e.head, sizeof(e), is_delete, | ||
331 | &tomoyo_policy_list | ||
332 | [TOMOYO_ID_DOMAIN_KEEPER], | ||
333 | tomoyo_same_domain_keeper_entry); | ||
334 | out: | ||
335 | tomoyo_put_name(e.domainname); | ||
336 | tomoyo_put_name(e.program); | ||
337 | return error; | ||
338 | } | ||
339 | |||
340 | /** | ||
341 | * tomoyo_write_domain_keeper_policy - Write "struct tomoyo_domain_keeper_entry" list. | ||
342 | * | ||
343 | * @data: String to parse. | ||
344 | * @is_not: True if it is "no_keep_domain" entry. | ||
345 | * @is_delete: True if it is a delete request. | ||
346 | * | ||
347 | * Caller holds tomoyo_read_lock(). | ||
348 | */ | ||
349 | int tomoyo_write_domain_keeper_policy(char *data, const bool is_not, | ||
350 | const bool is_delete) | ||
351 | { | ||
352 | char *cp = strstr(data, " from "); | ||
353 | |||
354 | if (cp) { | ||
355 | *cp = '\0'; | ||
356 | return tomoyo_update_domain_keeper_entry(cp + 6, data, is_not, | ||
357 | is_delete); | ||
358 | } | ||
359 | return tomoyo_update_domain_keeper_entry(data, NULL, is_not, is_delete); | ||
360 | } | ||
361 | |||
362 | /** | ||
363 | * tomoyo_domain_keeper - Check whether the given program causes domain transition suppression. | ||
364 | * | ||
365 | * @domainname: The name of domain. | ||
366 | * @program: The name of program. | ||
367 | * @last_name: The last component of @domainname. | ||
368 | * | ||
369 | * Returns true if executing @program supresses domain transition, | ||
370 | * false otherwise. | ||
371 | * | ||
372 | * Caller holds tomoyo_read_lock(). | ||
373 | */ | ||
374 | static bool tomoyo_domain_keeper(const struct tomoyo_path_info *domainname, | ||
375 | const struct tomoyo_path_info *program, | ||
376 | const struct tomoyo_path_info *last_name) | ||
377 | { | ||
378 | struct tomoyo_domain_keeper_entry *ptr; | ||
379 | bool flag = false; | ||
380 | |||
381 | list_for_each_entry_rcu(ptr, | ||
382 | &tomoyo_policy_list[TOMOYO_ID_DOMAIN_KEEPER], | ||
383 | head.list) { | ||
384 | if (ptr->head.is_deleted) | ||
385 | continue; | ||
386 | if (!ptr->is_last_name) { | ||
387 | if (ptr->domainname != domainname) | ||
388 | continue; | 262 | continue; |
389 | } else { | 263 | if (ptr->domainname) { |
390 | if (tomoyo_pathcmp(ptr->domainname, last_name)) | 264 | if (!ptr->is_last_name) { |
265 | if (ptr->domainname != domainname) | ||
266 | continue; | ||
267 | } else { | ||
268 | /* | ||
269 | * Use direct strcmp() since this is | ||
270 | * unlikely used. | ||
271 | */ | ||
272 | if (strcmp(ptr->domainname->name, | ||
273 | last_name)) | ||
274 | continue; | ||
275 | } | ||
276 | } | ||
277 | if (ptr->program && | ||
278 | tomoyo_pathcmp(ptr->program, program)) | ||
391 | continue; | 279 | continue; |
280 | if (type == TOMOYO_TRANSITION_CONTROL_NO_INITIALIZE) { | ||
281 | /* | ||
282 | * Do not check for initialize_domain if | ||
283 | * no_initialize_domain matched. | ||
284 | */ | ||
285 | type = TOMOYO_TRANSITION_CONTROL_NO_KEEP; | ||
286 | goto next; | ||
287 | } | ||
288 | goto done; | ||
392 | } | 289 | } |
393 | if (ptr->program && tomoyo_pathcmp(ptr->program, program)) | ||
394 | continue; | ||
395 | if (ptr->is_not) { | ||
396 | flag = false; | ||
397 | break; | ||
398 | } | ||
399 | flag = true; | ||
400 | } | 290 | } |
401 | return flag; | 291 | done: |
292 | return type; | ||
402 | } | 293 | } |
403 | 294 | ||
404 | static bool tomoyo_same_aggregator_entry(const struct tomoyo_acl_head *a, | 295 | static bool tomoyo_same_aggregator_entry(const struct tomoyo_acl_head *a, |
@@ -533,7 +424,6 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm) | |||
533 | char *tmp = kzalloc(TOMOYO_EXEC_TMPSIZE, GFP_NOFS); | 424 | char *tmp = kzalloc(TOMOYO_EXEC_TMPSIZE, GFP_NOFS); |
534 | struct tomoyo_domain_info *old_domain = tomoyo_domain(); | 425 | struct tomoyo_domain_info *old_domain = tomoyo_domain(); |
535 | struct tomoyo_domain_info *domain = NULL; | 426 | struct tomoyo_domain_info *domain = NULL; |
536 | const char *old_domain_name = old_domain->domainname->name; | ||
537 | const char *original_name = bprm->filename; | 427 | const char *original_name = bprm->filename; |
538 | u8 mode; | 428 | u8 mode; |
539 | bool is_enforce; | 429 | bool is_enforce; |
@@ -586,25 +476,33 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm) | |||
586 | if (retval < 0) | 476 | if (retval < 0) |
587 | goto out; | 477 | goto out; |
588 | 478 | ||
589 | if (tomoyo_domain_initializer(old_domain->domainname, &rn, &ln)) { | 479 | /* Calculate domain to transit to. */ |
480 | switch (tomoyo_transition_type(old_domain->domainname, &rn)) { | ||
481 | case TOMOYO_TRANSITION_CONTROL_INITIALIZE: | ||
590 | /* Transit to the child of tomoyo_kernel_domain domain. */ | 482 | /* Transit to the child of tomoyo_kernel_domain domain. */ |
591 | snprintf(tmp, TOMOYO_EXEC_TMPSIZE - 1, | 483 | snprintf(tmp, TOMOYO_EXEC_TMPSIZE - 1, TOMOYO_ROOT_NAME " " |
592 | TOMOYO_ROOT_NAME " " "%s", rn.name); | 484 | "%s", rn.name); |
593 | } else if (old_domain == &tomoyo_kernel_domain && | 485 | break; |
594 | !tomoyo_policy_loaded) { | 486 | case TOMOYO_TRANSITION_CONTROL_KEEP: |
595 | /* | ||
596 | * Needn't to transit from kernel domain before starting | ||
597 | * /sbin/init. But transit from kernel domain if executing | ||
598 | * initializers because they might start before /sbin/init. | ||
599 | */ | ||
600 | domain = old_domain; | ||
601 | } else if (tomoyo_domain_keeper(old_domain->domainname, &rn, &ln)) { | ||
602 | /* Keep current domain. */ | 487 | /* Keep current domain. */ |
603 | domain = old_domain; | 488 | domain = old_domain; |
604 | } else { | 489 | break; |
605 | /* Normal domain transition. */ | 490 | default: |
606 | snprintf(tmp, TOMOYO_EXEC_TMPSIZE - 1, | 491 | if (old_domain == &tomoyo_kernel_domain && |
607 | "%s %s", old_domain_name, rn.name); | 492 | !tomoyo_policy_loaded) { |
493 | /* | ||
494 | * Needn't to transit from kernel domain before | ||
495 | * starting /sbin/init. But transit from kernel domain | ||
496 | * if executing initializers because they might start | ||
497 | * before /sbin/init. | ||
498 | */ | ||
499 | domain = old_domain; | ||
500 | } else { | ||
501 | /* Normal domain transition. */ | ||
502 | snprintf(tmp, TOMOYO_EXEC_TMPSIZE - 1, "%s %s", | ||
503 | old_domain->domainname->name, rn.name); | ||
504 | } | ||
505 | break; | ||
608 | } | 506 | } |
609 | if (domain || strlen(tmp) >= TOMOYO_EXEC_TMPSIZE - 10) | 507 | if (domain || strlen(tmp) >= TOMOYO_EXEC_TMPSIZE - 10) |
610 | goto done; | 508 | goto done; |
diff --git a/security/tomoyo/gc.c b/security/tomoyo/gc.c index 4d4ba84f8749..254ac1145552 100644 --- a/security/tomoyo/gc.c +++ b/security/tomoyo/gc.c | |||
@@ -53,17 +53,9 @@ static void tomoyo_del_no_rewrite(struct list_head *element) | |||
53 | tomoyo_put_name(ptr->pattern); | 53 | tomoyo_put_name(ptr->pattern); |
54 | } | 54 | } |
55 | 55 | ||
56 | static void tomoyo_del_domain_initializer(struct list_head *element) | 56 | static void tomoyo_del_transition_control(struct list_head *element) |
57 | { | 57 | { |
58 | struct tomoyo_domain_initializer_entry *ptr = | 58 | struct tomoyo_transition_control *ptr = |
59 | container_of(element, typeof(*ptr), head.list); | ||
60 | tomoyo_put_name(ptr->domainname); | ||
61 | tomoyo_put_name(ptr->program); | ||
62 | } | ||
63 | |||
64 | static void tomoyo_del_domain_keeper(struct list_head *element) | ||
65 | { | ||
66 | struct tomoyo_domain_keeper_entry *ptr = | ||
67 | container_of(element, typeof(*ptr), head.list); | 59 | container_of(element, typeof(*ptr), head.list); |
68 | tomoyo_put_name(ptr->domainname); | 60 | tomoyo_put_name(ptr->domainname); |
69 | tomoyo_put_name(ptr->program); | 61 | tomoyo_put_name(ptr->program); |
@@ -292,11 +284,8 @@ static void tomoyo_kfree_entry(void) | |||
292 | list_for_each_entry_safe(p, tmp, &tomoyo_gc_queue, list) { | 284 | list_for_each_entry_safe(p, tmp, &tomoyo_gc_queue, list) { |
293 | struct list_head *element = p->element; | 285 | struct list_head *element = p->element; |
294 | switch (p->type) { | 286 | switch (p->type) { |
295 | case TOMOYO_ID_DOMAIN_INITIALIZER: | 287 | case TOMOYO_ID_TRANSITION_CONTROL: |
296 | tomoyo_del_domain_initializer(element); | 288 | tomoyo_del_transition_control(element); |
297 | break; | ||
298 | case TOMOYO_ID_DOMAIN_KEEPER: | ||
299 | tomoyo_del_domain_keeper(element); | ||
300 | break; | 289 | break; |
301 | case TOMOYO_ID_AGGREGATOR: | 290 | case TOMOYO_ID_AGGREGATOR: |
302 | tomoyo_del_aggregator(element); | 291 | tomoyo_del_aggregator(element); |
diff --git a/security/tomoyo/memory.c b/security/tomoyo/memory.c index a1d75df93e16..95a77599ff98 100644 --- a/security/tomoyo/memory.c +++ b/security/tomoyo/memory.c | |||
@@ -211,10 +211,10 @@ void __init tomoyo_mm_init(void) | |||
211 | panic("Can't register tomoyo_kernel_domain"); | 211 | panic("Can't register tomoyo_kernel_domain"); |
212 | { | 212 | { |
213 | /* Load built-in policy. */ | 213 | /* Load built-in policy. */ |
214 | tomoyo_write_domain_initializer_policy("/sbin/hotplug", | 214 | tomoyo_write_transition_control("/sbin/hotplug", false, |
215 | false, false); | 215 | TOMOYO_TRANSITION_CONTROL_INITIALIZE); |
216 | tomoyo_write_domain_initializer_policy("/sbin/modprobe", | 216 | tomoyo_write_transition_control("/sbin/modprobe", false, |
217 | false, false); | 217 | TOMOYO_TRANSITION_CONTROL_INITIALIZE); |
218 | } | 218 | } |
219 | tomoyo_read_unlock(idx); | 219 | tomoyo_read_unlock(idx); |
220 | } | 220 | } |
diff --git a/security/tomoyo/util.c b/security/tomoyo/util.c index 20abba22af42..12a768e6ee3f 100644 --- a/security/tomoyo/util.c +++ b/security/tomoyo/util.c | |||
@@ -844,7 +844,7 @@ int tomoyo_init_request_info(struct tomoyo_request_info *r, | |||
844 | * | 844 | * |
845 | * Returns the last word of a line. | 845 | * Returns the last word of a line. |
846 | */ | 846 | */ |
847 | static const char *tomoyo_last_word(const char *name) | 847 | const char *tomoyo_last_word(const char *name) |
848 | { | 848 | { |
849 | const char *cp = strrchr(name, ' '); | 849 | const char *cp = strrchr(name, ' '); |
850 | if (cp) | 850 | if (cp) |