aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>2010-06-20 22:14:39 -0400
committerJames Morris <jmorris@namei.org>2010-08-02 01:34:43 -0400
commit5448ec4f5062ef75ce74f8d7784d4cea9c46ad00 (patch)
treec4c742b928c799e03328e345e1d4af738f315afb
parent0617c7ff34dc9b1d641640c3953274bb2dbe21a6 (diff)
TOMOYO: Use common code for domain transition control.
Use common code for "initialize_domain"/"no_initialize_domain"/"keep_domain"/ "no_keep_domain" keywords. Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp> Signed-off-by: James Morris <jmorris@namei.org>
-rw-r--r--security/tomoyo/common.c55
-rw-r--r--security/tomoyo/common.h64
-rw-r--r--security/tomoyo/domain.c316
-rw-r--r--security/tomoyo/gc.c19
-rw-r--r--security/tomoyo/memory.c8
-rw-r--r--security/tomoyo/util.c2
6 files changed, 159 insertions, 305 deletions
diff --git a/security/tomoyo/common.c b/security/tomoyo/common.c
index 0e6b1b598b8..6568ef18112 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
1153static 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 12b0c5c46c8..1277724edae 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
99enum 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. */
101enum tomoyo_acl_entry_type_index { 109enum 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 */
635struct 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 */
659struct tomoyo_domain_keeper_entry { 643struct 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. */
795int tomoyo_write_aggregator_policy(char *data, const bool is_delete); 779int tomoyo_write_aggregator_policy(char *data, const bool is_delete);
796/* 780int 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 */
800int 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. */
803int 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,
922void tomoyo_check_acl(struct tomoyo_request_info *r, 899void 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 *));
902const 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 273e670acf0..05450b17c57 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
153static bool tomoyo_same_domain_initializer_entry(const struct tomoyo_acl_head * 153static 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 */
179static int tomoyo_update_domain_initializer_entry(const char *domainname, 179static 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 */
223int tomoyo_write_domain_initializer_policy(char *data, const bool is_not, 222int 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 */
250static bool tomoyo_domain_initializer(const struct tomoyo_path_info * 250static 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
283static 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 */
307static 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 */
349int 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 */
374static 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
404static bool tomoyo_same_aggregator_entry(const struct tomoyo_acl_head *a, 295static 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 4d4ba84f874..254ac114555 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
56static void tomoyo_del_domain_initializer(struct list_head *element) 56static 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
64static 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 a1d75df93e1..95a77599ff9 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 20abba22af4..12a768e6ee3 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 */
847static const char *tomoyo_last_word(const char *name) 847const 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)