5 |
* |
* |
6 |
* Copyright (C) 2005-2008 NTT DATA CORPORATION |
* Copyright (C) 2005-2008 NTT DATA CORPORATION |
7 |
* |
* |
8 |
* Version: 1.6.0-rc 2008/03/26 |
* Version: 1.6.0-rc 2008/03/28 |
9 |
* |
* |
10 |
* This file is applicable to both 2.4.30 and 2.6.11 and later. |
* This file is applicable to both 2.4.30 and 2.6.11 and later. |
11 |
* See README.ccs for ChangeLog. |
* See README.ccs for ChangeLog. |
117 |
/** |
/** |
118 |
* ccs_add_domain_acl - Add the given ACL to the given domain. |
* ccs_add_domain_acl - Add the given ACL to the given domain. |
119 |
* |
* |
120 |
* @domain: Pointer to "struct domain_info". |
* @domain: Pointer to "struct domain_info". May be NULL. |
121 |
* @acl: Pointer to "struct acl_info". |
* @acl: Pointer to "struct acl_info". |
122 |
* |
* |
123 |
* Returns 0. |
* Returns 0. |
135 |
/** |
/** |
136 |
* ccs_del_domain_acl - Delete the given ACL from the domain. |
* ccs_del_domain_acl - Delete the given ACL from the domain. |
137 |
* |
* |
138 |
* @acl: Pointer to "struct acl_info". |
* @acl: Pointer to "struct acl_info". May be NULL. |
139 |
* |
* |
140 |
* Returns 0. |
* Returns 0. |
141 |
*/ |
*/ |
150 |
/** |
/** |
151 |
* audit_execute_handler_log - Audit execute_handler log. |
* audit_execute_handler_log - Audit execute_handler log. |
152 |
* |
* |
153 |
* @is_preferred: True if it is "preffered_execute_handler" log. |
* @is_default: True if it is "execute_handler" log. |
154 |
* @handler: The realpath of the handler. |
* @handler: The realpath of the handler. |
155 |
* @bprm: Pointer to "struct linux_binprm". |
* @bprm: Pointer to "struct linux_binprm". |
156 |
* |
* |
157 |
* Returns 0 on success, negative value otherwise. |
* Returns 0 on success, negative value otherwise. |
158 |
*/ |
*/ |
159 |
static int audit_execute_handler_log(const bool is_preferred, |
static int audit_execute_handler_log(const bool is_default, |
160 |
const char *handler, |
const char *handler, |
161 |
struct linux_binprm *bprm) |
struct linux_binprm *bprm) |
162 |
{ |
{ |
175 |
return -ENOMEM; |
return -ENOMEM; |
176 |
len2 = strlen(buf); |
len2 = strlen(buf); |
177 |
snprintf(buf + len2, len - len2 - 1, "%s %s\n", |
snprintf(buf + len2, len - len2 - 1, "%s %s\n", |
178 |
is_preferred ? |
is_default ? KEYWORD_EXECUTE_HANDLER : |
179 |
KEYWORD_PREFERRED_EXECUTE_HANDLER : |
KEYWORD_DENIED_EXECUTE_HANDLER, handler); |
|
KEYWORD_DEFAULT_EXECUTE_HANDLER, |
|
|
handler); |
|
180 |
return ccs_write_audit_log(buf, true); |
return ccs_write_audit_log(buf, true); |
181 |
} |
} |
182 |
|
|
184 |
* audit_domain_creation_log - Audit domain creation log. |
* audit_domain_creation_log - Audit domain creation log. |
185 |
* |
* |
186 |
* @domainname: The name of newly created domain. |
* @domainname: The name of newly created domain. |
187 |
* @mode: Access control mode. |
* @mode: Access control mode used. |
188 |
* @profile: Profile number. |
* @profile: Profile number used. |
189 |
* |
* |
190 |
* Returns 0 on success, negative value otherwise. |
* Returns 0 on success, negative value otherwise. |
191 |
*/ |
*/ |
232 |
const bool is_not, |
const bool is_not, |
233 |
const bool is_delete) |
const bool is_delete) |
234 |
{ |
{ |
235 |
struct domain_initializer_entry *new_entry, *ptr; |
struct domain_initializer_entry *new_entry; |
236 |
|
struct domain_initializer_entry *ptr; |
237 |
static DEFINE_MUTEX(lock); |
static DEFINE_MUTEX(lock); |
238 |
const struct path_info *saved_program, *saved_domainname = NULL; |
const struct path_info *saved_program; |
239 |
|
const struct path_info *saved_domainname = NULL; |
240 |
int error = -ENOMEM; |
int error = -ENOMEM; |
241 |
bool is_last_name = false; |
bool is_last_name = false; |
242 |
if (!ccs_is_correct_path(program, 1, -1, -1, __func__)) |
if (!ccs_is_correct_path(program, 1, -1, -1, __func__)) |
279 |
error = 0; |
error = 0; |
280 |
out: |
out: |
281 |
mutex_unlock(&lock); |
mutex_unlock(&lock); |
282 |
|
ccs_update_counter(CCS_UPDATES_COUNTER_EXCEPTION_POLICY); |
283 |
return error; |
return error; |
284 |
} |
} |
285 |
|
|
294 |
{ |
{ |
295 |
struct list1_head *pos; |
struct list1_head *pos; |
296 |
list1_for_each_cookie(pos, head->read_var2, &domain_initializer_list) { |
list1_for_each_cookie(pos, head->read_var2, &domain_initializer_list) { |
297 |
|
const char *no; |
298 |
|
const char *from = ""; |
299 |
|
const char *domain = ""; |
300 |
struct domain_initializer_entry *ptr; |
struct domain_initializer_entry *ptr; |
301 |
ptr = list1_entry(pos, struct domain_initializer_entry, list); |
ptr = list1_entry(pos, struct domain_initializer_entry, list); |
302 |
if (ptr->is_deleted) |
if (ptr->is_deleted) |
303 |
continue; |
continue; |
304 |
|
no = ptr->is_not ? "no_" : ""; |
305 |
if (ptr->domainname) { |
if (ptr->domainname) { |
306 |
if (!ccs_io_printf(head, "%s" KEYWORD_INITIALIZE_DOMAIN |
from = " from "; |
307 |
"%s from %s\n", |
domain = ptr->domainname->name; |
|
ptr->is_not ? "no_" : "", |
|
|
ptr->program->name, |
|
|
ptr->domainname->name)) |
|
|
goto out; |
|
|
} else { |
|
|
if (!ccs_io_printf(head, "%s" |
|
|
KEYWORD_INITIALIZE_DOMAIN "%s\n", |
|
|
ptr->is_not ? "no_" : "", |
|
|
ptr->program->name)) |
|
|
goto out; |
|
308 |
} |
} |
309 |
|
if (!ccs_io_printf(head, |
310 |
|
"%s" KEYWORD_INITIALIZE_DOMAIN "%s%s%s\n", |
311 |
|
no, ptr->program->name, from, domain)) |
312 |
|
goto out; |
313 |
} |
} |
314 |
return true; |
return true; |
315 |
out: |
out: |
333 |
*cp = '\0'; |
*cp = '\0'; |
334 |
return update_domain_initializer_entry(cp + 6, data, is_not, |
return update_domain_initializer_entry(cp + 6, data, is_not, |
335 |
is_delete); |
is_delete); |
|
} else { |
|
|
return update_domain_initializer_entry(NULL, data, is_not, |
|
|
is_delete); |
|
336 |
} |
} |
337 |
|
return update_domain_initializer_entry(NULL, data, is_not, is_delete); |
338 |
} |
} |
339 |
|
|
340 |
/** |
/** |
391 |
const char *program, |
const char *program, |
392 |
const bool is_not, const bool is_delete) |
const bool is_not, const bool is_delete) |
393 |
{ |
{ |
394 |
struct domain_keeper_entry *new_entry, *ptr; |
struct domain_keeper_entry *new_entry; |
395 |
const struct path_info *saved_domainname, *saved_program = NULL; |
struct domain_keeper_entry *ptr; |
396 |
|
const struct path_info *saved_domainname; |
397 |
|
const struct path_info *saved_program = NULL; |
398 |
static DEFINE_MUTEX(lock); |
static DEFINE_MUTEX(lock); |
399 |
int error = -ENOMEM; |
int error = -ENOMEM; |
400 |
bool is_last_name = false; |
bool is_last_name = false; |
438 |
error = 0; |
error = 0; |
439 |
out: |
out: |
440 |
mutex_unlock(&lock); |
mutex_unlock(&lock); |
441 |
|
ccs_update_counter(CCS_UPDATES_COUNTER_EXCEPTION_POLICY); |
442 |
return error; |
return error; |
443 |
} |
} |
444 |
|
|
458 |
*cp = '\0'; |
*cp = '\0'; |
459 |
return update_domain_keeper_entry(cp + 6, data, |
return update_domain_keeper_entry(cp + 6, data, |
460 |
is_not, is_delete); |
is_not, is_delete); |
|
} else { |
|
|
return update_domain_keeper_entry(data, NULL, |
|
|
is_not, is_delete); |
|
461 |
} |
} |
462 |
|
return update_domain_keeper_entry(data, NULL, is_not, is_delete); |
463 |
} |
} |
464 |
|
|
465 |
/** |
/** |
474 |
struct list1_head *pos; |
struct list1_head *pos; |
475 |
list1_for_each_cookie(pos, head->read_var2, &domain_keeper_list) { |
list1_for_each_cookie(pos, head->read_var2, &domain_keeper_list) { |
476 |
struct domain_keeper_entry *ptr; |
struct domain_keeper_entry *ptr; |
477 |
const char *is_not; |
const char *no; |
478 |
|
const char *from = ""; |
479 |
|
const char *program = ""; |
480 |
ptr = list1_entry(pos, struct domain_keeper_entry, list); |
ptr = list1_entry(pos, struct domain_keeper_entry, list); |
481 |
if (ptr->is_deleted) |
if (ptr->is_deleted) |
482 |
continue; |
continue; |
483 |
is_not = ptr->is_not ? "no_" : ""; |
no = ptr->is_not ? "no_" : ""; |
484 |
if (ptr->program) { |
if (ptr->program) { |
485 |
if (!ccs_io_printf(head, |
from = " from "; |
486 |
"%s" KEYWORD_KEEP_DOMAIN "%s " |
program = ptr->program->name; |
|
"from %s\n", |
|
|
is_not, ptr->program->name, |
|
|
ptr->domainname->name)) |
|
|
goto out; |
|
|
} else { |
|
|
if (!ccs_io_printf(head, |
|
|
"%s" KEYWORD_KEEP_DOMAIN "%s\n", |
|
|
is_not, ptr->domainname->name)) |
|
|
goto out; |
|
487 |
} |
} |
488 |
|
if (!ccs_io_printf(head, |
489 |
|
"%s" KEYWORD_KEEP_DOMAIN "%s%s%s\n", no, |
490 |
|
program, from, ptr->domainname->name)) |
491 |
|
goto out; |
492 |
} |
} |
493 |
return true; |
return true; |
494 |
out: |
out: |
546 |
const char *aliased_name, |
const char *aliased_name, |
547 |
const bool is_delete) |
const bool is_delete) |
548 |
{ |
{ |
549 |
struct alias_entry *new_entry, *ptr; |
struct alias_entry *new_entry; |
550 |
|
struct alias_entry *ptr; |
551 |
static DEFINE_MUTEX(lock); |
static DEFINE_MUTEX(lock); |
552 |
const struct path_info *saved_original_name, *saved_aliased_name; |
const struct path_info *saved_original_name; |
553 |
|
const struct path_info *saved_aliased_name; |
554 |
int error = -ENOMEM; |
int error = -ENOMEM; |
555 |
if (!ccs_is_correct_path(original_name, 1, -1, -1, __func__) || |
if (!ccs_is_correct_path(original_name, 1, -1, -1, __func__) || |
556 |
!ccs_is_correct_path(aliased_name, 1, -1, -1, __func__)) |
!ccs_is_correct_path(aliased_name, 1, -1, -1, __func__)) |
581 |
error = 0; |
error = 0; |
582 |
out: |
out: |
583 |
mutex_unlock(&lock); |
mutex_unlock(&lock); |
584 |
|
ccs_update_counter(CCS_UPDATES_COUNTER_EXCEPTION_POLICY); |
585 |
return error; |
return error; |
586 |
} |
} |
587 |
|
|
643 |
const char *aggregated_name, |
const char *aggregated_name, |
644 |
const bool is_delete) |
const bool is_delete) |
645 |
{ |
{ |
646 |
struct aggregator_entry *new_entry, *ptr; |
struct aggregator_entry *new_entry; |
647 |
|
struct aggregator_entry *ptr; |
648 |
static DEFINE_MUTEX(lock); |
static DEFINE_MUTEX(lock); |
649 |
const struct path_info *saved_original_name, *saved_aggregated_name; |
const struct path_info *saved_original_name; |
650 |
|
const struct path_info *saved_aggregated_name; |
651 |
int error = -ENOMEM; |
int error = -ENOMEM; |
652 |
if (!ccs_is_correct_path(original_name, 1, 0, -1, __func__) || |
if (!ccs_is_correct_path(original_name, 1, 0, -1, __func__) || |
653 |
!ccs_is_correct_path(aggregated_name, 1, -1, -1, __func__)) |
!ccs_is_correct_path(aggregated_name, 1, -1, -1, __func__)) |
678 |
error = 0; |
error = 0; |
679 |
out: |
out: |
680 |
mutex_unlock(&lock); |
mutex_unlock(&lock); |
681 |
|
ccs_update_counter(CCS_UPDATES_COUNTER_EXCEPTION_POLICY); |
682 |
return error; |
return error; |
683 |
} |
} |
684 |
|
|
792 |
*/ |
*/ |
793 |
struct domain_info *ccs_undelete_domain(const char *domainname) |
struct domain_info *ccs_undelete_domain(const char *domainname) |
794 |
{ |
{ |
795 |
struct domain_info *domain, *candidate_domain = NULL; |
struct domain_info *domain; |
796 |
|
struct domain_info *candidate_domain = NULL; |
797 |
struct path_info name; |
struct path_info name; |
798 |
name.name = domainname; |
name.name = domainname; |
799 |
ccs_fill_path_info(&name); |
ccs_fill_path_info(&name); |
866 |
/***** CRITICAL SECTION START *****/ |
/***** CRITICAL SECTION START *****/ |
867 |
read_lock(&tasklist_lock); |
read_lock(&tasklist_lock); |
868 |
for_each_process(p) { |
for_each_process(p) { |
869 |
if (p->domain_info == domain) { |
if (p->domain_info != domain) |
870 |
flag = true; |
continue; |
871 |
break; |
flag = true; |
872 |
} |
break; |
873 |
} |
} |
874 |
read_unlock(&tasklist_lock); |
read_unlock(&tasklist_lock); |
875 |
/***** CRITICAL SECTION END *****/ |
/***** CRITICAL SECTION END *****/ |
1011 |
const u8 mode = ccs_check_flags(CCS_TOMOYO_MAC_FOR_FILE); |
const u8 mode = ccs_check_flags(CCS_TOMOYO_MAC_FOR_FILE); |
1012 |
const bool is_enforce = (mode == 3); |
const bool is_enforce = (mode == 3); |
1013 |
int retval; |
int retval; |
1014 |
struct path_info r, s, l; |
struct path_info r; /* real name */ |
1015 |
|
struct path_info s; /* symlink name */ |
1016 |
|
struct path_info l; /* last name */ |
1017 |
|
|
1018 |
{ |
{ |
1019 |
/* |
/* |
1020 |
* Built-in initializers. This is needed because policies are |
* Built-in initializers. This is needed because policies are |
1021 |
* not loaded until starting /sbin/init . |
* not loaded until starting /sbin/init. |
1022 |
*/ |
*/ |
1023 |
static bool first = true; |
static bool first = true; |
1024 |
if (first) { |
if (first) { |
1049 |
|
|
1050 |
if (path_to_verify) { |
if (path_to_verify) { |
1051 |
if (ccs_pathcmp(&r, path_to_verify)) { |
if (ccs_pathcmp(&r, path_to_verify)) { |
1052 |
|
/* Failed to verify execute handler. */ |
1053 |
static u8 counter = 20; |
static u8 counter = 20; |
1054 |
if (counter) { |
if (counter) { |
1055 |
counter--; |
counter--; |
1127 |
} else if (old_domain == &KERNEL_DOMAIN && !sbin_init_started) { |
} else if (old_domain == &KERNEL_DOMAIN && !sbin_init_started) { |
1128 |
/* |
/* |
1129 |
* Needn't to transit from kernel domain before starting |
* Needn't to transit from kernel domain before starting |
1130 |
* /sbin/init . But transit from kernel domain if executing |
* /sbin/init. But transit from kernel domain if executing |
1131 |
* initializers because they might start before /sbin/init . |
* initializers because they might start before /sbin/init. |
1132 |
*/ |
*/ |
1133 |
domain = old_domain; |
domain = old_domain; |
1134 |
} else if (is_domain_keeper(old_domain->domainname, &r, &l)) { |
} else if (is_domain_keeper(old_domain->domainname, &r, &l)) { |
1144 |
domain = ccs_find_domain(new_domain_name); |
domain = ccs_find_domain(new_domain_name); |
1145 |
if (domain) |
if (domain) |
1146 |
goto done; |
goto done; |
1147 |
if (is_enforce) { |
if (is_enforce && ccs_check_supervisor("#Need to create domain\n%s\n", |
1148 |
if (ccs_check_supervisor("#Need to create domain\n%s\n", |
new_domain_name)) |
|
new_domain_name)) |
|
1149 |
goto done; |
goto done; |
|
} |
|
1150 |
domain = ccs_find_or_assign_new_domain(new_domain_name, |
domain = ccs_find_or_assign_new_domain(new_domain_name, |
1151 |
old_domain->profile); |
old_domain->profile); |
1152 |
if (domain) |
if (domain) |
1183 |
char *arg_ptr = tmp->buffer; |
char *arg_ptr = tmp->buffer; |
1184 |
int arg_len = 0; |
int arg_len = 0; |
1185 |
unsigned long pos = bprm->p; |
unsigned long pos = bprm->p; |
1186 |
int i = pos / PAGE_SIZE, offset = pos % PAGE_SIZE; |
int i = pos / PAGE_SIZE; |
1187 |
|
int offset = pos % PAGE_SIZE; |
1188 |
int argv_count = bprm->argc; |
int argv_count = bprm->argc; |
1189 |
int envp_count = bprm->envc; |
int envp_count = bprm->envc; |
1190 |
/* printk(KERN_DEBUG "start %d %d\n", argv_count, envp_count); */ |
/* printk(KERN_DEBUG "start %d %d\n", argv_count, envp_count); */ |
1274 |
static void unescape(unsigned char *dest) |
static void unescape(unsigned char *dest) |
1275 |
{ |
{ |
1276 |
unsigned char *src = dest; |
unsigned char *src = dest; |
1277 |
unsigned char c, d, e; |
unsigned char c; |
1278 |
|
unsigned char d; |
1279 |
|
unsigned char e; |
1280 |
while ((c = *src++) != '\0') { |
while ((c = *src++) != '\0') { |
1281 |
if (c != '\\') { |
if (c != '\\') { |
1282 |
*dest++ = c; |
*dest++ = c; |
1392 |
* Contents of modified bprm. |
* Contents of modified bprm. |
1393 |
* The envp[] in original bprm is moved to argv[] so that |
* The envp[] in original bprm is moved to argv[] so that |
1394 |
* the alternatively executed program won't be affected by |
* the alternatively executed program won't be affected by |
1395 |
* some dangerous environment variables like LD_PRELOAD . |
* some dangerous environment variables like LD_PRELOAD. |
1396 |
* |
* |
1397 |
* modified bprm->argc |
* modified bprm->argc |
1398 |
* = original bprm->argc + original bprm->envc + 7 |
* = original bprm->argc + original bprm->envc + 7 |
1576 |
*/ |
*/ |
1577 |
static const struct path_info *find_execute_handler(const u8 type) |
static const struct path_info *find_execute_handler(const u8 type) |
1578 |
{ |
{ |
1579 |
const struct domain_info *domain = current->domain_info; |
struct task_struct *task = current; |
1580 |
|
const struct domain_info *domain = task->domain_info; |
1581 |
struct acl_info *ptr; |
struct acl_info *ptr; |
1582 |
|
/* |
1583 |
|
* Don't use execute handler if the current process is |
1584 |
|
* marked as execute handler to avoid infinite execute handler loop. |
1585 |
|
*/ |
1586 |
|
if (task->tomoyo_flags & TOMOYO_TASK_IS_EXECUTE_HANDLER) |
1587 |
|
return NULL; |
1588 |
list1_for_each_entry(ptr, &domain->acl_info_list, list) { |
list1_for_each_entry(ptr, &domain->acl_info_list, list) { |
1589 |
struct execute_handler_record *acl; |
struct execute_handler_record *acl; |
1590 |
if (ptr->type != type) |
if (ptr->type != type) |
1622 |
if (!buf) |
if (!buf) |
1623 |
return -ENOMEM; |
return -ENOMEM; |
1624 |
/* printk(KERN_DEBUG "rootdepth=%d\n", get_root_depth()); */ |
/* printk(KERN_DEBUG "rootdepth=%d\n", get_root_depth()); */ |
1625 |
handler = find_execute_handler(TYPE_PREFERRED_EXECUTE_HANDLER); |
handler = find_execute_handler(TYPE_EXECUTE_HANDLER); |
1626 |
if (handler) { |
if (handler) { |
1627 |
retval = try_alt_exec(bprm, handler, &work, &next_domain, buf); |
retval = try_alt_exec(bprm, handler, &work, &next_domain, buf); |
1628 |
if (!retval) |
if (!retval) |
1632 |
retval = find_next_domain(bprm, &next_domain, NULL, buf); |
retval = find_next_domain(bprm, &next_domain, NULL, buf); |
1633 |
if (retval != -EPERM) |
if (retval != -EPERM) |
1634 |
goto ok; |
goto ok; |
1635 |
handler = find_execute_handler(TYPE_DEFAULT_EXECUTE_HANDLER); |
handler = find_execute_handler(TYPE_DENIED_EXECUTE_HANDLER); |
1636 |
if (handler) { |
if (handler) { |
1637 |
retval = try_alt_exec(bprm, handler, &work, &next_domain, buf); |
retval = try_alt_exec(bprm, handler, &work, &next_domain, buf); |
1638 |
if (!retval) |
if (!retval) |
1649 |
retval = search_binary_handler(bprm, regs); |
retval = search_binary_handler(bprm, regs); |
1650 |
task->tomoyo_flags &= ~TOMOYO_CHECK_READ_FOR_OPEN_EXEC; |
task->tomoyo_flags &= ~TOMOYO_CHECK_READ_FOR_OPEN_EXEC; |
1651 |
out: |
out: |
1652 |
|
/* Return to previous domain if execution failed. */ |
1653 |
if (retval < 0) |
if (retval < 0) |
1654 |
task->domain_info = prev_domain; |
task->domain_info = prev_domain; |
1655 |
|
/* Mark the current process as execute handler. */ |
1656 |
|
else if (handler) |
1657 |
|
task->tomoyo_flags |= TOMOYO_TASK_IS_EXECUTE_HANDLER; |
1658 |
|
/* Mark the current process as normal process. */ |
1659 |
|
else |
1660 |
|
task->tomoyo_flags &= ~TOMOYO_TASK_IS_EXECUTE_HANDLER; |
1661 |
ccs_free(work); |
ccs_free(work); |
1662 |
ccs_free(buf); |
ccs_free(buf); |
1663 |
return retval; |
return retval; |