Commit | Line | Data |
---|---|---|
26a2a1c9 KT |
1 | /* |
2 | * security/tomoyo/domain.c | |
3 | * | |
c3ef1500 | 4 | * Domain transition functions for TOMOYO. |
26a2a1c9 | 5 | * |
c3ef1500 | 6 | * Copyright (C) 2005-2010 NTT DATA CORPORATION |
26a2a1c9 KT |
7 | */ |
8 | ||
9 | #include "common.h" | |
26a2a1c9 | 10 | #include <linux/binfmts.h> |
5a0e3ad6 | 11 | #include <linux/slab.h> |
26a2a1c9 KT |
12 | |
13 | /* Variables definitions.*/ | |
14 | ||
15 | /* The initial domain. */ | |
16 | struct tomoyo_domain_info tomoyo_kernel_domain; | |
17 | ||
36f5e1ff TH |
18 | /** |
19 | * tomoyo_update_policy - Update an entry for exception policy. | |
20 | * | |
21 | * @new_entry: Pointer to "struct tomoyo_acl_info". | |
22 | * @size: Size of @new_entry in bytes. | |
23 | * @is_delete: True if it is a delete request. | |
24 | * @list: Pointer to "struct list_head". | |
25 | * @check_duplicate: Callback function to find duplicated entry. | |
26 | * | |
27 | * Returns 0 on success, negative value otherwise. | |
28 | * | |
29 | * Caller holds tomoyo_read_lock(). | |
30 | */ | |
31 | int tomoyo_update_policy(struct tomoyo_acl_head *new_entry, const int size, | |
32 | bool is_delete, struct list_head *list, | |
33 | bool (*check_duplicate) (const struct tomoyo_acl_head | |
34 | *, | |
35 | const struct tomoyo_acl_head | |
36 | *)) | |
37 | { | |
38 | int error = is_delete ? -ENOENT : -ENOMEM; | |
39 | struct tomoyo_acl_head *entry; | |
40 | ||
41 | if (mutex_lock_interruptible(&tomoyo_policy_lock)) | |
42 | return -ENOMEM; | |
43 | list_for_each_entry_rcu(entry, list, list) { | |
44 | if (!check_duplicate(entry, new_entry)) | |
45 | continue; | |
46 | entry->is_deleted = is_delete; | |
47 | error = 0; | |
48 | break; | |
49 | } | |
50 | if (error && !is_delete) { | |
51 | entry = tomoyo_commit_ok(new_entry, size); | |
52 | if (entry) { | |
53 | list_add_tail_rcu(&entry->list, list); | |
54 | error = 0; | |
55 | } | |
56 | } | |
57 | mutex_unlock(&tomoyo_policy_lock); | |
58 | return error; | |
59 | } | |
60 | ||
0df7e8b8 TH |
61 | /** |
62 | * tomoyo_same_acl_head - Check for duplicated "struct tomoyo_acl_info" entry. | |
63 | * | |
64 | * @a: Pointer to "struct tomoyo_acl_info". | |
65 | * @b: Pointer to "struct tomoyo_acl_info". | |
66 | * | |
67 | * Returns true if @a == @b, false otherwise. | |
68 | */ | |
69 | static inline bool tomoyo_same_acl_head(const struct tomoyo_acl_info *a, | |
70 | const struct tomoyo_acl_info *b) | |
71 | { | |
72 | return a->type == b->type; | |
73 | } | |
74 | ||
237ab459 TH |
75 | /** |
76 | * tomoyo_update_domain - Update an entry for domain policy. | |
77 | * | |
78 | * @new_entry: Pointer to "struct tomoyo_acl_info". | |
79 | * @size: Size of @new_entry in bytes. | |
80 | * @is_delete: True if it is a delete request. | |
81 | * @domain: Pointer to "struct tomoyo_domain_info". | |
82 | * @check_duplicate: Callback function to find duplicated entry. | |
83 | * @merge_duplicate: Callback function to merge duplicated entry. | |
84 | * | |
85 | * Returns 0 on success, negative value otherwise. | |
86 | * | |
87 | * Caller holds tomoyo_read_lock(). | |
88 | */ | |
89 | int tomoyo_update_domain(struct tomoyo_acl_info *new_entry, const int size, | |
90 | bool is_delete, struct tomoyo_domain_info *domain, | |
91 | bool (*check_duplicate) (const struct tomoyo_acl_info | |
92 | *, | |
93 | const struct tomoyo_acl_info | |
94 | *), | |
95 | bool (*merge_duplicate) (struct tomoyo_acl_info *, | |
96 | struct tomoyo_acl_info *, | |
97 | const bool)) | |
98 | { | |
99 | int error = is_delete ? -ENOENT : -ENOMEM; | |
100 | struct tomoyo_acl_info *entry; | |
101 | ||
102 | if (mutex_lock_interruptible(&tomoyo_policy_lock)) | |
103 | return error; | |
104 | list_for_each_entry_rcu(entry, &domain->acl_info_list, list) { | |
0df7e8b8 TH |
105 | if (!tomoyo_same_acl_head(entry, new_entry) || |
106 | !check_duplicate(entry, new_entry)) | |
237ab459 TH |
107 | continue; |
108 | if (merge_duplicate) | |
109 | entry->is_deleted = merge_duplicate(entry, new_entry, | |
110 | is_delete); | |
111 | else | |
112 | entry->is_deleted = is_delete; | |
113 | error = 0; | |
114 | break; | |
115 | } | |
116 | if (error && !is_delete) { | |
117 | entry = tomoyo_commit_ok(new_entry, size); | |
118 | if (entry) { | |
119 | list_add_tail_rcu(&entry->list, &domain->acl_info_list); | |
120 | error = 0; | |
121 | } | |
122 | } | |
123 | mutex_unlock(&tomoyo_policy_lock); | |
124 | return error; | |
125 | } | |
126 | ||
99a85259 | 127 | void tomoyo_check_acl(struct tomoyo_request_info *r, |
484ca79c | 128 | bool (*check_entry) (struct tomoyo_request_info *, |
99a85259 TH |
129 | const struct tomoyo_acl_info *)) |
130 | { | |
131 | const struct tomoyo_domain_info *domain = r->domain; | |
132 | struct tomoyo_acl_info *ptr; | |
133 | ||
134 | list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { | |
135 | if (ptr->is_deleted || ptr->type != r->param_type) | |
136 | continue; | |
137 | if (check_entry(r, ptr)) { | |
138 | r->granted = true; | |
139 | return; | |
140 | } | |
141 | } | |
142 | r->granted = false; | |
143 | } | |
144 | ||
a230f9e7 | 145 | /* The list for "struct tomoyo_domain_info". */ |
26a2a1c9 | 146 | LIST_HEAD(tomoyo_domain_list); |
26a2a1c9 | 147 | |
a230f9e7 TH |
148 | struct list_head tomoyo_policy_list[TOMOYO_MAX_POLICY]; |
149 | struct list_head tomoyo_group_list[TOMOYO_MAX_GROUP]; | |
150 | ||
26a2a1c9 | 151 | /** |
e2bf6907 | 152 | * tomoyo_last_word - Get last component of a domainname. |
26a2a1c9 | 153 | * |
e2bf6907 | 154 | * @domainname: Domainname to check. |
26a2a1c9 | 155 | * |
e2bf6907 | 156 | * Returns the last word of @domainname. |
26a2a1c9 | 157 | */ |
e2bf6907 | 158 | static const char *tomoyo_last_word(const char *name) |
26a2a1c9 | 159 | { |
e2bf6907 TH |
160 | const char *cp = strrchr(name, ' '); |
161 | if (cp) | |
162 | return cp + 1; | |
163 | return name; | |
26a2a1c9 KT |
164 | } |
165 | ||
e2bf6907 TH |
166 | static bool tomoyo_same_transition_control(const struct tomoyo_acl_head *a, |
167 | const struct tomoyo_acl_head *b) | |
36f5e1ff | 168 | { |
5448ec4f TH |
169 | const struct tomoyo_transition_control *p1 = container_of(a, |
170 | typeof(*p1), | |
171 | head); | |
172 | const struct tomoyo_transition_control *p2 = container_of(b, | |
173 | typeof(*p2), | |
174 | head); | |
175 | return p1->type == p2->type && p1->is_last_name == p2->is_last_name | |
36f5e1ff TH |
176 | && p1->domainname == p2->domainname |
177 | && p1->program == p2->program; | |
178 | } | |
179 | ||
26a2a1c9 | 180 | /** |
5448ec4f | 181 | * tomoyo_update_transition_control_entry - Update "struct tomoyo_transition_control" list. |
26a2a1c9 | 182 | * |
5448ec4f TH |
183 | * @domainname: The name of domain. Maybe NULL. |
184 | * @program: The name of program. Maybe NULL. | |
185 | * @type: Type of transition. | |
26a2a1c9 KT |
186 | * @is_delete: True if it is a delete request. |
187 | * | |
188 | * Returns 0 on success, negative value otherwise. | |
189 | */ | |
5448ec4f | 190 | static int tomoyo_update_transition_control_entry(const char *domainname, |
26a2a1c9 | 191 | const char *program, |
5448ec4f | 192 | const u8 type, |
26a2a1c9 KT |
193 | const bool is_delete) |
194 | { | |
5448ec4f | 195 | struct tomoyo_transition_control e = { .type = type }; |
ca0b7df3 | 196 | int error = is_delete ? -ENOENT : -ENOMEM; |
5448ec4f TH |
197 | if (program) { |
198 | if (!tomoyo_correct_path(program)) | |
199 | return -EINVAL; | |
200 | e.program = tomoyo_get_name(program); | |
201 | if (!e.program) | |
202 | goto out; | |
203 | } | |
26a2a1c9 | 204 | if (domainname) { |
5448ec4f TH |
205 | if (!tomoyo_correct_domain(domainname)) { |
206 | if (!tomoyo_correct_path(domainname)) | |
207 | goto out; | |
9e4b50e9 | 208 | e.is_last_name = true; |
5448ec4f | 209 | } |
9e4b50e9 TH |
210 | e.domainname = tomoyo_get_name(domainname); |
211 | if (!e.domainname) | |
ca0b7df3 | 212 | goto out; |
26a2a1c9 | 213 | } |
36f5e1ff | 214 | error = tomoyo_update_policy(&e.head, sizeof(e), is_delete, |
a230f9e7 | 215 | &tomoyo_policy_list |
5448ec4f | 216 | [TOMOYO_ID_TRANSITION_CONTROL], |
e2bf6907 | 217 | tomoyo_same_transition_control); |
ca0b7df3 | 218 | out: |
9e4b50e9 TH |
219 | tomoyo_put_name(e.domainname); |
220 | tomoyo_put_name(e.program); | |
26a2a1c9 KT |
221 | return error; |
222 | } | |
223 | ||
26a2a1c9 | 224 | /** |
5448ec4f | 225 | * tomoyo_write_transition_control - Write "struct tomoyo_transition_control" list. |
26a2a1c9 KT |
226 | * |
227 | * @data: String to parse. | |
26a2a1c9 | 228 | * @is_delete: True if it is a delete request. |
5448ec4f | 229 | * @type: Type of this entry. |
26a2a1c9 KT |
230 | * |
231 | * Returns 0 on success, negative value otherwise. | |
232 | */ | |
5448ec4f TH |
233 | int tomoyo_write_transition_control(char *data, const bool is_delete, |
234 | const u8 type) | |
26a2a1c9 | 235 | { |
5448ec4f TH |
236 | char *domainname = strstr(data, " from "); |
237 | if (domainname) { | |
238 | *domainname = '\0'; | |
239 | domainname += 6; | |
240 | } else if (type == TOMOYO_TRANSITION_CONTROL_NO_KEEP || | |
241 | type == TOMOYO_TRANSITION_CONTROL_KEEP) { | |
242 | domainname = data; | |
243 | data = NULL; | |
26a2a1c9 | 244 | } |
5448ec4f | 245 | return tomoyo_update_transition_control_entry(domainname, data, type, |
26a2a1c9 KT |
246 | is_delete); |
247 | } | |
248 | ||
249 | /** | |
5448ec4f | 250 | * tomoyo_transition_type - Get domain transition type. |
26a2a1c9 KT |
251 | * |
252 | * @domainname: The name of domain. | |
253 | * @program: The name of program. | |
26a2a1c9 | 254 | * |
5448ec4f TH |
255 | * Returns TOMOYO_TRANSITION_CONTROL_INITIALIZE if executing @program |
256 | * reinitializes domain transition, TOMOYO_TRANSITION_CONTROL_KEEP if executing | |
257 | * @program suppresses domain transition, others otherwise. | |
fdb8ebb7 TH |
258 | * |
259 | * Caller holds tomoyo_read_lock(). | |
26a2a1c9 | 260 | */ |
5448ec4f TH |
261 | static u8 tomoyo_transition_type(const struct tomoyo_path_info *domainname, |
262 | const struct tomoyo_path_info *program) | |
26a2a1c9 | 263 | { |
5448ec4f TH |
264 | const struct tomoyo_transition_control *ptr; |
265 | const char *last_name = tomoyo_last_word(domainname->name); | |
266 | u8 type; | |
267 | for (type = 0; type < TOMOYO_MAX_TRANSITION_TYPE; type++) { | |
268 | next: | |
269 | list_for_each_entry_rcu(ptr, &tomoyo_policy_list | |
270 | [TOMOYO_ID_TRANSITION_CONTROL], | |
271 | head.list) { | |
272 | if (ptr->head.is_deleted || ptr->type != type) | |
26a2a1c9 | 273 | continue; |
5448ec4f TH |
274 | if (ptr->domainname) { |
275 | if (!ptr->is_last_name) { | |
276 | if (ptr->domainname != domainname) | |
277 | continue; | |
278 | } else { | |
279 | /* | |
280 | * Use direct strcmp() since this is | |
281 | * unlikely used. | |
282 | */ | |
283 | if (strcmp(ptr->domainname->name, | |
284 | last_name)) | |
285 | continue; | |
286 | } | |
287 | } | |
288 | if (ptr->program && | |
289 | tomoyo_pathcmp(ptr->program, program)) | |
26a2a1c9 | 290 | continue; |
5448ec4f TH |
291 | if (type == TOMOYO_TRANSITION_CONTROL_NO_INITIALIZE) { |
292 | /* | |
293 | * Do not check for initialize_domain if | |
294 | * no_initialize_domain matched. | |
295 | */ | |
296 | type = TOMOYO_TRANSITION_CONTROL_NO_KEEP; | |
297 | goto next; | |
298 | } | |
299 | goto done; | |
26a2a1c9 | 300 | } |
26a2a1c9 | 301 | } |
5448ec4f TH |
302 | done: |
303 | return type; | |
26a2a1c9 KT |
304 | } |
305 | ||
e2bf6907 TH |
306 | static bool tomoyo_same_aggregator(const struct tomoyo_acl_head *a, |
307 | const struct tomoyo_acl_head *b) | |
36f5e1ff | 308 | { |
e2bf6907 TH |
309 | const struct tomoyo_aggregator *p1 = container_of(a, typeof(*p1), head); |
310 | const struct tomoyo_aggregator *p2 = container_of(b, typeof(*p2), head); | |
36f5e1ff TH |
311 | return p1->original_name == p2->original_name && |
312 | p1->aggregated_name == p2->aggregated_name; | |
313 | } | |
314 | ||
1084307c | 315 | /** |
e2bf6907 | 316 | * tomoyo_update_aggregator_entry - Update "struct tomoyo_aggregator" list. |
1084307c TH |
317 | * |
318 | * @original_name: The original program's name. | |
319 | * @aggregated_name: The program name to use. | |
320 | * @is_delete: True if it is a delete request. | |
321 | * | |
322 | * Returns 0 on success, negative value otherwise. | |
323 | * | |
324 | * Caller holds tomoyo_read_lock(). | |
325 | */ | |
326 | static int tomoyo_update_aggregator_entry(const char *original_name, | |
327 | const char *aggregated_name, | |
328 | const bool is_delete) | |
329 | { | |
e2bf6907 | 330 | struct tomoyo_aggregator e = { }; |
1084307c TH |
331 | int error = is_delete ? -ENOENT : -ENOMEM; |
332 | ||
75093152 TH |
333 | if (!tomoyo_correct_path(original_name) || |
334 | !tomoyo_correct_path(aggregated_name)) | |
1084307c TH |
335 | return -EINVAL; |
336 | e.original_name = tomoyo_get_name(original_name); | |
337 | e.aggregated_name = tomoyo_get_name(aggregated_name); | |
338 | if (!e.original_name || !e.aggregated_name || | |
339 | e.aggregated_name->is_patterned) /* No patterns allowed. */ | |
340 | goto out; | |
36f5e1ff | 341 | error = tomoyo_update_policy(&e.head, sizeof(e), is_delete, |
a230f9e7 | 342 | &tomoyo_policy_list[TOMOYO_ID_AGGREGATOR], |
e2bf6907 | 343 | tomoyo_same_aggregator); |
1084307c TH |
344 | out: |
345 | tomoyo_put_name(e.original_name); | |
346 | tomoyo_put_name(e.aggregated_name); | |
347 | return error; | |
348 | } | |
349 | ||
1084307c | 350 | /** |
e2bf6907 | 351 | * tomoyo_write_aggregator - Write "struct tomoyo_aggregator" list. |
1084307c TH |
352 | * |
353 | * @data: String to parse. | |
354 | * @is_delete: True if it is a delete request. | |
355 | * | |
356 | * Returns 0 on success, negative value otherwise. | |
357 | * | |
358 | * Caller holds tomoyo_read_lock(). | |
359 | */ | |
e2bf6907 | 360 | int tomoyo_write_aggregator(char *data, const bool is_delete) |
1084307c TH |
361 | { |
362 | char *cp = strchr(data, ' '); | |
363 | ||
364 | if (!cp) | |
365 | return -EINVAL; | |
366 | *cp++ = '\0'; | |
367 | return tomoyo_update_aggregator_entry(data, cp, is_delete); | |
368 | } | |
369 | ||
26a2a1c9 | 370 | /** |
e2bf6907 | 371 | * tomoyo_assign_domain - Create a domain. |
26a2a1c9 KT |
372 | * |
373 | * @domainname: The name of domain. | |
374 | * @profile: Profile number to assign if the domain was newly created. | |
375 | * | |
376 | * Returns pointer to "struct tomoyo_domain_info" on success, NULL otherwise. | |
fdb8ebb7 TH |
377 | * |
378 | * Caller holds tomoyo_read_lock(). | |
26a2a1c9 | 379 | */ |
e2bf6907 TH |
380 | struct tomoyo_domain_info *tomoyo_assign_domain(const char *domainname, |
381 | const u8 profile) | |
26a2a1c9 | 382 | { |
ca0b7df3 | 383 | struct tomoyo_domain_info *entry; |
29282381 | 384 | struct tomoyo_domain_info *domain = NULL; |
26a2a1c9 | 385 | const struct tomoyo_path_info *saved_domainname; |
ca0b7df3 | 386 | bool found = false; |
26a2a1c9 | 387 | |
75093152 | 388 | if (!tomoyo_correct_domain(domainname)) |
ca0b7df3 | 389 | return NULL; |
bf24fb01 | 390 | saved_domainname = tomoyo_get_name(domainname); |
26a2a1c9 | 391 | if (!saved_domainname) |
ca0b7df3 | 392 | return NULL; |
4e5d6f7e | 393 | entry = kzalloc(sizeof(*entry), GFP_NOFS); |
29282381 TH |
394 | if (mutex_lock_interruptible(&tomoyo_policy_lock)) |
395 | goto out; | |
ca0b7df3 TH |
396 | list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) { |
397 | if (domain->is_deleted || | |
398 | tomoyo_pathcmp(saved_domainname, domain->domainname)) | |
399 | continue; | |
400 | found = true; | |
401 | break; | |
402 | } | |
403 | if (!found && tomoyo_memory_ok(entry)) { | |
404 | INIT_LIST_HEAD(&entry->acl_info_list); | |
405 | entry->domainname = saved_domainname; | |
bf24fb01 | 406 | saved_domainname = NULL; |
ca0b7df3 TH |
407 | entry->profile = profile; |
408 | list_add_tail_rcu(&entry->list, &tomoyo_domain_list); | |
409 | domain = entry; | |
410 | entry = NULL; | |
411 | found = true; | |
26a2a1c9 | 412 | } |
f737d95d | 413 | mutex_unlock(&tomoyo_policy_lock); |
29282381 | 414 | out: |
bf24fb01 | 415 | tomoyo_put_name(saved_domainname); |
ca0b7df3 TH |
416 | kfree(entry); |
417 | return found ? domain : NULL; | |
26a2a1c9 KT |
418 | } |
419 | ||
420 | /** | |
421 | * tomoyo_find_next_domain - Find a domain. | |
422 | * | |
56f8c9bc | 423 | * @bprm: Pointer to "struct linux_binprm". |
26a2a1c9 KT |
424 | * |
425 | * Returns 0 on success, negative value otherwise. | |
fdb8ebb7 TH |
426 | * |
427 | * Caller holds tomoyo_read_lock(). | |
26a2a1c9 | 428 | */ |
56f8c9bc | 429 | int tomoyo_find_next_domain(struct linux_binprm *bprm) |
26a2a1c9 | 430 | { |
17fcfbd9 | 431 | struct tomoyo_request_info r; |
c8c57e84 | 432 | char *tmp = kzalloc(TOMOYO_EXEC_TMPSIZE, GFP_NOFS); |
26a2a1c9 KT |
433 | struct tomoyo_domain_info *old_domain = tomoyo_domain(); |
434 | struct tomoyo_domain_info *domain = NULL; | |
26a2a1c9 | 435 | const char *original_name = bprm->filename; |
57c2590f TH |
436 | u8 mode; |
437 | bool is_enforce; | |
26a2a1c9 | 438 | int retval = -ENOMEM; |
c8c57e84 TH |
439 | bool need_kfree = false; |
440 | struct tomoyo_path_info rn = { }; /* real name */ | |
26a2a1c9 | 441 | |
57c2590f TH |
442 | mode = tomoyo_init_request_info(&r, NULL, TOMOYO_MAC_FILE_EXECUTE); |
443 | is_enforce = (mode == TOMOYO_CONFIG_ENFORCING); | |
26a2a1c9 KT |
444 | if (!tmp) |
445 | goto out; | |
446 | ||
17fcfbd9 | 447 | retry: |
c8c57e84 TH |
448 | if (need_kfree) { |
449 | kfree(rn.name); | |
450 | need_kfree = false; | |
451 | } | |
0617c7ff | 452 | /* Get symlink's pathname of program. */ |
26a2a1c9 | 453 | retval = -ENOENT; |
0617c7ff | 454 | rn.name = tomoyo_realpath_nofollow(original_name); |
c8c57e84 | 455 | if (!rn.name) |
26a2a1c9 | 456 | goto out; |
c8c57e84 TH |
457 | tomoyo_fill_path_info(&rn); |
458 | need_kfree = true; | |
459 | ||
1084307c TH |
460 | /* Check 'aggregator' directive. */ |
461 | { | |
e2bf6907 | 462 | struct tomoyo_aggregator *ptr; |
a230f9e7 TH |
463 | list_for_each_entry_rcu(ptr, &tomoyo_policy_list |
464 | [TOMOYO_ID_AGGREGATOR], head.list) { | |
82e0f001 | 465 | if (ptr->head.is_deleted || |
1084307c TH |
466 | !tomoyo_path_matches_pattern(&rn, |
467 | ptr->original_name)) | |
468 | continue; | |
0617c7ff | 469 | kfree(rn.name); |
1084307c TH |
470 | need_kfree = false; |
471 | /* This is OK because it is read only. */ | |
472 | rn = *ptr->aggregated_name; | |
473 | break; | |
474 | } | |
475 | } | |
476 | ||
26a2a1c9 | 477 | /* Check execute permission. */ |
05336dee | 478 | retval = tomoyo_path_permission(&r, TOMOYO_TYPE_EXECUTE, &rn); |
17fcfbd9 TH |
479 | if (retval == TOMOYO_RETRY_REQUEST) |
480 | goto retry; | |
26a2a1c9 KT |
481 | if (retval < 0) |
482 | goto out; | |
484ca79c TH |
483 | /* |
484 | * To be able to specify domainnames with wildcards, use the | |
485 | * pathname specified in the policy (which may contain | |
486 | * wildcard) rather than the pathname passed to execve() | |
487 | * (which never contains wildcard). | |
488 | */ | |
489 | if (r.param.path.matched_path) { | |
490 | if (need_kfree) | |
491 | kfree(rn.name); | |
492 | need_kfree = false; | |
493 | /* This is OK because it is read only. */ | |
494 | rn = *r.param.path.matched_path; | |
495 | } | |
26a2a1c9 | 496 | |
5448ec4f TH |
497 | /* Calculate domain to transit to. */ |
498 | switch (tomoyo_transition_type(old_domain->domainname, &rn)) { | |
499 | case TOMOYO_TRANSITION_CONTROL_INITIALIZE: | |
26a2a1c9 | 500 | /* Transit to the child of tomoyo_kernel_domain domain. */ |
5448ec4f TH |
501 | snprintf(tmp, TOMOYO_EXEC_TMPSIZE - 1, TOMOYO_ROOT_NAME " " |
502 | "%s", rn.name); | |
503 | break; | |
504 | case TOMOYO_TRANSITION_CONTROL_KEEP: | |
26a2a1c9 KT |
505 | /* Keep current domain. */ |
506 | domain = old_domain; | |
5448ec4f TH |
507 | break; |
508 | default: | |
509 | if (old_domain == &tomoyo_kernel_domain && | |
510 | !tomoyo_policy_loaded) { | |
511 | /* | |
512 | * Needn't to transit from kernel domain before | |
513 | * starting /sbin/init. But transit from kernel domain | |
514 | * if executing initializers because they might start | |
515 | * before /sbin/init. | |
516 | */ | |
517 | domain = old_domain; | |
518 | } else { | |
519 | /* Normal domain transition. */ | |
520 | snprintf(tmp, TOMOYO_EXEC_TMPSIZE - 1, "%s %s", | |
521 | old_domain->domainname->name, rn.name); | |
522 | } | |
523 | break; | |
26a2a1c9 | 524 | } |
c8c57e84 | 525 | if (domain || strlen(tmp) >= TOMOYO_EXEC_TMPSIZE - 10) |
26a2a1c9 | 526 | goto done; |
c8c57e84 | 527 | domain = tomoyo_find_domain(tmp); |
7c75964f TH |
528 | if (!domain) |
529 | domain = tomoyo_assign_domain(tmp, old_domain->profile); | |
26a2a1c9 KT |
530 | done: |
531 | if (domain) | |
532 | goto out; | |
c8c57e84 | 533 | printk(KERN_WARNING "TOMOYO-ERROR: Domain '%s' not defined.\n", tmp); |
26a2a1c9 KT |
534 | if (is_enforce) |
535 | retval = -EPERM; | |
536 | else | |
ea13ddba | 537 | old_domain->transition_failed = true; |
26a2a1c9 | 538 | out: |
56f8c9bc TH |
539 | if (!domain) |
540 | domain = old_domain; | |
ec8e6a4e TH |
541 | /* Update reference count on "struct tomoyo_domain_info". */ |
542 | atomic_inc(&domain->users); | |
56f8c9bc | 543 | bprm->cred->security = domain; |
c8c57e84 TH |
544 | if (need_kfree) |
545 | kfree(rn.name); | |
8e2d39a1 | 546 | kfree(tmp); |
26a2a1c9 KT |
547 | return retval; |
548 | } |