5 |
* |
* |
6 |
* Copyright (C) 2005-2008 NTT DATA CORPORATION |
* Copyright (C) 2005-2008 NTT DATA CORPORATION |
7 |
* |
* |
8 |
* Version: 1.6.2-pre 2008/06/10 |
* Version: 1.6.5-pre 2008/10/11 |
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. |
56 |
#endif |
#endif |
57 |
|
|
58 |
/* Has /sbin/init started? */ |
/* Has /sbin/init started? */ |
59 |
bool sbin_init_started = false; |
bool sbin_init_started; |
60 |
|
|
61 |
/* Log level for SAKURA's printk(). */ |
/* Log level for SAKURA's printk(). */ |
62 |
const char *ccs_log_level = KERN_DEBUG; |
const char *ccs_log_level = KERN_DEBUG; |
94 |
[CCS_TOMOYO_MAX_REJECT_LOG] |
[CCS_TOMOYO_MAX_REJECT_LOG] |
95 |
= { "MAX_REJECT_LOG", MAX_REJECT_LOG, INT_MAX }, |
= { "MAX_REJECT_LOG", MAX_REJECT_LOG, INT_MAX }, |
96 |
[CCS_TOMOYO_VERBOSE] = { "TOMOYO_VERBOSE", 1, 1 }, |
[CCS_TOMOYO_VERBOSE] = { "TOMOYO_VERBOSE", 1, 1 }, |
|
[CCS_ALLOW_ENFORCE_GRACE] = { "ALLOW_ENFORCE_GRACE", 0, 1 }, |
|
97 |
[CCS_SLEEP_PERIOD] |
[CCS_SLEEP_PERIOD] |
98 |
= { "SLEEP_PERIOD", 0, 3000 }, /* in 0.1 second */ |
= { "SLEEP_PERIOD", 0, 3000 }, /* in 0.1 second */ |
99 |
}; |
}; |
145 |
} *profile_ptr[MAX_PROFILES]; |
} *profile_ptr[MAX_PROFILES]; |
146 |
|
|
147 |
/* Permit policy management by non-root user? */ |
/* Permit policy management by non-root user? */ |
148 |
static bool manage_by_non_root = false; |
static bool manage_by_non_root; |
149 |
|
|
150 |
/* Utility functions. */ |
/* Utility functions. */ |
151 |
|
|
189 |
*/ |
*/ |
190 |
static bool is_decimal(const char c) |
static bool is_decimal(const char c) |
191 |
{ |
{ |
192 |
return (c >= '0' && c <= '9'); |
return c >= '0' && c <= '9'; |
193 |
} |
} |
194 |
|
|
195 |
/** |
/** |
201 |
*/ |
*/ |
202 |
static bool is_hexadecimal(const char c) |
static bool is_hexadecimal(const char c) |
203 |
{ |
{ |
204 |
return ((c >= '0' && c <= '9') || |
return (c >= '0' && c <= '9') || |
205 |
(c >= 'A' && c <= 'F') || |
(c >= 'A' && c <= 'F') || |
206 |
(c >= 'a' && c <= 'f')); |
(c >= 'a' && c <= 'f'); |
207 |
} |
} |
208 |
|
|
209 |
/** |
/** |
215 |
*/ |
*/ |
216 |
static bool is_alphabet_char(const char c) |
static bool is_alphabet_char(const char c) |
217 |
{ |
{ |
218 |
return ((c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f')); |
return (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f'); |
219 |
} |
} |
220 |
|
|
221 |
/** |
/** |
670 |
while (*pattern == '\\' && |
while (*pattern == '\\' && |
671 |
(*(pattern + 1) == '*' || *(pattern + 1) == '@')) |
(*(pattern + 1) == '*' || *(pattern + 1) == '@')) |
672 |
pattern += 2; |
pattern += 2; |
673 |
return (filename == filename_end && pattern == pattern_end); |
return filename == filename_end && pattern == pattern_end; |
674 |
} |
} |
675 |
|
|
676 |
/** |
/** |
772 |
while (*p == '\\' && |
while (*p == '\\' && |
773 |
(*(p + 1) == '*' || *(p + 1) == '@')) |
(*(p + 1) == '*' || *(p + 1) == '@')) |
774 |
p += 2; |
p += 2; |
775 |
return (!*f && !*p); |
return !*f && !*p; |
776 |
} |
} |
777 |
|
|
778 |
/** |
/** |
845 |
} |
} |
846 |
|
|
847 |
/** |
/** |
848 |
* ccs_check_flags_no_sleep_check - Check mode for specified functionality. |
* ccs_can_sleep - Check whether it is permitted to do operations that may sleep. |
|
* |
|
|
* @index: The functionality to check mode. |
|
|
* |
|
|
* Returns the mode of specified functionality. |
|
|
*/ |
|
|
unsigned int ccs_check_flags_no_sleep_check(const u8 index) |
|
|
{ |
|
|
const u8 profile = current->domain_info->profile; |
|
|
return sbin_init_started && index < CCS_MAX_CONTROL_INDEX |
|
|
#if MAX_PROFILES != 256 |
|
|
&& profile < MAX_PROFILES |
|
|
#endif |
|
|
&& profile_ptr[profile] ? |
|
|
profile_ptr[profile]->value[index] : 0; |
|
|
} |
|
|
|
|
|
/** |
|
|
* sleep_check - Check whether it is permitted to do operations that may sleep. |
|
849 |
* |
* |
850 |
* Returns true if it is permitted to do operations that may sleep, |
* Returns true if it is permitted to do operations that may sleep, |
851 |
* false otherwise. |
* false otherwise. |
856 |
* it is permitted to do operations that may sleep. |
* it is permitted to do operations that may sleep. |
857 |
* Thus, this warning should not happen. |
* Thus, this warning should not happen. |
858 |
*/ |
*/ |
859 |
static bool sleep_check(void) |
bool ccs_can_sleep(void) |
860 |
{ |
{ |
861 |
static u8 count = 20; |
static u8 count = 20; |
862 |
if (likely(!in_interrupt())) |
if (likely(!in_interrupt())) |
873 |
/** |
/** |
874 |
* ccs_check_flags - Check mode for specified functionality. |
* ccs_check_flags - Check mode for specified functionality. |
875 |
* |
* |
876 |
* @index: The functionality to check mode. |
* @domain: Pointer to "struct domain_info". NULL for current->domain_info. |
877 |
|
* @index: The functionality to check mode. |
878 |
* |
* |
879 |
* Returns the mode of specified functionality. |
* Returns the mode of specified functionality. |
880 |
*/ |
*/ |
881 |
unsigned int ccs_check_flags(const u8 index) |
unsigned int ccs_check_flags(const struct domain_info *domain, const u8 index) |
882 |
{ |
{ |
883 |
return sleep_check() ? ccs_check_flags_no_sleep_check(index) : 0; |
u8 profile; |
884 |
|
if (!domain) |
885 |
|
domain = current->domain_info; |
886 |
|
profile = domain->profile; |
887 |
|
return sbin_init_started && index < CCS_MAX_CONTROL_INDEX |
888 |
|
#if MAX_PROFILES != 256 |
889 |
|
&& profile < MAX_PROFILES |
890 |
|
#endif |
891 |
|
&& profile_ptr[profile] ? |
892 |
|
profile_ptr[profile]->value[index] : 0; |
893 |
} |
} |
894 |
|
|
895 |
#ifdef CONFIG_TOMOYO |
#ifdef CONFIG_TOMOYO |
896 |
/** |
/** |
897 |
* ccs_check_capability_flags - Check mode for specified capability. |
* ccs_check_capability_flags - Check mode for specified capability. |
898 |
* |
* |
899 |
* @index: The capability to check mode. |
* @domain: Pointer to "struct domain_info". NULL for current->domain_info. |
900 |
|
* @index: The capability to check mode. |
901 |
* |
* |
902 |
* Returns the mode of specified capability. |
* Returns the mode of specified capability. |
903 |
*/ |
*/ |
904 |
u8 ccs_check_capability_flags(const u8 index) |
static u8 ccs_check_capability_flags(const struct domain_info *domain, |
905 |
|
const u8 index) |
906 |
{ |
{ |
907 |
const u8 profile = current->domain_info->profile; |
const u8 profile = domain ? domain->profile : |
908 |
|
current->domain_info->profile; |
909 |
return sbin_init_started && index < TOMOYO_MAX_CAPABILITY_INDEX |
return sbin_init_started && index < TOMOYO_MAX_CAPABILITY_INDEX |
910 |
#if MAX_PROFILES != 256 |
#if MAX_PROFILES != 256 |
911 |
&& profile < MAX_PROFILES |
&& profile < MAX_PROFILES |
912 |
#endif |
#endif |
|
&& sleep_check() |
|
913 |
&& profile_ptr[profile] ? |
&& profile_ptr[profile] ? |
914 |
profile_ptr[profile]->capability_value[index] : 0; |
profile_ptr[profile]->capability_value[index] : 0; |
915 |
} |
} |
930 |
#endif |
#endif |
931 |
|
|
932 |
/** |
/** |
933 |
|
* ccs_init_request_info - Initialize "struct ccs_request_info" members. |
934 |
|
* |
935 |
|
* @r: Pointer to "struct ccs_request_info" to initialize. |
936 |
|
* @domain: Pointer to "struct domain_info". NULL for current->domain_info. |
937 |
|
* @index: Index number of functionality. |
938 |
|
*/ |
939 |
|
void ccs_init_request_info(struct ccs_request_info *r, |
940 |
|
struct domain_info *domain, const u8 index) |
941 |
|
{ |
942 |
|
memset(r, 0, sizeof(*r)); |
943 |
|
if (!domain) |
944 |
|
domain = current->domain_info; |
945 |
|
r->domain = domain; |
946 |
|
r->profile = domain->profile; |
947 |
|
if (index < CCS_MAX_CONTROL_INDEX) |
948 |
|
r->mode = ccs_check_flags(domain, index); |
949 |
|
#ifdef CONFIG_TOMOYO |
950 |
|
else |
951 |
|
r->mode = ccs_check_capability_flags(domain, index |
952 |
|
- CCS_MAX_CONTROL_INDEX); |
953 |
|
#endif |
954 |
|
r->tomoyo_flags = current->tomoyo_flags; |
955 |
|
} |
956 |
|
|
957 |
|
/** |
958 |
* ccs_verbose_mode - Check whether TOMOYO is verbose mode. |
* ccs_verbose_mode - Check whether TOMOYO is verbose mode. |
959 |
* |
* |
960 |
|
* @domain: Pointer to "struct domain_info". NULL for current->domain_info. |
961 |
|
* |
962 |
* Returns true if domain policy violation warning should be printed to |
* Returns true if domain policy violation warning should be printed to |
963 |
* console. |
* console. |
964 |
*/ |
*/ |
965 |
bool ccs_verbose_mode(void) |
bool ccs_verbose_mode(const struct domain_info *domain) |
966 |
{ |
{ |
967 |
return ccs_check_flags(CCS_TOMOYO_VERBOSE) != 0; |
return ccs_check_flags(domain, CCS_TOMOYO_VERBOSE) != 0; |
968 |
} |
} |
969 |
|
|
970 |
/** |
/** |
1035 |
count++; |
count++; |
1036 |
} |
} |
1037 |
} |
} |
1038 |
if (count < ccs_check_flags(CCS_TOMOYO_MAX_ACCEPT_ENTRY)) |
if (count < ccs_check_flags(domain, CCS_TOMOYO_MAX_ACCEPT_ENTRY)) |
1039 |
return true; |
return true; |
1040 |
if (!domain->quota_warned) { |
if (!domain->quota_warned) { |
1041 |
domain->quota_warned = true; |
domain->quota_warned = true; |
1085 |
/** |
/** |
1086 |
* write_profile - Write profile table. |
* write_profile - Write profile table. |
1087 |
* |
* |
1088 |
* @head: Pointer to "struct ccs_io_buffer" |
* @head: Pointer to "struct ccs_io_buffer". |
1089 |
* |
* |
1090 |
* Returns 0 on success, negative value otherwise. |
* Returns 0 on success, negative value otherwise. |
1091 |
*/ |
*/ |
1146 |
switch (i) { |
switch (i) { |
1147 |
case CCS_SAKURA_RESTRICT_AUTOBIND: |
case CCS_SAKURA_RESTRICT_AUTOBIND: |
1148 |
case CCS_TOMOYO_VERBOSE: |
case CCS_TOMOYO_VERBOSE: |
|
case CCS_ALLOW_ENFORCE_GRACE: |
|
1149 |
modes = mode_2; |
modes = mode_2; |
1150 |
break; |
break; |
1151 |
default: |
default: |
1178 |
/** |
/** |
1179 |
* read_profile - Read profile table. |
* read_profile - Read profile table. |
1180 |
* |
* |
1181 |
* @head: Pointer to "struct ccs_io_buffer" |
* @head: Pointer to "struct ccs_io_buffer". |
1182 |
* |
* |
1183 |
* Returns 0. |
* Returns 0. |
1184 |
*/ |
*/ |
1335 |
/** |
/** |
1336 |
* write_manager_policy - Write manager policy. |
* write_manager_policy - Write manager policy. |
1337 |
* |
* |
1338 |
* @head: Pointer to "struct ccs_io_buffer" |
* @head: Pointer to "struct ccs_io_buffer". |
1339 |
* |
* |
1340 |
* Returns 0 on success, negative value otherwise. |
* Returns 0 on success, negative value otherwise. |
1341 |
*/ |
*/ |
1353 |
/** |
/** |
1354 |
* read_manager_policy - Read manager policy. |
* read_manager_policy - Read manager policy. |
1355 |
* |
* |
1356 |
* @head: Pointer to "struct ccs_io_buffer" |
* @head: Pointer to "struct ccs_io_buffer". |
1357 |
* |
* |
1358 |
* Returns 0. |
* Returns 0. |
1359 |
*/ |
*/ |
1384 |
{ |
{ |
1385 |
struct policy_manager_entry *ptr; |
struct policy_manager_entry *ptr; |
1386 |
const char *exe; |
const char *exe; |
1387 |
const struct task_struct *task = current; |
struct task_struct *task = current; |
1388 |
const struct path_info *domainname = task->domain_info->domainname; |
const struct path_info *domainname = task->domain_info->domainname; |
1389 |
bool found = false; |
bool found = false; |
1390 |
if (!sbin_init_started) |
if (!sbin_init_started) |
1391 |
return true; |
return true; |
1392 |
|
if (task->tomoyo_flags & CCS_TASK_IS_POLICY_MANAGER) |
1393 |
|
return true; |
1394 |
if (!manage_by_non_root && (task->uid || task->euid)) |
if (!manage_by_non_root && (task->uid || task->euid)) |
1395 |
return false; |
return false; |
1396 |
list1_for_each_entry(ptr, &policy_manager_list, list) { |
list1_for_each_entry(ptr, &policy_manager_list, list) { |
1397 |
if (!ptr->is_deleted && ptr->is_domain |
if (!ptr->is_deleted && ptr->is_domain |
1398 |
&& !ccs_pathcmp(domainname, ptr->manager)) |
&& !ccs_pathcmp(domainname, ptr->manager)) { |
1399 |
|
/* Set manager flag. */ |
1400 |
|
task->tomoyo_flags |= CCS_TASK_IS_POLICY_MANAGER; |
1401 |
return true; |
return true; |
1402 |
|
} |
1403 |
} |
} |
1404 |
exe = ccs_get_exe(); |
exe = ccs_get_exe(); |
1405 |
if (!exe) |
if (!exe) |
1408 |
if (!ptr->is_deleted && !ptr->is_domain |
if (!ptr->is_deleted && !ptr->is_domain |
1409 |
&& !strcmp(exe, ptr->manager->name)) { |
&& !strcmp(exe, ptr->manager->name)) { |
1410 |
found = true; |
found = true; |
1411 |
|
/* Set manager flag. */ |
1412 |
|
task->tomoyo_flags |= CCS_TASK_IS_POLICY_MANAGER; |
1413 |
break; |
break; |
1414 |
} |
} |
1415 |
} |
} |
1453 |
} |
} |
1454 |
|
|
1455 |
/** |
/** |
1456 |
|
* is_select_one - Parse select command. |
1457 |
|
* |
1458 |
|
* @head: Pointer to "struct ccs_io_buffer". |
1459 |
|
* @data: String to parse. |
1460 |
|
* |
1461 |
|
* Returns true on success, false otherwise. |
1462 |
|
*/ |
1463 |
|
static bool is_select_one(struct ccs_io_buffer *head, const char *data) |
1464 |
|
{ |
1465 |
|
unsigned int pid; |
1466 |
|
struct domain_info *domain = NULL; |
1467 |
|
if (sscanf(data, "pid=%u", &pid) == 1) { |
1468 |
|
struct task_struct *p; |
1469 |
|
/***** CRITICAL SECTION START *****/ |
1470 |
|
read_lock(&tasklist_lock); |
1471 |
|
p = find_task_by_pid(pid); |
1472 |
|
if (p) |
1473 |
|
domain = p->domain_info; |
1474 |
|
read_unlock(&tasklist_lock); |
1475 |
|
/***** CRITICAL SECTION END *****/ |
1476 |
|
} else if (!strncmp(data, "domain=", 7)) { |
1477 |
|
if (ccs_is_domain_def(data + 7)) |
1478 |
|
domain = ccs_find_domain(data + 7); |
1479 |
|
} else |
1480 |
|
return false; |
1481 |
|
head->read_avail = 0; |
1482 |
|
ccs_io_printf(head, "# select %s\n", data); |
1483 |
|
head->read_single_domain = true; |
1484 |
|
head->read_eof = !domain; |
1485 |
|
if (domain) { |
1486 |
|
struct domain_info *d; |
1487 |
|
head->read_var1 = NULL; |
1488 |
|
list1_for_each_entry(d, &domain_list, list) { |
1489 |
|
if (d == domain) |
1490 |
|
break; |
1491 |
|
head->read_var1 = &d->list; |
1492 |
|
} |
1493 |
|
head->read_var2 = NULL; |
1494 |
|
head->read_bit = 0; |
1495 |
|
head->read_step = 0; |
1496 |
|
if (domain->is_deleted) |
1497 |
|
ccs_io_printf(head, "# This is a deleted domain.\n"); |
1498 |
|
} |
1499 |
|
head->write_var1 = domain; |
1500 |
|
return true; |
1501 |
|
} |
1502 |
|
|
1503 |
|
/** |
1504 |
* write_domain_policy - Write domain policy. |
* write_domain_policy - Write domain policy. |
1505 |
* |
* |
1506 |
* @head: Pointer to "struct ccs_io_buffer". |
* @head: Pointer to "struct ccs_io_buffer". |
1523 |
is_select = true; |
is_select = true; |
1524 |
else if (str_starts(&data, KEYWORD_UNDELETE)) |
else if (str_starts(&data, KEYWORD_UNDELETE)) |
1525 |
is_undelete = true; |
is_undelete = true; |
1526 |
|
if (is_select && is_select_one(head, data)) |
1527 |
|
return 0; |
1528 |
|
/* Don't allow updating policies by non manager programs. */ |
1529 |
|
if (!is_policy_manager()) |
1530 |
|
return -EPERM; |
1531 |
if (ccs_is_domain_def(data)) { |
if (ccs_is_domain_def(data)) { |
1532 |
domain = NULL; |
domain = NULL; |
1533 |
if (is_delete) |
if (is_delete) |
1997 |
domain = list1_entry(dpos, struct domain_info, list); |
domain = list1_entry(dpos, struct domain_info, list); |
1998 |
if (head->read_step != 1) |
if (head->read_step != 1) |
1999 |
goto acl_loop; |
goto acl_loop; |
2000 |
if (domain->is_deleted) |
if (domain->is_deleted && !head->read_single_domain) |
2001 |
continue; |
continue; |
2002 |
/* Print domainname and flags. */ |
/* Print domainname and flags. */ |
2003 |
if (domain->quota_warned) |
if (domain->quota_warned) |
2034 |
if (!ccs_io_printf(head, "\n")) |
if (!ccs_io_printf(head, "\n")) |
2035 |
return 0; |
return 0; |
2036 |
head->read_step = 1; |
head->read_step = 1; |
2037 |
|
if (head->read_single_domain) |
2038 |
|
break; |
2039 |
} |
} |
2040 |
head->read_eof = true; |
head->read_eof = true; |
2041 |
return 0; |
return 0; |
2132 |
static int read_pid(struct ccs_io_buffer *head) |
static int read_pid(struct ccs_io_buffer *head) |
2133 |
{ |
{ |
2134 |
if (head->read_avail == 0 && !head->read_eof) { |
if (head->read_avail == 0 && !head->read_eof) { |
2135 |
|
const char *is_manager = ""; |
2136 |
|
const char *is_execute_handler = ""; |
2137 |
const int pid = head->read_step; |
const int pid = head->read_step; |
2138 |
struct task_struct *p; |
struct task_struct *p; |
2139 |
struct domain_info *domain = NULL; |
struct domain_info *domain = NULL; |
2140 |
|
u32 tomoyo_flags = 0; |
2141 |
/***** CRITICAL SECTION START *****/ |
/***** CRITICAL SECTION START *****/ |
2142 |
read_lock(&tasklist_lock); |
read_lock(&tasklist_lock); |
2143 |
p = find_task_by_pid(pid); |
p = find_task_by_pid(pid); |
2144 |
if (p) |
if (p) { |
2145 |
domain = p->domain_info; |
domain = p->domain_info; |
2146 |
|
tomoyo_flags = p->tomoyo_flags; |
2147 |
|
} |
2148 |
read_unlock(&tasklist_lock); |
read_unlock(&tasklist_lock); |
2149 |
/***** CRITICAL SECTION END *****/ |
/***** CRITICAL SECTION END *****/ |
2150 |
|
if (tomoyo_flags & TOMOYO_TASK_IS_EXECUTE_HANDLER) |
2151 |
|
is_execute_handler = "(execute_handler)"; |
2152 |
|
if (tomoyo_flags & CCS_TASK_IS_POLICY_MANAGER) |
2153 |
|
is_manager = "(manager)"; |
2154 |
if (domain) |
if (domain) |
2155 |
ccs_io_printf(head, "%d %u %s", pid, domain->profile, |
ccs_io_printf(head, "%d%s%s %u %s", pid, is_manager, |
2156 |
|
is_execute_handler, domain->profile, |
2157 |
domain->domainname->name); |
domain->domainname->name); |
2158 |
head->read_eof = true; |
head->read_eof = true; |
2159 |
} |
} |
2464 |
envp[2] = NULL; |
envp[2] = NULL; |
2465 |
call_usermodehelper(argv[0], argv, envp, 1); |
call_usermodehelper(argv[0], argv, envp, 1); |
2466 |
} |
} |
2467 |
|
#elif defined(TASK_DEAD) |
2468 |
|
{ |
2469 |
|
/* Copied from kernel/kmod.c */ |
2470 |
|
struct task_struct *task = current; |
2471 |
|
pid_t pid = kernel_thread(run_ccs_loader, NULL, 0); |
2472 |
|
sigset_t tmpsig; |
2473 |
|
spin_lock_irq(&task->sighand->siglock); |
2474 |
|
tmpsig = task->blocked; |
2475 |
|
siginitsetinv(&task->blocked, |
2476 |
|
sigmask(SIGKILL) | sigmask(SIGSTOP)); |
2477 |
|
recalc_sigpending(); |
2478 |
|
spin_unlock_irq(¤t->sighand->siglock); |
2479 |
|
if (pid >= 0) |
2480 |
|
waitpid(pid, NULL, __WCLONE); |
2481 |
|
spin_lock_irq(&task->sighand->siglock); |
2482 |
|
task->blocked = tmpsig; |
2483 |
|
recalc_sigpending(); |
2484 |
|
spin_unlock_irq(&task->sighand->siglock); |
2485 |
|
} |
2486 |
#else |
#else |
2487 |
{ |
{ |
2488 |
/* Copied from kernel/kmod.c */ |
/* Copied from kernel/kmod.c */ |
2504 |
} |
} |
2505 |
#endif |
#endif |
2506 |
#ifdef CONFIG_SAKURA |
#ifdef CONFIG_SAKURA |
2507 |
printk(KERN_INFO "SAKURA: 1.6.2-pre 2008/06/10\n"); |
printk(KERN_INFO "SAKURA: 1.6.5-pre 2008/10/07\n"); |
2508 |
#endif |
#endif |
2509 |
#ifdef CONFIG_TOMOYO |
#ifdef CONFIG_TOMOYO |
2510 |
printk(KERN_INFO "TOMOYO: 1.6.2-pre 2008/06/10\n"); |
printk(KERN_INFO "TOMOYO: 1.6.5-pre 2008/10/11\n"); |
2511 |
#endif |
#endif |
2512 |
printk(KERN_INFO "Mandatory Access Control activated.\n"); |
printk(KERN_INFO "Mandatory Access Control activated.\n"); |
2513 |
sbin_init_started = true; |
sbin_init_started = true; |
2549 |
/** |
/** |
2550 |
* ccs_check_supervisor - Ask for the supervisor's decision. |
* ccs_check_supervisor - Ask for the supervisor's decision. |
2551 |
* |
* |
2552 |
* @bprm: Pointer to "struct linux_binprm". May be NULL. |
* @r: Pointer to "struct ccs_request_info". |
2553 |
* @fmt: The printf()'s format string, followed by parameters. |
* @fmt: The printf()'s format string, followed by parameters. |
2554 |
* |
* |
2555 |
* Returns 0 if the supervisor decided to permit the access request which |
* Returns 0 if the supervisor decided to permit the access request which |
2556 |
* violated the policy in enforcing mode, -EPERM otherwise. |
* violated the policy in enforcing mode, 1 if the supervisor decided to |
2557 |
|
* retry the access request which violated the policy in enforcing mode, |
2558 |
|
* -EPERM otherwise. |
2559 |
*/ |
*/ |
2560 |
int ccs_check_supervisor(struct linux_binprm *bprm, const char *fmt, ...) |
int ccs_check_supervisor(struct ccs_request_info *r, const char *fmt, ...) |
2561 |
{ |
{ |
2562 |
va_list args; |
va_list args; |
2563 |
int error = -EPERM; |
int error = -EPERM; |
2566 |
static unsigned int serial; |
static unsigned int serial; |
2567 |
struct query_entry *query_entry = NULL; |
struct query_entry *query_entry = NULL; |
2568 |
char *header; |
char *header; |
2569 |
|
if (!r->domain) |
2570 |
|
r->domain = current->domain_info; |
2571 |
if (!atomic_read(&queryd_watcher)) { |
if (!atomic_read(&queryd_watcher)) { |
2572 |
int i; |
int i; |
2573 |
if (current->tomoyo_flags & CCS_DONT_SLEEP_ON_ENFORCE_ERROR) |
if (current->tomoyo_flags & CCS_DONT_SLEEP_ON_ENFORCE_ERROR) |
2574 |
return -EPERM; |
return -EPERM; |
2575 |
for (i = 0; i < ccs_check_flags(CCS_SLEEP_PERIOD); i++) { |
for (i = 0; i < ccs_check_flags(r->domain, CCS_SLEEP_PERIOD); |
2576 |
|
i++) { |
2577 |
set_current_state(TASK_INTERRUPTIBLE); |
set_current_state(TASK_INTERRUPTIBLE); |
2578 |
schedule_timeout(HZ / 10); |
schedule_timeout(HZ / 10); |
2579 |
} |
} |
2583 |
len = vsnprintf((char *) &pos, sizeof(pos) - 1, fmt, args) + 32; |
len = vsnprintf((char *) &pos, sizeof(pos) - 1, fmt, args) + 32; |
2584 |
va_end(args); |
va_end(args); |
2585 |
#ifdef CONFIG_TOMOYO |
#ifdef CONFIG_TOMOYO |
2586 |
header = ccs_init_audit_log(&len, current->domain_info->profile, |
header = ccs_init_audit_log(&len, r); |
|
3, bprm); |
|
2587 |
#else |
#else |
2588 |
header = ccs_alloc(1); |
header = ccs_alloc(1); |
2589 |
#endif |
#endif |
2601 |
query_entry->serial = serial++; |
query_entry->serial = serial++; |
2602 |
spin_unlock(&query_lock); |
spin_unlock(&query_lock); |
2603 |
/***** CRITICAL SECTION END *****/ |
/***** CRITICAL SECTION END *****/ |
2604 |
pos = snprintf(query_entry->query, len - 1, "Q%u\n%s", |
pos = snprintf(query_entry->query, len - 1, "Q%u-%hu\n%s", |
2605 |
query_entry->serial, header); |
query_entry->serial, r->retry, header); |
2606 |
ccs_free(header); |
ccs_free(header); |
2607 |
header = NULL; |
header = NULL; |
2608 |
va_start(args, fmt); |
va_start(args, fmt); |
2631 |
spin_unlock(&query_lock); |
spin_unlock(&query_lock); |
2632 |
/***** CRITICAL SECTION END *****/ |
/***** CRITICAL SECTION END *****/ |
2633 |
switch (query_entry->answer) { |
switch (query_entry->answer) { |
2634 |
|
case 3: /* Asked to retry by administrator. */ |
2635 |
|
error = 1; |
2636 |
|
break; |
2637 |
case 1: |
case 1: |
2638 |
/* Granted by administrator. */ |
/* Granted by administrator. */ |
2639 |
error = 0; |
error = 0; |
2665 |
*/ |
*/ |
2666 |
static int poll_query(struct file *file, poll_table *wait) |
static int poll_query(struct file *file, poll_table *wait) |
2667 |
{ |
{ |
2668 |
bool found; |
struct list_head *tmp; |
2669 |
/***** CRITICAL SECTION START *****/ |
bool found = false; |
2670 |
spin_lock(&query_lock); |
u8 i; |
2671 |
found = !list_empty(&query_list); |
for (i = 0; i < 2; i++) { |
2672 |
spin_unlock(&query_lock); |
/***** CRITICAL SECTION START *****/ |
2673 |
/***** CRITICAL SECTION END *****/ |
spin_lock(&query_lock); |
2674 |
if (found) |
list_for_each(tmp, &query_list) { |
2675 |
return POLLIN | POLLRDNORM; |
struct query_entry *ptr |
2676 |
poll_wait(file, &query_wait, wait); |
= list_entry(tmp, struct query_entry, list); |
2677 |
/***** CRITICAL SECTION START *****/ |
if (ptr->answer) |
2678 |
spin_lock(&query_lock); |
continue; |
2679 |
found = !list_empty(&query_list); |
found = true; |
2680 |
spin_unlock(&query_lock); |
break; |
2681 |
/***** CRITICAL SECTION END *****/ |
} |
2682 |
if (found) |
spin_unlock(&query_lock); |
2683 |
return POLLIN | POLLRDNORM; |
/***** CRITICAL SECTION END *****/ |
2684 |
|
if (found) |
2685 |
|
return POLLIN | POLLRDNORM; |
2686 |
|
if (i) |
2687 |
|
break; |
2688 |
|
poll_wait(file, &query_wait, wait); |
2689 |
|
} |
2690 |
return 0; |
return 0; |
2691 |
} |
} |
2692 |
|
|
2715 |
list_for_each(tmp, &query_list) { |
list_for_each(tmp, &query_list) { |
2716 |
struct query_entry *ptr |
struct query_entry *ptr |
2717 |
= list_entry(tmp, struct query_entry, list); |
= list_entry(tmp, struct query_entry, list); |
2718 |
|
if (ptr->answer) |
2719 |
|
continue; |
2720 |
if (pos++ != head->read_step) |
if (pos++ != head->read_step) |
2721 |
continue; |
continue; |
2722 |
len = ptr->query_len; |
len = ptr->query_len; |
2729 |
return 0; |
return 0; |
2730 |
} |
} |
2731 |
buf = ccs_alloc(len); |
buf = ccs_alloc(len); |
2732 |
if (buf) { |
if (!buf) |
2733 |
pos = 0; |
return 0; |
2734 |
/***** CRITICAL SECTION START *****/ |
pos = 0; |
2735 |
spin_lock(&query_lock); |
/***** CRITICAL SECTION START *****/ |
2736 |
list_for_each(tmp, &query_list) { |
spin_lock(&query_lock); |
2737 |
struct query_entry *ptr |
list_for_each(tmp, &query_list) { |
2738 |
= list_entry(tmp, struct query_entry, list); |
struct query_entry *ptr |
2739 |
if (pos++ != head->read_step) |
= list_entry(tmp, struct query_entry, list); |
2740 |
continue; |
if (ptr->answer) |
2741 |
/* |
continue; |
2742 |
* Some query can be skipped because query_list |
if (pos++ != head->read_step) |
2743 |
* can change, but I don't care. |
continue; |
2744 |
*/ |
/* |
2745 |
if (len == ptr->query_len) |
* Some query can be skipped because query_list |
2746 |
memmove(buf, ptr->query, len); |
* can change, but I don't care. |
2747 |
break; |
*/ |
2748 |
} |
if (len == ptr->query_len) |
2749 |
spin_unlock(&query_lock); |
memmove(buf, ptr->query, len); |
2750 |
/***** CRITICAL SECTION END *****/ |
break; |
2751 |
if (buf[0]) { |
} |
2752 |
head->read_avail = len; |
spin_unlock(&query_lock); |
2753 |
head->readbuf_size = head->read_avail; |
/***** CRITICAL SECTION END *****/ |
2754 |
head->read_buf = buf; |
if (buf[0]) { |
2755 |
head->read_step++; |
head->read_avail = len; |
2756 |
} else { |
head->readbuf_size = head->read_avail; |
2757 |
ccs_free(buf); |
head->read_buf = buf; |
2758 |
} |
head->read_step++; |
2759 |
|
} else { |
2760 |
|
ccs_free(buf); |
2761 |
} |
} |
2762 |
return 0; |
return 0; |
2763 |
} |
} |
2775 |
struct list_head *tmp; |
struct list_head *tmp; |
2776 |
unsigned int serial; |
unsigned int serial; |
2777 |
unsigned int answer; |
unsigned int answer; |
|
if (!ccs_check_flags(CCS_ALLOW_ENFORCE_GRACE)) |
|
|
return -EPERM; |
|
2778 |
/***** CRITICAL SECTION START *****/ |
/***** CRITICAL SECTION START *****/ |
2779 |
spin_lock(&query_lock); |
spin_lock(&query_lock); |
2780 |
list_for_each(tmp, &query_list) { |
list_for_each(tmp, &query_list) { |
2874 |
static int read_version(struct ccs_io_buffer *head) |
static int read_version(struct ccs_io_buffer *head) |
2875 |
{ |
{ |
2876 |
if (!head->read_eof) { |
if (!head->read_eof) { |
2877 |
ccs_io_printf(head, "1.6.1"); |
ccs_io_printf(head, "1.6.4"); |
2878 |
head->read_eof = true; |
head->read_eof = true; |
2879 |
} |
} |
2880 |
return 0; |
return 0; |
2915 |
struct ccs_io_buffer *head = ccs_alloc(sizeof(*head)); |
struct ccs_io_buffer *head = ccs_alloc(sizeof(*head)); |
2916 |
if (!head) |
if (!head) |
2917 |
return -ENOMEM; |
return -ENOMEM; |
2918 |
mutex_init(&head->read_sem); |
mutex_init(&head->io_sem); |
|
mutex_init(&head->write_sem); |
|
2919 |
switch (type) { |
switch (type) { |
2920 |
#ifdef CONFIG_SAKURA |
#ifdef CONFIG_SAKURA |
2921 |
case CCS_SYSTEMPOLICY: /* /proc/ccs/system_policy */ |
case CCS_SYSTEMPOLICY: /* /proc/ccs/system_policy */ |
3070 |
return -ENOSYS; |
return -ENOSYS; |
3071 |
if (!access_ok(VERIFY_WRITE, buffer, buffer_len)) |
if (!access_ok(VERIFY_WRITE, buffer, buffer_len)) |
3072 |
return -EFAULT; |
return -EFAULT; |
3073 |
if (mutex_lock_interruptible(&head->read_sem)) |
if (mutex_lock_interruptible(&head->io_sem)) |
3074 |
return -EINTR; |
return -EINTR; |
3075 |
/* Call the policy handler. */ |
/* Call the policy handler. */ |
3076 |
len = head->read(head); |
len = head->read(head); |
3091 |
head->read_avail -= len; |
head->read_avail -= len; |
3092 |
memmove(cp, cp + len, head->read_avail); |
memmove(cp, cp + len, head->read_avail); |
3093 |
out: |
out: |
3094 |
mutex_unlock(&head->read_sem); |
mutex_unlock(&head->io_sem); |
3095 |
return len; |
return len; |
3096 |
} |
} |
3097 |
|
|
3116 |
if (!access_ok(VERIFY_READ, buffer, buffer_len)) |
if (!access_ok(VERIFY_READ, buffer, buffer_len)) |
3117 |
return -EFAULT; |
return -EFAULT; |
3118 |
/* Don't allow updating policies by non manager programs. */ |
/* Don't allow updating policies by non manager programs. */ |
3119 |
if (head->write != write_pid && !is_policy_manager()) |
if (head->write != write_pid && |
3120 |
|
#ifdef CONFIG_TOMOYO |
3121 |
|
head->write != write_domain_policy && |
3122 |
|
#endif |
3123 |
|
!is_policy_manager()) |
3124 |
return -EPERM; |
return -EPERM; |
3125 |
if (mutex_lock_interruptible(&head->write_sem)) |
if (mutex_lock_interruptible(&head->io_sem)) |
3126 |
return -EINTR; |
return -EINTR; |
3127 |
/* Read a line and dispatch it to the policy handler. */ |
/* Read a line and dispatch it to the policy handler. */ |
3128 |
while (avail_len > 0) { |
while (avail_len > 0) { |
3144 |
normalize_line(cp0); |
normalize_line(cp0); |
3145 |
head->write(head); |
head->write(head); |
3146 |
} |
} |
3147 |
mutex_unlock(&head->write_sem); |
mutex_unlock(&head->io_sem); |
3148 |
return error; |
return error; |
3149 |
} |
} |
3150 |
|
|