2 * security/tomoyo/domain.c
4 * Domain transition functions for TOMOYO.
6 * Copyright (C) 2005-2010 NTT DATA CORPORATION
10 #include <linux/binfmts.h>
11 #include <linux/slab.h>
13 /* Variables definitions.*/
15 /* The global ACL referred by "use_group" keyword. */
16 struct list_head tomoyo_acl_group
[TOMOYO_MAX_ACL_GROUPS
];
18 /* The initial domain. */
19 struct tomoyo_domain_info tomoyo_kernel_domain
;
22 * tomoyo_update_policy - Update an entry for exception policy.
24 * @new_entry: Pointer to "struct tomoyo_acl_info".
25 * @size: Size of @new_entry in bytes.
26 * @param: Pointer to "struct tomoyo_acl_param".
27 * @check_duplicate: Callback function to find duplicated entry.
29 * Returns 0 on success, negative value otherwise.
31 * Caller holds tomoyo_read_lock().
33 int tomoyo_update_policy(struct tomoyo_acl_head
*new_entry
, const int size
,
34 struct tomoyo_acl_param
*param
,
35 bool (*check_duplicate
) (const struct tomoyo_acl_head
37 const struct tomoyo_acl_head
40 int error
= param
->is_delete
? -ENOENT
: -ENOMEM
;
41 struct tomoyo_acl_head
*entry
;
42 struct list_head
*list
= param
->list
;
44 if (mutex_lock_interruptible(&tomoyo_policy_lock
))
46 list_for_each_entry_rcu(entry
, list
, list
) {
47 if (!check_duplicate(entry
, new_entry
))
49 entry
->is_deleted
= param
->is_delete
;
53 if (error
&& !param
->is_delete
) {
54 entry
= tomoyo_commit_ok(new_entry
, size
);
56 list_add_tail_rcu(&entry
->list
, list
);
60 mutex_unlock(&tomoyo_policy_lock
);
65 * tomoyo_same_acl_head - Check for duplicated "struct tomoyo_acl_info" entry.
67 * @a: Pointer to "struct tomoyo_acl_info".
68 * @b: Pointer to "struct tomoyo_acl_info".
70 * Returns true if @a == @b, false otherwise.
72 static inline bool tomoyo_same_acl_head(const struct tomoyo_acl_info
*a
,
73 const struct tomoyo_acl_info
*b
)
75 return a
->type
== b
->type
;
79 * tomoyo_update_domain - Update an entry for domain policy.
81 * @new_entry: Pointer to "struct tomoyo_acl_info".
82 * @size: Size of @new_entry in bytes.
83 * @param: Pointer to "struct tomoyo_acl_param".
84 * @check_duplicate: Callback function to find duplicated entry.
85 * @merge_duplicate: Callback function to merge duplicated entry.
87 * Returns 0 on success, negative value otherwise.
89 * Caller holds tomoyo_read_lock().
91 int tomoyo_update_domain(struct tomoyo_acl_info
*new_entry
, const int size
,
92 struct tomoyo_acl_param
*param
,
93 bool (*check_duplicate
) (const struct tomoyo_acl_info
95 const struct tomoyo_acl_info
97 bool (*merge_duplicate
) (struct tomoyo_acl_info
*,
98 struct tomoyo_acl_info
*,
101 const bool is_delete
= param
->is_delete
;
102 int error
= is_delete
? -ENOENT
: -ENOMEM
;
103 struct tomoyo_acl_info
*entry
;
104 struct list_head
* const list
= param
->list
;
106 if (mutex_lock_interruptible(&tomoyo_policy_lock
))
108 list_for_each_entry_rcu(entry
, list
, list
) {
109 if (!tomoyo_same_acl_head(entry
, new_entry
) ||
110 !check_duplicate(entry
, new_entry
))
113 entry
->is_deleted
= merge_duplicate(entry
, new_entry
,
116 entry
->is_deleted
= is_delete
;
120 if (error
&& !is_delete
) {
121 entry
= tomoyo_commit_ok(new_entry
, size
);
123 list_add_tail_rcu(&entry
->list
, list
);
127 mutex_unlock(&tomoyo_policy_lock
);
132 * tomoyo_check_acl - Do permission check.
134 * @r: Pointer to "struct tomoyo_request_info".
135 * @check_entry: Callback function to check type specific parameters.
137 * Returns 0 on success, negative value otherwise.
139 * Caller holds tomoyo_read_lock().
141 void tomoyo_check_acl(struct tomoyo_request_info
*r
,
142 bool (*check_entry
) (struct tomoyo_request_info
*,
143 const struct tomoyo_acl_info
*))
145 const struct tomoyo_domain_info
*domain
= r
->domain
;
146 struct tomoyo_acl_info
*ptr
;
147 bool retried
= false;
148 const struct list_head
*list
= &domain
->acl_info_list
;
151 list_for_each_entry_rcu(ptr
, list
, list
) {
152 if (ptr
->is_deleted
|| ptr
->type
!= r
->param_type
)
154 if (check_entry(r
, ptr
)) {
161 list
= &tomoyo_acl_group
[domain
->group
];
167 /* The list for "struct tomoyo_domain_info". */
168 LIST_HEAD(tomoyo_domain_list
);
170 struct list_head tomoyo_policy_list
[TOMOYO_MAX_POLICY
];
171 struct list_head tomoyo_group_list
[TOMOYO_MAX_GROUP
];
174 * tomoyo_last_word - Get last component of a domainname.
176 * @domainname: Domainname to check.
178 * Returns the last word of @domainname.
180 static const char *tomoyo_last_word(const char *name
)
182 const char *cp
= strrchr(name
, ' ');
189 * tomoyo_same_transition_control - Check for duplicated "struct tomoyo_transition_control" entry.
191 * @a: Pointer to "struct tomoyo_acl_head".
192 * @b: Pointer to "struct tomoyo_acl_head".
194 * Returns true if @a == @b, false otherwise.
196 static bool tomoyo_same_transition_control(const struct tomoyo_acl_head
*a
,
197 const struct tomoyo_acl_head
*b
)
199 const struct tomoyo_transition_control
*p1
= container_of(a
,
202 const struct tomoyo_transition_control
*p2
= container_of(b
,
205 return p1
->type
== p2
->type
&& p1
->is_last_name
== p2
->is_last_name
206 && p1
->domainname
== p2
->domainname
207 && p1
->program
== p2
->program
;
211 * tomoyo_write_transition_control - Write "struct tomoyo_transition_control" list.
213 * @param: Pointer to "struct tomoyo_acl_param".
214 * @type: Type of this entry.
216 * Returns 0 on success, negative value otherwise.
218 int tomoyo_write_transition_control(struct tomoyo_acl_param
*param
,
221 struct tomoyo_transition_control e
= { .type
= type
};
222 int error
= param
->is_delete
? -ENOENT
: -ENOMEM
;
223 char *program
= param
->data
;
224 char *domainname
= strstr(program
, " from ");
228 } else if (type
== TOMOYO_TRANSITION_CONTROL_NO_KEEP
||
229 type
== TOMOYO_TRANSITION_CONTROL_KEEP
) {
230 domainname
= program
;
233 if (program
&& strcmp(program
, "any")) {
234 if (!tomoyo_correct_path(program
))
236 e
.program
= tomoyo_get_name(program
);
240 if (domainname
&& strcmp(domainname
, "any")) {
241 if (!tomoyo_correct_domain(domainname
)) {
242 if (!tomoyo_correct_path(domainname
))
244 e
.is_last_name
= true;
246 e
.domainname
= tomoyo_get_name(domainname
);
250 param
->list
= &tomoyo_policy_list
[TOMOYO_ID_TRANSITION_CONTROL
];
251 error
= tomoyo_update_policy(&e
.head
, sizeof(e
), param
,
252 tomoyo_same_transition_control
);
254 tomoyo_put_name(e
.domainname
);
255 tomoyo_put_name(e
.program
);
260 * tomoyo_transition_type - Get domain transition type.
262 * @domainname: The name of domain.
263 * @program: The name of program.
265 * Returns TOMOYO_TRANSITION_CONTROL_INITIALIZE if executing @program
266 * reinitializes domain transition, TOMOYO_TRANSITION_CONTROL_KEEP if executing
267 * @program suppresses domain transition, others otherwise.
269 * Caller holds tomoyo_read_lock().
271 static u8
tomoyo_transition_type(const struct tomoyo_path_info
*domainname
,
272 const struct tomoyo_path_info
*program
)
274 const struct tomoyo_transition_control
*ptr
;
275 const char *last_name
= tomoyo_last_word(domainname
->name
);
277 for (type
= 0; type
< TOMOYO_MAX_TRANSITION_TYPE
; type
++) {
279 list_for_each_entry_rcu(ptr
, &tomoyo_policy_list
280 [TOMOYO_ID_TRANSITION_CONTROL
],
282 if (ptr
->head
.is_deleted
|| ptr
->type
!= type
)
284 if (ptr
->domainname
) {
285 if (!ptr
->is_last_name
) {
286 if (ptr
->domainname
!= domainname
)
290 * Use direct strcmp() since this is
293 if (strcmp(ptr
->domainname
->name
,
299 tomoyo_pathcmp(ptr
->program
, program
))
301 if (type
== TOMOYO_TRANSITION_CONTROL_NO_INITIALIZE
) {
303 * Do not check for initialize_domain if
304 * no_initialize_domain matched.
306 type
= TOMOYO_TRANSITION_CONTROL_NO_KEEP
;
317 * tomoyo_same_aggregator - Check for duplicated "struct tomoyo_aggregator" entry.
319 * @a: Pointer to "struct tomoyo_acl_head".
320 * @b: Pointer to "struct tomoyo_acl_head".
322 * Returns true if @a == @b, false otherwise.
324 static bool tomoyo_same_aggregator(const struct tomoyo_acl_head
*a
,
325 const struct tomoyo_acl_head
*b
)
327 const struct tomoyo_aggregator
*p1
= container_of(a
, typeof(*p1
),
329 const struct tomoyo_aggregator
*p2
= container_of(b
, typeof(*p2
),
331 return p1
->original_name
== p2
->original_name
&&
332 p1
->aggregated_name
== p2
->aggregated_name
;
336 * tomoyo_write_aggregator - Write "struct tomoyo_aggregator" list.
338 * @param: Pointer to "struct tomoyo_acl_param".
340 * Returns 0 on success, negative value otherwise.
342 * Caller holds tomoyo_read_lock().
344 int tomoyo_write_aggregator(struct tomoyo_acl_param
*param
)
346 struct tomoyo_aggregator e
= { };
347 int error
= param
->is_delete
? -ENOENT
: -ENOMEM
;
348 const char *original_name
= tomoyo_read_token(param
);
349 const char *aggregated_name
= tomoyo_read_token(param
);
350 if (!tomoyo_correct_word(original_name
) ||
351 !tomoyo_correct_path(aggregated_name
))
353 e
.original_name
= tomoyo_get_name(original_name
);
354 e
.aggregated_name
= tomoyo_get_name(aggregated_name
);
355 if (!e
.original_name
|| !e
.aggregated_name
||
356 e
.aggregated_name
->is_patterned
) /* No patterns allowed. */
358 param
->list
= &tomoyo_policy_list
[TOMOYO_ID_AGGREGATOR
];
359 error
= tomoyo_update_policy(&e
.head
, sizeof(e
), param
,
360 tomoyo_same_aggregator
);
362 tomoyo_put_name(e
.original_name
);
363 tomoyo_put_name(e
.aggregated_name
);
368 * tomoyo_assign_domain - Create a domain.
370 * @domainname: The name of domain.
371 * @profile: Profile number to assign if the domain was newly created.
373 * Returns pointer to "struct tomoyo_domain_info" on success, NULL otherwise.
375 * Caller holds tomoyo_read_lock().
377 struct tomoyo_domain_info
*tomoyo_assign_domain(const char *domainname
,
380 struct tomoyo_domain_info
*entry
;
381 struct tomoyo_domain_info
*domain
= NULL
;
382 const struct tomoyo_path_info
*saved_domainname
;
385 if (!tomoyo_correct_domain(domainname
))
387 saved_domainname
= tomoyo_get_name(domainname
);
388 if (!saved_domainname
)
390 entry
= kzalloc(sizeof(*entry
), GFP_NOFS
);
391 if (mutex_lock_interruptible(&tomoyo_policy_lock
))
393 list_for_each_entry_rcu(domain
, &tomoyo_domain_list
, list
) {
394 if (domain
->is_deleted
||
395 tomoyo_pathcmp(saved_domainname
, domain
->domainname
))
400 if (!found
&& tomoyo_memory_ok(entry
)) {
401 INIT_LIST_HEAD(&entry
->acl_info_list
);
402 entry
->domainname
= saved_domainname
;
403 saved_domainname
= NULL
;
404 entry
->profile
= profile
;
405 list_add_tail_rcu(&entry
->list
, &tomoyo_domain_list
);
410 mutex_unlock(&tomoyo_policy_lock
);
412 tomoyo_put_name(saved_domainname
);
414 return found
? domain
: NULL
;
418 * tomoyo_find_next_domain - Find a domain.
420 * @bprm: Pointer to "struct linux_binprm".
422 * Returns 0 on success, negative value otherwise.
424 * Caller holds tomoyo_read_lock().
426 int tomoyo_find_next_domain(struct linux_binprm
*bprm
)
428 struct tomoyo_request_info r
;
429 char *tmp
= kzalloc(TOMOYO_EXEC_TMPSIZE
, GFP_NOFS
);
430 struct tomoyo_domain_info
*old_domain
= tomoyo_domain();
431 struct tomoyo_domain_info
*domain
= NULL
;
432 const char *original_name
= bprm
->filename
;
435 int retval
= -ENOMEM
;
436 bool need_kfree
= false;
437 struct tomoyo_path_info rn
= { }; /* real name */
439 mode
= tomoyo_init_request_info(&r
, NULL
, TOMOYO_MAC_FILE_EXECUTE
);
440 is_enforce
= (mode
== TOMOYO_CONFIG_ENFORCING
);
449 /* Get symlink's pathname of program. */
451 rn
.name
= tomoyo_realpath_nofollow(original_name
);
454 tomoyo_fill_path_info(&rn
);
457 /* Check 'aggregator' directive. */
459 struct tomoyo_aggregator
*ptr
;
460 list_for_each_entry_rcu(ptr
, &tomoyo_policy_list
461 [TOMOYO_ID_AGGREGATOR
], head
.list
) {
462 if (ptr
->head
.is_deleted
||
463 !tomoyo_path_matches_pattern(&rn
,
468 /* This is OK because it is read only. */
469 rn
= *ptr
->aggregated_name
;
474 /* Check execute permission. */
475 retval
= tomoyo_path_permission(&r
, TOMOYO_TYPE_EXECUTE
, &rn
);
476 if (retval
== TOMOYO_RETRY_REQUEST
)
481 * To be able to specify domainnames with wildcards, use the
482 * pathname specified in the policy (which may contain
483 * wildcard) rather than the pathname passed to execve()
484 * (which never contains wildcard).
486 if (r
.param
.path
.matched_path
) {
490 /* This is OK because it is read only. */
491 rn
= *r
.param
.path
.matched_path
;
494 /* Calculate domain to transit to. */
495 switch (tomoyo_transition_type(old_domain
->domainname
, &rn
)) {
496 case TOMOYO_TRANSITION_CONTROL_INITIALIZE
:
497 /* Transit to the child of tomoyo_kernel_domain domain. */
498 snprintf(tmp
, TOMOYO_EXEC_TMPSIZE
- 1, TOMOYO_ROOT_NAME
" "
501 case TOMOYO_TRANSITION_CONTROL_KEEP
:
502 /* Keep current domain. */
506 if (old_domain
== &tomoyo_kernel_domain
&&
507 !tomoyo_policy_loaded
) {
509 * Needn't to transit from kernel domain before
510 * starting /sbin/init. But transit from kernel domain
511 * if executing initializers because they might start
516 /* Normal domain transition. */
517 snprintf(tmp
, TOMOYO_EXEC_TMPSIZE
- 1, "%s %s",
518 old_domain
->domainname
->name
, rn
.name
);
522 if (domain
|| strlen(tmp
) >= TOMOYO_EXEC_TMPSIZE
- 10)
524 domain
= tomoyo_find_domain(tmp
);
526 domain
= tomoyo_assign_domain(tmp
, old_domain
->profile
);
530 printk(KERN_WARNING
"TOMOYO-ERROR: Domain '%s' not defined.\n", tmp
);
534 old_domain
->transition_failed
= true;
538 /* Update reference count on "struct tomoyo_domain_info". */
539 atomic_inc(&domain
->users
);
540 bprm
->cred
->security
= domain
;