1 |
/* |
/* |
2 |
* security/ccsecurity/policy_io.c |
* security/ccsecurity/policy_io.c |
3 |
* |
* |
4 |
* Copyright (C) 2005-2011 NTT DATA CORPORATION |
* Copyright (C) 2005-2012 NTT DATA CORPORATION |
5 |
* |
* |
6 |
* Version: 1.8.3+ 2011/11/18 |
* Version: 1.8.3+ 2012/04/01 |
7 |
*/ |
*/ |
8 |
|
|
9 |
#include "internal.h" |
#include "internal.h" |
109 |
}; |
}; |
110 |
|
|
111 |
/* String table for /proc/ccs/profile interface. */ |
/* String table for /proc/ccs/profile interface. */ |
112 |
const char * const ccs_mac_keywords[CCS_MAX_MAC_INDEX |
static const char * const ccs_mac_keywords[CCS_MAX_MAC_INDEX |
113 |
+ CCS_MAX_MAC_CATEGORY_INDEX] = { |
+ CCS_MAX_MAC_CATEGORY_INDEX] = { |
114 |
/* CONFIG::file group */ |
/* CONFIG::file group */ |
115 |
[CCS_MAC_FILE_EXECUTE] = "execute", |
[CCS_MAC_FILE_EXECUTE] = "execute", |
116 |
[CCS_MAC_FILE_OPEN] = "open", |
[CCS_MAC_FILE_OPEN] = "open", |
205 |
}; |
}; |
206 |
|
|
207 |
/* String table for path operation. */ |
/* String table for path operation. */ |
208 |
const char * const ccs_path_keyword[CCS_MAX_PATH_OPERATION] = { |
static const char * const ccs_path_keyword[CCS_MAX_PATH_OPERATION] = { |
209 |
[CCS_TYPE_EXECUTE] = "execute", |
[CCS_TYPE_EXECUTE] = "execute", |
210 |
[CCS_TYPE_READ] = "read", |
[CCS_TYPE_READ] = "read", |
211 |
[CCS_TYPE_WRITE] = "write", |
[CCS_TYPE_WRITE] = "write", |
222 |
}; |
}; |
223 |
|
|
224 |
#ifdef CONFIG_CCSECURITY_NETWORK |
#ifdef CONFIG_CCSECURITY_NETWORK |
225 |
|
|
226 |
/* String table for socket's operation. */ |
/* String table for socket's operation. */ |
227 |
const char * const ccs_socket_keyword[CCS_MAX_NETWORK_OPERATION] = { |
static const char * const ccs_socket_keyword[CCS_MAX_NETWORK_OPERATION] = { |
228 |
[CCS_NETWORK_BIND] = "bind", |
[CCS_NETWORK_BIND] = "bind", |
229 |
[CCS_NETWORK_LISTEN] = "listen", |
[CCS_NETWORK_LISTEN] = "listen", |
230 |
[CCS_NETWORK_CONNECT] = "connect", |
[CCS_NETWORK_CONNECT] = "connect", |
234 |
[CCS_NETWORK_RECV] = "recv", |
[CCS_NETWORK_RECV] = "recv", |
235 |
#endif |
#endif |
236 |
}; |
}; |
237 |
|
|
238 |
|
/* String table for socket's protocols. */ |
239 |
|
static const char * const ccs_proto_keyword[CCS_SOCK_MAX] = { |
240 |
|
[SOCK_STREAM] = "stream", |
241 |
|
[SOCK_DGRAM] = "dgram", |
242 |
|
[SOCK_RAW] = "raw", |
243 |
|
[SOCK_SEQPACKET] = "seqpacket", |
244 |
|
[0] = " ", /* Dummy for avoiding NULL pointer dereference. */ |
245 |
|
[4] = " ", /* Dummy for avoiding NULL pointer dereference. */ |
246 |
|
}; |
247 |
|
|
248 |
#endif |
#endif |
249 |
|
|
250 |
/* String table for categories. */ |
/* String table for categories. */ |
401 |
|
|
402 |
/***** SECTION3: Prototype definition section *****/ |
/***** SECTION3: Prototype definition section *****/ |
403 |
|
|
404 |
int ccs_supervisor(struct ccs_request_info *r, const char *fmt, ...); |
int ccs_audit_log(struct ccs_request_info *r); |
405 |
|
struct ccs_domain_info *ccs_assign_domain(const char *domainname, |
406 |
|
const bool transit); |
407 |
u8 ccs_get_config(const u8 profile, const u8 index); |
u8 ccs_get_config(const u8 profile, const u8 index); |
408 |
void ccs_transition_failed(const char *domainname); |
void ccs_transition_failed(const char *domainname); |
409 |
void ccs_write_log(struct ccs_request_info *r, const char *fmt, ...); |
void ccs_write_log(struct ccs_request_info *r, const char *fmt, ...); |
410 |
|
|
|
static char *ccs_init_log(struct ccs_request_info *r, int len, const char *fmt, |
|
|
va_list args); |
|
|
static const char *ccs_yesno(const unsigned int value); |
|
|
static int ccs_poll_log(struct file *file, poll_table *wait); |
|
|
static void ccs_read_log(struct ccs_io_buffer *head); |
|
|
static void ccs_write_log2(struct ccs_request_info *r, int len, |
|
|
const char *fmt, va_list args); |
|
|
static bool ccs_get_audit(const u8 profile, const u8 index, |
|
|
const struct ccs_acl_info *matched_acl, |
|
|
const bool is_granted); |
|
|
static char *ccs_print_bprm(struct linux_binprm *bprm, |
|
|
struct ccs_page_dump *dump); |
|
|
static char *ccs_print_header(struct ccs_request_info *r); |
|
|
static char *ccs_read_token(struct ccs_acl_param *param); |
|
|
static void ccs_update_task_domain(struct ccs_request_info *r); |
|
|
|
|
411 |
static bool ccs_correct_domain(const unsigned char *domainname); |
static bool ccs_correct_domain(const unsigned char *domainname); |
412 |
static bool ccs_correct_path(const char *filename); |
static bool ccs_correct_path(const char *filename); |
413 |
static bool ccs_correct_word(const char *string); |
static bool ccs_correct_word(const char *string); |
415 |
static bool ccs_domain_def(const unsigned char *buffer); |
static bool ccs_domain_def(const unsigned char *buffer); |
416 |
static bool ccs_domain_quota_ok(struct ccs_request_info *r); |
static bool ccs_domain_quota_ok(struct ccs_request_info *r); |
417 |
static bool ccs_flush(struct ccs_io_buffer *head); |
static bool ccs_flush(struct ccs_io_buffer *head); |
418 |
|
static bool ccs_get_audit(const struct ccs_request_info *r); |
419 |
static bool ccs_has_more_namespace(struct ccs_io_buffer *head); |
static bool ccs_has_more_namespace(struct ccs_io_buffer *head); |
420 |
static bool ccs_manager(void); |
static bool ccs_manager(void); |
421 |
static bool ccs_namespace_jump(const char *domainname); |
static bool ccs_namespace_jump(const char *domainname); |
432 |
const struct ccs_condition *cond); |
const struct ccs_condition *cond); |
433 |
static bool ccs_print_entry(struct ccs_io_buffer *head, |
static bool ccs_print_entry(struct ccs_io_buffer *head, |
434 |
const struct ccs_acl_info *acl); |
const struct ccs_acl_info *acl); |
435 |
static bool ccs_read_domain2(struct ccs_io_buffer *head, |
static bool ccs_print_group(struct ccs_io_buffer *head, |
436 |
struct list_head *list); |
const struct ccs_group *group); |
437 |
|
static bool ccs_read_acl(struct ccs_io_buffer *head, struct list_head *list); |
438 |
static bool ccs_read_group(struct ccs_io_buffer *head, const int idx); |
static bool ccs_read_group(struct ccs_io_buffer *head, const int idx); |
439 |
static bool ccs_read_policy(struct ccs_io_buffer *head, const int idx); |
static bool ccs_read_policy(struct ccs_io_buffer *head, const int idx); |
440 |
static bool ccs_same_condition(const struct ccs_condition *a, |
static bool ccs_same_condition(const struct ccs_condition *a, |
444 |
static bool ccs_str_starts(char **src, const char *find); |
static bool ccs_str_starts(char **src, const char *find); |
445 |
static char *ccs_get_transit_preference(struct ccs_acl_param *param, |
static char *ccs_get_transit_preference(struct ccs_acl_param *param, |
446 |
struct ccs_condition *e); |
struct ccs_condition *e); |
447 |
|
static char *ccs_init_log(struct ccs_request_info *r, int len, const char *fmt, |
448 |
|
va_list args); |
449 |
|
static char *ccs_print_bprm(struct linux_binprm *bprm, |
450 |
|
struct ccs_page_dump *dump); |
451 |
|
static char *ccs_print_header(struct ccs_request_info *r); |
452 |
|
static char *ccs_read_token(struct ccs_acl_param *param); |
453 |
|
static const char *ccs_yesno(const unsigned int value); |
454 |
static const struct ccs_path_info *ccs_get_domainname |
static const struct ccs_path_info *ccs_get_domainname |
455 |
(struct ccs_acl_param *param); |
(struct ccs_acl_param *param); |
456 |
static const struct ccs_path_info *ccs_get_dqword(char *start); |
static const struct ccs_path_info *ccs_get_dqword(char *start); |
458 |
static int ccs_delete_domain(char *domainname); |
static int ccs_delete_domain(char *domainname); |
459 |
static int ccs_open(struct inode *inode, struct file *file); |
static int ccs_open(struct inode *inode, struct file *file); |
460 |
static int ccs_parse_policy(struct ccs_io_buffer *head, char *line); |
static int ccs_parse_policy(struct ccs_io_buffer *head, char *line); |
|
static int ccs_poll_query(struct file *file, poll_table *wait); |
|
461 |
static int ccs_release(struct inode *inode, struct file *file); |
static int ccs_release(struct inode *inode, struct file *file); |
462 |
static int ccs_set_mode(char *name, const char *value, |
static int ccs_set_mode(char *name, const char *value, |
463 |
struct ccs_profile *profile); |
struct ccs_profile *profile); |
464 |
|
static int ccs_supervisor(struct ccs_request_info *r, const char *fmt, ...) |
465 |
|
__printf(2, 3); |
466 |
static int ccs_truncate(char *str); |
static int ccs_truncate(char *str); |
467 |
static int ccs_update_domain(const int size, struct ccs_acl_param *param); |
static int ccs_update_acl(const int size, struct ccs_acl_param *param); |
468 |
static int ccs_update_manager_entry(const char *manager, const bool is_delete); |
static int ccs_update_manager_entry(const char *manager, const bool is_delete); |
469 |
static int ccs_update_policy(const int size, struct ccs_acl_param *param); |
static int ccs_update_policy(const int size, struct ccs_acl_param *param); |
470 |
|
static int ccs_write_acl(struct ccs_policy_namespace *ns, |
471 |
|
struct list_head *list, char *data, |
472 |
|
const bool is_delete); |
473 |
static int ccs_write_aggregator(struct ccs_acl_param *param); |
static int ccs_write_aggregator(struct ccs_acl_param *param); |
474 |
static int ccs_write_answer(struct ccs_io_buffer *head); |
static int ccs_write_answer(struct ccs_io_buffer *head); |
475 |
static int ccs_write_domain(struct ccs_io_buffer *head); |
static int ccs_write_domain(struct ccs_io_buffer *head); |
|
static int ccs_write_domain2(struct ccs_policy_namespace *ns, |
|
|
struct list_head *list, char *data, |
|
|
const bool is_delete); |
|
476 |
static int ccs_write_exception(struct ccs_io_buffer *head); |
static int ccs_write_exception(struct ccs_io_buffer *head); |
477 |
static int ccs_write_file(struct ccs_acl_param *param); |
static int ccs_write_file(struct ccs_acl_param *param); |
478 |
static int ccs_write_group(struct ccs_acl_param *param, const u8 type); |
static int ccs_write_group(struct ccs_acl_param *param, const u8 type); |
507 |
static u8 ccs_make_byte(const u8 c1, const u8 c2, const u8 c3); |
static u8 ccs_make_byte(const u8 c1, const u8 c2, const u8 c3); |
508 |
static u8 ccs_parse_ulong(unsigned long *result, char **str); |
static u8 ccs_parse_ulong(unsigned long *result, char **str); |
509 |
static unsigned int ccs_poll(struct file *file, poll_table *wait); |
static unsigned int ccs_poll(struct file *file, poll_table *wait); |
510 |
static void __init ccs_create_entry(const char *name, const mode_t mode, |
static void __init ccs_create_entry(const char *name, const umode_t mode, |
511 |
struct proc_dir_entry *parent, |
struct proc_dir_entry *parent, |
512 |
const u8 key); |
const u8 key); |
513 |
static void __init ccs_load_builtin_policy(void); |
static void __init ccs_load_builtin_policy(void); |
535 |
const struct ccs_number_union *ptr); |
const struct ccs_number_union *ptr); |
536 |
static void ccs_read_domain(struct ccs_io_buffer *head); |
static void ccs_read_domain(struct ccs_io_buffer *head); |
537 |
static void ccs_read_exception(struct ccs_io_buffer *head); |
static void ccs_read_exception(struct ccs_io_buffer *head); |
538 |
|
static void ccs_read_log(struct ccs_io_buffer *head); |
539 |
static void ccs_read_manager(struct ccs_io_buffer *head); |
static void ccs_read_manager(struct ccs_io_buffer *head); |
540 |
static void ccs_read_pid(struct ccs_io_buffer *head); |
static void ccs_read_pid(struct ccs_io_buffer *head); |
541 |
static void ccs_read_profile(struct ccs_io_buffer *head); |
static void ccs_read_profile(struct ccs_io_buffer *head); |
550 |
static void ccs_set_uint(unsigned int *i, const char *string, |
static void ccs_set_uint(unsigned int *i, const char *string, |
551 |
const char *find); |
const char *find); |
552 |
static void ccs_update_stat(const u8 index); |
static void ccs_update_stat(const u8 index); |
553 |
|
static void ccs_update_task_domain(struct ccs_request_info *r); |
554 |
|
static void ccs_write_log2(struct ccs_request_info *r, int len, |
555 |
|
const char *fmt, va_list args); |
556 |
|
|
557 |
#ifdef CONFIG_CCSECURITY_PORTRESERVE |
#ifdef CONFIG_CCSECURITY_PORTRESERVE |
558 |
static bool __ccs_lport_reserved(const u16 port); |
static bool __ccs_lport_reserved(const u16 port); |
562 |
#ifdef CONFIG_CCSECURITY_NETWORK |
#ifdef CONFIG_CCSECURITY_NETWORK |
563 |
static bool ccs_parse_ipaddr_union(struct ccs_acl_param *param, |
static bool ccs_parse_ipaddr_union(struct ccs_acl_param *param, |
564 |
struct ccs_ipaddr_union *ptr); |
struct ccs_ipaddr_union *ptr); |
565 |
|
static int ccs_print_ipv4(char *buffer, const unsigned int buffer_len, |
566 |
|
const u32 *ip); |
567 |
|
static int ccs_print_ipv6(char *buffer, const unsigned int buffer_len, |
568 |
|
const struct in6_addr *ip); |
569 |
static int ccs_write_inet_network(struct ccs_acl_param *param); |
static int ccs_write_inet_network(struct ccs_acl_param *param); |
570 |
static int ccs_write_unix_network(struct ccs_acl_param *param); |
static int ccs_write_unix_network(struct ccs_acl_param *param); |
571 |
static void ccs_print_ip(char *buf, const unsigned int size, |
static void ccs_print_ip(char *buf, const unsigned int size, |
1120 |
* |
* |
1121 |
* Returns written length. |
* Returns written length. |
1122 |
*/ |
*/ |
1123 |
int ccs_print_ipv4(char *buffer, const unsigned int buffer_len, const u32 *ip) |
static int ccs_print_ipv4(char *buffer, const unsigned int buffer_len, |
1124 |
|
const u32 *ip) |
1125 |
{ |
{ |
1126 |
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) |
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) |
1127 |
return snprintf(buffer, buffer_len, "%pI4", ip); |
return snprintf(buffer, buffer_len, "%pI4", ip); |
1141 |
* |
* |
1142 |
* Returns written length. |
* Returns written length. |
1143 |
*/ |
*/ |
1144 |
int ccs_print_ipv6(char *buffer, const unsigned int buffer_len, |
static int ccs_print_ipv6(char *buffer, const unsigned int buffer_len, |
1145 |
const struct in6_addr *ip) |
const struct in6_addr *ip) |
1146 |
{ |
{ |
1147 |
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) |
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32) |
1148 |
return snprintf(buffer, buffer_len, "%pI6c", ip); |
return snprintf(buffer, buffer_len, "%pI6c", ip); |
1153 |
#endif |
#endif |
1154 |
} |
} |
1155 |
|
|
1156 |
|
/** |
1157 |
|
* ccs_print_ip - Print an IP address. |
1158 |
|
* |
1159 |
|
* @buf: Buffer to write to. |
1160 |
|
* @size: Size of @buf. |
1161 |
|
* @ptr: Pointer to "struct ipaddr_union". |
1162 |
|
* |
1163 |
|
* Returns nothing. |
1164 |
|
*/ |
1165 |
|
static void ccs_print_ip(char *buf, const unsigned int size, |
1166 |
|
const struct ccs_ipaddr_union *ptr) |
1167 |
|
{ |
1168 |
|
int len; |
1169 |
|
if (ptr->is_ipv6) |
1170 |
|
len = ccs_print_ipv6(buf, size, &ptr->ip[0]); |
1171 |
|
else |
1172 |
|
len = ccs_print_ipv4(buf, size, &ptr->ip[0].s6_addr32[0]); |
1173 |
|
if (!memcmp(&ptr->ip[0], &ptr->ip[1], 16) || len >= size / 2) |
1174 |
|
return; |
1175 |
|
buf[len++] = '-'; |
1176 |
|
if (ptr->is_ipv6) |
1177 |
|
ccs_print_ipv6(buf + len, size - len, &ptr->ip[1]); |
1178 |
|
else |
1179 |
|
ccs_print_ipv4(buf + len, size - len, |
1180 |
|
&ptr->ip[1].s6_addr32[0]); |
1181 |
|
} |
1182 |
|
|
1183 |
#endif |
#endif |
1184 |
|
|
1185 |
/***** SECTION5: Variables definition section *****/ |
/***** SECTION5: Variables definition section *****/ |
1288 |
for (pos = pos ? pos : srcu_dereference((head)->next, &ccs_ss); \ |
for (pos = pos ? pos : srcu_dereference((head)->next, &ccs_ss); \ |
1289 |
pos != (head); pos = srcu_dereference(pos->next, &ccs_ss)) |
pos != (head); pos = srcu_dereference(pos->next, &ccs_ss)) |
1290 |
|
|
|
#ifdef CONFIG_CCSECURITY_NETWORK |
|
|
|
|
|
/** |
|
|
* ccs_print_ip - Print an IP address. |
|
|
* |
|
|
* @buf: Buffer to write to. |
|
|
* @size: Size of @buf. |
|
|
* @ptr: Pointer to "struct ipaddr_union". |
|
|
* |
|
|
* Returns nothing. |
|
|
*/ |
|
|
static void ccs_print_ip(char *buf, const unsigned int size, |
|
|
const struct ccs_ipaddr_union *ptr) |
|
|
{ |
|
|
int len; |
|
|
if (ptr->is_ipv6) |
|
|
len = ccs_print_ipv6(buf, size, &ptr->ip[0]); |
|
|
else |
|
|
len = ccs_print_ipv4(buf, size, &ptr->ip[0].s6_addr32[0]); |
|
|
if (!memcmp(&ptr->ip[0], &ptr->ip[1], 16) || len >= size / 2) |
|
|
return; |
|
|
buf[len++] = '-'; |
|
|
if (ptr->is_ipv6) |
|
|
ccs_print_ipv6(buf + len, size - len, &ptr->ip[1]); |
|
|
else |
|
|
ccs_print_ipv4(buf + len, size - len, |
|
|
&ptr->ip[1].s6_addr32[0]); |
|
|
} |
|
|
|
|
|
#endif |
|
|
|
|
1291 |
/** |
/** |
1292 |
* ccs_read_token - Read a word from a line. |
* ccs_read_token - Read a word from a line. |
1293 |
* |
* |
2304 |
* |
* |
2305 |
* @head: Pointer to "struct ccs_io_buffer". |
* @head: Pointer to "struct ccs_io_buffer". |
2306 |
* |
* |
2307 |
* Returns nothing. |
* Returns true if all data was flushed, false otherwise. |
2308 |
*/ |
*/ |
2309 |
static bool ccs_set_lf(struct ccs_io_buffer *head) |
static bool ccs_set_lf(struct ccs_io_buffer *head) |
2310 |
{ |
{ |
2414 |
struct ccs_domain_info *domain; |
struct ccs_domain_info *domain; |
2415 |
const int idx = ccs_read_lock(); |
const int idx = ccs_read_lock(); |
2416 |
ccs_policy_loaded = true; |
ccs_policy_loaded = true; |
2417 |
printk(KERN_INFO "CCSecurity: 1.8.3+ 2011/11/18\n"); |
printk(KERN_INFO "CCSecurity: 1.8.3+ 2012/04/01\n"); |
2418 |
list_for_each_entry_srcu(domain, &ccs_domain_list, list, &ccs_ss) { |
list_for_each_entry_srcu(domain, &ccs_domain_list, list, &ccs_ss) { |
2419 |
const u8 profile = domain->profile; |
const u8 profile = domain->profile; |
2420 |
const struct ccs_policy_namespace *ns = domain->ns; |
const struct ccs_policy_namespace *ns = domain->ns; |
2456 |
return ptr; |
return ptr; |
2457 |
} |
} |
2458 |
|
|
|
|
|
2459 |
/** |
/** |
2460 |
* ccs_get_config - Get config for specified profile's specified functionality. |
* ccs_get_config - Get config for specified profile's specified functionality. |
2461 |
* |
* |
2545 |
} |
} |
2546 |
|
|
2547 |
/** |
/** |
2548 |
|
* ccs_print_group - Print group's name. |
2549 |
|
* |
2550 |
|
* @head: Pointer to "struct ccs_io_buffer". |
2551 |
|
* @group: Pointer to "struct ccsgroup". Maybe NULL. |
2552 |
|
* |
2553 |
|
* Returns true if @group is not NULL. false otherwise. |
2554 |
|
*/ |
2555 |
|
static bool ccs_print_group(struct ccs_io_buffer *head, |
2556 |
|
const struct ccs_group *group) |
2557 |
|
{ |
2558 |
|
if (group) { |
2559 |
|
ccs_set_string(head, "@"); |
2560 |
|
ccs_set_string(head, group->group_name->name); |
2561 |
|
return true; |
2562 |
|
} |
2563 |
|
return false; |
2564 |
|
} |
2565 |
|
|
2566 |
|
/** |
2567 |
* ccs_set_mode - Set mode for specified profile. |
* ccs_set_mode - Set mode for specified profile. |
2568 |
* |
* |
2569 |
* @name: Name of functionality. |
* @name: Name of functionality. |
2813 |
*/ |
*/ |
2814 |
static int ccs_update_policy(const int size, struct ccs_acl_param *param) |
static int ccs_update_policy(const int size, struct ccs_acl_param *param) |
2815 |
{ |
{ |
2816 |
struct ccs_acl_head *new_entry = ¶m->e.acl_head; |
struct ccs_acl_head *new_entry = ¶m->e.acl_head; |
2817 |
int error = param->is_delete ? -ENOENT : -ENOMEM; |
int error = param->is_delete ? -ENOENT : -ENOMEM; |
2818 |
struct ccs_acl_head *entry; |
struct ccs_acl_head *entry; |
2819 |
struct list_head *list = param->list; |
struct list_head *list = param->list; |
2860 |
int error = is_delete ? -ENOENT : -ENOMEM; |
int error = is_delete ? -ENOENT : -ENOMEM; |
2861 |
/* Forced zero clear for using memcmp() at ccs_update_policy(). */ |
/* Forced zero clear for using memcmp() at ccs_update_policy(). */ |
2862 |
memset(¶m.e, 0, sizeof(param.e)); |
memset(¶m.e, 0, sizeof(param.e)); |
2863 |
if (ccs_domain_def(manager)) { |
if (!ccs_correct_domain(manager) && !ccs_correct_word(manager)) |
2864 |
if (!ccs_correct_domain(manager)) |
return -EINVAL; |
|
return -EINVAL; |
|
|
e->is_domain = true; |
|
|
} else { |
|
|
if (!ccs_correct_path(manager)) |
|
|
return -EINVAL; |
|
|
} |
|
2865 |
e->manager = ccs_get_name(manager); |
e->manager = ccs_get_name(manager); |
2866 |
if (e->manager) { |
if (e->manager) { |
2867 |
error = ccs_update_policy(sizeof(*e), ¶m); |
error = ccs_update_policy(sizeof(*e), ¶m); |
2925 |
static bool ccs_manager(void) |
static bool ccs_manager(void) |
2926 |
{ |
{ |
2927 |
struct ccs_manager *ptr; |
struct ccs_manager *ptr; |
2928 |
const char *exe; |
struct ccs_path_info exe; |
2929 |
struct ccs_security *task = ccs_current_security(); |
struct ccs_security *task = ccs_current_security(); |
2930 |
const struct ccs_path_info *domainname |
const struct ccs_path_info *domainname |
2931 |
= ccs_current_domain()->domainname; |
= ccs_current_domain()->domainname; |
2936 |
return true; |
return true; |
2937 |
if (!ccs_manage_by_non_root && (current_uid() || current_euid())) |
if (!ccs_manage_by_non_root && (current_uid() || current_euid())) |
2938 |
return false; |
return false; |
2939 |
exe = ccs_get_exe(); |
exe.name = ccs_get_exe(); |
2940 |
|
if (!exe.name) |
2941 |
|
return false; |
2942 |
|
ccs_fill_path_info(&exe); |
2943 |
list_for_each_entry_srcu(ptr, &ccs_kernel_namespace. |
list_for_each_entry_srcu(ptr, &ccs_kernel_namespace. |
2944 |
policy_list[CCS_ID_MANAGER], head.list, |
policy_list[CCS_ID_MANAGER], head.list, |
2945 |
&ccs_ss) { |
&ccs_ss) { |
2946 |
if (ptr->head.is_deleted) |
if (ptr->head.is_deleted) |
2947 |
continue; |
continue; |
2948 |
if (ptr->is_domain) { |
if (ccs_pathcmp(domainname, ptr->manager) && |
2949 |
if (ccs_pathcmp(domainname, ptr->manager)) |
ccs_pathcmp(&exe, ptr->manager)) |
2950 |
continue; |
continue; |
|
} else { |
|
|
if (!exe || strcmp(exe, ptr->manager->name)) |
|
|
continue; |
|
|
} |
|
2951 |
/* Set manager flag. */ |
/* Set manager flag. */ |
2952 |
task->ccs_flags |= CCS_TASK_IS_MANAGER; |
task->ccs_flags |= CCS_TASK_IS_MANAGER; |
2953 |
found = true; |
found = true; |
2958 |
const pid_t pid = current->pid; |
const pid_t pid = current->pid; |
2959 |
if (ccs_last_pid != pid) { |
if (ccs_last_pid != pid) { |
2960 |
printk(KERN_WARNING "%s ( %s ) is not permitted to " |
printk(KERN_WARNING "%s ( %s ) is not permitted to " |
2961 |
"update policies.\n", domainname->name, exe); |
"update policies.\n", domainname->name, |
2962 |
|
exe.name); |
2963 |
ccs_last_pid = pid; |
ccs_last_pid = pid; |
2964 |
} |
} |
2965 |
} |
} |
2966 |
kfree(exe); |
kfree(exe.name); |
2967 |
return found; |
return found; |
2968 |
} |
} |
2969 |
|
|
3048 |
} |
} |
3049 |
|
|
3050 |
/** |
/** |
3051 |
* ccs_update_domain - Update an entry for domain policy. |
* ccs_update_acl - Update "struct ccs_acl_info" entry. |
3052 |
* |
* |
3053 |
* @size: Size of new entry in bytes. |
* @size: Size of new entry in bytes. |
3054 |
* @param: Pointer to "struct ccs_acl_param". |
* @param: Pointer to "struct ccs_acl_param". |
3057 |
* |
* |
3058 |
* Caller holds ccs_read_lock(). |
* Caller holds ccs_read_lock(). |
3059 |
*/ |
*/ |
3060 |
static int ccs_update_domain(const int size, struct ccs_acl_param *param) |
static int ccs_update_acl(const int size, struct ccs_acl_param *param) |
3061 |
{ |
{ |
3062 |
struct ccs_acl_info *new_entry = ¶m->e.acl_info; |
struct ccs_acl_info *new_entry = ¶m->e.acl_info; |
3063 |
const bool is_delete = param->is_delete; |
const bool is_delete = param->is_delete; |
3064 |
int error = is_delete ? -ENOENT : -ENOMEM; |
int error = is_delete ? -ENOENT : -ENOMEM; |
3065 |
struct ccs_acl_info *entry; |
struct ccs_acl_info *entry; |
3164 |
return -ENOMEM; |
return -ENOMEM; |
3165 |
if (e->handler->is_patterned) |
if (e->handler->is_patterned) |
3166 |
return -EINVAL; /* No patterns allowed. */ |
return -EINVAL; /* No patterns allowed. */ |
3167 |
return ccs_update_domain(sizeof(*e), param); |
return ccs_update_acl(sizeof(*e), param); |
3168 |
#else |
#else |
3169 |
error = -EINVAL; |
error = -EINVAL; |
3170 |
#endif |
#endif |
3176 |
e->domainname = ccs_get_domainname(param); |
e->domainname = ccs_get_domainname(param); |
3177 |
if (!e->domainname) |
if (!e->domainname) |
3178 |
return -EINVAL; |
return -EINVAL; |
3179 |
return ccs_update_domain(sizeof(*e), param); |
return ccs_update_acl(sizeof(*e), param); |
3180 |
#else |
#else |
3181 |
error = -EINVAL; |
error = -EINVAL; |
3182 |
#endif |
#endif |
3226 |
if (!ccs_parse_number_union(param, &e->port) || |
if (!ccs_parse_number_union(param, &e->port) || |
3227 |
e->port.values[1] > 65535) |
e->port.values[1] > 65535) |
3228 |
return -EINVAL; |
return -EINVAL; |
3229 |
return ccs_update_domain(sizeof(*e), param); |
return ccs_update_acl(sizeof(*e), param); |
3230 |
} |
} |
3231 |
|
|
3232 |
/** |
/** |
3257 |
return -EINVAL; |
return -EINVAL; |
3258 |
if (!ccs_parse_name_union(param, &e->name)) |
if (!ccs_parse_name_union(param, &e->name)) |
3259 |
return -EINVAL; |
return -EINVAL; |
3260 |
return ccs_update_domain(sizeof(*e), param); |
return ccs_update_acl(sizeof(*e), param); |
3261 |
} |
} |
3262 |
|
|
3263 |
#endif |
#endif |
3285 |
e->head.perm = perm; |
e->head.perm = perm; |
3286 |
if (!ccs_parse_name_union(param, &e->name)) |
if (!ccs_parse_name_union(param, &e->name)) |
3287 |
return -EINVAL; |
return -EINVAL; |
3288 |
return ccs_update_domain(sizeof(*e), param); |
return ccs_update_acl(sizeof(*e), param); |
3289 |
} |
} |
3290 |
for (type = 0; type < CCS_MAX_PATH2_OPERATION; type++) |
for (type = 0; type < CCS_MAX_PATH2_OPERATION; type++) |
3291 |
if (ccs_permstr(operation, ccs_mac_keywords[ccs_pp2mac[type]])) |
if (ccs_permstr(operation, ccs_mac_keywords[ccs_pp2mac[type]])) |
3297 |
if (!ccs_parse_name_union(param, &e->name1) || |
if (!ccs_parse_name_union(param, &e->name1) || |
3298 |
!ccs_parse_name_union(param, &e->name2)) |
!ccs_parse_name_union(param, &e->name2)) |
3299 |
return -EINVAL; |
return -EINVAL; |
3300 |
return ccs_update_domain(sizeof(*e), param); |
return ccs_update_acl(sizeof(*e), param); |
3301 |
} |
} |
3302 |
for (type = 0; type < CCS_MAX_PATH_NUMBER_OPERATION; type++) |
for (type = 0; type < CCS_MAX_PATH_NUMBER_OPERATION; type++) |
3303 |
if (ccs_permstr(operation, ccs_mac_keywords[ccs_pn2mac[type]])) |
if (ccs_permstr(operation, ccs_mac_keywords[ccs_pn2mac[type]])) |
3309 |
if (!ccs_parse_name_union(param, &e->name) || |
if (!ccs_parse_name_union(param, &e->name) || |
3310 |
!ccs_parse_number_union(param, &e->number)) |
!ccs_parse_number_union(param, &e->number)) |
3311 |
return -EINVAL; |
return -EINVAL; |
3312 |
return ccs_update_domain(sizeof(*e), param); |
return ccs_update_acl(sizeof(*e), param); |
3313 |
} |
} |
3314 |
for (type = 0; type < CCS_MAX_MKDEV_OPERATION; type++) |
for (type = 0; type < CCS_MAX_MKDEV_OPERATION; type++) |
3315 |
if (ccs_permstr(operation, |
if (ccs_permstr(operation, |
3324 |
!ccs_parse_number_union(param, &e->major) || |
!ccs_parse_number_union(param, &e->major) || |
3325 |
!ccs_parse_number_union(param, &e->minor)) |
!ccs_parse_number_union(param, &e->minor)) |
3326 |
return -EINVAL; |
return -EINVAL; |
3327 |
return ccs_update_domain(sizeof(*e), param); |
return ccs_update_acl(sizeof(*e), param); |
3328 |
} |
} |
3329 |
if (ccs_permstr(operation, ccs_mac_keywords[CCS_MAC_FILE_MOUNT])) { |
if (ccs_permstr(operation, ccs_mac_keywords[CCS_MAC_FILE_MOUNT])) { |
3330 |
struct ccs_mount_acl *e = ¶m->e.mount_acl; |
struct ccs_mount_acl *e = ¶m->e.mount_acl; |
3334 |
!ccs_parse_name_union(param, &e->fs_type) || |
!ccs_parse_name_union(param, &e->fs_type) || |
3335 |
!ccs_parse_number_union(param, &e->flags)) |
!ccs_parse_number_union(param, &e->flags)) |
3336 |
return -EINVAL; |
return -EINVAL; |
3337 |
return ccs_update_domain(sizeof(*e), param); |
return ccs_update_acl(sizeof(*e), param); |
3338 |
} |
} |
3339 |
return -EINVAL; |
return -EINVAL; |
3340 |
} |
} |
3359 |
e->env = ccs_get_name(data); |
e->env = ccs_get_name(data); |
3360 |
if (!e->env) |
if (!e->env) |
3361 |
return -ENOMEM; |
return -ENOMEM; |
3362 |
return ccs_update_domain(sizeof(*e), param); |
return ccs_update_acl(sizeof(*e), param); |
3363 |
} |
} |
3364 |
return -EINVAL; |
return -EINVAL; |
3365 |
} |
} |
3384 |
e->domainname = ccs_get_domainname(param); |
e->domainname = ccs_get_domainname(param); |
3385 |
if (!e->domainname) |
if (!e->domainname) |
3386 |
return -EINVAL; |
return -EINVAL; |
3387 |
return ccs_update_domain(sizeof(*e), param); |
return ccs_update_acl(sizeof(*e), param); |
3388 |
} |
} |
3389 |
|
|
3390 |
#endif |
#endif |
3410 |
if (strcmp(operation, ccs_mac_keywords[ccs_c2mac[type]])) |
if (strcmp(operation, ccs_mac_keywords[ccs_c2mac[type]])) |
3411 |
continue; |
continue; |
3412 |
e->operation = type; |
e->operation = type; |
3413 |
return ccs_update_domain(sizeof(*e), param); |
return ccs_update_acl(sizeof(*e), param); |
3414 |
} |
} |
3415 |
return -EINVAL; |
return -EINVAL; |
3416 |
} |
} |
3418 |
#endif |
#endif |
3419 |
|
|
3420 |
/** |
/** |
3421 |
* ccs_write_domain2 - Write domain policy. |
* ccs_write_acl - Write "struct ccs_acl_info" list. |
3422 |
* |
* |
3423 |
* @ns: Pointer to "struct ccs_policy_namespace". |
* @ns: Pointer to "struct ccs_policy_namespace". |
3424 |
* @list: Pointer to "struct list_head". |
* @list: Pointer to "struct list_head". |
3429 |
* |
* |
3430 |
* Caller holds ccs_read_lock(). |
* Caller holds ccs_read_lock(). |
3431 |
*/ |
*/ |
3432 |
static int ccs_write_domain2(struct ccs_policy_namespace *ns, |
static int ccs_write_acl(struct ccs_policy_namespace *ns, |
3433 |
struct list_head *list, char *data, |
struct list_head *list, char *data, |
3434 |
const bool is_delete) |
const bool is_delete) |
3435 |
{ |
{ |
3436 |
struct ccs_acl_param param = { |
struct ccs_acl_param param = { |
3437 |
.ns = ns, |
.ns = ns, |
3460 |
{ "task ", ccs_write_task }, |
{ "task ", ccs_write_task }, |
3461 |
}; |
}; |
3462 |
u8 i; |
u8 i; |
3463 |
/* Forced zero clear for using memcmp() at ccs_update_domain(). */ |
/* Forced zero clear for using memcmp() at ccs_update_acl(). */ |
3464 |
memset(¶m.e, 0, sizeof(param.e)); |
memset(¶m.e, 0, sizeof(param.e)); |
3465 |
param.e.acl_info.perm = 1; |
param.e.acl_info.perm = 1; |
3466 |
for (i = 0; i < ARRAY_SIZE(ccs_callback); i++) { |
for (i = 0; i < ARRAY_SIZE(ccs_callback); i++) { |
3555 |
domain->flags[profile] = !is_delete; |
domain->flags[profile] = !is_delete; |
3556 |
return 0; |
return 0; |
3557 |
} |
} |
3558 |
return ccs_write_domain2(ns, &domain->acl_info_list, data, is_delete); |
return ccs_write_acl(ns, &domain->acl_info_list, data, is_delete); |
3559 |
} |
} |
3560 |
|
|
3561 |
/** |
/** |
3570 |
const struct ccs_name_union *ptr) |
const struct ccs_name_union *ptr) |
3571 |
{ |
{ |
3572 |
ccs_set_space(head); |
ccs_set_space(head); |
3573 |
if (ptr->group) { |
if (!ccs_print_group(head, ptr->group)) |
|
ccs_set_string(head, "@"); |
|
|
ccs_set_string(head, ptr->group->group_name->name); |
|
|
} else { |
|
3574 |
ccs_set_string(head, ptr->filename->name); |
ccs_set_string(head, ptr->filename->name); |
|
} |
|
3575 |
} |
} |
3576 |
|
|
3577 |
/** |
/** |
3585 |
static void ccs_print_name_union_quoted(struct ccs_io_buffer *head, |
static void ccs_print_name_union_quoted(struct ccs_io_buffer *head, |
3586 |
const struct ccs_name_union *ptr) |
const struct ccs_name_union *ptr) |
3587 |
{ |
{ |
3588 |
if (ptr->group) { |
if (!ccs_print_group(head, ptr->group)) { |
|
ccs_set_string(head, "@"); |
|
|
ccs_set_string(head, ptr->group->group_name->name); |
|
|
} else { |
|
3589 |
ccs_set_string(head, "\""); |
ccs_set_string(head, "\""); |
3590 |
ccs_set_string(head, ptr->filename->name); |
ccs_set_string(head, ptr->filename->name); |
3591 |
ccs_set_string(head, "\""); |
ccs_set_string(head, "\""); |
3603 |
static void ccs_print_number_union_nospace(struct ccs_io_buffer *head, |
static void ccs_print_number_union_nospace(struct ccs_io_buffer *head, |
3604 |
const struct ccs_number_union *ptr) |
const struct ccs_number_union *ptr) |
3605 |
{ |
{ |
3606 |
if (ptr->group) { |
if (!ccs_print_group(head, ptr->group)) { |
|
ccs_set_string(head, "@"); |
|
|
ccs_set_string(head, ptr->group->group_name->name); |
|
|
} else { |
|
3607 |
int i; |
int i; |
3608 |
unsigned long min = ptr->values[0]; |
unsigned long min = ptr->values[0]; |
3609 |
const unsigned long max = ptr->values[1]; |
const unsigned long max = ptr->values[1]; |
3805 |
*/ |
*/ |
3806 |
static void ccs_set_group(struct ccs_io_buffer *head, const char *category) |
static void ccs_set_group(struct ccs_io_buffer *head, const char *category) |
3807 |
{ |
{ |
3808 |
if (head->type == CCS_EXCEPTIONPOLICY) { |
if (head->type == CCS_EXCEPTION_POLICY) { |
3809 |
ccs_print_namespace(head); |
ccs_print_namespace(head); |
3810 |
ccs_io_printf(head, "acl_group %u ", head->r.acl_group_index); |
ccs_io_printf(head, "acl_group %u ", head->r.acl_group_index); |
3811 |
} |
} |
3973 |
if (first) |
if (first) |
3974 |
return true; |
return true; |
3975 |
ccs_set_space(head); |
ccs_set_space(head); |
3976 |
if (ptr->address.group) { |
if (!ccs_print_group(head, ptr->address.group)) { |
|
ccs_set_string(head, "@"); |
|
|
ccs_set_string(head, |
|
|
ptr->address.group->group_name->name); |
|
|
} else { |
|
3977 |
char buf[128]; |
char buf[128]; |
3978 |
ccs_print_ip(buf, sizeof(buf), &ptr->address); |
ccs_print_ip(buf, sizeof(buf), &ptr->address); |
3979 |
ccs_io_printf(head, "%s", buf); |
ccs_io_printf(head, "%s", buf); |
4034 |
} |
} |
4035 |
|
|
4036 |
/** |
/** |
4037 |
* ccs_read_domain2 - Read domain policy. |
* ccs_read_acl - Read "struct ccs_acl_info" list. |
4038 |
* |
* |
4039 |
* @head: Pointer to "struct ccs_io_buffer". |
* @head: Pointer to "struct ccs_io_buffer". |
4040 |
* @list: Pointer to "struct list_head". |
* @list: Pointer to "struct list_head". |
4043 |
* |
* |
4044 |
* Caller holds ccs_read_lock(). |
* Caller holds ccs_read_lock(). |
4045 |
*/ |
*/ |
4046 |
static bool ccs_read_domain2(struct ccs_io_buffer *head, |
static bool ccs_read_acl(struct ccs_io_buffer *head, struct list_head *list) |
|
struct list_head *list) |
|
4047 |
{ |
{ |
4048 |
list_for_each_cookie(head->r.acl, list) { |
list_for_each_cookie(head->r.acl, list) { |
4049 |
struct ccs_acl_info *ptr = |
struct ccs_acl_info *ptr = |
4090 |
ccs_set_lf(head); |
ccs_set_lf(head); |
4091 |
/* fall through */ |
/* fall through */ |
4092 |
case 1: |
case 1: |
4093 |
if (!ccs_read_domain2(head, &domain->acl_info_list)) |
if (!ccs_read_acl(head, &domain->acl_info_list)) |
4094 |
return; |
return; |
4095 |
head->r.step++; |
head->r.step++; |
4096 |
if (!ccs_set_lf(head)) |
if (!ccs_set_lf(head)) |
4253 |
struct ccs_policy_namespace *ns = param->ns; |
struct ccs_policy_namespace *ns = param->ns; |
4254 |
int error; |
int error; |
4255 |
u8 *tmp; |
u8 *tmp; |
4256 |
if (param->data[0] == '@' || !ccs_parse_number_union(param, &e->port) || |
if (param->data[0] == '@' || |
4257 |
|
!ccs_parse_number_union(param, &e->port) || |
4258 |
e->port.values[1] > 65535 || param->data[0]) |
e->port.values[1] > 65535 || param->data[0]) |
4259 |
return -EINVAL; |
return -EINVAL; |
4260 |
param->list = &ns->policy_list[CCS_ID_RESERVEDPORT]; |
param->list = &ns->policy_list[CCS_ID_RESERVEDPORT]; |
4401 |
char *data; |
char *data; |
4402 |
group = simple_strtoul(param.data, &data, 10); |
group = simple_strtoul(param.data, &data, 10); |
4403 |
if (group < CCS_MAX_ACL_GROUPS && *data++ == ' ') |
if (group < CCS_MAX_ACL_GROUPS && *data++ == ' ') |
4404 |
return ccs_write_domain2(head->w.ns, |
return ccs_write_acl(head->w.ns, |
4405 |
&head->w.ns->acl_group[group], |
&head->w.ns->acl_group[group], |
4406 |
data, is_delete); |
data, is_delete); |
4407 |
} |
} |
4408 |
return -EINVAL; |
return -EINVAL; |
4409 |
} |
} |
4566 |
+ CCS_MAX_ACL_GROUPS) { |
+ CCS_MAX_ACL_GROUPS) { |
4567 |
head->r.acl_group_index = |
head->r.acl_group_index = |
4568 |
head->r.step - CCS_MAX_POLICY - CCS_MAX_GROUP; |
head->r.step - CCS_MAX_POLICY - CCS_MAX_GROUP; |
4569 |
if (!ccs_read_domain2(head, &ns->acl_group |
if (!ccs_read_acl(head, &ns->acl_group |
4570 |
[head->r.acl_group_index])) |
[head->r.acl_group_index])) |
4571 |
return; |
return; |
4572 |
head->r.step++; |
head->r.step++; |
4573 |
} |
} |
4653 |
ccs_normalize_line(buffer); |
ccs_normalize_line(buffer); |
4654 |
{ |
{ |
4655 |
struct ccs_domain_info *domain = ccs_current_domain(); |
struct ccs_domain_info *domain = ccs_current_domain(); |
4656 |
if (!ccs_write_domain2(domain->ns, &domain->acl_info_list, |
if (!ccs_write_acl(domain->ns, &domain->acl_info_list, |
4657 |
buffer, false)) |
buffer, false)) |
4658 |
ccs_update_stat(CCS_STAT_POLICY_UPDATES); |
ccs_update_stat(CCS_STAT_POLICY_UPDATES); |
4659 |
} |
} |
4660 |
kfree(buffer); |
kfree(buffer); |
4735 |
* decided to retry the access request which violated the policy in enforcing |
* decided to retry the access request which violated the policy in enforcing |
4736 |
* mode, 0 if it is not in enforcing mode, -EPERM otherwise. |
* mode, 0 if it is not in enforcing mode, -EPERM otherwise. |
4737 |
*/ |
*/ |
4738 |
int ccs_supervisor(struct ccs_request_info *r, const char *fmt, ...) |
static int ccs_supervisor(struct ccs_request_info *r, const char *fmt, ...) |
4739 |
{ |
{ |
4740 |
va_list args; |
va_list args; |
4741 |
int error; |
int error; |
4840 |
} |
} |
4841 |
|
|
4842 |
/** |
/** |
4843 |
|
* ccs_audit_log - Audit permission check log. |
4844 |
|
* |
4845 |
|
* @r: Pointer to "struct ccs_request_info". |
4846 |
|
* |
4847 |
|
* Returns return value of ccs_supervisor(). |
4848 |
|
*/ |
4849 |
|
int ccs_audit_log(struct ccs_request_info *r) |
4850 |
|
{ |
4851 |
|
switch (r->param_type) { |
4852 |
|
u8 type; |
4853 |
|
char buf[48]; |
4854 |
|
#ifdef CONFIG_CCSECURITY_NETWORK |
4855 |
|
const u32 *address; |
4856 |
|
#endif |
4857 |
|
case CCS_TYPE_PATH_ACL: |
4858 |
|
return ccs_supervisor(r, "file %s %s\n", ccs_path_keyword |
4859 |
|
[r->param.path.operation], |
4860 |
|
r->param.path.filename->name); |
4861 |
|
case CCS_TYPE_PATH2_ACL: |
4862 |
|
return ccs_supervisor(r, "file %s %s %s\n", ccs_mac_keywords |
4863 |
|
[ccs_pp2mac[r->param.path2.operation]], |
4864 |
|
r->param.path2.filename1->name, |
4865 |
|
r->param.path2.filename2->name); |
4866 |
|
case CCS_TYPE_PATH_NUMBER_ACL: |
4867 |
|
type = r->param.path_number.operation; |
4868 |
|
switch (type) { |
4869 |
|
case CCS_TYPE_CREATE: |
4870 |
|
case CCS_TYPE_MKDIR: |
4871 |
|
case CCS_TYPE_MKFIFO: |
4872 |
|
case CCS_TYPE_MKSOCK: |
4873 |
|
case CCS_TYPE_CHMOD: |
4874 |
|
snprintf(buf, sizeof(buf), "0%lo", |
4875 |
|
r->param.path_number.number); |
4876 |
|
break; |
4877 |
|
case CCS_TYPE_IOCTL: |
4878 |
|
snprintf(buf, sizeof(buf), "0x%lX", |
4879 |
|
r->param.path_number.number); |
4880 |
|
break; |
4881 |
|
default: |
4882 |
|
snprintf(buf, sizeof(buf), "%lu", |
4883 |
|
r->param.path_number.number); |
4884 |
|
break; |
4885 |
|
} |
4886 |
|
return ccs_supervisor(r, "file %s %s %s\n", ccs_mac_keywords |
4887 |
|
[ccs_pn2mac[type]], |
4888 |
|
r->param.path_number.filename->name, |
4889 |
|
buf); |
4890 |
|
case CCS_TYPE_MKDEV_ACL: |
4891 |
|
return ccs_supervisor(r, "file %s %s 0%o %u %u\n", |
4892 |
|
ccs_mac_keywords |
4893 |
|
[ccs_pnnn2mac[r->param.mkdev.operation]], |
4894 |
|
r->param.mkdev.filename->name, |
4895 |
|
r->param.mkdev.mode, |
4896 |
|
r->param.mkdev.major, |
4897 |
|
r->param.mkdev.minor); |
4898 |
|
case CCS_TYPE_MOUNT_ACL: |
4899 |
|
return ccs_supervisor(r, "file mount %s %s %s 0x%lX\n", |
4900 |
|
r->param.mount.dev->name, |
4901 |
|
r->param.mount.dir->name, |
4902 |
|
r->param.mount.type->name, |
4903 |
|
r->param.mount.flags); |
4904 |
|
#ifdef CONFIG_CCSECURITY_MISC |
4905 |
|
case CCS_TYPE_ENV_ACL: |
4906 |
|
return ccs_supervisor(r, "misc env %s\n", |
4907 |
|
r->param.environ.name->name); |
4908 |
|
#endif |
4909 |
|
#ifdef CONFIG_CCSECURITY_CAPABILITY |
4910 |
|
case CCS_TYPE_CAPABILITY_ACL: |
4911 |
|
return ccs_supervisor(r, "capability %s\n", ccs_mac_keywords |
4912 |
|
[ccs_c2mac[r->param.capability. |
4913 |
|
operation]]); |
4914 |
|
#endif |
4915 |
|
#ifdef CONFIG_CCSECURITY_NETWORK |
4916 |
|
case CCS_TYPE_INET_ACL: |
4917 |
|
address = r->param.inet_network.address; |
4918 |
|
if (r->param.inet_network.is_ipv6) |
4919 |
|
ccs_print_ipv6(buf, sizeof(buf), |
4920 |
|
(const struct in6_addr *) address); |
4921 |
|
else |
4922 |
|
ccs_print_ipv4(buf, sizeof(buf), address); |
4923 |
|
return ccs_supervisor(r, "network inet %s %s %s %u\n", |
4924 |
|
ccs_proto_keyword[r->param.inet_network. |
4925 |
|
protocol], |
4926 |
|
ccs_socket_keyword[r->param.inet_network. |
4927 |
|
operation], |
4928 |
|
buf, r->param.inet_network.port); |
4929 |
|
case CCS_TYPE_UNIX_ACL: |
4930 |
|
return ccs_supervisor(r, "network unix %s %s %s\n", |
4931 |
|
ccs_proto_keyword[r->param. |
4932 |
|
unix_network.protocol], |
4933 |
|
ccs_socket_keyword[r->param.unix_network. |
4934 |
|
operation], |
4935 |
|
r->param.unix_network.address->name); |
4936 |
|
#endif |
4937 |
|
#ifdef CONFIG_CCSECURITY_IPC |
4938 |
|
case CCS_TYPE_SIGNAL_ACL: |
4939 |
|
return ccs_supervisor(r, "ipc signal %d %s\n", |
4940 |
|
r->param.signal.sig, |
4941 |
|
r->param.signal.dest_pattern); |
4942 |
|
#endif |
4943 |
|
} |
4944 |
|
return 0; |
4945 |
|
} |
4946 |
|
|
4947 |
|
/** |
4948 |
* ccs_find_domain_by_qid - Get domain by query id. |
* ccs_find_domain_by_qid - Get domain by query id. |
4949 |
* |
* |
4950 |
* @serial: Query ID assigned by ccs_supervisor(). |
* @serial: Query ID assigned by ccs_supervisor(). |
4957 |
struct ccs_domain_info *domain = NULL; |
struct ccs_domain_info *domain = NULL; |
4958 |
spin_lock(&ccs_query_list_lock); |
spin_lock(&ccs_query_list_lock); |
4959 |
list_for_each_entry(ptr, &ccs_query_list, list) { |
list_for_each_entry(ptr, &ccs_query_list, list) { |
4960 |
if (ptr->serial != serial || ptr->answer) |
if (ptr->serial != serial) |
4961 |
continue; |
continue; |
4962 |
domain = ptr->domain; |
domain = ptr->domain; |
4963 |
break; |
break; |
4967 |
} |
} |
4968 |
|
|
4969 |
/** |
/** |
|
* ccs_poll_query - poll() for /proc/ccs/query. |
|
|
* |
|
|
* @file: Pointer to "struct file". |
|
|
* @wait: Pointer to "poll_table". |
|
|
* |
|
|
* Returns POLLIN | POLLRDNORM when ready to read, 0 otherwise. |
|
|
* |
|
|
* Waits for access requests which violated policy in enforcing mode. |
|
|
*/ |
|
|
static int ccs_poll_query(struct file *file, poll_table *wait) |
|
|
{ |
|
|
struct list_head *tmp; |
|
|
bool found = false; |
|
|
u8 i; |
|
|
for (i = 0; i < 2; i++) { |
|
|
spin_lock(&ccs_query_list_lock); |
|
|
list_for_each(tmp, &ccs_query_list) { |
|
|
struct ccs_query *ptr = |
|
|
list_entry(tmp, typeof(*ptr), list); |
|
|
if (ptr->answer) |
|
|
continue; |
|
|
found = true; |
|
|
break; |
|
|
} |
|
|
spin_unlock(&ccs_query_list_lock); |
|
|
if (found) |
|
|
return POLLIN | POLLRDNORM; |
|
|
if (i) |
|
|
break; |
|
|
poll_wait(file, &ccs_query_wait, wait); |
|
|
} |
|
|
return 0; |
|
|
} |
|
|
|
|
|
/** |
|
4970 |
* ccs_read_query - Read access requests which violated policy in enforcing mode. |
* ccs_read_query - Read access requests which violated policy in enforcing mode. |
4971 |
* |
* |
4972 |
* @head: Pointer to "struct ccs_io_buffer". |
* @head: Pointer to "struct ccs_io_buffer". |
4986 |
spin_lock(&ccs_query_list_lock); |
spin_lock(&ccs_query_list_lock); |
4987 |
list_for_each(tmp, &ccs_query_list) { |
list_for_each(tmp, &ccs_query_list) { |
4988 |
struct ccs_query *ptr = list_entry(tmp, typeof(*ptr), list); |
struct ccs_query *ptr = list_entry(tmp, typeof(*ptr), list); |
|
if (ptr->answer) |
|
|
continue; |
|
4989 |
if (pos++ != head->r.query_index) |
if (pos++ != head->r.query_index) |
4990 |
continue; |
continue; |
4991 |
len = ptr->query_len; |
len = ptr->query_len; |
5003 |
spin_lock(&ccs_query_list_lock); |
spin_lock(&ccs_query_list_lock); |
5004 |
list_for_each(tmp, &ccs_query_list) { |
list_for_each(tmp, &ccs_query_list) { |
5005 |
struct ccs_query *ptr = list_entry(tmp, typeof(*ptr), list); |
struct ccs_query *ptr = list_entry(tmp, typeof(*ptr), list); |
|
if (ptr->answer) |
|
|
continue; |
|
5006 |
if (pos++ != head->r.query_index) |
if (pos++ != head->r.query_index) |
5007 |
continue; |
continue; |
5008 |
/* |
/* |
5050 |
struct ccs_query *ptr = list_entry(tmp, typeof(*ptr), list); |
struct ccs_query *ptr = list_entry(tmp, typeof(*ptr), list); |
5051 |
if (ptr->serial != serial) |
if (ptr->serial != serial) |
5052 |
continue; |
continue; |
5053 |
if (!ptr->answer) |
ptr->answer = (u8) answer; |
5054 |
ptr->answer = (u8) answer; |
/* Remove from ccs_query_list. */ |
5055 |
|
if (ptr->answer) { |
5056 |
|
list_del(&ptr->list); |
5057 |
|
INIT_LIST_HEAD(&ptr->list); |
5058 |
|
} |
5059 |
break; |
break; |
5060 |
} |
} |
5061 |
spin_unlock(&ccs_query_list_lock); |
spin_unlock(&ccs_query_list_lock); |
5263 |
* |
* |
5264 |
* Returns file type string. |
* Returns file type string. |
5265 |
*/ |
*/ |
5266 |
static inline const char *ccs_filetype(const mode_t mode) |
static inline const char *ccs_filetype(const umode_t mode) |
5267 |
{ |
{ |
5268 |
switch (mode & S_IFMT) { |
switch (mode & S_IFMT) { |
5269 |
case S_IFREG: |
case S_IFREG: |
5337 |
for (i = 0; i < CCS_MAX_PATH_STAT; i++) { |
for (i = 0; i < CCS_MAX_PATH_STAT; i++) { |
5338 |
struct ccs_mini_stat *stat; |
struct ccs_mini_stat *stat; |
5339 |
unsigned int dev; |
unsigned int dev; |
5340 |
mode_t mode; |
umode_t mode; |
5341 |
if (!obj->stat_valid[i]) |
if (!obj->stat_valid[i]) |
5342 |
continue; |
continue; |
5343 |
stat = &obj->stat[i]; |
stat = &obj->stat[i]; |
5404 |
struct file *file = r->ee->bprm->file; |
struct file *file = r->ee->bprm->file; |
5405 |
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) |
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) |
5406 |
struct path path = { file->f_vfsmnt, file->f_dentry }; |
struct path path = { file->f_vfsmnt, file->f_dentry }; |
5407 |
realpath = ccs_realpath_from_path(&path); |
realpath = ccs_realpath(&path); |
5408 |
#else |
#else |
5409 |
realpath = ccs_realpath_from_path(&file->f_path); |
realpath = ccs_realpath(&file->f_path); |
5410 |
#endif |
#endif |
5411 |
bprm_info = ccs_print_bprm(r->ee->bprm, &r->ee->dump); |
bprm_info = ccs_print_bprm(r->ee->bprm, &r->ee->dump); |
5412 |
if (!realpath || !bprm_info) |
if (!realpath || !bprm_info) |
5498 |
/** |
/** |
5499 |
* ccs_get_audit - Get audit mode. |
* ccs_get_audit - Get audit mode. |
5500 |
* |
* |
5501 |
* @profile: Profile number. |
* @r: Pointer to "struct ccs_request_info". |
|
* @index: Index number of functionality. |
|
|
* @matched_acl: Pointer to "struct ccs_acl_info". Maybe NULL. |
|
|
* @is_granted: True if granted log, false otherwise. |
|
5502 |
* |
* |
5503 |
* Returns true if this request should be audited, false otherwise. |
* Returns true if this request should be audited, false otherwise. |
5504 |
*/ |
*/ |
5505 |
static bool ccs_get_audit(const u8 profile, const u8 index, |
static bool ccs_get_audit(const struct ccs_request_info *r) |
|
const struct ccs_acl_info *matched_acl, |
|
|
const bool is_granted) |
|
5506 |
{ |
{ |
5507 |
|
const struct ccs_acl_info *matched_acl = r->matched_acl; |
5508 |
|
const u8 profile = r->profile; |
5509 |
|
const u8 index = r->type; |
5510 |
|
const bool is_granted = r->granted; |
5511 |
u8 mode; |
u8 mode; |
|
const u8 category = ccs_index2category[index] + CCS_MAX_MAC_INDEX; |
|
5512 |
struct ccs_profile *p; |
struct ccs_profile *p; |
5513 |
if (!ccs_policy_loaded) |
if (!ccs_policy_loaded) |
5514 |
return false; |
return false; |
5520 |
return matched_acl->cond->grant_log == CCS_GRANTLOG_YES; |
return matched_acl->cond->grant_log == CCS_GRANTLOG_YES; |
5521 |
mode = p->config[index]; |
mode = p->config[index]; |
5522 |
if (mode == CCS_CONFIG_USE_DEFAULT) |
if (mode == CCS_CONFIG_USE_DEFAULT) |
5523 |
mode = p->config[category]; |
mode = p->config |
5524 |
|
[ccs_index2category[index] + CCS_MAX_MAC_INDEX]; |
5525 |
if (mode == CCS_CONFIG_USE_DEFAULT) |
if (mode == CCS_CONFIG_USE_DEFAULT) |
5526 |
mode = p->default_config; |
mode = p->default_config; |
5527 |
if (is_granted) |
if (is_granted) |
5545 |
char *buf; |
char *buf; |
5546 |
struct ccs_log *entry; |
struct ccs_log *entry; |
5547 |
bool quota_exceeded = false; |
bool quota_exceeded = false; |
5548 |
if (!ccs_get_audit(r->profile, r->type, r->matched_acl, r->granted)) |
if (!ccs_get_audit(r)) |
5549 |
goto out; |
goto out; |
5550 |
buf = ccs_init_log(r, len, fmt, args); |
buf = ccs_init_log(r, len, fmt, args); |
5551 |
if (!buf) |
if (!buf) |
5633 |
} |
} |
5634 |
|
|
5635 |
/** |
/** |
|
* ccs_poll_log - Wait for an audit log. |
|
|
* |
|
|
* @file: Pointer to "struct file". |
|
|
* @wait: Pointer to "poll_table". |
|
|
* |
|
|
* Returns POLLIN | POLLRDNORM when ready to read an audit log. |
|
|
*/ |
|
|
static int ccs_poll_log(struct file *file, poll_table *wait) |
|
|
{ |
|
|
if (ccs_log_count) |
|
|
return POLLIN | POLLRDNORM; |
|
|
poll_wait(file, &ccs_log_wait, wait); |
|
|
if (ccs_log_count) |
|
|
return POLLIN | POLLRDNORM; |
|
|
return 0; |
|
|
} |
|
|
|
|
|
/** |
|
5636 |
* ccs_set_namespace_cursor - Set namespace to read. |
* ccs_set_namespace_cursor - Set namespace to read. |
5637 |
* |
* |
5638 |
* @head: Pointer to "struct ccs_io_buffer". |
* @head: Pointer to "struct ccs_io_buffer". |
5642 |
static void ccs_set_namespace_cursor(struct ccs_io_buffer *head) |
static void ccs_set_namespace_cursor(struct ccs_io_buffer *head) |
5643 |
{ |
{ |
5644 |
struct list_head *ns; |
struct list_head *ns; |
5645 |
if (head->type != CCS_EXCEPTIONPOLICY && head->type != CCS_PROFILE) |
if (head->type != CCS_EXCEPTION_POLICY && head->type != CCS_PROFILE) |
5646 |
return; |
return; |
5647 |
/* |
/* |
5648 |
* If this is the first read, or reading previous namespace finished |
* If this is the first read, or reading previous namespace finished |
5665 |
*/ |
*/ |
5666 |
static bool ccs_has_more_namespace(struct ccs_io_buffer *head) |
static bool ccs_has_more_namespace(struct ccs_io_buffer *head) |
5667 |
{ |
{ |
5668 |
return (head->type == CCS_EXCEPTIONPOLICY || |
return (head->type == CCS_EXCEPTION_POLICY || |
5669 |
head->type == CCS_PROFILE) && head->r.eof && |
head->type == CCS_PROFILE) && head->r.eof && |
5670 |
head->r.ns->next != &ccs_namespace_list; |
head->r.ns->next != &ccs_namespace_list; |
5671 |
} |
} |
5859 |
if (head->w.is_delete) |
if (head->w.is_delete) |
5860 |
memmove(line, line + 7, strlen(line + 7) + 1); |
memmove(line, line + 7, strlen(line + 7) + 1); |
5861 |
/* Selecting namespace to update. */ |
/* Selecting namespace to update. */ |
5862 |
if (head->type == CCS_EXCEPTIONPOLICY || head->type == CCS_PROFILE) { |
if (head->type == CCS_EXCEPTION_POLICY || head->type == CCS_PROFILE) { |
5863 |
if (*line == '<') { |
if (*line == '<') { |
5864 |
char *cp = strchr(line, ' '); |
char *cp = strchr(line, ' '); |
5865 |
if (cp) { |
if (cp) { |
5876 |
} |
} |
5877 |
/* Do the update. */ |
/* Do the update. */ |
5878 |
switch (head->type) { |
switch (head->type) { |
5879 |
case CCS_DOMAINPOLICY: |
case CCS_DOMAIN_POLICY: |
5880 |
return ccs_write_domain(head); |
return ccs_write_domain(head); |
5881 |
case CCS_EXCEPTIONPOLICY: |
case CCS_EXCEPTION_POLICY: |
5882 |
return ccs_write_exception(head); |
return ccs_write_exception(head); |
5883 |
#ifdef CONFIG_CCSECURITY_TASK_EXECUTE_HANDLER |
#ifdef CONFIG_CCSECURITY_TASK_EXECUTE_HANDLER |
5884 |
case CCS_EXECUTE_HANDLER: |
case CCS_EXECUTE_HANDLER: |
5934 |
break; |
break; |
5935 |
case 1: |
case 1: |
5936 |
start = ccs_builtin_exception_policy; |
start = ccs_builtin_exception_policy; |
5937 |
head.type = CCS_EXCEPTIONPOLICY; |
head.type = CCS_EXCEPTION_POLICY; |
5938 |
break; |
break; |
5939 |
case 2: |
case 2: |
5940 |
start = ccs_builtin_domain_policy; |
start = ccs_builtin_domain_policy; |
5941 |
head.type = CCS_DOMAINPOLICY; |
head.type = CCS_DOMAIN_POLICY; |
5942 |
break; |
break; |
5943 |
case 3: |
case 3: |
5944 |
start = ccs_builtin_manager; |
start = ccs_builtin_manager; |
6074 |
* ccs_poll - poll() for /proc/ccs/ interface. |
* ccs_poll - poll() for /proc/ccs/ interface. |
6075 |
* |
* |
6076 |
* @file: Pointer to "struct file". |
* @file: Pointer to "struct file". |
6077 |
* @wait: Pointer to "poll_table". |
* @wait: Pointer to "poll_table". Maybe NULL. |
6078 |
* |
* |
6079 |
* Returns 0 on success, negative value otherwise. |
* Returns POLLIN | POLLRDNORM | POLLOUT | POLLWRNORM if ready to read/write, |
6080 |
|
* POLLOUT | POLLWRNORM otherwise. |
6081 |
*/ |
*/ |
6082 |
static unsigned int ccs_poll(struct file *file, poll_table *wait) |
static unsigned int ccs_poll(struct file *file, poll_table *wait) |
6083 |
{ |
{ |
6084 |
struct ccs_io_buffer *head = file->private_data; |
struct ccs_io_buffer *head = file->private_data; |
6085 |
switch (head->type) { |
if (head->type == CCS_AUDIT) { |
6086 |
case CCS_AUDIT: |
if (!ccs_memory_used[CCS_MEMORY_AUDIT]) { |
6087 |
return ccs_poll_log(file, wait); |
poll_wait(file, &ccs_log_wait, wait); |
6088 |
case CCS_QUERY: |
if (!ccs_memory_used[CCS_MEMORY_AUDIT]) |
6089 |
return ccs_poll_query(file, wait); |
return POLLOUT | POLLWRNORM; |
6090 |
default: |
} |
6091 |
return -ENOSYS; |
} else if (head->type == CCS_QUERY) { |
6092 |
|
if (list_empty(&ccs_query_list)) { |
6093 |
|
poll_wait(file, &ccs_query_wait, wait); |
6094 |
|
if (list_empty(&ccs_query_list)) |
6095 |
|
return POLLOUT | POLLWRNORM; |
6096 |
|
} |
6097 |
} |
} |
6098 |
|
return POLLIN | POLLRDNORM | POLLOUT | POLLWRNORM; |
6099 |
} |
} |
6100 |
|
|
6101 |
/** |
/** |
6124 |
do { |
do { |
6125 |
ccs_set_namespace_cursor(head); |
ccs_set_namespace_cursor(head); |
6126 |
switch (head->type) { |
switch (head->type) { |
6127 |
case CCS_DOMAINPOLICY: |
case CCS_DOMAIN_POLICY: |
6128 |
ccs_read_domain(head); |
ccs_read_domain(head); |
6129 |
break; |
break; |
6130 |
case CCS_EXCEPTIONPOLICY: |
case CCS_EXCEPTION_POLICY: |
6131 |
ccs_read_exception(head); |
ccs_read_exception(head); |
6132 |
break; |
break; |
6133 |
case CCS_AUDIT: |
case CCS_AUDIT: |
6277 |
case CCS_PROCESS_STATUS: |
case CCS_PROCESS_STATUS: |
6278 |
/* This does not write anything. */ |
/* This does not write anything. */ |
6279 |
break; |
break; |
6280 |
case CCS_DOMAINPOLICY: |
case CCS_DOMAIN_POLICY: |
6281 |
if (ccs_select_domain(head, cp0)) |
if (ccs_select_domain(head, cp0)) |
6282 |
continue; |
continue; |
6283 |
/* fall through */ |
/* fall through */ |
6284 |
case CCS_EXCEPTIONPOLICY: |
case CCS_EXCEPTION_POLICY: |
6285 |
if (!strcmp(cp0, "select transition_only")) { |
if (!strcmp(cp0, "select transition_only")) { |
6286 |
head->r.print_transition_related_only = true; |
head->r.print_transition_related_only = true; |
6287 |
continue; |
continue; |
6300 |
case 0: |
case 0: |
6301 |
/* Update statistics. */ |
/* Update statistics. */ |
6302 |
switch (head->type) { |
switch (head->type) { |
6303 |
case CCS_DOMAINPOLICY: |
case CCS_DOMAIN_POLICY: |
6304 |
case CCS_EXCEPTIONPOLICY: |
case CCS_EXCEPTION_POLICY: |
6305 |
case CCS_STAT: |
case CCS_STAT: |
6306 |
case CCS_PROFILE: |
case CCS_PROFILE: |
6307 |
case CCS_MANAGER: |
case CCS_MANAGER: |
6329 |
* |
* |
6330 |
* Returns nothing. |
* Returns nothing. |
6331 |
*/ |
*/ |
6332 |
static void __init ccs_create_entry(const char *name, const mode_t mode, |
static void __init ccs_create_entry(const char *name, const umode_t mode, |
6333 |
struct proc_dir_entry *parent, |
struct proc_dir_entry *parent, |
6334 |
const u8 key) |
const u8 key) |
6335 |
{ |
{ |
6350 |
/** |
/** |
6351 |
* ccs_proc_init - Initialize /proc/ccs/ interface. |
* ccs_proc_init - Initialize /proc/ccs/ interface. |
6352 |
* |
* |
6353 |
* Returns 0. |
* Returns nothing. |
6354 |
*/ |
*/ |
6355 |
static void __init ccs_proc_init(void) |
static void __init ccs_proc_init(void) |
6356 |
{ |
{ |
6363 |
ccs_dir->proc_iops = &ccs_dir_inode_operations; |
ccs_dir->proc_iops = &ccs_dir_inode_operations; |
6364 |
#endif |
#endif |
6365 |
ccs_create_entry("query", 0600, ccs_dir, CCS_QUERY); |
ccs_create_entry("query", 0600, ccs_dir, CCS_QUERY); |
6366 |
ccs_create_entry("domain_policy", 0600, ccs_dir, CCS_DOMAINPOLICY); |
ccs_create_entry("domain_policy", 0600, ccs_dir, CCS_DOMAIN_POLICY); |
6367 |
ccs_create_entry("exception_policy", 0600, ccs_dir, |
ccs_create_entry("exception_policy", 0600, ccs_dir, |
6368 |
CCS_EXCEPTIONPOLICY); |
CCS_EXCEPTION_POLICY); |
6369 |
ccs_create_entry("audit", 0400, ccs_dir, CCS_AUDIT); |
ccs_create_entry("audit", 0400, ccs_dir, CCS_AUDIT); |
6370 |
ccs_create_entry(".process_status", 0600, ccs_dir, |
ccs_create_entry(".process_status", 0600, ccs_dir, |
6371 |
CCS_PROCESS_STATUS); |
CCS_PROCESS_STATUS); |