5 |
* |
* |
6 |
* Copyright (C) 2005-2009 NTT DATA CORPORATION |
* Copyright (C) 2005-2009 NTT DATA CORPORATION |
7 |
* |
* |
8 |
* Version: 1.6.8 2009/05/28 |
* Version: 1.7.0-pre 2009/07/03 |
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. |
70 |
} else { |
} else { |
71 |
acl->type &= ~ACL_DELETED; |
acl->type &= ~ACL_DELETED; |
72 |
} |
} |
|
ccs_update_counter(CCS_UPDATES_COUNTER_DOMAIN_POLICY); |
|
73 |
return 0; |
return 0; |
74 |
} |
} |
75 |
|
|
84 |
{ |
{ |
85 |
if (acl) |
if (acl) |
86 |
acl->type |= ACL_DELETED; |
acl->type |= ACL_DELETED; |
|
ccs_update_counter(CCS_UPDATES_COUNTER_DOMAIN_POLICY); |
|
87 |
return 0; |
return 0; |
88 |
} |
} |
89 |
|
|
175 |
error = 0; |
error = 0; |
176 |
break; |
break; |
177 |
} |
} |
178 |
if (!is_delete && error && ccs_memory_ok(entry)) { |
if (!is_delete && error && ccs_memory_ok(entry, sizeof(*entry))) { |
179 |
entry->domainname = saved_domainname; |
entry->domainname = saved_domainname; |
180 |
saved_domainname = NULL; |
saved_domainname = NULL; |
181 |
entry->program = saved_program; |
entry->program = saved_program; |
190 |
ccs_put_name(saved_domainname); |
ccs_put_name(saved_domainname); |
191 |
ccs_put_name(saved_program); |
ccs_put_name(saved_program); |
192 |
kfree(entry); |
kfree(entry); |
|
ccs_update_counter(CCS_UPDATES_COUNTER_EXCEPTION_POLICY); |
|
193 |
return error; |
return error; |
194 |
} |
} |
195 |
|
|
346 |
error = 0; |
error = 0; |
347 |
break; |
break; |
348 |
} |
} |
349 |
if (!is_delete && error && ccs_memory_ok(entry)) { |
if (!is_delete && error && ccs_memory_ok(entry, sizeof(*entry))) { |
350 |
entry->domainname = saved_domainname; |
entry->domainname = saved_domainname; |
351 |
saved_domainname = NULL; |
saved_domainname = NULL; |
352 |
entry->program = saved_program; |
entry->program = saved_program; |
361 |
ccs_put_name(saved_domainname); |
ccs_put_name(saved_domainname); |
362 |
ccs_put_name(saved_program); |
ccs_put_name(saved_program); |
363 |
kfree(entry); |
kfree(entry); |
|
ccs_update_counter(CCS_UPDATES_COUNTER_EXCEPTION_POLICY); |
|
364 |
return error; |
return error; |
365 |
} |
} |
366 |
|
|
459 |
return flag; |
return flag; |
460 |
} |
} |
461 |
|
|
|
/* The list for "struct ccs_alias_entry". */ |
|
|
LIST_HEAD(ccs_alias_list); |
|
|
|
|
|
/** |
|
|
* ccs_update_alias_entry - Update "struct ccs_alias_entry" list. |
|
|
* |
|
|
* @original_name: The original program's real name. |
|
|
* @aliased_name: The symbolic program's symbolic link's name. |
|
|
* @is_delete: True if it is a delete request. |
|
|
* |
|
|
* Returns 0 on success, negative value otherwise. |
|
|
*/ |
|
|
static int ccs_update_alias_entry(const char *original_name, |
|
|
const char *aliased_name, |
|
|
const bool is_delete) |
|
|
{ |
|
|
struct ccs_alias_entry *entry = NULL; |
|
|
struct ccs_alias_entry *ptr; |
|
|
const struct ccs_path_info *saved_original_name; |
|
|
const struct ccs_path_info *saved_aliased_name; |
|
|
int error = is_delete ? -ENOENT : -ENOMEM; |
|
|
if (!ccs_is_correct_path(original_name, 1, -1, -1) || |
|
|
!ccs_is_correct_path(aliased_name, 1, -1, -1)) |
|
|
return -EINVAL; /* No patterns allowed. */ |
|
|
saved_original_name = ccs_get_name(original_name); |
|
|
saved_aliased_name = ccs_get_name(aliased_name); |
|
|
if (!saved_original_name || !saved_aliased_name) { |
|
|
ccs_put_name(saved_original_name); |
|
|
ccs_put_name(saved_aliased_name); |
|
|
return -ENOMEM; |
|
|
} |
|
|
if (!is_delete) |
|
|
entry = kzalloc(sizeof(*entry), GFP_KERNEL); |
|
|
mutex_lock(&ccs_policy_lock); |
|
|
list_for_each_entry_rcu(ptr, &ccs_alias_list, list) { |
|
|
if (ptr->original_name != saved_original_name || |
|
|
ptr->aliased_name != saved_aliased_name) |
|
|
continue; |
|
|
ptr->is_deleted = is_delete; |
|
|
error = 0; |
|
|
break; |
|
|
} |
|
|
if (!is_delete && error && ccs_memory_ok(entry)) { |
|
|
entry->original_name = saved_original_name; |
|
|
saved_original_name = NULL; |
|
|
entry->aliased_name = saved_aliased_name; |
|
|
saved_aliased_name = NULL; |
|
|
list_add_tail_rcu(&entry->list, &ccs_alias_list); |
|
|
entry = NULL; |
|
|
error = 0; |
|
|
} |
|
|
mutex_unlock(&ccs_policy_lock); |
|
|
ccs_put_name(saved_original_name); |
|
|
ccs_put_name(saved_aliased_name); |
|
|
kfree(entry); |
|
|
ccs_update_counter(CCS_UPDATES_COUNTER_EXCEPTION_POLICY); |
|
|
return error; |
|
|
} |
|
|
|
|
|
/** |
|
|
* ccs_read_alias_policy - Read "struct ccs_alias_entry" list. |
|
|
* |
|
|
* @head: Pointer to "struct ccs_io_buffer". |
|
|
* |
|
|
* Returns true on success, false otherwise. |
|
|
* |
|
|
* Caller holds srcu_read_lock(&ccs_ss). |
|
|
*/ |
|
|
bool ccs_read_alias_policy(struct ccs_io_buffer *head) |
|
|
{ |
|
|
struct list_head *pos; |
|
|
bool done = true; |
|
|
list_for_each_cookie(pos, head->read_var2, &ccs_alias_list) { |
|
|
struct ccs_alias_entry *ptr; |
|
|
ptr = list_entry(pos, struct ccs_alias_entry, list); |
|
|
if (ptr->is_deleted) |
|
|
continue; |
|
|
done = ccs_io_printf(head, KEYWORD_ALIAS "%s %s\n", |
|
|
ptr->original_name->name, |
|
|
ptr->aliased_name->name); |
|
|
if (!done) |
|
|
break; |
|
|
} |
|
|
return done; |
|
|
} |
|
|
|
|
|
/** |
|
|
* ccs_write_alias_policy - Write "struct ccs_alias_entry" list. |
|
|
* |
|
|
* @data: String to parse. |
|
|
* @is_delete: True if it is a delete request. |
|
|
* |
|
|
* Returns 0 on success, negative value otherwise. |
|
|
*/ |
|
|
int ccs_write_alias_policy(char *data, const bool is_delete) |
|
|
{ |
|
|
char *cp = strchr(data, ' '); |
|
|
if (!cp) |
|
|
return -EINVAL; |
|
|
*cp++ = '\0'; |
|
|
return ccs_update_alias_entry(data, cp, is_delete); |
|
|
} |
|
|
|
|
462 |
/* The list for "struct ccs_aggregator_entry". */ |
/* The list for "struct ccs_aggregator_entry". */ |
463 |
LIST_HEAD(ccs_aggregator_list); |
LIST_HEAD(ccs_aggregator_list); |
464 |
|
|
501 |
error = 0; |
error = 0; |
502 |
break; |
break; |
503 |
} |
} |
504 |
if (!is_delete && error && ccs_memory_ok(entry)) { |
if (!is_delete && error && ccs_memory_ok(entry, sizeof(*entry))) { |
505 |
entry->original_name = saved_original_name; |
entry->original_name = saved_original_name; |
506 |
saved_original_name = NULL; |
saved_original_name = NULL; |
507 |
entry->aggregated_name = saved_aggregated_name; |
entry->aggregated_name = saved_aggregated_name; |
514 |
ccs_put_name(saved_original_name); |
ccs_put_name(saved_original_name); |
515 |
ccs_put_name(saved_aggregated_name); |
ccs_put_name(saved_aggregated_name); |
516 |
kfree(entry); |
kfree(entry); |
|
ccs_update_counter(CCS_UPDATES_COUNTER_EXCEPTION_POLICY); |
|
517 |
return error; |
return error; |
518 |
} |
} |
519 |
|
|
622 |
found = true; |
found = true; |
623 |
break; |
break; |
624 |
} |
} |
625 |
if (!found && ccs_memory_ok(entry)) { |
if (!found && ccs_memory_ok(entry, sizeof(*entry))) { |
626 |
INIT_LIST_HEAD(&entry->acl_info_list); |
INIT_LIST_HEAD(&entry->acl_info_list); |
627 |
entry->domainname = saved_domainname; |
entry->domainname = saved_domainname; |
628 |
saved_domainname = NULL; |
saved_domainname = NULL; |
714 |
const u32 ccs_flags = current->ccs_flags; |
const u32 ccs_flags = current->ccs_flags; |
715 |
char *new_domain_name = NULL; |
char *new_domain_name = NULL; |
716 |
struct ccs_path_info rn; /* real name */ |
struct ccs_path_info rn; /* real name */ |
|
struct ccs_path_info sn; /* symlink name */ |
|
717 |
struct ccs_path_info ln; /* last name */ |
struct ccs_path_info ln; /* last name */ |
718 |
int retval; |
int retval; |
719 |
retry: |
retry: |
720 |
current->ccs_flags = ccs_flags; |
current->ccs_flags = ccs_flags; |
721 |
r->cond = NULL; |
r->cond = NULL; |
722 |
/* Get realpath of program and symbolic link. */ |
/* Get symlink's pathname of program. */ |
723 |
retval = ccs_realpath_both(bprm->filename, ee); |
retval = ccs_symlink_path(bprm->filename, ee); |
724 |
if (retval < 0) |
if (retval < 0) |
725 |
goto out; |
goto out; |
726 |
|
|
727 |
rn.name = ee->program_path; |
rn.name = ee->program_path; |
728 |
ccs_fill_path_info(&rn); |
ccs_fill_path_info(&rn); |
|
sn.name = ee->tmp; |
|
|
ccs_fill_path_info(&sn); |
|
729 |
ln.name = ccs_get_last_name(r->domain); |
ln.name = ccs_get_last_name(r->domain); |
730 |
ccs_fill_path_info(&ln); |
ccs_fill_path_info(&ln); |
731 |
|
|
743 |
goto calculate_domain; |
goto calculate_domain; |
744 |
} |
} |
745 |
|
|
|
/* Check 'alias' directive. */ |
|
|
if (ccs_pathcmp(&rn, &sn)) { |
|
|
struct ccs_alias_entry *ptr; |
|
|
/* Is this program allowed to be called via symbolic links? */ |
|
|
list_for_each_entry_rcu(ptr, &ccs_alias_list, list) { |
|
|
if (ptr->is_deleted || |
|
|
ccs_pathcmp(&rn, ptr->original_name) || |
|
|
ccs_pathcmp(&sn, ptr->aliased_name)) |
|
|
continue; |
|
|
strncpy(ee->program_path, ptr->aliased_name->name, |
|
|
CCS_MAX_PATHNAME_LEN - 1); |
|
|
ccs_fill_path_info(&rn); |
|
|
break; |
|
|
} |
|
|
} |
|
|
/* sn will be overwritten after here. */ |
|
|
|
|
746 |
/* Compare basename of program_path and argv[0] */ |
/* Compare basename of program_path and argv[0] */ |
747 |
r->mode = ccs_check_flags(r->domain, CCS_MAC_FOR_ARGV0); |
r->mode = ccs_check_flags(r->domain, CCS_MAC_FOR_ARGV0); |
748 |
if (bprm->argc > 0 && r->mode) { |
if (bprm->argc > 0 && r->mode) { |
1036 |
*/ |
*/ |
1037 |
static struct ccs_execve_entry *ccs_allocate_execve_entry(void) |
static struct ccs_execve_entry *ccs_allocate_execve_entry(void) |
1038 |
{ |
{ |
1039 |
struct ccs_execve_entry *ee = ccs_alloc(sizeof(*ee), false); |
struct ccs_execve_entry *ee = kzalloc(sizeof(*ee), GFP_KERNEL); |
1040 |
if (!ee) |
if (!ee) |
1041 |
return NULL; |
return NULL; |
1042 |
memset(ee, 0, sizeof(*ee)); |
ee->program_path = kzalloc(CCS_MAX_PATHNAME_LEN, GFP_KERNEL); |
1043 |
ee->program_path = ccs_alloc(CCS_MAX_PATHNAME_LEN, false); |
ee->tmp = kzalloc(CCS_EXEC_TMPSIZE, GFP_KERNEL); |
|
ee->tmp = ccs_alloc(CCS_MAX_PATHNAME_LEN, false); |
|
1044 |
if (!ee->program_path || !ee->tmp) { |
if (!ee->program_path || !ee->tmp) { |
1045 |
ccs_free(ee->program_path); |
kfree(ee->program_path); |
1046 |
ccs_free(ee->tmp); |
kfree(ee->tmp); |
1047 |
ccs_free(ee); |
kfree(ee); |
1048 |
return NULL; |
return NULL; |
1049 |
} |
} |
1050 |
ee->srcu_idx = srcu_read_lock(&ccs_ss); |
ee->srcu_idx = srcu_read_lock(&ccs_ss); |
1095 |
list_del(&ee->list); |
list_del(&ee->list); |
1096 |
spin_unlock(&ccs_execve_list_lock); |
spin_unlock(&ccs_execve_list_lock); |
1097 |
/***** CRITICAL SECTION END *****/ |
/***** CRITICAL SECTION END *****/ |
1098 |
ccs_free(ee->program_path); |
kfree(ee->program_path); |
1099 |
ccs_free(ee->tmp); |
kfree(ee->tmp); |
1100 |
kfree(ee->dump.data); |
kfree(ee->dump.data); |
1101 |
srcu_read_unlock(&ccs_ss, ee->srcu_idx); |
srcu_read_unlock(&ccs_ss, ee->srcu_idx); |
1102 |
ccs_free(ee); |
kfree(ee); |
1103 |
} |
} |
1104 |
|
|
1105 |
/** |
/** |
1218 |
char *exe = (char *) ccs_get_exe(); |
char *exe = (char *) ccs_get_exe(); |
1219 |
if (exe) { |
if (exe) { |
1220 |
retval = copy_strings_kernel(1, &exe, bprm); |
retval = copy_strings_kernel(1, &exe, bprm); |
1221 |
ccs_free(exe); |
kfree(exe); |
1222 |
} else { |
} else { |
1223 |
exe = ee->tmp; |
exe = ee->tmp; |
1224 |
strncpy(ee->tmp, "<unknown>", CCS_EXEC_TMPSIZE - 1); |
strncpy(ee->tmp, "<unknown>", CCS_EXEC_TMPSIZE - 1); |
1289 |
* overwrite ee->program_path and ee->tmp. |
* overwrite ee->program_path and ee->tmp. |
1290 |
*/ |
*/ |
1291 |
const int len = strlen(ee->program_path) + 1; |
const int len = strlen(ee->program_path) + 1; |
1292 |
char *cp = kmalloc(len, GFP_KERNEL); |
char *cp = kzalloc(len, GFP_KERNEL); |
1293 |
if (!cp) { |
if (!cp) { |
1294 |
retval = -ENOMEM; |
retval = -ENOMEM; |
1295 |
goto out; |
goto out; |
1365 |
struct page *page; |
struct page *page; |
1366 |
/* dump->data is released by ccs_free_execve_entry(). */ |
/* dump->data is released by ccs_free_execve_entry(). */ |
1367 |
if (!dump->data) { |
if (!dump->data) { |
1368 |
dump->data = kmalloc(PAGE_SIZE, GFP_KERNEL); |
dump->data = kzalloc(PAGE_SIZE, GFP_KERNEL); |
1369 |
if (!dump->data) |
if (!dump->data) |
1370 |
return false; |
return false; |
1371 |
} |
} |