38 |
struct list_head ccs_shared_list[CCS_MAX_LIST]; |
struct list_head ccs_shared_list[CCS_MAX_LIST]; |
39 |
|
|
40 |
/** |
/** |
|
* ccs_audit_execute_handler_log - Audit execute_handler log. |
|
|
* |
|
|
* @ee: Pointer to "struct ccs_execve". |
|
|
* |
|
|
* Returns 0 on success, negative value otherwise. |
|
|
*/ |
|
|
static int ccs_audit_execute_handler_log(struct ccs_execve *ee) |
|
|
{ |
|
|
struct ccs_request_info *r = &ee->r; |
|
|
const char *handler = ee->handler->name; |
|
|
r->type = CCS_MAC_FILE_EXECUTE; |
|
|
r->mode = ccs_get_mode(r->profile, CCS_MAC_FILE_EXECUTE); |
|
|
r->granted = true; |
|
|
return ccs_write_log(r, "%s %s\n", ee->handler_type == |
|
|
CCS_TYPE_DENIED_EXECUTE_HANDLER ? |
|
|
CCS_KEYWORD_DENIED_EXECUTE_HANDLER : |
|
|
CCS_KEYWORD_EXECUTE_HANDLER, handler); |
|
|
} |
|
|
|
|
|
/** |
|
|
* ccs_audit_domain_creation_log - Audit domain creation log. |
|
|
* |
|
|
* Returns 0 on success, negative value otherwise. |
|
|
*/ |
|
|
static int ccs_audit_domain_creation_log(void) |
|
|
{ |
|
|
struct ccs_request_info r; |
|
|
ccs_init_request_info(&r, CCS_MAC_FILE_EXECUTE); |
|
|
r.granted = false; |
|
|
return ccs_write_log(&r, "use_profile %u\n", r.profile); |
|
|
} |
|
|
|
|
|
/** |
|
41 |
* ccs_update_policy - Update an entry for exception policy. |
* ccs_update_policy - Update an entry for exception policy. |
42 |
* |
* |
43 |
* @new_entry: Pointer to "struct ccs_acl_info". |
* @new_entry: Pointer to "struct ccs_acl_info". |
405 |
* @domainname: The name of domain. |
* @domainname: The name of domain. |
406 |
* @profile: Profile number to assign if the domain was newly created. |
* @profile: Profile number to assign if the domain was newly created. |
407 |
* @group: Group number to assign if the domain was newly created. |
* @group: Group number to assign if the domain was newly created. |
408 |
|
* @transit: True if transit to domain found or created. |
409 |
* |
* |
410 |
* Returns pointer to "struct ccs_domain_info" on success, NULL otherwise. |
* Returns pointer to "struct ccs_domain_info" on success, NULL otherwise. |
411 |
|
* |
412 |
|
* Caller holds ccs_read_lock(). |
413 |
*/ |
*/ |
414 |
struct ccs_domain_info *ccs_assign_domain(const char *domainname, |
struct ccs_domain_info *ccs_assign_domain(const char *domainname, |
415 |
const u8 profile, const u8 group) |
const u8 profile, const u8 group, |
416 |
|
const bool transit) |
417 |
{ |
{ |
418 |
struct ccs_domain_info e = { }; |
struct ccs_domain_info e = { }; |
419 |
struct ccs_domain_info *entry = NULL; |
struct ccs_domain_info *entry = ccs_find_domain(domainname); |
420 |
bool found = false; |
bool created = false; |
421 |
|
if (entry) |
422 |
if (!ccs_correct_domain(domainname)) |
goto out; |
423 |
|
if (strlen(domainname) >= CCS_EXEC_TMPSIZE - 10 || |
424 |
|
!ccs_correct_domain(domainname)) |
425 |
return NULL; |
return NULL; |
426 |
e.profile = profile; |
e.profile = profile; |
427 |
e.group = group; |
e.group = group; |
430 |
return NULL; |
return NULL; |
431 |
if (mutex_lock_interruptible(&ccs_policy_lock)) |
if (mutex_lock_interruptible(&ccs_policy_lock)) |
432 |
goto out; |
goto out; |
433 |
list_for_each_entry_rcu(entry, &ccs_domain_list, list) { |
entry = ccs_find_domain(domainname); |
434 |
if (entry->is_deleted || |
if (!entry) { |
|
ccs_pathcmp(e.domainname, entry->domainname)) |
|
|
continue; |
|
|
found = true; |
|
|
break; |
|
|
} |
|
|
if (!found) { |
|
435 |
entry = ccs_commit_ok(&e, sizeof(e)); |
entry = ccs_commit_ok(&e, sizeof(e)); |
436 |
if (entry) { |
if (entry) { |
437 |
INIT_LIST_HEAD(&entry->acl_info_list); |
INIT_LIST_HEAD(&entry->acl_info_list); |
438 |
list_add_tail_rcu(&entry->list, &ccs_domain_list); |
list_add_tail_rcu(&entry->list, &ccs_domain_list); |
439 |
found = true; |
created = true; |
440 |
} |
} |
441 |
} |
} |
442 |
mutex_unlock(&ccs_policy_lock); |
mutex_unlock(&ccs_policy_lock); |
443 |
out: |
out: |
444 |
ccs_put_name(e.domainname); |
ccs_put_name(e.domainname); |
445 |
return found ? entry : NULL; |
if (entry && transit) { |
446 |
|
current->ccs_domain_info = entry; |
447 |
|
if (created) { |
448 |
|
struct ccs_request_info r; |
449 |
|
ccs_init_request_info(&r, CCS_MAC_FILE_EXECUTE); |
450 |
|
r.granted = false; |
451 |
|
ccs_write_log(&r, "use_profile %u\n", r.profile); |
452 |
|
} |
453 |
|
} |
454 |
|
return entry; |
455 |
} |
} |
456 |
|
|
457 |
/** |
/** |
475 |
struct ccs_path_info rn = { }; /* real name */ |
struct ccs_path_info rn = { }; /* real name */ |
476 |
int retval; |
int retval; |
477 |
bool need_kfree = false; |
bool need_kfree = false; |
|
bool domain_created = false; |
|
478 |
retry: |
retry: |
479 |
current->ccs_flags = ccs_flags; |
current->ccs_flags = ccs_flags; |
480 |
r->cond = NULL; |
r->cond = NULL; |
500 |
} |
} |
501 |
goto out; |
goto out; |
502 |
} |
} |
503 |
|
r->type = CCS_MAC_FILE_EXECUTE; |
504 |
|
r->mode = ccs_get_mode(r->profile, CCS_MAC_FILE_EXECUTE); |
505 |
|
r->granted = true; |
506 |
|
ccs_write_log(r, "%s %s\n", ee->handler_type == |
507 |
|
CCS_TYPE_DENIED_EXECUTE_HANDLER ? |
508 |
|
CCS_KEYWORD_DENIED_EXECUTE_HANDLER : |
509 |
|
CCS_KEYWORD_EXECUTE_HANDLER, handler->name); |
510 |
} else { |
} else { |
511 |
struct ccs_aggregator *ptr; |
struct ccs_aggregator *ptr; |
512 |
/* Check 'aggregator' directive. */ |
/* Check 'aggregator' directive. */ |
571 |
} |
} |
572 |
break; |
break; |
573 |
} |
} |
|
if (domain || strlen(ee->tmp) >= CCS_EXEC_TMPSIZE - 10) |
|
|
goto done; |
|
|
domain = ccs_find_domain(ee->tmp); |
|
|
if (domain) |
|
|
goto done; |
|
|
if (r->mode == CCS_CONFIG_ENFORCING) { |
|
|
int error = ccs_supervisor(r, "# wants to create domain\n" |
|
|
"%s\n", ee->tmp); |
|
|
if (error == CCS_RETRY_REQUEST) |
|
|
goto retry; |
|
|
if (error < 0) |
|
|
goto done; |
|
|
} |
|
|
domain = ccs_assign_domain(ee->tmp, r->profile, old_domain->group); |
|
|
if (domain) |
|
|
domain_created = true; |
|
|
done: |
|
|
if (!domain) { |
|
|
retval = (r->mode == CCS_CONFIG_ENFORCING) ? -EPERM : 0; |
|
|
if (!old_domain->flags[CCS_DIF_TRANSITION_FAILED]) { |
|
|
old_domain->flags[CCS_DIF_TRANSITION_FAILED] = true; |
|
|
r->granted = false; |
|
|
ccs_write_log(r, CCS_KEYWORD_TRANSITION_FAILED "\n"); |
|
|
printk(KERN_WARNING |
|
|
"ERROR: Domain '%s' not defined.\n", ee->tmp); |
|
|
} |
|
|
} else { |
|
|
retval = 0; |
|
|
} |
|
|
if (!retval && handler) |
|
|
ccs_audit_execute_handler_log(ee); |
|
574 |
/* |
/* |
575 |
* Tell GC that I started execve(). |
* Tell GC that I started execve(). |
576 |
* Also, tell open_exec() to check read permission. |
* Also, tell open_exec() to check read permission. |
587 |
* But it is better than being unable to reach via PID in interactive |
* But it is better than being unable to reach via PID in interactive |
588 |
* enforcing mode. |
* enforcing mode. |
589 |
*/ |
*/ |
590 |
|
if (!domain) |
591 |
|
domain = ccs_assign_domain(ee->tmp, r->profile, |
592 |
|
old_domain->group, true); |
593 |
if (domain) |
if (domain) |
594 |
task->ccs_domain_info = domain; |
retval = 0; |
595 |
if (domain_created) |
else if (r->mode == CCS_CONFIG_ENFORCING) |
596 |
ccs_audit_domain_creation_log(); |
retval = -ENOMEM; |
597 |
|
else { |
598 |
|
retval = 0; |
599 |
|
if (!old_domain->flags[CCS_DIF_TRANSITION_FAILED]) { |
600 |
|
old_domain->flags[CCS_DIF_TRANSITION_FAILED] = true; |
601 |
|
r->granted = false; |
602 |
|
ccs_write_log(r, CCS_KEYWORD_TRANSITION_FAILED "\n"); |
603 |
|
printk(KERN_WARNING |
604 |
|
"ERROR: Domain '%s' not defined.\n", ee->tmp); |
605 |
|
} |
606 |
|
} |
607 |
out: |
out: |
608 |
if (need_kfree) |
if (need_kfree) |
609 |
kfree(rn.name); |
kfree(rn.name); |
1147 |
kfree(ee); |
kfree(ee); |
1148 |
} |
} |
1149 |
|
|
|
/** |
|
|
* ccs_may_transit - Check permission and do domain transition without execve(). |
|
|
* |
|
|
* @domainname: Domainname to transit to. |
|
|
* @pathname: Pathname to check. |
|
|
* |
|
|
* Returns 0 on success, negative value otherwise. |
|
|
* |
|
|
* Caller holds ccs_read_lock(). |
|
|
*/ |
|
|
int ccs_may_transit(const char *domainname, const char *pathname) |
|
|
{ |
|
|
struct ccs_path_info name; |
|
|
struct ccs_request_info r; |
|
|
struct ccs_domain_info *domain; |
|
|
int error; |
|
|
bool domain_created = false; |
|
|
name.name = pathname; |
|
|
ccs_fill_path_info(&name); |
|
|
/* Check "file transit" permission. */ |
|
|
ccs_init_request_info(&r, CCS_MAC_FILE_TRANSIT); |
|
|
error = ccs_path_permission(&r, CCS_TYPE_TRANSIT, &name); |
|
|
if (error) |
|
|
return error; |
|
|
/* Check destination domain. */ |
|
|
domain = ccs_find_domain(domainname); |
|
|
if (!domain && r.mode != CCS_CONFIG_ENFORCING && |
|
|
strlen(domainname) < CCS_EXEC_TMPSIZE - 10) { |
|
|
domain = ccs_assign_domain(domainname, r.profile, |
|
|
ccs_current_domain()->group); |
|
|
if (domain) |
|
|
domain_created = true; |
|
|
} |
|
|
if (domain) { |
|
|
error = 0; |
|
|
current->ccs_domain_info = domain; |
|
|
if (domain_created) |
|
|
ccs_audit_domain_creation_log(); |
|
|
} else { |
|
|
error = -ENOENT; |
|
|
} |
|
|
return error; |
|
|
} |
|
|
|
|
1150 |
static int __ccs_search_binary_handler(struct linux_binprm *bprm, |
static int __ccs_search_binary_handler(struct linux_binprm *bprm, |
1151 |
struct pt_regs *regs) |
struct pt_regs *regs) |
1152 |
{ |
{ |