mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-29 03:01:39 -04:00
Merge branch 'next' of git://selinuxproject.org/~jmorris/linux-security
* 'next' of git://selinuxproject.org/~jmorris/linux-security: (95 commits) TOMOYO: Fix incomplete read after seek. Smack: allow to access /smack/access as normal user TOMOYO: Fix unused kernel config option. Smack: fix: invalid length set for the result of /smack/access Smack: compilation fix Smack: fix for /smack/access output, use string instead of byte Smack: domain transition protections (v3) Smack: Provide information for UDS getsockopt(SO_PEERCRED) Smack: Clean up comments Smack: Repair processing of fcntl Smack: Rule list lookup performance Smack: check permissions from user space (v2) TOMOYO: Fix quota and garbage collector. TOMOYO: Remove redundant tasklist_lock. TOMOYO: Fix domain transition failure warning. TOMOYO: Remove tomoyo_policy_memory_lock spinlock. TOMOYO: Simplify garbage collector. TOMOYO: Fix make namespacecheck warnings. target: check hex2bin result encrypted-keys: check hex2bin result ...
This commit is contained in:
commit
36b8d186e6
99 changed files with 4701 additions and 1432 deletions
|
|
@ -1,8 +1,10 @@
|
|||
config SECURITY_TOMOYO
|
||||
bool "TOMOYO Linux Support"
|
||||
depends on SECURITY
|
||||
depends on NET
|
||||
select SECURITYFS
|
||||
select SECURITY_PATH
|
||||
select SECURITY_NETWORK
|
||||
default n
|
||||
help
|
||||
This selects TOMOYO Linux, pathname-based access control.
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
obj-y = audit.o common.o condition.o domain.o file.o gc.o group.o load_policy.o memory.o mount.o realpath.o securityfs_if.o tomoyo.o util.o
|
||||
obj-y = audit.o common.o condition.o domain.o environ.o file.o gc.o group.o load_policy.o memory.o mount.o network.o realpath.o securityfs_if.o tomoyo.o util.o
|
||||
|
||||
$(obj)/policy/profile.conf:
|
||||
@mkdir -p $(obj)/policy/
|
||||
|
|
@ -27,7 +27,7 @@ $(obj)/policy/stat.conf:
|
|||
@touch $@
|
||||
|
||||
$(obj)/builtin-policy.h: $(obj)/policy/profile.conf $(obj)/policy/exception_policy.conf $(obj)/policy/domain_policy.conf $(obj)/policy/manager.conf $(obj)/policy/stat.conf
|
||||
@echo Generating built-in policy for TOMOYO 2.4.x.
|
||||
@echo Generating built-in policy for TOMOYO 2.5.x.
|
||||
@echo "static char tomoyo_builtin_profile[] __initdata =" > $@.tmp
|
||||
@sed -e 's/\\/\\\\/g' -e 's/\"/\\"/g' -e 's/\(.*\)/"\1\\n"/' < $(obj)/policy/profile.conf >> $@.tmp
|
||||
@echo "\"\";" >> $@.tmp
|
||||
|
|
|
|||
|
|
@ -313,6 +313,7 @@ static unsigned int tomoyo_log_count;
|
|||
*/
|
||||
static bool tomoyo_get_audit(const struct tomoyo_policy_namespace *ns,
|
||||
const u8 profile, const u8 index,
|
||||
const struct tomoyo_acl_info *matched_acl,
|
||||
const bool is_granted)
|
||||
{
|
||||
u8 mode;
|
||||
|
|
@ -324,6 +325,9 @@ static bool tomoyo_get_audit(const struct tomoyo_policy_namespace *ns,
|
|||
p = tomoyo_profile(ns, profile);
|
||||
if (tomoyo_log_count >= p->pref[TOMOYO_PREF_MAX_AUDIT_LOG])
|
||||
return false;
|
||||
if (is_granted && matched_acl && matched_acl->cond &&
|
||||
matched_acl->cond->grant_log != TOMOYO_GRANTLOG_AUTO)
|
||||
return matched_acl->cond->grant_log == TOMOYO_GRANTLOG_YES;
|
||||
mode = p->config[index];
|
||||
if (mode == TOMOYO_CONFIG_USE_DEFAULT)
|
||||
mode = p->config[category];
|
||||
|
|
@ -350,7 +354,8 @@ void tomoyo_write_log2(struct tomoyo_request_info *r, int len, const char *fmt,
|
|||
char *buf;
|
||||
struct tomoyo_log *entry;
|
||||
bool quota_exceeded = false;
|
||||
if (!tomoyo_get_audit(r->domain->ns, r->profile, r->type, r->granted))
|
||||
if (!tomoyo_get_audit(r->domain->ns, r->profile, r->type,
|
||||
r->matched_acl, r->granted))
|
||||
goto out;
|
||||
buf = tomoyo_init_log(r, len, fmt, args);
|
||||
if (!buf)
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ const char * const tomoyo_mode[TOMOYO_CONFIG_MAX_MODE] = {
|
|||
/* String table for /sys/kernel/security/tomoyo/profile */
|
||||
const char * const tomoyo_mac_keywords[TOMOYO_MAX_MAC_INDEX
|
||||
+ TOMOYO_MAX_MAC_CATEGORY_INDEX] = {
|
||||
/* CONFIG::file group */
|
||||
[TOMOYO_MAC_FILE_EXECUTE] = "execute",
|
||||
[TOMOYO_MAC_FILE_OPEN] = "open",
|
||||
[TOMOYO_MAC_FILE_CREATE] = "create",
|
||||
|
|
@ -43,7 +44,28 @@ const char * const tomoyo_mac_keywords[TOMOYO_MAX_MAC_INDEX
|
|||
[TOMOYO_MAC_FILE_MOUNT] = "mount",
|
||||
[TOMOYO_MAC_FILE_UMOUNT] = "unmount",
|
||||
[TOMOYO_MAC_FILE_PIVOT_ROOT] = "pivot_root",
|
||||
/* CONFIG::network group */
|
||||
[TOMOYO_MAC_NETWORK_INET_STREAM_BIND] = "inet_stream_bind",
|
||||
[TOMOYO_MAC_NETWORK_INET_STREAM_LISTEN] = "inet_stream_listen",
|
||||
[TOMOYO_MAC_NETWORK_INET_STREAM_CONNECT] = "inet_stream_connect",
|
||||
[TOMOYO_MAC_NETWORK_INET_DGRAM_BIND] = "inet_dgram_bind",
|
||||
[TOMOYO_MAC_NETWORK_INET_DGRAM_SEND] = "inet_dgram_send",
|
||||
[TOMOYO_MAC_NETWORK_INET_RAW_BIND] = "inet_raw_bind",
|
||||
[TOMOYO_MAC_NETWORK_INET_RAW_SEND] = "inet_raw_send",
|
||||
[TOMOYO_MAC_NETWORK_UNIX_STREAM_BIND] = "unix_stream_bind",
|
||||
[TOMOYO_MAC_NETWORK_UNIX_STREAM_LISTEN] = "unix_stream_listen",
|
||||
[TOMOYO_MAC_NETWORK_UNIX_STREAM_CONNECT] = "unix_stream_connect",
|
||||
[TOMOYO_MAC_NETWORK_UNIX_DGRAM_BIND] = "unix_dgram_bind",
|
||||
[TOMOYO_MAC_NETWORK_UNIX_DGRAM_SEND] = "unix_dgram_send",
|
||||
[TOMOYO_MAC_NETWORK_UNIX_SEQPACKET_BIND] = "unix_seqpacket_bind",
|
||||
[TOMOYO_MAC_NETWORK_UNIX_SEQPACKET_LISTEN] = "unix_seqpacket_listen",
|
||||
[TOMOYO_MAC_NETWORK_UNIX_SEQPACKET_CONNECT] = "unix_seqpacket_connect",
|
||||
/* CONFIG::misc group */
|
||||
[TOMOYO_MAC_ENVIRON] = "env",
|
||||
/* CONFIG group */
|
||||
[TOMOYO_MAX_MAC_INDEX + TOMOYO_MAC_CATEGORY_FILE] = "file",
|
||||
[TOMOYO_MAX_MAC_INDEX + TOMOYO_MAC_CATEGORY_NETWORK] = "network",
|
||||
[TOMOYO_MAX_MAC_INDEX + TOMOYO_MAC_CATEGORY_MISC] = "misc",
|
||||
};
|
||||
|
||||
/* String table for conditions. */
|
||||
|
|
@ -130,10 +152,20 @@ const char * const tomoyo_path_keyword[TOMOYO_MAX_PATH_OPERATION] = {
|
|||
[TOMOYO_TYPE_UMOUNT] = "unmount",
|
||||
};
|
||||
|
||||
/* String table for socket's operation. */
|
||||
const char * const tomoyo_socket_keyword[TOMOYO_MAX_NETWORK_OPERATION] = {
|
||||
[TOMOYO_NETWORK_BIND] = "bind",
|
||||
[TOMOYO_NETWORK_LISTEN] = "listen",
|
||||
[TOMOYO_NETWORK_CONNECT] = "connect",
|
||||
[TOMOYO_NETWORK_SEND] = "send",
|
||||
};
|
||||
|
||||
/* String table for categories. */
|
||||
static const char * const tomoyo_category_keywords
|
||||
[TOMOYO_MAX_MAC_CATEGORY_INDEX] = {
|
||||
[TOMOYO_MAC_CATEGORY_FILE] = "file",
|
||||
[TOMOYO_MAC_CATEGORY_FILE] = "file",
|
||||
[TOMOYO_MAC_CATEGORY_NETWORK] = "network",
|
||||
[TOMOYO_MAC_CATEGORY_MISC] = "misc",
|
||||
};
|
||||
|
||||
/* Permit policy management by non-root user? */
|
||||
|
|
@ -230,13 +262,17 @@ static void tomoyo_set_string(struct tomoyo_io_buffer *head, const char *string)
|
|||
WARN_ON(1);
|
||||
}
|
||||
|
||||
static void tomoyo_io_printf(struct tomoyo_io_buffer *head, const char *fmt,
|
||||
...) __printf(2, 3);
|
||||
|
||||
/**
|
||||
* tomoyo_io_printf - printf() to "struct tomoyo_io_buffer" structure.
|
||||
*
|
||||
* @head: Pointer to "struct tomoyo_io_buffer".
|
||||
* @fmt: The printf()'s format string, followed by parameters.
|
||||
*/
|
||||
void tomoyo_io_printf(struct tomoyo_io_buffer *head, const char *fmt, ...)
|
||||
static void tomoyo_io_printf(struct tomoyo_io_buffer *head, const char *fmt,
|
||||
...)
|
||||
{
|
||||
va_list args;
|
||||
size_t len;
|
||||
|
|
@ -313,7 +349,7 @@ void tomoyo_init_policy_namespace(struct tomoyo_policy_namespace *ns)
|
|||
INIT_LIST_HEAD(&ns->group_list[idx]);
|
||||
for (idx = 0; idx < TOMOYO_MAX_POLICY; idx++)
|
||||
INIT_LIST_HEAD(&ns->policy_list[idx]);
|
||||
ns->profile_version = 20100903;
|
||||
ns->profile_version = 20110903;
|
||||
tomoyo_namespace_enabled = !list_empty(&tomoyo_namespace_list);
|
||||
list_add_tail_rcu(&ns->namespace_list, &tomoyo_namespace_list);
|
||||
}
|
||||
|
|
@ -466,8 +502,10 @@ static struct tomoyo_profile *tomoyo_assign_profile
|
|||
TOMOYO_CONFIG_WANT_REJECT_LOG;
|
||||
memset(ptr->config, TOMOYO_CONFIG_USE_DEFAULT,
|
||||
sizeof(ptr->config));
|
||||
ptr->pref[TOMOYO_PREF_MAX_AUDIT_LOG] = 1024;
|
||||
ptr->pref[TOMOYO_PREF_MAX_LEARNING_ENTRY] = 2048;
|
||||
ptr->pref[TOMOYO_PREF_MAX_AUDIT_LOG] =
|
||||
CONFIG_SECURITY_TOMOYO_MAX_AUDIT_LOG;
|
||||
ptr->pref[TOMOYO_PREF_MAX_LEARNING_ENTRY] =
|
||||
CONFIG_SECURITY_TOMOYO_MAX_ACCEPT_ENTRY;
|
||||
mb(); /* Avoid out-of-order execution. */
|
||||
ns->profile_ptr[profile] = ptr;
|
||||
entry = NULL;
|
||||
|
|
@ -951,14 +989,12 @@ static bool tomoyo_select_domain(struct tomoyo_io_buffer *head,
|
|||
(global_pid = true, sscanf(data, "global-pid=%u", &pid) == 1)) {
|
||||
struct task_struct *p;
|
||||
rcu_read_lock();
|
||||
read_lock(&tasklist_lock);
|
||||
if (global_pid)
|
||||
p = find_task_by_pid_ns(pid, &init_pid_ns);
|
||||
else
|
||||
p = find_task_by_vpid(pid);
|
||||
if (p)
|
||||
domain = tomoyo_real_domain(p);
|
||||
read_unlock(&tasklist_lock);
|
||||
rcu_read_unlock();
|
||||
} else if (!strncmp(data, "domain=", 7)) {
|
||||
if (tomoyo_domain_def(data + 7))
|
||||
|
|
@ -981,6 +1017,48 @@ static bool tomoyo_select_domain(struct tomoyo_io_buffer *head,
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* tomoyo_same_task_acl - Check for duplicated "struct tomoyo_task_acl" entry.
|
||||
*
|
||||
* @a: Pointer to "struct tomoyo_acl_info".
|
||||
* @b: Pointer to "struct tomoyo_acl_info".
|
||||
*
|
||||
* Returns true if @a == @b, false otherwise.
|
||||
*/
|
||||
static bool tomoyo_same_task_acl(const struct tomoyo_acl_info *a,
|
||||
const struct tomoyo_acl_info *b)
|
||||
{
|
||||
const struct tomoyo_task_acl *p1 = container_of(a, typeof(*p1), head);
|
||||
const struct tomoyo_task_acl *p2 = container_of(b, typeof(*p2), head);
|
||||
return p1->domainname == p2->domainname;
|
||||
}
|
||||
|
||||
/**
|
||||
* tomoyo_write_task - Update task related list.
|
||||
*
|
||||
* @param: Pointer to "struct tomoyo_acl_param".
|
||||
*
|
||||
* Returns 0 on success, negative value otherwise.
|
||||
*
|
||||
* Caller holds tomoyo_read_lock().
|
||||
*/
|
||||
static int tomoyo_write_task(struct tomoyo_acl_param *param)
|
||||
{
|
||||
int error = -EINVAL;
|
||||
if (tomoyo_str_starts(¶m->data, "manual_domain_transition ")) {
|
||||
struct tomoyo_task_acl e = {
|
||||
.head.type = TOMOYO_TYPE_MANUAL_TASK_ACL,
|
||||
.domainname = tomoyo_get_domainname(param),
|
||||
};
|
||||
if (e.domainname)
|
||||
error = tomoyo_update_domain(&e.head, sizeof(e), param,
|
||||
tomoyo_same_task_acl,
|
||||
NULL);
|
||||
tomoyo_put_name(e.domainname);
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
/**
|
||||
* tomoyo_delete_domain - Delete a domain.
|
||||
*
|
||||
|
|
@ -1039,11 +1117,16 @@ static int tomoyo_write_domain2(struct tomoyo_policy_namespace *ns,
|
|||
static const struct {
|
||||
const char *keyword;
|
||||
int (*write) (struct tomoyo_acl_param *);
|
||||
} tomoyo_callback[1] = {
|
||||
} tomoyo_callback[5] = {
|
||||
{ "file ", tomoyo_write_file },
|
||||
{ "network inet ", tomoyo_write_inet_network },
|
||||
{ "network unix ", tomoyo_write_unix_network },
|
||||
{ "misc ", tomoyo_write_misc },
|
||||
{ "task ", tomoyo_write_task },
|
||||
};
|
||||
u8 i;
|
||||
for (i = 0; i < 1; i++) {
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(tomoyo_callback); i++) {
|
||||
if (!tomoyo_str_starts(¶m.data,
|
||||
tomoyo_callback[i].keyword))
|
||||
continue;
|
||||
|
|
@ -1127,6 +1210,10 @@ static bool tomoyo_print_condition(struct tomoyo_io_buffer *head,
|
|||
case 0:
|
||||
head->r.cond_index = 0;
|
||||
head->r.cond_step++;
|
||||
if (cond->transit) {
|
||||
tomoyo_set_space(head);
|
||||
tomoyo_set_string(head, cond->transit->name);
|
||||
}
|
||||
/* fall through */
|
||||
case 1:
|
||||
{
|
||||
|
|
@ -1239,6 +1326,10 @@ static bool tomoyo_print_condition(struct tomoyo_io_buffer *head,
|
|||
head->r.cond_step++;
|
||||
/* fall through */
|
||||
case 3:
|
||||
if (cond->grant_log != TOMOYO_GRANTLOG_AUTO)
|
||||
tomoyo_io_printf(head, " grant_log=%s",
|
||||
tomoyo_yesno(cond->grant_log ==
|
||||
TOMOYO_GRANTLOG_YES));
|
||||
tomoyo_set_lf(head);
|
||||
return true;
|
||||
}
|
||||
|
|
@ -1306,6 +1397,12 @@ static bool tomoyo_print_entry(struct tomoyo_io_buffer *head,
|
|||
if (first)
|
||||
return true;
|
||||
tomoyo_print_name_union(head, &ptr->name);
|
||||
} else if (acl_type == TOMOYO_TYPE_MANUAL_TASK_ACL) {
|
||||
struct tomoyo_task_acl *ptr =
|
||||
container_of(acl, typeof(*ptr), head);
|
||||
tomoyo_set_group(head, "task ");
|
||||
tomoyo_set_string(head, "manual_domain_transition ");
|
||||
tomoyo_set_string(head, ptr->domainname->name);
|
||||
} else if (head->r.print_transition_related_only) {
|
||||
return true;
|
||||
} else if (acl_type == TOMOYO_TYPE_PATH2_ACL) {
|
||||
|
|
@ -1370,6 +1467,60 @@ static bool tomoyo_print_entry(struct tomoyo_io_buffer *head,
|
|||
tomoyo_print_number_union(head, &ptr->mode);
|
||||
tomoyo_print_number_union(head, &ptr->major);
|
||||
tomoyo_print_number_union(head, &ptr->minor);
|
||||
} else if (acl_type == TOMOYO_TYPE_INET_ACL) {
|
||||
struct tomoyo_inet_acl *ptr =
|
||||
container_of(acl, typeof(*ptr), head);
|
||||
const u8 perm = ptr->perm;
|
||||
|
||||
for (bit = 0; bit < TOMOYO_MAX_NETWORK_OPERATION; bit++) {
|
||||
if (!(perm & (1 << bit)))
|
||||
continue;
|
||||
if (first) {
|
||||
tomoyo_set_group(head, "network inet ");
|
||||
tomoyo_set_string(head, tomoyo_proto_keyword
|
||||
[ptr->protocol]);
|
||||
tomoyo_set_space(head);
|
||||
first = false;
|
||||
} else {
|
||||
tomoyo_set_slash(head);
|
||||
}
|
||||
tomoyo_set_string(head, tomoyo_socket_keyword[bit]);
|
||||
}
|
||||
if (first)
|
||||
return true;
|
||||
tomoyo_set_space(head);
|
||||
if (ptr->address.group) {
|
||||
tomoyo_set_string(head, "@");
|
||||
tomoyo_set_string(head, ptr->address.group->group_name
|
||||
->name);
|
||||
} else {
|
||||
char buf[128];
|
||||
tomoyo_print_ip(buf, sizeof(buf), &ptr->address);
|
||||
tomoyo_io_printf(head, "%s", buf);
|
||||
}
|
||||
tomoyo_print_number_union(head, &ptr->port);
|
||||
} else if (acl_type == TOMOYO_TYPE_UNIX_ACL) {
|
||||
struct tomoyo_unix_acl *ptr =
|
||||
container_of(acl, typeof(*ptr), head);
|
||||
const u8 perm = ptr->perm;
|
||||
|
||||
for (bit = 0; bit < TOMOYO_MAX_NETWORK_OPERATION; bit++) {
|
||||
if (!(perm & (1 << bit)))
|
||||
continue;
|
||||
if (first) {
|
||||
tomoyo_set_group(head, "network unix ");
|
||||
tomoyo_set_string(head, tomoyo_proto_keyword
|
||||
[ptr->protocol]);
|
||||
tomoyo_set_space(head);
|
||||
first = false;
|
||||
} else {
|
||||
tomoyo_set_slash(head);
|
||||
}
|
||||
tomoyo_set_string(head, tomoyo_socket_keyword[bit]);
|
||||
}
|
||||
if (first)
|
||||
return true;
|
||||
tomoyo_print_name_union(head, &ptr->name);
|
||||
} else if (acl_type == TOMOYO_TYPE_MOUNT_ACL) {
|
||||
struct tomoyo_mount_acl *ptr =
|
||||
container_of(acl, typeof(*ptr), head);
|
||||
|
|
@ -1378,6 +1529,12 @@ static bool tomoyo_print_entry(struct tomoyo_io_buffer *head,
|
|||
tomoyo_print_name_union(head, &ptr->dir_name);
|
||||
tomoyo_print_name_union(head, &ptr->fs_type);
|
||||
tomoyo_print_number_union(head, &ptr->flags);
|
||||
} else if (acl_type == TOMOYO_TYPE_ENV_ACL) {
|
||||
struct tomoyo_env_acl *ptr =
|
||||
container_of(acl, typeof(*ptr), head);
|
||||
|
||||
tomoyo_set_group(head, "misc env ");
|
||||
tomoyo_set_string(head, ptr->env->name);
|
||||
}
|
||||
if (acl->cond) {
|
||||
head->r.print_cond_part = true;
|
||||
|
|
@ -1510,14 +1667,12 @@ static void tomoyo_read_pid(struct tomoyo_io_buffer *head)
|
|||
global_pid = true;
|
||||
pid = (unsigned int) simple_strtoul(buf, NULL, 10);
|
||||
rcu_read_lock();
|
||||
read_lock(&tasklist_lock);
|
||||
if (global_pid)
|
||||
p = find_task_by_pid_ns(pid, &init_pid_ns);
|
||||
else
|
||||
p = find_task_by_vpid(pid);
|
||||
if (p)
|
||||
domain = tomoyo_real_domain(p);
|
||||
read_unlock(&tasklist_lock);
|
||||
rcu_read_unlock();
|
||||
if (!domain)
|
||||
return;
|
||||
|
|
@ -1537,8 +1692,9 @@ static const char *tomoyo_transition_type[TOMOYO_MAX_TRANSITION_TYPE] = {
|
|||
|
||||
/* String table for grouping keywords. */
|
||||
static const char *tomoyo_group_name[TOMOYO_MAX_GROUP] = {
|
||||
[TOMOYO_PATH_GROUP] = "path_group ",
|
||||
[TOMOYO_NUMBER_GROUP] = "number_group ",
|
||||
[TOMOYO_PATH_GROUP] = "path_group ",
|
||||
[TOMOYO_NUMBER_GROUP] = "number_group ",
|
||||
[TOMOYO_ADDRESS_GROUP] = "address_group ",
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -1580,7 +1736,7 @@ static int tomoyo_write_exception(struct tomoyo_io_buffer *head)
|
|||
}
|
||||
|
||||
/**
|
||||
* tomoyo_read_group - Read "struct tomoyo_path_group"/"struct tomoyo_number_group" list.
|
||||
* tomoyo_read_group - Read "struct tomoyo_path_group"/"struct tomoyo_number_group"/"struct tomoyo_address_group" list.
|
||||
*
|
||||
* @head: Pointer to "struct tomoyo_io_buffer".
|
||||
* @idx: Index number.
|
||||
|
|
@ -1617,6 +1773,15 @@ static bool tomoyo_read_group(struct tomoyo_io_buffer *head, const int idx)
|
|||
(ptr,
|
||||
struct tomoyo_number_group,
|
||||
head)->number);
|
||||
} else if (idx == TOMOYO_ADDRESS_GROUP) {
|
||||
char buffer[128];
|
||||
|
||||
struct tomoyo_address_group *member =
|
||||
container_of(ptr, typeof(*member),
|
||||
head);
|
||||
tomoyo_print_ip(buffer, sizeof(buffer),
|
||||
&member->address);
|
||||
tomoyo_io_printf(head, " %s", buffer);
|
||||
}
|
||||
tomoyo_set_lf(head);
|
||||
}
|
||||
|
|
@ -2066,27 +2231,7 @@ static int tomoyo_write_answer(struct tomoyo_io_buffer *head)
|
|||
static void tomoyo_read_version(struct tomoyo_io_buffer *head)
|
||||
{
|
||||
if (!head->r.eof) {
|
||||
tomoyo_io_printf(head, "2.4.0");
|
||||
head->r.eof = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* tomoyo_read_self_domain - Get the current process's domainname.
|
||||
*
|
||||
* @head: Pointer to "struct tomoyo_io_buffer".
|
||||
*
|
||||
* Returns the current process's domainname.
|
||||
*/
|
||||
static void tomoyo_read_self_domain(struct tomoyo_io_buffer *head)
|
||||
{
|
||||
if (!head->r.eof) {
|
||||
/*
|
||||
* tomoyo_domain()->domainname != NULL
|
||||
* because every process belongs to a domain and
|
||||
* the domain's name cannot be NULL.
|
||||
*/
|
||||
tomoyo_io_printf(head, "%s", tomoyo_domain()->domainname->name);
|
||||
tomoyo_io_printf(head, "2.5.0");
|
||||
head->r.eof = true;
|
||||
}
|
||||
}
|
||||
|
|
@ -2221,10 +2366,6 @@ int tomoyo_open_control(const u8 type, struct file *file)
|
|||
head->poll = tomoyo_poll_log;
|
||||
head->read = tomoyo_read_log;
|
||||
break;
|
||||
case TOMOYO_SELFDOMAIN:
|
||||
/* /sys/kernel/security/tomoyo/self_domain */
|
||||
head->read = tomoyo_read_self_domain;
|
||||
break;
|
||||
case TOMOYO_PROCESS_STATUS:
|
||||
/* /sys/kernel/security/tomoyo/.process_status */
|
||||
head->write = tomoyo_write_pid;
|
||||
|
|
@ -2453,6 +2594,7 @@ ssize_t tomoyo_write_control(struct tomoyo_io_buffer *head,
|
|||
return -EFAULT;
|
||||
if (mutex_lock_interruptible(&head->io_sem))
|
||||
return -EINTR;
|
||||
head->read_user_buf_avail = 0;
|
||||
idx = tomoyo_read_lock();
|
||||
/* Read a line and dispatch it to the policy handler. */
|
||||
while (avail_len > 0) {
|
||||
|
|
@ -2562,11 +2704,11 @@ void tomoyo_check_profile(void)
|
|||
struct tomoyo_domain_info *domain;
|
||||
const int idx = tomoyo_read_lock();
|
||||
tomoyo_policy_loaded = true;
|
||||
printk(KERN_INFO "TOMOYO: 2.4.0\n");
|
||||
printk(KERN_INFO "TOMOYO: 2.5.0\n");
|
||||
list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) {
|
||||
const u8 profile = domain->profile;
|
||||
const struct tomoyo_policy_namespace *ns = domain->ns;
|
||||
if (ns->profile_version != 20100903)
|
||||
if (ns->profile_version != 20110903)
|
||||
printk(KERN_ERR
|
||||
"Profile version %u is not supported.\n",
|
||||
ns->profile_version);
|
||||
|
|
@ -2577,9 +2719,9 @@ void tomoyo_check_profile(void)
|
|||
else
|
||||
continue;
|
||||
printk(KERN_ERR
|
||||
"Userland tools for TOMOYO 2.4 must be installed and "
|
||||
"Userland tools for TOMOYO 2.5 must be installed and "
|
||||
"policy must be initialized.\n");
|
||||
printk(KERN_ERR "Please see http://tomoyo.sourceforge.jp/2.4/ "
|
||||
printk(KERN_ERR "Please see http://tomoyo.sourceforge.jp/2.5/ "
|
||||
"for more information.\n");
|
||||
panic("STOP!");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
*
|
||||
* Header file for TOMOYO.
|
||||
*
|
||||
* Copyright (C) 2005-2010 NTT DATA CORPORATION
|
||||
* Copyright (C) 2005-2011 NTT DATA CORPORATION
|
||||
*/
|
||||
|
||||
#ifndef _SECURITY_TOMOYO_COMMON_H
|
||||
|
|
@ -23,6 +23,16 @@
|
|||
#include <linux/poll.h>
|
||||
#include <linux/binfmts.h>
|
||||
#include <linux/highmem.h>
|
||||
#include <linux/net.h>
|
||||
#include <linux/inet.h>
|
||||
#include <linux/in.h>
|
||||
#include <linux/in6.h>
|
||||
#include <linux/un.h>
|
||||
#include <net/sock.h>
|
||||
#include <net/af_unix.h>
|
||||
#include <net/ip.h>
|
||||
#include <net/ipv6.h>
|
||||
#include <net/udp.h>
|
||||
|
||||
/********** Constants definitions. **********/
|
||||
|
||||
|
|
@ -34,8 +44,17 @@
|
|||
#define TOMOYO_HASH_BITS 8
|
||||
#define TOMOYO_MAX_HASH (1u<<TOMOYO_HASH_BITS)
|
||||
|
||||
/*
|
||||
* TOMOYO checks only SOCK_STREAM, SOCK_DGRAM, SOCK_RAW, SOCK_SEQPACKET.
|
||||
* Therefore, we don't need SOCK_MAX.
|
||||
*/
|
||||
#define TOMOYO_SOCK_MAX 6
|
||||
|
||||
#define TOMOYO_EXEC_TMPSIZE 4096
|
||||
|
||||
/* Garbage collector is trying to kfree() this element. */
|
||||
#define TOMOYO_GC_IN_PROGRESS -1
|
||||
|
||||
/* Profile number is an integer between 0 and 255. */
|
||||
#define TOMOYO_MAX_PROFILES 256
|
||||
|
||||
|
|
@ -136,6 +155,7 @@ enum tomoyo_mode_index {
|
|||
/* Index numbers for entry type. */
|
||||
enum tomoyo_policy_id {
|
||||
TOMOYO_ID_GROUP,
|
||||
TOMOYO_ID_ADDRESS_GROUP,
|
||||
TOMOYO_ID_PATH_GROUP,
|
||||
TOMOYO_ID_NUMBER_GROUP,
|
||||
TOMOYO_ID_TRANSITION_CONTROL,
|
||||
|
|
@ -162,10 +182,21 @@ enum tomoyo_domain_info_flags_index {
|
|||
TOMOYO_MAX_DOMAIN_INFO_FLAGS
|
||||
};
|
||||
|
||||
/* Index numbers for audit type. */
|
||||
enum tomoyo_grant_log {
|
||||
/* Follow profile's configuration. */
|
||||
TOMOYO_GRANTLOG_AUTO,
|
||||
/* Do not generate grant log. */
|
||||
TOMOYO_GRANTLOG_NO,
|
||||
/* Generate grant_log. */
|
||||
TOMOYO_GRANTLOG_YES,
|
||||
};
|
||||
|
||||
/* Index numbers for group entries. */
|
||||
enum tomoyo_group_id {
|
||||
TOMOYO_PATH_GROUP,
|
||||
TOMOYO_NUMBER_GROUP,
|
||||
TOMOYO_ADDRESS_GROUP,
|
||||
TOMOYO_MAX_GROUP
|
||||
};
|
||||
|
||||
|
|
@ -196,6 +227,10 @@ enum tomoyo_acl_entry_type_index {
|
|||
TOMOYO_TYPE_PATH_NUMBER_ACL,
|
||||
TOMOYO_TYPE_MKDEV_ACL,
|
||||
TOMOYO_TYPE_MOUNT_ACL,
|
||||
TOMOYO_TYPE_INET_ACL,
|
||||
TOMOYO_TYPE_UNIX_ACL,
|
||||
TOMOYO_TYPE_ENV_ACL,
|
||||
TOMOYO_TYPE_MANUAL_TASK_ACL,
|
||||
};
|
||||
|
||||
/* Index numbers for access controls with one pathname. */
|
||||
|
|
@ -228,6 +263,15 @@ enum tomoyo_mkdev_acl_index {
|
|||
TOMOYO_MAX_MKDEV_OPERATION
|
||||
};
|
||||
|
||||
/* Index numbers for socket operations. */
|
||||
enum tomoyo_network_acl_index {
|
||||
TOMOYO_NETWORK_BIND, /* bind() operation. */
|
||||
TOMOYO_NETWORK_LISTEN, /* listen() operation. */
|
||||
TOMOYO_NETWORK_CONNECT, /* connect() operation. */
|
||||
TOMOYO_NETWORK_SEND, /* send() operation. */
|
||||
TOMOYO_MAX_NETWORK_OPERATION
|
||||
};
|
||||
|
||||
/* Index numbers for access controls with two pathnames. */
|
||||
enum tomoyo_path2_acl_index {
|
||||
TOMOYO_TYPE_LINK,
|
||||
|
|
@ -255,7 +299,6 @@ enum tomoyo_securityfs_interface_index {
|
|||
TOMOYO_EXCEPTIONPOLICY,
|
||||
TOMOYO_PROCESS_STATUS,
|
||||
TOMOYO_STAT,
|
||||
TOMOYO_SELFDOMAIN,
|
||||
TOMOYO_AUDIT,
|
||||
TOMOYO_VERSION,
|
||||
TOMOYO_PROFILE,
|
||||
|
|
@ -300,12 +343,30 @@ enum tomoyo_mac_index {
|
|||
TOMOYO_MAC_FILE_MOUNT,
|
||||
TOMOYO_MAC_FILE_UMOUNT,
|
||||
TOMOYO_MAC_FILE_PIVOT_ROOT,
|
||||
TOMOYO_MAC_NETWORK_INET_STREAM_BIND,
|
||||
TOMOYO_MAC_NETWORK_INET_STREAM_LISTEN,
|
||||
TOMOYO_MAC_NETWORK_INET_STREAM_CONNECT,
|
||||
TOMOYO_MAC_NETWORK_INET_DGRAM_BIND,
|
||||
TOMOYO_MAC_NETWORK_INET_DGRAM_SEND,
|
||||
TOMOYO_MAC_NETWORK_INET_RAW_BIND,
|
||||
TOMOYO_MAC_NETWORK_INET_RAW_SEND,
|
||||
TOMOYO_MAC_NETWORK_UNIX_STREAM_BIND,
|
||||
TOMOYO_MAC_NETWORK_UNIX_STREAM_LISTEN,
|
||||
TOMOYO_MAC_NETWORK_UNIX_STREAM_CONNECT,
|
||||
TOMOYO_MAC_NETWORK_UNIX_DGRAM_BIND,
|
||||
TOMOYO_MAC_NETWORK_UNIX_DGRAM_SEND,
|
||||
TOMOYO_MAC_NETWORK_UNIX_SEQPACKET_BIND,
|
||||
TOMOYO_MAC_NETWORK_UNIX_SEQPACKET_LISTEN,
|
||||
TOMOYO_MAC_NETWORK_UNIX_SEQPACKET_CONNECT,
|
||||
TOMOYO_MAC_ENVIRON,
|
||||
TOMOYO_MAX_MAC_INDEX
|
||||
};
|
||||
|
||||
/* Index numbers for category of functionality. */
|
||||
enum tomoyo_mac_category_index {
|
||||
TOMOYO_MAC_CATEGORY_FILE,
|
||||
TOMOYO_MAC_CATEGORY_NETWORK,
|
||||
TOMOYO_MAC_CATEGORY_MISC,
|
||||
TOMOYO_MAX_MAC_CATEGORY_INDEX
|
||||
};
|
||||
|
||||
|
|
@ -340,7 +401,7 @@ enum tomoyo_pref_index {
|
|||
/* Common header for holding ACL entries. */
|
||||
struct tomoyo_acl_head {
|
||||
struct list_head list;
|
||||
bool is_deleted;
|
||||
s8 is_deleted; /* true or false or TOMOYO_GC_IN_PROGRESS */
|
||||
} __packed;
|
||||
|
||||
/* Common header for shared entries. */
|
||||
|
|
@ -396,6 +457,25 @@ struct tomoyo_request_info {
|
|||
*/
|
||||
u8 operation;
|
||||
} path_number;
|
||||
struct {
|
||||
const struct tomoyo_path_info *name;
|
||||
} environ;
|
||||
struct {
|
||||
const __be32 *address;
|
||||
u16 port;
|
||||
/* One of values smaller than TOMOYO_SOCK_MAX. */
|
||||
u8 protocol;
|
||||
/* One of values in "enum tomoyo_network_acl_index". */
|
||||
u8 operation;
|
||||
bool is_ipv6;
|
||||
} inet_network;
|
||||
struct {
|
||||
const struct tomoyo_path_info *address;
|
||||
/* One of values smaller than TOMOYO_SOCK_MAX. */
|
||||
u8 protocol;
|
||||
/* One of values in "enum tomoyo_network_acl_index". */
|
||||
u8 operation;
|
||||
} unix_network;
|
||||
struct {
|
||||
const struct tomoyo_path_info *type;
|
||||
const struct tomoyo_path_info *dir;
|
||||
|
|
@ -403,7 +483,11 @@ struct tomoyo_request_info {
|
|||
unsigned long flags;
|
||||
int need_dev;
|
||||
} mount;
|
||||
struct {
|
||||
const struct tomoyo_path_info *domainname;
|
||||
} task;
|
||||
} param;
|
||||
struct tomoyo_acl_info *matched_acl;
|
||||
u8 param_type;
|
||||
bool granted;
|
||||
u8 retry;
|
||||
|
|
@ -442,7 +526,14 @@ struct tomoyo_number_union {
|
|||
u8 value_type[2];
|
||||
};
|
||||
|
||||
/* Structure for "path_group"/"number_group" directive. */
|
||||
/* Structure for holding an IP address. */
|
||||
struct tomoyo_ipaddr_union {
|
||||
struct in6_addr ip[2]; /* Big endian. */
|
||||
struct tomoyo_group *group; /* Pointer to address group. */
|
||||
bool is_ipv6; /* Valid only if @group == NULL. */
|
||||
};
|
||||
|
||||
/* Structure for "path_group"/"number_group"/"address_group" directive. */
|
||||
struct tomoyo_group {
|
||||
struct tomoyo_shared_acl_head head;
|
||||
const struct tomoyo_path_info *group_name;
|
||||
|
|
@ -461,6 +552,13 @@ struct tomoyo_number_group {
|
|||
struct tomoyo_number_union number;
|
||||
};
|
||||
|
||||
/* Structure for "address_group" directive. */
|
||||
struct tomoyo_address_group {
|
||||
struct tomoyo_acl_head head;
|
||||
/* Structure for holding an IP address. */
|
||||
struct tomoyo_ipaddr_union address;
|
||||
};
|
||||
|
||||
/* Subset of "struct stat". Used by conditional ACL and audit logs. */
|
||||
struct tomoyo_mini_stat {
|
||||
uid_t uid;
|
||||
|
|
@ -520,6 +618,7 @@ struct tomoyo_execve {
|
|||
struct tomoyo_request_info r;
|
||||
struct tomoyo_obj_info obj;
|
||||
struct linux_binprm *bprm;
|
||||
const struct tomoyo_path_info *transition;
|
||||
/* For dumping argv[] and envp[]. */
|
||||
struct tomoyo_page_dump dump;
|
||||
/* For temporary use. */
|
||||
|
|
@ -554,6 +653,8 @@ struct tomoyo_condition {
|
|||
u16 names_count; /* Number of "struct tomoyo_name_union names". */
|
||||
u16 argc; /* Number of "struct tomoyo_argv". */
|
||||
u16 envc; /* Number of "struct tomoyo_envp". */
|
||||
u8 grant_log; /* One of values in "enum tomoyo_grant_log". */
|
||||
const struct tomoyo_path_info *transit; /* Maybe NULL. */
|
||||
/*
|
||||
* struct tomoyo_condition_element condition[condc];
|
||||
* struct tomoyo_number_union values[numbers_count];
|
||||
|
|
@ -567,7 +668,7 @@ struct tomoyo_condition {
|
|||
struct tomoyo_acl_info {
|
||||
struct list_head list;
|
||||
struct tomoyo_condition *cond; /* Maybe NULL. */
|
||||
bool is_deleted;
|
||||
s8 is_deleted; /* true or false or TOMOYO_GC_IN_PROGRESS */
|
||||
u8 type; /* One of values in "enum tomoyo_acl_entry_type_index". */
|
||||
} __packed;
|
||||
|
||||
|
|
@ -586,6 +687,15 @@ struct tomoyo_domain_info {
|
|||
atomic_t users; /* Number of referring credentials. */
|
||||
};
|
||||
|
||||
/*
|
||||
* Structure for "task manual_domain_transition" directive.
|
||||
*/
|
||||
struct tomoyo_task_acl {
|
||||
struct tomoyo_acl_info head; /* type = TOMOYO_TYPE_MANUAL_TASK_ACL */
|
||||
/* Pointer to domainname. */
|
||||
const struct tomoyo_path_info *domainname;
|
||||
};
|
||||
|
||||
/*
|
||||
* Structure for "file execute", "file read", "file write", "file append",
|
||||
* "file unlink", "file getattr", "file rmdir", "file truncate",
|
||||
|
|
@ -638,6 +748,29 @@ struct tomoyo_mount_acl {
|
|||
struct tomoyo_number_union flags;
|
||||
};
|
||||
|
||||
/* Structure for "misc env" directive in domain policy. */
|
||||
struct tomoyo_env_acl {
|
||||
struct tomoyo_acl_info head; /* type = TOMOYO_TYPE_ENV_ACL */
|
||||
const struct tomoyo_path_info *env; /* environment variable */
|
||||
};
|
||||
|
||||
/* Structure for "network inet" directive. */
|
||||
struct tomoyo_inet_acl {
|
||||
struct tomoyo_acl_info head; /* type = TOMOYO_TYPE_INET_ACL */
|
||||
u8 protocol;
|
||||
u8 perm; /* Bitmask of values in "enum tomoyo_network_acl_index" */
|
||||
struct tomoyo_ipaddr_union address;
|
||||
struct tomoyo_number_union port;
|
||||
};
|
||||
|
||||
/* Structure for "network unix" directive. */
|
||||
struct tomoyo_unix_acl {
|
||||
struct tomoyo_acl_info head; /* type = TOMOYO_TYPE_UNIX_ACL */
|
||||
u8 protocol;
|
||||
u8 perm; /* Bitmask of values in "enum tomoyo_network_acl_index" */
|
||||
struct tomoyo_name_union name;
|
||||
};
|
||||
|
||||
/* Structure for holding a line from /sys/kernel/security/tomoyo/ interface. */
|
||||
struct tomoyo_acl_param {
|
||||
char *data;
|
||||
|
|
@ -773,7 +906,7 @@ struct tomoyo_policy_namespace {
|
|||
struct list_head acl_group[TOMOYO_MAX_ACL_GROUPS];
|
||||
/* List for connecting to tomoyo_namespace_list list. */
|
||||
struct list_head namespace_list;
|
||||
/* Profile version. Currently only 20100903 is defined. */
|
||||
/* Profile version. Currently only 20110903 is defined. */
|
||||
unsigned int profile_version;
|
||||
/* Name of this namespace (e.g. "<kernel>", "</usr/sbin/httpd>" ). */
|
||||
const char *name;
|
||||
|
|
@ -781,6 +914,8 @@ struct tomoyo_policy_namespace {
|
|||
|
||||
/********** Function prototypes. **********/
|
||||
|
||||
bool tomoyo_address_matches_group(const bool is_ipv6, const __be32 *address,
|
||||
const struct tomoyo_group *group);
|
||||
bool tomoyo_compare_number_union(const unsigned long value,
|
||||
const struct tomoyo_number_union *ptr);
|
||||
bool tomoyo_condition(struct tomoyo_request_info *r,
|
||||
|
|
@ -796,6 +931,8 @@ bool tomoyo_memory_ok(void *ptr);
|
|||
bool tomoyo_number_matches_group(const unsigned long min,
|
||||
const unsigned long max,
|
||||
const struct tomoyo_group *group);
|
||||
bool tomoyo_parse_ipaddr_union(struct tomoyo_acl_param *param,
|
||||
struct tomoyo_ipaddr_union *ptr);
|
||||
bool tomoyo_parse_name_union(struct tomoyo_acl_param *param,
|
||||
struct tomoyo_name_union *ptr);
|
||||
bool tomoyo_parse_number_union(struct tomoyo_acl_param *param,
|
||||
|
|
@ -805,6 +942,7 @@ bool tomoyo_path_matches_pattern(const struct tomoyo_path_info *filename,
|
|||
bool tomoyo_permstr(const char *string, const char *keyword);
|
||||
bool tomoyo_str_starts(char **src, const char *find);
|
||||
char *tomoyo_encode(const char *str);
|
||||
char *tomoyo_encode2(const char *str, int str_len);
|
||||
char *tomoyo_init_log(struct tomoyo_request_info *r, int len, const char *fmt,
|
||||
va_list args);
|
||||
char *tomoyo_read_token(struct tomoyo_acl_param *param);
|
||||
|
|
@ -814,12 +952,17 @@ const char *tomoyo_get_exe(void);
|
|||
const char *tomoyo_yesno(const unsigned int value);
|
||||
const struct tomoyo_path_info *tomoyo_compare_name_union
|
||||
(const struct tomoyo_path_info *name, const struct tomoyo_name_union *ptr);
|
||||
const struct tomoyo_path_info *tomoyo_get_domainname
|
||||
(struct tomoyo_acl_param *param);
|
||||
const struct tomoyo_path_info *tomoyo_get_name(const char *name);
|
||||
const struct tomoyo_path_info *tomoyo_path_matches_group
|
||||
(const struct tomoyo_path_info *pathname, const struct tomoyo_group *group);
|
||||
int tomoyo_check_open_permission(struct tomoyo_domain_info *domain,
|
||||
struct path *path, const int flag);
|
||||
int tomoyo_close_control(struct tomoyo_io_buffer *head);
|
||||
int tomoyo_env_perm(struct tomoyo_request_info *r, const char *env);
|
||||
int tomoyo_execute_permission(struct tomoyo_request_info *r,
|
||||
const struct tomoyo_path_info *filename);
|
||||
int tomoyo_find_next_domain(struct linux_binprm *bprm);
|
||||
int tomoyo_get_mode(const struct tomoyo_policy_namespace *ns, const u8 profile,
|
||||
const u8 index);
|
||||
|
|
@ -838,10 +981,15 @@ int tomoyo_path_number_perm(const u8 operation, struct path *path,
|
|||
unsigned long number);
|
||||
int tomoyo_path_perm(const u8 operation, struct path *path,
|
||||
const char *target);
|
||||
int tomoyo_path_permission(struct tomoyo_request_info *r, u8 operation,
|
||||
const struct tomoyo_path_info *filename);
|
||||
int tomoyo_poll_control(struct file *file, poll_table *wait);
|
||||
int tomoyo_poll_log(struct file *file, poll_table *wait);
|
||||
int tomoyo_socket_bind_permission(struct socket *sock, struct sockaddr *addr,
|
||||
int addr_len);
|
||||
int tomoyo_socket_connect_permission(struct socket *sock,
|
||||
struct sockaddr *addr, int addr_len);
|
||||
int tomoyo_socket_listen_permission(struct socket *sock);
|
||||
int tomoyo_socket_sendmsg_permission(struct socket *sock, struct msghdr *msg,
|
||||
int size);
|
||||
int tomoyo_supervisor(struct tomoyo_request_info *r, const char *fmt, ...)
|
||||
__printf(2, 3);
|
||||
int tomoyo_update_domain(struct tomoyo_acl_info *new_entry, const int size,
|
||||
|
|
@ -860,8 +1008,11 @@ int tomoyo_update_policy(struct tomoyo_acl_head *new_entry, const int size,
|
|||
int tomoyo_write_aggregator(struct tomoyo_acl_param *param);
|
||||
int tomoyo_write_file(struct tomoyo_acl_param *param);
|
||||
int tomoyo_write_group(struct tomoyo_acl_param *param, const u8 type);
|
||||
int tomoyo_write_misc(struct tomoyo_acl_param *param);
|
||||
int tomoyo_write_inet_network(struct tomoyo_acl_param *param);
|
||||
int tomoyo_write_transition_control(struct tomoyo_acl_param *param,
|
||||
const u8 type);
|
||||
int tomoyo_write_unix_network(struct tomoyo_acl_param *param);
|
||||
ssize_t tomoyo_read_control(struct tomoyo_io_buffer *head, char __user *buffer,
|
||||
const int buffer_len);
|
||||
ssize_t tomoyo_write_control(struct tomoyo_io_buffer *head,
|
||||
|
|
@ -891,12 +1042,11 @@ void tomoyo_del_condition(struct list_head *element);
|
|||
void tomoyo_fill_path_info(struct tomoyo_path_info *ptr);
|
||||
void tomoyo_get_attributes(struct tomoyo_obj_info *obj);
|
||||
void tomoyo_init_policy_namespace(struct tomoyo_policy_namespace *ns);
|
||||
void tomoyo_io_printf(struct tomoyo_io_buffer *head, const char *fmt, ...)
|
||||
__printf(2, 3);
|
||||
void tomoyo_load_policy(const char *filename);
|
||||
void tomoyo_memory_free(void *ptr);
|
||||
void tomoyo_normalize_line(unsigned char *buffer);
|
||||
void tomoyo_notify_gc(struct tomoyo_io_buffer *head, const bool is_register);
|
||||
void tomoyo_print_ip(char *buf, const unsigned int size,
|
||||
const struct tomoyo_ipaddr_union *ptr);
|
||||
void tomoyo_print_ulong(char *buffer, const int buffer_len,
|
||||
const unsigned long value, const u8 type);
|
||||
void tomoyo_put_name_union(struct tomoyo_name_union *ptr);
|
||||
|
|
@ -919,6 +1069,8 @@ extern const char * const tomoyo_mac_keywords[TOMOYO_MAX_MAC_INDEX
|
|||
+ TOMOYO_MAX_MAC_CATEGORY_INDEX];
|
||||
extern const char * const tomoyo_mode[TOMOYO_CONFIG_MAX_MODE];
|
||||
extern const char * const tomoyo_path_keyword[TOMOYO_MAX_PATH_OPERATION];
|
||||
extern const char * const tomoyo_proto_keyword[TOMOYO_SOCK_MAX];
|
||||
extern const char * const tomoyo_socket_keyword[TOMOYO_MAX_NETWORK_OPERATION];
|
||||
extern const u8 tomoyo_index2category[TOMOYO_MAX_MAC_INDEX];
|
||||
extern const u8 tomoyo_pn2mac[TOMOYO_MAX_PATH_NUMBER_OPERATION];
|
||||
extern const u8 tomoyo_pnnn2mac[TOMOYO_MAX_MKDEV_OPERATION];
|
||||
|
|
@ -1097,6 +1249,21 @@ static inline bool tomoyo_same_number_union
|
|||
a->value_type[1] == b->value_type[1];
|
||||
}
|
||||
|
||||
/**
|
||||
* tomoyo_same_ipaddr_union - Check for duplicated "struct tomoyo_ipaddr_union" entry.
|
||||
*
|
||||
* @a: Pointer to "struct tomoyo_ipaddr_union".
|
||||
* @b: Pointer to "struct tomoyo_ipaddr_union".
|
||||
*
|
||||
* Returns true if @a == @b, false otherwise.
|
||||
*/
|
||||
static inline bool tomoyo_same_ipaddr_union
|
||||
(const struct tomoyo_ipaddr_union *a, const struct tomoyo_ipaddr_union *b)
|
||||
{
|
||||
return !memcmp(a->ip, b->ip, sizeof(a->ip)) && a->group == b->group &&
|
||||
a->is_ipv6 == b->is_ipv6;
|
||||
}
|
||||
|
||||
/**
|
||||
* tomoyo_current_namespace - Get "struct tomoyo_policy_namespace" for current thread.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -348,6 +348,7 @@ static inline bool tomoyo_same_condition(const struct tomoyo_condition *a,
|
|||
a->numbers_count == b->numbers_count &&
|
||||
a->names_count == b->names_count &&
|
||||
a->argc == b->argc && a->envc == b->envc &&
|
||||
a->grant_log == b->grant_log && a->transit == b->transit &&
|
||||
!memcmp(a + 1, b + 1, a->size - sizeof(*a));
|
||||
}
|
||||
|
||||
|
|
@ -399,8 +400,9 @@ static struct tomoyo_condition *tomoyo_commit_condition
|
|||
found = true;
|
||||
goto out;
|
||||
}
|
||||
list_for_each_entry_rcu(ptr, &tomoyo_condition_list, head.list) {
|
||||
if (!tomoyo_same_condition(ptr, entry))
|
||||
list_for_each_entry(ptr, &tomoyo_condition_list, head.list) {
|
||||
if (!tomoyo_same_condition(ptr, entry) ||
|
||||
atomic_read(&ptr->head.users) == TOMOYO_GC_IN_PROGRESS)
|
||||
continue;
|
||||
/* Same entry found. Share this entry. */
|
||||
atomic_inc(&ptr->head.users);
|
||||
|
|
@ -410,8 +412,7 @@ static struct tomoyo_condition *tomoyo_commit_condition
|
|||
if (!found) {
|
||||
if (tomoyo_memory_ok(entry)) {
|
||||
atomic_set(&entry->head.users, 1);
|
||||
list_add_rcu(&entry->head.list,
|
||||
&tomoyo_condition_list);
|
||||
list_add(&entry->head.list, &tomoyo_condition_list);
|
||||
} else {
|
||||
found = true;
|
||||
ptr = NULL;
|
||||
|
|
@ -427,6 +428,46 @@ out:
|
|||
return entry;
|
||||
}
|
||||
|
||||
/**
|
||||
* tomoyo_get_transit_preference - Parse domain transition preference for execve().
|
||||
*
|
||||
* @param: Pointer to "struct tomoyo_acl_param".
|
||||
* @e: Pointer to "struct tomoyo_condition".
|
||||
*
|
||||
* Returns the condition string part.
|
||||
*/
|
||||
static char *tomoyo_get_transit_preference(struct tomoyo_acl_param *param,
|
||||
struct tomoyo_condition *e)
|
||||
{
|
||||
char * const pos = param->data;
|
||||
bool flag;
|
||||
if (*pos == '<') {
|
||||
e->transit = tomoyo_get_domainname(param);
|
||||
goto done;
|
||||
}
|
||||
{
|
||||
char *cp = strchr(pos, ' ');
|
||||
if (cp)
|
||||
*cp = '\0';
|
||||
flag = tomoyo_correct_path(pos) || !strcmp(pos, "keep") ||
|
||||
!strcmp(pos, "initialize") || !strcmp(pos, "reset") ||
|
||||
!strcmp(pos, "child") || !strcmp(pos, "parent");
|
||||
if (cp)
|
||||
*cp = ' ';
|
||||
}
|
||||
if (!flag)
|
||||
return pos;
|
||||
e->transit = tomoyo_get_name(tomoyo_read_token(param));
|
||||
done:
|
||||
if (e->transit)
|
||||
return param->data;
|
||||
/*
|
||||
* Return a bad read-only condition string that will let
|
||||
* tomoyo_get_condition() return NULL.
|
||||
*/
|
||||
return "/";
|
||||
}
|
||||
|
||||
/**
|
||||
* tomoyo_get_condition - Parse condition part.
|
||||
*
|
||||
|
|
@ -443,7 +484,8 @@ struct tomoyo_condition *tomoyo_get_condition(struct tomoyo_acl_param *param)
|
|||
struct tomoyo_argv *argv = NULL;
|
||||
struct tomoyo_envp *envp = NULL;
|
||||
struct tomoyo_condition e = { };
|
||||
char * const start_of_string = param->data;
|
||||
char * const start_of_string =
|
||||
tomoyo_get_transit_preference(param, &e);
|
||||
char * const end_of_string = start_of_string + strlen(start_of_string);
|
||||
char *pos;
|
||||
rerun:
|
||||
|
|
@ -486,6 +528,20 @@ rerun:
|
|||
goto out;
|
||||
dprintk(KERN_WARNING "%u: <%s>%s=<%s>\n", __LINE__, left_word,
|
||||
is_not ? "!" : "", right_word);
|
||||
if (!strcmp(left_word, "grant_log")) {
|
||||
if (entry) {
|
||||
if (is_not ||
|
||||
entry->grant_log != TOMOYO_GRANTLOG_AUTO)
|
||||
goto out;
|
||||
else if (!strcmp(right_word, "yes"))
|
||||
entry->grant_log = TOMOYO_GRANTLOG_YES;
|
||||
else if (!strcmp(right_word, "no"))
|
||||
entry->grant_log = TOMOYO_GRANTLOG_NO;
|
||||
else
|
||||
goto out;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (!strncmp(left_word, "exec.argv[", 10)) {
|
||||
if (!argv) {
|
||||
e.argc++;
|
||||
|
|
@ -593,8 +649,9 @@ store_value:
|
|||
+ e.envc * sizeof(struct tomoyo_envp);
|
||||
entry = kzalloc(e.size, GFP_NOFS);
|
||||
if (!entry)
|
||||
return NULL;
|
||||
goto out2;
|
||||
*entry = e;
|
||||
e.transit = NULL;
|
||||
condp = (struct tomoyo_condition_element *) (entry + 1);
|
||||
numbers_p = (struct tomoyo_number_union *) (condp + e.condc);
|
||||
names_p = (struct tomoyo_name_union *) (numbers_p + e.numbers_count);
|
||||
|
|
@ -621,6 +678,8 @@ out:
|
|||
tomoyo_del_condition(&entry->head.list);
|
||||
kfree(entry);
|
||||
}
|
||||
out2:
|
||||
tomoyo_put_name(e.transit);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -39,6 +39,8 @@ int tomoyo_update_policy(struct tomoyo_acl_head *new_entry, const int size,
|
|||
if (mutex_lock_interruptible(&tomoyo_policy_lock))
|
||||
return -ENOMEM;
|
||||
list_for_each_entry_rcu(entry, list, list) {
|
||||
if (entry->is_deleted == TOMOYO_GC_IN_PROGRESS)
|
||||
continue;
|
||||
if (!check_duplicate(entry, new_entry))
|
||||
continue;
|
||||
entry->is_deleted = param->is_delete;
|
||||
|
|
@ -102,10 +104,21 @@ int tomoyo_update_domain(struct tomoyo_acl_info *new_entry, const int size,
|
|||
new_entry->cond = tomoyo_get_condition(param);
|
||||
if (!new_entry->cond)
|
||||
return -EINVAL;
|
||||
/*
|
||||
* Domain transition preference is allowed for only
|
||||
* "file execute" entries.
|
||||
*/
|
||||
if (new_entry->cond->transit &&
|
||||
!(new_entry->type == TOMOYO_TYPE_PATH_ACL &&
|
||||
container_of(new_entry, struct tomoyo_path_acl, head)
|
||||
->perm == 1 << TOMOYO_TYPE_EXECUTE))
|
||||
goto out;
|
||||
}
|
||||
if (mutex_lock_interruptible(&tomoyo_policy_lock))
|
||||
goto out;
|
||||
list_for_each_entry_rcu(entry, list, list) {
|
||||
if (entry->is_deleted == TOMOYO_GC_IN_PROGRESS)
|
||||
continue;
|
||||
if (!tomoyo_same_acl_head(entry, new_entry) ||
|
||||
!check_duplicate(entry, new_entry))
|
||||
continue;
|
||||
|
|
@ -157,6 +170,7 @@ retry:
|
|||
continue;
|
||||
if (!tomoyo_condition(r, ptr->cond))
|
||||
continue;
|
||||
r->matched_acl = ptr;
|
||||
r->granted = true;
|
||||
return;
|
||||
}
|
||||
|
|
@ -501,7 +515,8 @@ struct tomoyo_domain_info *tomoyo_assign_domain(const char *domainname,
|
|||
* that domain. Do not perform domain transition if
|
||||
* profile for that domain is not yet created.
|
||||
*/
|
||||
if (!entry->ns->profile_ptr[entry->profile])
|
||||
if (tomoyo_policy_loaded &&
|
||||
!entry->ns->profile_ptr[entry->profile])
|
||||
return NULL;
|
||||
}
|
||||
return entry;
|
||||
|
|
@ -557,11 +572,98 @@ out:
|
|||
tomoyo_write_log(&r, "use_profile %u\n",
|
||||
entry->profile);
|
||||
tomoyo_write_log(&r, "use_group %u\n", entry->group);
|
||||
tomoyo_update_stat(TOMOYO_STAT_POLICY_UPDATES);
|
||||
}
|
||||
}
|
||||
return entry;
|
||||
}
|
||||
|
||||
/**
|
||||
* tomoyo_environ - Check permission for environment variable names.
|
||||
*
|
||||
* @ee: Pointer to "struct tomoyo_execve".
|
||||
*
|
||||
* Returns 0 on success, negative value otherwise.
|
||||
*/
|
||||
static int tomoyo_environ(struct tomoyo_execve *ee)
|
||||
{
|
||||
struct tomoyo_request_info *r = &ee->r;
|
||||
struct linux_binprm *bprm = ee->bprm;
|
||||
/* env_page.data is allocated by tomoyo_dump_page(). */
|
||||
struct tomoyo_page_dump env_page = { };
|
||||
char *arg_ptr; /* Size is TOMOYO_EXEC_TMPSIZE bytes */
|
||||
int arg_len = 0;
|
||||
unsigned long pos = bprm->p;
|
||||
int offset = pos % PAGE_SIZE;
|
||||
int argv_count = bprm->argc;
|
||||
int envp_count = bprm->envc;
|
||||
int error = -ENOMEM;
|
||||
|
||||
ee->r.type = TOMOYO_MAC_ENVIRON;
|
||||
ee->r.profile = r->domain->profile;
|
||||
ee->r.mode = tomoyo_get_mode(r->domain->ns, ee->r.profile,
|
||||
TOMOYO_MAC_ENVIRON);
|
||||
if (!r->mode || !envp_count)
|
||||
return 0;
|
||||
arg_ptr = kzalloc(TOMOYO_EXEC_TMPSIZE, GFP_NOFS);
|
||||
if (!arg_ptr)
|
||||
goto out;
|
||||
while (error == -ENOMEM) {
|
||||
if (!tomoyo_dump_page(bprm, pos, &env_page))
|
||||
goto out;
|
||||
pos += PAGE_SIZE - offset;
|
||||
/* Read. */
|
||||
while (argv_count && offset < PAGE_SIZE) {
|
||||
if (!env_page.data[offset++])
|
||||
argv_count--;
|
||||
}
|
||||
if (argv_count) {
|
||||
offset = 0;
|
||||
continue;
|
||||
}
|
||||
while (offset < PAGE_SIZE) {
|
||||
const unsigned char c = env_page.data[offset++];
|
||||
|
||||
if (c && arg_len < TOMOYO_EXEC_TMPSIZE - 10) {
|
||||
if (c == '=') {
|
||||
arg_ptr[arg_len++] = '\0';
|
||||
} else if (c == '\\') {
|
||||
arg_ptr[arg_len++] = '\\';
|
||||
arg_ptr[arg_len++] = '\\';
|
||||
} else if (c > ' ' && c < 127) {
|
||||
arg_ptr[arg_len++] = c;
|
||||
} else {
|
||||
arg_ptr[arg_len++] = '\\';
|
||||
arg_ptr[arg_len++] = (c >> 6) + '0';
|
||||
arg_ptr[arg_len++]
|
||||
= ((c >> 3) & 7) + '0';
|
||||
arg_ptr[arg_len++] = (c & 7) + '0';
|
||||
}
|
||||
} else {
|
||||
arg_ptr[arg_len] = '\0';
|
||||
}
|
||||
if (c)
|
||||
continue;
|
||||
if (tomoyo_env_perm(r, arg_ptr)) {
|
||||
error = -EPERM;
|
||||
break;
|
||||
}
|
||||
if (!--envp_count) {
|
||||
error = 0;
|
||||
break;
|
||||
}
|
||||
arg_len = 0;
|
||||
}
|
||||
offset = 0;
|
||||
}
|
||||
out:
|
||||
if (r->mode != TOMOYO_CONFIG_ENFORCING)
|
||||
error = 0;
|
||||
kfree(env_page.data);
|
||||
kfree(arg_ptr);
|
||||
return error;
|
||||
}
|
||||
|
||||
/**
|
||||
* tomoyo_find_next_domain - Find a domain.
|
||||
*
|
||||
|
|
@ -577,10 +679,11 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm)
|
|||
struct tomoyo_domain_info *domain = NULL;
|
||||
const char *original_name = bprm->filename;
|
||||
int retval = -ENOMEM;
|
||||
bool need_kfree = false;
|
||||
bool reject_on_transition_failure = false;
|
||||
struct tomoyo_path_info rn = { }; /* real name */
|
||||
const struct tomoyo_path_info *candidate;
|
||||
struct tomoyo_path_info exename;
|
||||
struct tomoyo_execve *ee = kzalloc(sizeof(*ee), GFP_NOFS);
|
||||
|
||||
if (!ee)
|
||||
return -ENOMEM;
|
||||
ee->tmp = kzalloc(TOMOYO_EXEC_TMPSIZE, GFP_NOFS);
|
||||
|
|
@ -594,40 +697,32 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm)
|
|||
ee->bprm = bprm;
|
||||
ee->r.obj = &ee->obj;
|
||||
ee->obj.path1 = bprm->file->f_path;
|
||||
retry:
|
||||
if (need_kfree) {
|
||||
kfree(rn.name);
|
||||
need_kfree = false;
|
||||
}
|
||||
/* Get symlink's pathname of program. */
|
||||
retval = -ENOENT;
|
||||
rn.name = tomoyo_realpath_nofollow(original_name);
|
||||
if (!rn.name)
|
||||
exename.name = tomoyo_realpath_nofollow(original_name);
|
||||
if (!exename.name)
|
||||
goto out;
|
||||
tomoyo_fill_path_info(&rn);
|
||||
need_kfree = true;
|
||||
|
||||
tomoyo_fill_path_info(&exename);
|
||||
retry:
|
||||
/* Check 'aggregator' directive. */
|
||||
{
|
||||
struct tomoyo_aggregator *ptr;
|
||||
struct list_head *list =
|
||||
&old_domain->ns->policy_list[TOMOYO_ID_AGGREGATOR];
|
||||
/* Check 'aggregator' directive. */
|
||||
candidate = &exename;
|
||||
list_for_each_entry_rcu(ptr, list, head.list) {
|
||||
if (ptr->head.is_deleted ||
|
||||
!tomoyo_path_matches_pattern(&rn,
|
||||
!tomoyo_path_matches_pattern(&exename,
|
||||
ptr->original_name))
|
||||
continue;
|
||||
kfree(rn.name);
|
||||
need_kfree = false;
|
||||
/* This is OK because it is read only. */
|
||||
rn = *ptr->aggregated_name;
|
||||
candidate = ptr->aggregated_name;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check execute permission. */
|
||||
retval = tomoyo_path_permission(&ee->r, TOMOYO_TYPE_EXECUTE, &rn);
|
||||
retval = tomoyo_execute_permission(&ee->r, candidate);
|
||||
if (retval == TOMOYO_RETRY_REQUEST)
|
||||
goto retry;
|
||||
if (retval < 0)
|
||||
|
|
@ -638,20 +733,51 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm)
|
|||
* wildcard) rather than the pathname passed to execve()
|
||||
* (which never contains wildcard).
|
||||
*/
|
||||
if (ee->r.param.path.matched_path) {
|
||||
if (need_kfree)
|
||||
kfree(rn.name);
|
||||
need_kfree = false;
|
||||
/* This is OK because it is read only. */
|
||||
rn = *ee->r.param.path.matched_path;
|
||||
}
|
||||
if (ee->r.param.path.matched_path)
|
||||
candidate = ee->r.param.path.matched_path;
|
||||
|
||||
/* Calculate domain to transit to. */
|
||||
/*
|
||||
* Check for domain transition preference if "file execute" matched.
|
||||
* If preference is given, make do_execve() fail if domain transition
|
||||
* has failed, for domain transition preference should be used with
|
||||
* destination domain defined.
|
||||
*/
|
||||
if (ee->transition) {
|
||||
const char *domainname = ee->transition->name;
|
||||
reject_on_transition_failure = true;
|
||||
if (!strcmp(domainname, "keep"))
|
||||
goto force_keep_domain;
|
||||
if (!strcmp(domainname, "child"))
|
||||
goto force_child_domain;
|
||||
if (!strcmp(domainname, "reset"))
|
||||
goto force_reset_domain;
|
||||
if (!strcmp(domainname, "initialize"))
|
||||
goto force_initialize_domain;
|
||||
if (!strcmp(domainname, "parent")) {
|
||||
char *cp;
|
||||
strncpy(ee->tmp, old_domain->domainname->name,
|
||||
TOMOYO_EXEC_TMPSIZE - 1);
|
||||
cp = strrchr(ee->tmp, ' ');
|
||||
if (cp)
|
||||
*cp = '\0';
|
||||
} else if (*domainname == '<')
|
||||
strncpy(ee->tmp, domainname, TOMOYO_EXEC_TMPSIZE - 1);
|
||||
else
|
||||
snprintf(ee->tmp, TOMOYO_EXEC_TMPSIZE - 1, "%s %s",
|
||||
old_domain->domainname->name, domainname);
|
||||
goto force_jump_domain;
|
||||
}
|
||||
/*
|
||||
* No domain transition preference specified.
|
||||
* Calculate domain to transit to.
|
||||
*/
|
||||
switch (tomoyo_transition_type(old_domain->ns, old_domain->domainname,
|
||||
&rn)) {
|
||||
candidate)) {
|
||||
case TOMOYO_TRANSITION_CONTROL_RESET:
|
||||
force_reset_domain:
|
||||
/* Transit to the root of specified namespace. */
|
||||
snprintf(ee->tmp, TOMOYO_EXEC_TMPSIZE - 1, "<%s>", rn.name);
|
||||
snprintf(ee->tmp, TOMOYO_EXEC_TMPSIZE - 1, "<%s>",
|
||||
candidate->name);
|
||||
/*
|
||||
* Make do_execve() fail if domain transition across namespaces
|
||||
* has failed.
|
||||
|
|
@ -659,11 +785,13 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm)
|
|||
reject_on_transition_failure = true;
|
||||
break;
|
||||
case TOMOYO_TRANSITION_CONTROL_INITIALIZE:
|
||||
force_initialize_domain:
|
||||
/* Transit to the child of current namespace's root. */
|
||||
snprintf(ee->tmp, TOMOYO_EXEC_TMPSIZE - 1, "%s %s",
|
||||
old_domain->ns->name, rn.name);
|
||||
old_domain->ns->name, candidate->name);
|
||||
break;
|
||||
case TOMOYO_TRANSITION_CONTROL_KEEP:
|
||||
force_keep_domain:
|
||||
/* Keep current domain. */
|
||||
domain = old_domain;
|
||||
break;
|
||||
|
|
@ -677,13 +805,15 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm)
|
|||
* before /sbin/init.
|
||||
*/
|
||||
domain = old_domain;
|
||||
} else {
|
||||
/* Normal domain transition. */
|
||||
snprintf(ee->tmp, TOMOYO_EXEC_TMPSIZE - 1, "%s %s",
|
||||
old_domain->domainname->name, rn.name);
|
||||
break;
|
||||
}
|
||||
force_child_domain:
|
||||
/* Normal domain transition. */
|
||||
snprintf(ee->tmp, TOMOYO_EXEC_TMPSIZE - 1, "%s %s",
|
||||
old_domain->domainname->name, candidate->name);
|
||||
break;
|
||||
}
|
||||
force_jump_domain:
|
||||
if (!domain)
|
||||
domain = tomoyo_assign_domain(ee->tmp, true);
|
||||
if (domain)
|
||||
|
|
@ -711,8 +841,11 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm)
|
|||
/* Update reference count on "struct tomoyo_domain_info". */
|
||||
atomic_inc(&domain->users);
|
||||
bprm->cred->security = domain;
|
||||
if (need_kfree)
|
||||
kfree(rn.name);
|
||||
kfree(exename.name);
|
||||
if (!retval) {
|
||||
ee->r.domain = domain;
|
||||
retval = tomoyo_environ(ee);
|
||||
}
|
||||
kfree(ee->tmp);
|
||||
kfree(ee->dump.data);
|
||||
kfree(ee);
|
||||
|
|
@ -732,7 +865,8 @@ bool tomoyo_dump_page(struct linux_binprm *bprm, unsigned long pos,
|
|||
struct tomoyo_page_dump *dump)
|
||||
{
|
||||
struct page *page;
|
||||
/* dump->data is released by tomoyo_finish_execve(). */
|
||||
|
||||
/* dump->data is released by tomoyo_find_next_domain(). */
|
||||
if (!dump->data) {
|
||||
dump->data = kzalloc(PAGE_SIZE, GFP_NOFS);
|
||||
if (!dump->data)
|
||||
|
|
@ -753,6 +887,7 @@ bool tomoyo_dump_page(struct linux_binprm *bprm, unsigned long pos,
|
|||
* So do I.
|
||||
*/
|
||||
char *kaddr = kmap_atomic(page, KM_USER0);
|
||||
|
||||
dump->page = page;
|
||||
memcpy(dump->data + offset, kaddr + offset,
|
||||
PAGE_SIZE - offset);
|
||||
|
|
|
|||
122
security/tomoyo/environ.c
Normal file
122
security/tomoyo/environ.c
Normal file
|
|
@ -0,0 +1,122 @@
|
|||
/*
|
||||
* security/tomoyo/environ.c
|
||||
*
|
||||
* Copyright (C) 2005-2011 NTT DATA CORPORATION
|
||||
*/
|
||||
|
||||
#include "common.h"
|
||||
|
||||
/**
|
||||
* tomoyo_check_env_acl - Check permission for environment variable's name.
|
||||
*
|
||||
* @r: Pointer to "struct tomoyo_request_info".
|
||||
* @ptr: Pointer to "struct tomoyo_acl_info".
|
||||
*
|
||||
* Returns true if granted, false otherwise.
|
||||
*/
|
||||
static bool tomoyo_check_env_acl(struct tomoyo_request_info *r,
|
||||
const struct tomoyo_acl_info *ptr)
|
||||
{
|
||||
const struct tomoyo_env_acl *acl =
|
||||
container_of(ptr, typeof(*acl), head);
|
||||
|
||||
return tomoyo_path_matches_pattern(r->param.environ.name, acl->env);
|
||||
}
|
||||
|
||||
/**
|
||||
* tomoyo_audit_env_log - Audit environment variable name log.
|
||||
*
|
||||
* @r: Pointer to "struct tomoyo_request_info".
|
||||
*
|
||||
* Returns 0 on success, negative value otherwise.
|
||||
*/
|
||||
static int tomoyo_audit_env_log(struct tomoyo_request_info *r)
|
||||
{
|
||||
return tomoyo_supervisor(r, "misc env %s\n",
|
||||
r->param.environ.name->name);
|
||||
}
|
||||
|
||||
/**
|
||||
* tomoyo_env_perm - Check permission for environment variable's name.
|
||||
*
|
||||
* @r: Pointer to "struct tomoyo_request_info".
|
||||
* @env: The name of environment variable.
|
||||
*
|
||||
* Returns 0 on success, negative value otherwise.
|
||||
*
|
||||
* Caller holds tomoyo_read_lock().
|
||||
*/
|
||||
int tomoyo_env_perm(struct tomoyo_request_info *r, const char *env)
|
||||
{
|
||||
struct tomoyo_path_info environ;
|
||||
int error;
|
||||
|
||||
if (!env || !*env)
|
||||
return 0;
|
||||
environ.name = env;
|
||||
tomoyo_fill_path_info(&environ);
|
||||
r->param_type = TOMOYO_TYPE_ENV_ACL;
|
||||
r->param.environ.name = &environ;
|
||||
do {
|
||||
tomoyo_check_acl(r, tomoyo_check_env_acl);
|
||||
error = tomoyo_audit_env_log(r);
|
||||
} while (error == TOMOYO_RETRY_REQUEST);
|
||||
return error;
|
||||
}
|
||||
|
||||
/**
|
||||
* tomoyo_same_env_acl - Check for duplicated "struct tomoyo_env_acl" entry.
|
||||
*
|
||||
* @a: Pointer to "struct tomoyo_acl_info".
|
||||
* @b: Pointer to "struct tomoyo_acl_info".
|
||||
*
|
||||
* Returns true if @a == @b, false otherwise.
|
||||
*/
|
||||
static bool tomoyo_same_env_acl(const struct tomoyo_acl_info *a,
|
||||
const struct tomoyo_acl_info *b)
|
||||
{
|
||||
const struct tomoyo_env_acl *p1 = container_of(a, typeof(*p1), head);
|
||||
const struct tomoyo_env_acl *p2 = container_of(b, typeof(*p2), head);
|
||||
|
||||
return p1->env == p2->env;
|
||||
}
|
||||
|
||||
/**
|
||||
* tomoyo_write_env - Write "struct tomoyo_env_acl" list.
|
||||
*
|
||||
* @param: Pointer to "struct tomoyo_acl_param".
|
||||
*
|
||||
* Returns 0 on success, negative value otherwise.
|
||||
*
|
||||
* Caller holds tomoyo_read_lock().
|
||||
*/
|
||||
static int tomoyo_write_env(struct tomoyo_acl_param *param)
|
||||
{
|
||||
struct tomoyo_env_acl e = { .head.type = TOMOYO_TYPE_ENV_ACL };
|
||||
int error = -ENOMEM;
|
||||
const char *data = tomoyo_read_token(param);
|
||||
|
||||
if (!tomoyo_correct_word(data) || strchr(data, '='))
|
||||
return -EINVAL;
|
||||
e.env = tomoyo_get_name(data);
|
||||
if (!e.env)
|
||||
return error;
|
||||
error = tomoyo_update_domain(&e.head, sizeof(e), param,
|
||||
tomoyo_same_env_acl, NULL);
|
||||
tomoyo_put_name(e.env);
|
||||
return error;
|
||||
}
|
||||
|
||||
/**
|
||||
* tomoyo_write_misc - Update environment variable list.
|
||||
*
|
||||
* @param: Pointer to "struct tomoyo_acl_param".
|
||||
*
|
||||
* Returns 0 on success, negative value otherwise.
|
||||
*/
|
||||
int tomoyo_write_misc(struct tomoyo_acl_param *param)
|
||||
{
|
||||
if (tomoyo_str_starts(¶m->data, "env "))
|
||||
return tomoyo_write_env(param);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
|
@ -555,8 +555,8 @@ static int tomoyo_update_path2_acl(const u8 perm,
|
|||
*
|
||||
* Caller holds tomoyo_read_lock().
|
||||
*/
|
||||
int tomoyo_path_permission(struct tomoyo_request_info *r, u8 operation,
|
||||
const struct tomoyo_path_info *filename)
|
||||
static int tomoyo_path_permission(struct tomoyo_request_info *r, u8 operation,
|
||||
const struct tomoyo_path_info *filename)
|
||||
{
|
||||
int error;
|
||||
|
||||
|
|
@ -570,15 +570,41 @@ int tomoyo_path_permission(struct tomoyo_request_info *r, u8 operation,
|
|||
do {
|
||||
tomoyo_check_acl(r, tomoyo_check_path_acl);
|
||||
error = tomoyo_audit_path_log(r);
|
||||
/*
|
||||
* Do not retry for execute request, for alias may have
|
||||
* changed.
|
||||
*/
|
||||
} while (error == TOMOYO_RETRY_REQUEST &&
|
||||
operation != TOMOYO_TYPE_EXECUTE);
|
||||
} while (error == TOMOYO_RETRY_REQUEST);
|
||||
return error;
|
||||
}
|
||||
|
||||
/**
|
||||
* tomoyo_execute_permission - Check permission for execute operation.
|
||||
*
|
||||
* @r: Pointer to "struct tomoyo_request_info".
|
||||
* @filename: Filename to check.
|
||||
*
|
||||
* Returns 0 on success, negative value otherwise.
|
||||
*
|
||||
* Caller holds tomoyo_read_lock().
|
||||
*/
|
||||
int tomoyo_execute_permission(struct tomoyo_request_info *r,
|
||||
const struct tomoyo_path_info *filename)
|
||||
{
|
||||
/*
|
||||
* Unlike other permission checks, this check is done regardless of
|
||||
* profile mode settings in order to check for domain transition
|
||||
* preference.
|
||||
*/
|
||||
r->type = TOMOYO_MAC_FILE_EXECUTE;
|
||||
r->mode = tomoyo_get_mode(r->domain->ns, r->profile, r->type);
|
||||
r->param_type = TOMOYO_TYPE_PATH_ACL;
|
||||
r->param.path.filename = filename;
|
||||
r->param.path.operation = TOMOYO_TYPE_EXECUTE;
|
||||
tomoyo_check_acl(r, tomoyo_check_path_acl);
|
||||
r->ee->transition = r->matched_acl && r->matched_acl->cond ?
|
||||
r->matched_acl->cond->transit : NULL;
|
||||
if (r->mode != TOMOYO_CONFIG_DISABLED)
|
||||
return tomoyo_audit_path_log(r);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* tomoyo_same_path_number_acl - Check for duplicated "struct tomoyo_path_number_acl" entry.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -8,36 +8,26 @@
|
|||
#include <linux/kthread.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
/**
|
||||
* tomoyo_memory_free - Free memory for elements.
|
||||
*
|
||||
* @ptr: Pointer to allocated memory.
|
||||
*
|
||||
* Returns nothing.
|
||||
*
|
||||
* Caller holds tomoyo_policy_lock mutex.
|
||||
*/
|
||||
static inline void tomoyo_memory_free(void *ptr)
|
||||
{
|
||||
tomoyo_memory_used[TOMOYO_MEMORY_POLICY] -= ksize(ptr);
|
||||
kfree(ptr);
|
||||
}
|
||||
|
||||
/* The list for "struct tomoyo_io_buffer". */
|
||||
static LIST_HEAD(tomoyo_io_buffer_list);
|
||||
/* Lock for protecting tomoyo_io_buffer_list. */
|
||||
static DEFINE_SPINLOCK(tomoyo_io_buffer_list_lock);
|
||||
|
||||
/* Size of an element. */
|
||||
static const u8 tomoyo_element_size[TOMOYO_MAX_POLICY] = {
|
||||
[TOMOYO_ID_GROUP] = sizeof(struct tomoyo_group),
|
||||
[TOMOYO_ID_PATH_GROUP] = sizeof(struct tomoyo_path_group),
|
||||
[TOMOYO_ID_NUMBER_GROUP] = sizeof(struct tomoyo_number_group),
|
||||
[TOMOYO_ID_AGGREGATOR] = sizeof(struct tomoyo_aggregator),
|
||||
[TOMOYO_ID_TRANSITION_CONTROL] =
|
||||
sizeof(struct tomoyo_transition_control),
|
||||
[TOMOYO_ID_MANAGER] = sizeof(struct tomoyo_manager),
|
||||
/* [TOMOYO_ID_CONDITION] = "struct tomoyo_condition"->size, */
|
||||
/* [TOMOYO_ID_NAME] = "struct tomoyo_name"->size, */
|
||||
/* [TOMOYO_ID_ACL] =
|
||||
tomoyo_acl_size["struct tomoyo_acl_info"->type], */
|
||||
[TOMOYO_ID_DOMAIN] = sizeof(struct tomoyo_domain_info),
|
||||
};
|
||||
|
||||
/* Size of a domain ACL element. */
|
||||
static const u8 tomoyo_acl_size[] = {
|
||||
[TOMOYO_TYPE_PATH_ACL] = sizeof(struct tomoyo_path_acl),
|
||||
[TOMOYO_TYPE_PATH2_ACL] = sizeof(struct tomoyo_path2_acl),
|
||||
[TOMOYO_TYPE_PATH_NUMBER_ACL] = sizeof(struct tomoyo_path_number_acl),
|
||||
[TOMOYO_TYPE_MKDEV_ACL] = sizeof(struct tomoyo_mkdev_acl),
|
||||
[TOMOYO_TYPE_MOUNT_ACL] = sizeof(struct tomoyo_mount_acl),
|
||||
};
|
||||
|
||||
/**
|
||||
* tomoyo_struct_used_by_io_buffer - Check whether the list element is used by /sys/kernel/security/tomoyo/ users or not.
|
||||
*
|
||||
|
|
@ -55,15 +45,11 @@ static bool tomoyo_struct_used_by_io_buffer(const struct list_head *element)
|
|||
list_for_each_entry(head, &tomoyo_io_buffer_list, list) {
|
||||
head->users++;
|
||||
spin_unlock(&tomoyo_io_buffer_list_lock);
|
||||
if (mutex_lock_interruptible(&head->io_sem)) {
|
||||
in_use = true;
|
||||
goto out;
|
||||
}
|
||||
mutex_lock(&head->io_sem);
|
||||
if (head->r.domain == element || head->r.group == element ||
|
||||
head->r.acl == element || &head->w.domain->list == element)
|
||||
in_use = true;
|
||||
mutex_unlock(&head->io_sem);
|
||||
out:
|
||||
spin_lock(&tomoyo_io_buffer_list_lock);
|
||||
head->users--;
|
||||
if (in_use)
|
||||
|
|
@ -77,15 +63,14 @@ out:
|
|||
* tomoyo_name_used_by_io_buffer - Check whether the string is used by /sys/kernel/security/tomoyo/ users or not.
|
||||
*
|
||||
* @string: String to check.
|
||||
* @size: Memory allocated for @string .
|
||||
*
|
||||
* Returns true if @string is used by /sys/kernel/security/tomoyo/ users,
|
||||
* false otherwise.
|
||||
*/
|
||||
static bool tomoyo_name_used_by_io_buffer(const char *string,
|
||||
const size_t size)
|
||||
static bool tomoyo_name_used_by_io_buffer(const char *string)
|
||||
{
|
||||
struct tomoyo_io_buffer *head;
|
||||
const size_t size = strlen(string) + 1;
|
||||
bool in_use = false;
|
||||
|
||||
spin_lock(&tomoyo_io_buffer_list_lock);
|
||||
|
|
@ -93,10 +78,7 @@ static bool tomoyo_name_used_by_io_buffer(const char *string,
|
|||
int i;
|
||||
head->users++;
|
||||
spin_unlock(&tomoyo_io_buffer_list_lock);
|
||||
if (mutex_lock_interruptible(&head->io_sem)) {
|
||||
in_use = true;
|
||||
goto out;
|
||||
}
|
||||
mutex_lock(&head->io_sem);
|
||||
for (i = 0; i < TOMOYO_MAX_IO_READ_QUEUE; i++) {
|
||||
const char *w = head->r.w[i];
|
||||
if (w < string || w > string + size)
|
||||
|
|
@ -105,7 +87,6 @@ static bool tomoyo_name_used_by_io_buffer(const char *string,
|
|||
break;
|
||||
}
|
||||
mutex_unlock(&head->io_sem);
|
||||
out:
|
||||
spin_lock(&tomoyo_io_buffer_list_lock);
|
||||
head->users--;
|
||||
if (in_use)
|
||||
|
|
@ -115,84 +96,6 @@ out:
|
|||
return in_use;
|
||||
}
|
||||
|
||||
/* Structure for garbage collection. */
|
||||
struct tomoyo_gc {
|
||||
struct list_head list;
|
||||
enum tomoyo_policy_id type;
|
||||
size_t size;
|
||||
struct list_head *element;
|
||||
};
|
||||
/* List of entries to be deleted. */
|
||||
static LIST_HEAD(tomoyo_gc_list);
|
||||
/* Length of tomoyo_gc_list. */
|
||||
static int tomoyo_gc_list_len;
|
||||
|
||||
/**
|
||||
* tomoyo_add_to_gc - Add an entry to to be deleted list.
|
||||
*
|
||||
* @type: One of values in "enum tomoyo_policy_id".
|
||||
* @element: Pointer to "struct list_head".
|
||||
*
|
||||
* Returns true on success, false otherwise.
|
||||
*
|
||||
* Caller holds tomoyo_policy_lock mutex.
|
||||
*
|
||||
* Adding an entry needs kmalloc(). Thus, if we try to add thousands of
|
||||
* entries at once, it will take too long time. Thus, do not add more than 128
|
||||
* entries per a scan. But to be able to handle worst case where all entries
|
||||
* are in-use, we accept one more entry per a scan.
|
||||
*
|
||||
* If we use singly linked list using "struct list_head"->prev (which is
|
||||
* LIST_POISON2), we can avoid kmalloc().
|
||||
*/
|
||||
static bool tomoyo_add_to_gc(const int type, struct list_head *element)
|
||||
{
|
||||
struct tomoyo_gc *entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
|
||||
if (!entry)
|
||||
return false;
|
||||
entry->type = type;
|
||||
if (type == TOMOYO_ID_ACL)
|
||||
entry->size = tomoyo_acl_size[
|
||||
container_of(element,
|
||||
typeof(struct tomoyo_acl_info),
|
||||
list)->type];
|
||||
else if (type == TOMOYO_ID_NAME)
|
||||
entry->size = strlen(container_of(element,
|
||||
typeof(struct tomoyo_name),
|
||||
head.list)->entry.name) + 1;
|
||||
else if (type == TOMOYO_ID_CONDITION)
|
||||
entry->size =
|
||||
container_of(element, typeof(struct tomoyo_condition),
|
||||
head.list)->size;
|
||||
else
|
||||
entry->size = tomoyo_element_size[type];
|
||||
entry->element = element;
|
||||
list_add(&entry->list, &tomoyo_gc_list);
|
||||
list_del_rcu(element);
|
||||
return tomoyo_gc_list_len++ < 128;
|
||||
}
|
||||
|
||||
/**
|
||||
* tomoyo_element_linked_by_gc - Validate next element of an entry.
|
||||
*
|
||||
* @element: Pointer to an element.
|
||||
* @size: Size of @element in byte.
|
||||
*
|
||||
* Returns true if @element is linked by other elements in the garbage
|
||||
* collector's queue, false otherwise.
|
||||
*/
|
||||
static bool tomoyo_element_linked_by_gc(const u8 *element, const size_t size)
|
||||
{
|
||||
struct tomoyo_gc *p;
|
||||
list_for_each_entry(p, &tomoyo_gc_list, list) {
|
||||
const u8 *ptr = (const u8 *) p->element->next;
|
||||
if (ptr < element || element + size < ptr)
|
||||
continue;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* tomoyo_del_transition_control - Delete members in "struct tomoyo_transition_control".
|
||||
*
|
||||
|
|
@ -200,7 +103,7 @@ static bool tomoyo_element_linked_by_gc(const u8 *element, const size_t size)
|
|||
*
|
||||
* Returns nothing.
|
||||
*/
|
||||
static void tomoyo_del_transition_control(struct list_head *element)
|
||||
static inline void tomoyo_del_transition_control(struct list_head *element)
|
||||
{
|
||||
struct tomoyo_transition_control *ptr =
|
||||
container_of(element, typeof(*ptr), head.list);
|
||||
|
|
@ -215,7 +118,7 @@ static void tomoyo_del_transition_control(struct list_head *element)
|
|||
*
|
||||
* Returns nothing.
|
||||
*/
|
||||
static void tomoyo_del_aggregator(struct list_head *element)
|
||||
static inline void tomoyo_del_aggregator(struct list_head *element)
|
||||
{
|
||||
struct tomoyo_aggregator *ptr =
|
||||
container_of(element, typeof(*ptr), head.list);
|
||||
|
|
@ -230,7 +133,7 @@ static void tomoyo_del_aggregator(struct list_head *element)
|
|||
*
|
||||
* Returns nothing.
|
||||
*/
|
||||
static void tomoyo_del_manager(struct list_head *element)
|
||||
static inline void tomoyo_del_manager(struct list_head *element)
|
||||
{
|
||||
struct tomoyo_manager *ptr =
|
||||
container_of(element, typeof(*ptr), head.list);
|
||||
|
|
@ -293,6 +196,38 @@ static void tomoyo_del_acl(struct list_head *element)
|
|||
tomoyo_put_number_union(&entry->flags);
|
||||
}
|
||||
break;
|
||||
case TOMOYO_TYPE_ENV_ACL:
|
||||
{
|
||||
struct tomoyo_env_acl *entry =
|
||||
container_of(acl, typeof(*entry), head);
|
||||
|
||||
tomoyo_put_name(entry->env);
|
||||
}
|
||||
break;
|
||||
case TOMOYO_TYPE_INET_ACL:
|
||||
{
|
||||
struct tomoyo_inet_acl *entry =
|
||||
container_of(acl, typeof(*entry), head);
|
||||
|
||||
tomoyo_put_group(entry->address.group);
|
||||
tomoyo_put_number_union(&entry->port);
|
||||
}
|
||||
break;
|
||||
case TOMOYO_TYPE_UNIX_ACL:
|
||||
{
|
||||
struct tomoyo_unix_acl *entry =
|
||||
container_of(acl, typeof(*entry), head);
|
||||
|
||||
tomoyo_put_name_union(&entry->name);
|
||||
}
|
||||
break;
|
||||
case TOMOYO_TYPE_MANUAL_TASK_ACL:
|
||||
{
|
||||
struct tomoyo_task_acl *entry =
|
||||
container_of(acl, typeof(*entry), head);
|
||||
tomoyo_put_name(entry->domainname);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -301,44 +236,26 @@ static void tomoyo_del_acl(struct list_head *element)
|
|||
*
|
||||
* @element: Pointer to "struct list_head".
|
||||
*
|
||||
* Returns true if deleted, false otherwise.
|
||||
* Returns nothing.
|
||||
*
|
||||
* Caller holds tomoyo_policy_lock mutex.
|
||||
*/
|
||||
static bool tomoyo_del_domain(struct list_head *element)
|
||||
static inline void tomoyo_del_domain(struct list_head *element)
|
||||
{
|
||||
struct tomoyo_domain_info *domain =
|
||||
container_of(element, typeof(*domain), list);
|
||||
struct tomoyo_acl_info *acl;
|
||||
struct tomoyo_acl_info *tmp;
|
||||
/*
|
||||
* Since we don't protect whole execve() operation using SRCU,
|
||||
* we need to recheck domain->users at this point.
|
||||
*
|
||||
* (1) Reader starts SRCU section upon execve().
|
||||
* (2) Reader traverses tomoyo_domain_list and finds this domain.
|
||||
* (3) Writer marks this domain as deleted.
|
||||
* (4) Garbage collector removes this domain from tomoyo_domain_list
|
||||
* because this domain is marked as deleted and used by nobody.
|
||||
* (5) Reader saves reference to this domain into
|
||||
* "struct linux_binprm"->cred->security .
|
||||
* (6) Reader finishes SRCU section, although execve() operation has
|
||||
* not finished yet.
|
||||
* (7) Garbage collector waits for SRCU synchronization.
|
||||
* (8) Garbage collector kfree() this domain because this domain is
|
||||
* used by nobody.
|
||||
* (9) Reader finishes execve() operation and restores this domain from
|
||||
* "struct linux_binprm"->cred->security.
|
||||
*
|
||||
* By updating domain->users at (5), we can solve this race problem
|
||||
* by rechecking domain->users at (8).
|
||||
* Since this domain is referenced from neither
|
||||
* "struct tomoyo_io_buffer" nor "struct cred"->security, we can delete
|
||||
* elements without checking for is_deleted flag.
|
||||
*/
|
||||
if (atomic_read(&domain->users))
|
||||
return false;
|
||||
list_for_each_entry_safe(acl, tmp, &domain->acl_info_list, list) {
|
||||
tomoyo_del_acl(&acl->list);
|
||||
tomoyo_memory_free(acl);
|
||||
}
|
||||
tomoyo_put_name(domain->domainname);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -387,10 +304,9 @@ void tomoyo_del_condition(struct list_head *element)
|
|||
*
|
||||
* Returns nothing.
|
||||
*/
|
||||
static void tomoyo_del_name(struct list_head *element)
|
||||
static inline void tomoyo_del_name(struct list_head *element)
|
||||
{
|
||||
const struct tomoyo_name *ptr =
|
||||
container_of(element, typeof(*ptr), head.list);
|
||||
/* Nothing to do. */
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -400,7 +316,7 @@ static void tomoyo_del_name(struct list_head *element)
|
|||
*
|
||||
* Returns nothing.
|
||||
*/
|
||||
static void tomoyo_del_path_group(struct list_head *element)
|
||||
static inline void tomoyo_del_path_group(struct list_head *element)
|
||||
{
|
||||
struct tomoyo_path_group *member =
|
||||
container_of(element, typeof(*member), head.list);
|
||||
|
|
@ -414,13 +330,25 @@ static void tomoyo_del_path_group(struct list_head *element)
|
|||
*
|
||||
* Returns nothing.
|
||||
*/
|
||||
static void tomoyo_del_group(struct list_head *element)
|
||||
static inline void tomoyo_del_group(struct list_head *element)
|
||||
{
|
||||
struct tomoyo_group *group =
|
||||
container_of(element, typeof(*group), head.list);
|
||||
tomoyo_put_name(group->group_name);
|
||||
}
|
||||
|
||||
/**
|
||||
* tomoyo_del_address_group - Delete members in "struct tomoyo_address_group".
|
||||
*
|
||||
* @element: Pointer to "struct list_head".
|
||||
*
|
||||
* Returns nothing.
|
||||
*/
|
||||
static inline void tomoyo_del_address_group(struct list_head *element)
|
||||
{
|
||||
/* Nothing to do. */
|
||||
}
|
||||
|
||||
/**
|
||||
* tomoyo_del_number_group - Delete members in "struct tomoyo_number_group".
|
||||
*
|
||||
|
|
@ -428,10 +356,110 @@ static void tomoyo_del_group(struct list_head *element)
|
|||
*
|
||||
* Returns nothing.
|
||||
*/
|
||||
static void tomoyo_del_number_group(struct list_head *element)
|
||||
static inline void tomoyo_del_number_group(struct list_head *element)
|
||||
{
|
||||
struct tomoyo_number_group *member =
|
||||
container_of(element, typeof(*member), head.list);
|
||||
/* Nothing to do. */
|
||||
}
|
||||
|
||||
/**
|
||||
* tomoyo_try_to_gc - Try to kfree() an entry.
|
||||
*
|
||||
* @type: One of values in "enum tomoyo_policy_id".
|
||||
* @element: Pointer to "struct list_head".
|
||||
*
|
||||
* Returns nothing.
|
||||
*
|
||||
* Caller holds tomoyo_policy_lock mutex.
|
||||
*/
|
||||
static void tomoyo_try_to_gc(const enum tomoyo_policy_id type,
|
||||
struct list_head *element)
|
||||
{
|
||||
/*
|
||||
* __list_del_entry() guarantees that the list element became no longer
|
||||
* reachable from the list which the element was originally on (e.g.
|
||||
* tomoyo_domain_list). Also, synchronize_srcu() guarantees that the
|
||||
* list element became no longer referenced by syscall users.
|
||||
*/
|
||||
__list_del_entry(element);
|
||||
mutex_unlock(&tomoyo_policy_lock);
|
||||
synchronize_srcu(&tomoyo_ss);
|
||||
/*
|
||||
* However, there are two users which may still be using the list
|
||||
* element. We need to defer until both users forget this element.
|
||||
*
|
||||
* Don't kfree() until "struct tomoyo_io_buffer"->r.{domain,group,acl}
|
||||
* and "struct tomoyo_io_buffer"->w.domain forget this element.
|
||||
*/
|
||||
if (tomoyo_struct_used_by_io_buffer(element))
|
||||
goto reinject;
|
||||
switch (type) {
|
||||
case TOMOYO_ID_TRANSITION_CONTROL:
|
||||
tomoyo_del_transition_control(element);
|
||||
break;
|
||||
case TOMOYO_ID_MANAGER:
|
||||
tomoyo_del_manager(element);
|
||||
break;
|
||||
case TOMOYO_ID_AGGREGATOR:
|
||||
tomoyo_del_aggregator(element);
|
||||
break;
|
||||
case TOMOYO_ID_GROUP:
|
||||
tomoyo_del_group(element);
|
||||
break;
|
||||
case TOMOYO_ID_PATH_GROUP:
|
||||
tomoyo_del_path_group(element);
|
||||
break;
|
||||
case TOMOYO_ID_ADDRESS_GROUP:
|
||||
tomoyo_del_address_group(element);
|
||||
break;
|
||||
case TOMOYO_ID_NUMBER_GROUP:
|
||||
tomoyo_del_number_group(element);
|
||||
break;
|
||||
case TOMOYO_ID_CONDITION:
|
||||
tomoyo_del_condition(element);
|
||||
break;
|
||||
case TOMOYO_ID_NAME:
|
||||
/*
|
||||
* Don't kfree() until all "struct tomoyo_io_buffer"->r.w[]
|
||||
* forget this element.
|
||||
*/
|
||||
if (tomoyo_name_used_by_io_buffer
|
||||
(container_of(element, typeof(struct tomoyo_name),
|
||||
head.list)->entry.name))
|
||||
goto reinject;
|
||||
tomoyo_del_name(element);
|
||||
break;
|
||||
case TOMOYO_ID_ACL:
|
||||
tomoyo_del_acl(element);
|
||||
break;
|
||||
case TOMOYO_ID_DOMAIN:
|
||||
/*
|
||||
* Don't kfree() until all "struct cred"->security forget this
|
||||
* element.
|
||||
*/
|
||||
if (atomic_read(&container_of
|
||||
(element, typeof(struct tomoyo_domain_info),
|
||||
list)->users))
|
||||
goto reinject;
|
||||
break;
|
||||
case TOMOYO_MAX_POLICY:
|
||||
break;
|
||||
}
|
||||
mutex_lock(&tomoyo_policy_lock);
|
||||
if (type == TOMOYO_ID_DOMAIN)
|
||||
tomoyo_del_domain(element);
|
||||
tomoyo_memory_free(element);
|
||||
return;
|
||||
reinject:
|
||||
/*
|
||||
* We can safely reinject this element here bacause
|
||||
* (1) Appending list elements and removing list elements are protected
|
||||
* by tomoyo_policy_lock mutex.
|
||||
* (2) Only this function removes list elements and this function is
|
||||
* exclusively executed by tomoyo_gc_mutex mutex.
|
||||
* are true.
|
||||
*/
|
||||
mutex_lock(&tomoyo_policy_lock);
|
||||
list_add_rcu(element, element->prev);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -440,19 +468,19 @@ static void tomoyo_del_number_group(struct list_head *element)
|
|||
* @id: One of values in "enum tomoyo_policy_id".
|
||||
* @member_list: Pointer to "struct list_head".
|
||||
*
|
||||
* Returns true if some elements are deleted, false otherwise.
|
||||
* Returns nothing.
|
||||
*/
|
||||
static bool tomoyo_collect_member(const enum tomoyo_policy_id id,
|
||||
static void tomoyo_collect_member(const enum tomoyo_policy_id id,
|
||||
struct list_head *member_list)
|
||||
{
|
||||
struct tomoyo_acl_head *member;
|
||||
list_for_each_entry(member, member_list, list) {
|
||||
struct tomoyo_acl_head *tmp;
|
||||
list_for_each_entry_safe(member, tmp, member_list, list) {
|
||||
if (!member->is_deleted)
|
||||
continue;
|
||||
if (!tomoyo_add_to_gc(id, &member->list))
|
||||
return false;
|
||||
member->is_deleted = TOMOYO_GC_IN_PROGRESS;
|
||||
tomoyo_try_to_gc(id, &member->list);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -460,22 +488,22 @@ static bool tomoyo_collect_member(const enum tomoyo_policy_id id,
|
|||
*
|
||||
* @list: Pointer to "struct list_head".
|
||||
*
|
||||
* Returns true if some elements are deleted, false otherwise.
|
||||
* Returns nothing.
|
||||
*/
|
||||
static bool tomoyo_collect_acl(struct list_head *list)
|
||||
static void tomoyo_collect_acl(struct list_head *list)
|
||||
{
|
||||
struct tomoyo_acl_info *acl;
|
||||
list_for_each_entry(acl, list, list) {
|
||||
struct tomoyo_acl_info *tmp;
|
||||
list_for_each_entry_safe(acl, tmp, list, list) {
|
||||
if (!acl->is_deleted)
|
||||
continue;
|
||||
if (!tomoyo_add_to_gc(TOMOYO_ID_ACL, &acl->list))
|
||||
return false;
|
||||
acl->is_deleted = TOMOYO_GC_IN_PROGRESS;
|
||||
tomoyo_try_to_gc(TOMOYO_ID_ACL, &acl->list);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* tomoyo_collect_entry - Scan lists for deleted elements.
|
||||
* tomoyo_collect_entry - Try to kfree() deleted elements.
|
||||
*
|
||||
* Returns nothing.
|
||||
*/
|
||||
|
|
@ -484,174 +512,82 @@ static void tomoyo_collect_entry(void)
|
|||
int i;
|
||||
enum tomoyo_policy_id id;
|
||||
struct tomoyo_policy_namespace *ns;
|
||||
int idx;
|
||||
if (mutex_lock_interruptible(&tomoyo_policy_lock))
|
||||
return;
|
||||
idx = tomoyo_read_lock();
|
||||
mutex_lock(&tomoyo_policy_lock);
|
||||
{
|
||||
struct tomoyo_domain_info *domain;
|
||||
list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) {
|
||||
if (!tomoyo_collect_acl(&domain->acl_info_list))
|
||||
goto unlock;
|
||||
struct tomoyo_domain_info *tmp;
|
||||
list_for_each_entry_safe(domain, tmp, &tomoyo_domain_list,
|
||||
list) {
|
||||
tomoyo_collect_acl(&domain->acl_info_list);
|
||||
if (!domain->is_deleted || atomic_read(&domain->users))
|
||||
continue;
|
||||
/*
|
||||
* Nobody is referring this domain. But somebody may
|
||||
* refer this domain after successful execve().
|
||||
* We recheck domain->users after SRCU synchronization.
|
||||
*/
|
||||
if (!tomoyo_add_to_gc(TOMOYO_ID_DOMAIN, &domain->list))
|
||||
goto unlock;
|
||||
tomoyo_try_to_gc(TOMOYO_ID_DOMAIN, &domain->list);
|
||||
}
|
||||
}
|
||||
list_for_each_entry_rcu(ns, &tomoyo_namespace_list, namespace_list) {
|
||||
list_for_each_entry(ns, &tomoyo_namespace_list, namespace_list) {
|
||||
for (id = 0; id < TOMOYO_MAX_POLICY; id++)
|
||||
if (!tomoyo_collect_member(id, &ns->policy_list[id]))
|
||||
goto unlock;
|
||||
tomoyo_collect_member(id, &ns->policy_list[id]);
|
||||
for (i = 0; i < TOMOYO_MAX_ACL_GROUPS; i++)
|
||||
if (!tomoyo_collect_acl(&ns->acl_group[i]))
|
||||
goto unlock;
|
||||
tomoyo_collect_acl(&ns->acl_group[i]);
|
||||
}
|
||||
{
|
||||
struct tomoyo_shared_acl_head *ptr;
|
||||
struct tomoyo_shared_acl_head *tmp;
|
||||
list_for_each_entry_safe(ptr, tmp, &tomoyo_condition_list,
|
||||
list) {
|
||||
if (atomic_read(&ptr->users) > 0)
|
||||
continue;
|
||||
atomic_set(&ptr->users, TOMOYO_GC_IN_PROGRESS);
|
||||
tomoyo_try_to_gc(TOMOYO_ID_CONDITION, &ptr->list);
|
||||
}
|
||||
}
|
||||
list_for_each_entry(ns, &tomoyo_namespace_list, namespace_list) {
|
||||
for (i = 0; i < TOMOYO_MAX_GROUP; i++) {
|
||||
struct list_head *list = &ns->group_list[i];
|
||||
struct tomoyo_group *group;
|
||||
struct tomoyo_group *tmp;
|
||||
switch (i) {
|
||||
case 0:
|
||||
id = TOMOYO_ID_PATH_GROUP;
|
||||
break;
|
||||
default:
|
||||
case 1:
|
||||
id = TOMOYO_ID_NUMBER_GROUP;
|
||||
break;
|
||||
default:
|
||||
id = TOMOYO_ID_ADDRESS_GROUP;
|
||||
break;
|
||||
}
|
||||
list_for_each_entry(group, list, head.list) {
|
||||
if (!tomoyo_collect_member
|
||||
(id, &group->member_list))
|
||||
goto unlock;
|
||||
list_for_each_entry_safe(group, tmp, list, head.list) {
|
||||
tomoyo_collect_member(id, &group->member_list);
|
||||
if (!list_empty(&group->member_list) ||
|
||||
atomic_read(&group->head.users))
|
||||
atomic_read(&group->head.users) > 0)
|
||||
continue;
|
||||
if (!tomoyo_add_to_gc(TOMOYO_ID_GROUP,
|
||||
&group->head.list))
|
||||
goto unlock;
|
||||
atomic_set(&group->head.users,
|
||||
TOMOYO_GC_IN_PROGRESS);
|
||||
tomoyo_try_to_gc(TOMOYO_ID_GROUP,
|
||||
&group->head.list);
|
||||
}
|
||||
}
|
||||
}
|
||||
id = TOMOYO_ID_CONDITION;
|
||||
for (i = 0; i < TOMOYO_MAX_HASH + 1; i++) {
|
||||
struct list_head *list = !i ?
|
||||
&tomoyo_condition_list : &tomoyo_name_list[i - 1];
|
||||
for (i = 0; i < TOMOYO_MAX_HASH; i++) {
|
||||
struct list_head *list = &tomoyo_name_list[i];
|
||||
struct tomoyo_shared_acl_head *ptr;
|
||||
list_for_each_entry(ptr, list, list) {
|
||||
if (atomic_read(&ptr->users))
|
||||
struct tomoyo_shared_acl_head *tmp;
|
||||
list_for_each_entry_safe(ptr, tmp, list, list) {
|
||||
if (atomic_read(&ptr->users) > 0)
|
||||
continue;
|
||||
if (!tomoyo_add_to_gc(id, &ptr->list))
|
||||
goto unlock;
|
||||
atomic_set(&ptr->users, TOMOYO_GC_IN_PROGRESS);
|
||||
tomoyo_try_to_gc(TOMOYO_ID_NAME, &ptr->list);
|
||||
}
|
||||
id = TOMOYO_ID_NAME;
|
||||
}
|
||||
unlock:
|
||||
tomoyo_read_unlock(idx);
|
||||
mutex_unlock(&tomoyo_policy_lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* tomoyo_kfree_entry - Delete entries in tomoyo_gc_list.
|
||||
*
|
||||
* Returns true if some entries were kfree()d, false otherwise.
|
||||
*/
|
||||
static bool tomoyo_kfree_entry(void)
|
||||
{
|
||||
struct tomoyo_gc *p;
|
||||
struct tomoyo_gc *tmp;
|
||||
bool result = false;
|
||||
|
||||
list_for_each_entry_safe(p, tmp, &tomoyo_gc_list, list) {
|
||||
struct list_head *element = p->element;
|
||||
|
||||
/*
|
||||
* list_del_rcu() in tomoyo_add_to_gc() guarantees that the
|
||||
* list element became no longer reachable from the list which
|
||||
* the element was originally on (e.g. tomoyo_domain_list).
|
||||
* Also, synchronize_srcu() in tomoyo_gc_thread() guarantees
|
||||
* that the list element became no longer referenced by syscall
|
||||
* users.
|
||||
*
|
||||
* However, there are three users which may still be using the
|
||||
* list element. We need to defer until all of these users
|
||||
* forget the list element.
|
||||
*
|
||||
* Firstly, defer until "struct tomoyo_io_buffer"->r.{domain,
|
||||
* group,acl} and "struct tomoyo_io_buffer"->w.domain forget
|
||||
* the list element.
|
||||
*/
|
||||
if (tomoyo_struct_used_by_io_buffer(element))
|
||||
continue;
|
||||
/*
|
||||
* Secondly, defer until all other elements in the
|
||||
* tomoyo_gc_list list forget the list element.
|
||||
*/
|
||||
if (tomoyo_element_linked_by_gc((const u8 *) element, p->size))
|
||||
continue;
|
||||
switch (p->type) {
|
||||
case TOMOYO_ID_TRANSITION_CONTROL:
|
||||
tomoyo_del_transition_control(element);
|
||||
break;
|
||||
case TOMOYO_ID_AGGREGATOR:
|
||||
tomoyo_del_aggregator(element);
|
||||
break;
|
||||
case TOMOYO_ID_MANAGER:
|
||||
tomoyo_del_manager(element);
|
||||
break;
|
||||
case TOMOYO_ID_CONDITION:
|
||||
tomoyo_del_condition(element);
|
||||
break;
|
||||
case TOMOYO_ID_NAME:
|
||||
/*
|
||||
* Thirdly, defer until all "struct tomoyo_io_buffer"
|
||||
* ->r.w[] forget the list element.
|
||||
*/
|
||||
if (tomoyo_name_used_by_io_buffer(
|
||||
container_of(element, typeof(struct tomoyo_name),
|
||||
head.list)->entry.name, p->size))
|
||||
continue;
|
||||
tomoyo_del_name(element);
|
||||
break;
|
||||
case TOMOYO_ID_ACL:
|
||||
tomoyo_del_acl(element);
|
||||
break;
|
||||
case TOMOYO_ID_DOMAIN:
|
||||
if (!tomoyo_del_domain(element))
|
||||
continue;
|
||||
break;
|
||||
case TOMOYO_ID_PATH_GROUP:
|
||||
tomoyo_del_path_group(element);
|
||||
break;
|
||||
case TOMOYO_ID_GROUP:
|
||||
tomoyo_del_group(element);
|
||||
break;
|
||||
case TOMOYO_ID_NUMBER_GROUP:
|
||||
tomoyo_del_number_group(element);
|
||||
break;
|
||||
case TOMOYO_MAX_POLICY:
|
||||
break;
|
||||
}
|
||||
tomoyo_memory_free(element);
|
||||
list_del(&p->list);
|
||||
kfree(p);
|
||||
tomoyo_gc_list_len--;
|
||||
result = true;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* tomoyo_gc_thread - Garbage collector thread function.
|
||||
*
|
||||
* @unused: Unused.
|
||||
*
|
||||
* In case OOM-killer choose this thread for termination, we create this thread
|
||||
* as a short live thread whenever /sys/kernel/security/tomoyo/ interface was
|
||||
* close()d.
|
||||
*
|
||||
* Returns 0.
|
||||
*/
|
||||
static int tomoyo_gc_thread(void *unused)
|
||||
|
|
@ -660,13 +596,7 @@ static int tomoyo_gc_thread(void *unused)
|
|||
static DEFINE_MUTEX(tomoyo_gc_mutex);
|
||||
if (!mutex_trylock(&tomoyo_gc_mutex))
|
||||
goto out;
|
||||
daemonize("GC for TOMOYO");
|
||||
do {
|
||||
tomoyo_collect_entry();
|
||||
if (list_empty(&tomoyo_gc_list))
|
||||
break;
|
||||
synchronize_srcu(&tomoyo_ss);
|
||||
} while (tomoyo_kfree_entry());
|
||||
tomoyo_collect_entry();
|
||||
{
|
||||
struct tomoyo_io_buffer *head;
|
||||
struct tomoyo_io_buffer *tmp;
|
||||
|
|
|
|||
|
|
@ -42,7 +42,26 @@ static bool tomoyo_same_number_group(const struct tomoyo_acl_head *a,
|
|||
}
|
||||
|
||||
/**
|
||||
* tomoyo_write_group - Write "struct tomoyo_path_group"/"struct tomoyo_number_group" list.
|
||||
* tomoyo_same_address_group - Check for duplicated "struct tomoyo_address_group" entry.
|
||||
*
|
||||
* @a: Pointer to "struct tomoyo_acl_head".
|
||||
* @b: Pointer to "struct tomoyo_acl_head".
|
||||
*
|
||||
* Returns true if @a == @b, false otherwise.
|
||||
*/
|
||||
static bool tomoyo_same_address_group(const struct tomoyo_acl_head *a,
|
||||
const struct tomoyo_acl_head *b)
|
||||
{
|
||||
const struct tomoyo_address_group *p1 = container_of(a, typeof(*p1),
|
||||
head);
|
||||
const struct tomoyo_address_group *p2 = container_of(b, typeof(*p2),
|
||||
head);
|
||||
|
||||
return tomoyo_same_ipaddr_union(&p1->address, &p2->address);
|
||||
}
|
||||
|
||||
/**
|
||||
* tomoyo_write_group - Write "struct tomoyo_path_group"/"struct tomoyo_number_group"/"struct tomoyo_address_group" list.
|
||||
*
|
||||
* @param: Pointer to "struct tomoyo_acl_param".
|
||||
* @type: Type of this group.
|
||||
|
|
@ -77,6 +96,14 @@ int tomoyo_write_group(struct tomoyo_acl_param *param, const u8 type)
|
|||
* tomoyo_put_number_union() is not needed because
|
||||
* param->data[0] != '@'.
|
||||
*/
|
||||
} else {
|
||||
struct tomoyo_address_group e = { };
|
||||
|
||||
if (param->data[0] == '@' ||
|
||||
!tomoyo_parse_ipaddr_union(param, &e.address))
|
||||
goto out;
|
||||
error = tomoyo_update_policy(&e.head, sizeof(e), param,
|
||||
tomoyo_same_address_group);
|
||||
}
|
||||
out:
|
||||
tomoyo_put_group(group);
|
||||
|
|
@ -137,3 +164,35 @@ bool tomoyo_number_matches_group(const unsigned long min,
|
|||
}
|
||||
return matched;
|
||||
}
|
||||
|
||||
/**
|
||||
* tomoyo_address_matches_group - Check whether the given address matches members of the given address group.
|
||||
*
|
||||
* @is_ipv6: True if @address is an IPv6 address.
|
||||
* @address: An IPv4 or IPv6 address.
|
||||
* @group: Pointer to "struct tomoyo_address_group".
|
||||
*
|
||||
* Returns true if @address matches addresses in @group group, false otherwise.
|
||||
*
|
||||
* Caller holds tomoyo_read_lock().
|
||||
*/
|
||||
bool tomoyo_address_matches_group(const bool is_ipv6, const __be32 *address,
|
||||
const struct tomoyo_group *group)
|
||||
{
|
||||
struct tomoyo_address_group *member;
|
||||
bool matched = false;
|
||||
const u8 size = is_ipv6 ? 16 : 4;
|
||||
|
||||
list_for_each_entry_rcu(member, &group->member_list, head.list) {
|
||||
if (member->head.is_deleted)
|
||||
continue;
|
||||
if (member->address.is_ipv6 != is_ipv6)
|
||||
continue;
|
||||
if (memcmp(&member->address.ip[0], address, size) > 0 ||
|
||||
memcmp(address, &member->address.ip[1], size) > 0)
|
||||
continue;
|
||||
matched = true;
|
||||
break;
|
||||
}
|
||||
return matched;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,8 +27,6 @@ void tomoyo_warn_oom(const char *function)
|
|||
panic("MAC Initialization failed.\n");
|
||||
}
|
||||
|
||||
/* Lock for protecting tomoyo_memory_used. */
|
||||
static DEFINE_SPINLOCK(tomoyo_policy_memory_lock);
|
||||
/* Memoy currently used by policy/audit log/query. */
|
||||
unsigned int tomoyo_memory_used[TOMOYO_MAX_MEMORY_STAT];
|
||||
/* Memory quota for "policy"/"audit log"/"query". */
|
||||
|
|
@ -42,22 +40,19 @@ unsigned int tomoyo_memory_quota[TOMOYO_MAX_MEMORY_STAT];
|
|||
* Returns true on success, false otherwise.
|
||||
*
|
||||
* Returns true if @ptr is not NULL and quota not exceeded, false otherwise.
|
||||
*
|
||||
* Caller holds tomoyo_policy_lock mutex.
|
||||
*/
|
||||
bool tomoyo_memory_ok(void *ptr)
|
||||
{
|
||||
if (ptr) {
|
||||
const size_t s = ksize(ptr);
|
||||
bool result;
|
||||
spin_lock(&tomoyo_policy_memory_lock);
|
||||
tomoyo_memory_used[TOMOYO_MEMORY_POLICY] += s;
|
||||
result = !tomoyo_memory_quota[TOMOYO_MEMORY_POLICY] ||
|
||||
tomoyo_memory_used[TOMOYO_MEMORY_POLICY] <=
|
||||
tomoyo_memory_quota[TOMOYO_MEMORY_POLICY];
|
||||
if (!result)
|
||||
tomoyo_memory_used[TOMOYO_MEMORY_POLICY] -= s;
|
||||
spin_unlock(&tomoyo_policy_memory_lock);
|
||||
if (result)
|
||||
if (!tomoyo_memory_quota[TOMOYO_MEMORY_POLICY] ||
|
||||
tomoyo_memory_used[TOMOYO_MEMORY_POLICY] <=
|
||||
tomoyo_memory_quota[TOMOYO_MEMORY_POLICY])
|
||||
return true;
|
||||
tomoyo_memory_used[TOMOYO_MEMORY_POLICY] -= s;
|
||||
}
|
||||
tomoyo_warn_oom(__func__);
|
||||
return false;
|
||||
|
|
@ -71,6 +66,8 @@ bool tomoyo_memory_ok(void *ptr)
|
|||
*
|
||||
* Returns pointer to allocated memory on success, NULL otherwise.
|
||||
* @data is zero-cleared on success.
|
||||
*
|
||||
* Caller holds tomoyo_policy_lock mutex.
|
||||
*/
|
||||
void *tomoyo_commit_ok(void *data, const unsigned int size)
|
||||
{
|
||||
|
|
@ -84,20 +81,6 @@ void *tomoyo_commit_ok(void *data, const unsigned int size)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* tomoyo_memory_free - Free memory for elements.
|
||||
*
|
||||
* @ptr: Pointer to allocated memory.
|
||||
*/
|
||||
void tomoyo_memory_free(void *ptr)
|
||||
{
|
||||
size_t s = ksize(ptr);
|
||||
spin_lock(&tomoyo_policy_memory_lock);
|
||||
tomoyo_memory_used[TOMOYO_MEMORY_POLICY] -= s;
|
||||
spin_unlock(&tomoyo_policy_memory_lock);
|
||||
kfree(ptr);
|
||||
}
|
||||
|
||||
/**
|
||||
* tomoyo_get_group - Allocate memory for "struct tomoyo_path_group"/"struct tomoyo_number_group".
|
||||
*
|
||||
|
|
@ -123,7 +106,8 @@ struct tomoyo_group *tomoyo_get_group(struct tomoyo_acl_param *param,
|
|||
goto out;
|
||||
list = ¶m->ns->group_list[idx];
|
||||
list_for_each_entry(group, list, head.list) {
|
||||
if (e.group_name != group->group_name)
|
||||
if (e.group_name != group->group_name ||
|
||||
atomic_read(&group->head.users) == TOMOYO_GC_IN_PROGRESS)
|
||||
continue;
|
||||
atomic_inc(&group->head.users);
|
||||
found = true;
|
||||
|
|
@ -175,7 +159,8 @@ const struct tomoyo_path_info *tomoyo_get_name(const char *name)
|
|||
if (mutex_lock_interruptible(&tomoyo_policy_lock))
|
||||
return NULL;
|
||||
list_for_each_entry(ptr, head, head.list) {
|
||||
if (hash != ptr->entry.hash || strcmp(name, ptr->entry.name))
|
||||
if (hash != ptr->entry.hash || strcmp(name, ptr->entry.name) ||
|
||||
atomic_read(&ptr->head.users) == TOMOYO_GC_IN_PROGRESS)
|
||||
continue;
|
||||
atomic_inc(&ptr->head.users);
|
||||
goto out;
|
||||
|
|
|
|||
771
security/tomoyo/network.c
Normal file
771
security/tomoyo/network.c
Normal file
|
|
@ -0,0 +1,771 @@
|
|||
/*
|
||||
* security/tomoyo/network.c
|
||||
*
|
||||
* Copyright (C) 2005-2011 NTT DATA CORPORATION
|
||||
*/
|
||||
|
||||
#include "common.h"
|
||||
#include <linux/slab.h>
|
||||
|
||||
/* Structure for holding inet domain socket's address. */
|
||||
struct tomoyo_inet_addr_info {
|
||||
__be16 port; /* In network byte order. */
|
||||
const __be32 *address; /* In network byte order. */
|
||||
bool is_ipv6;
|
||||
};
|
||||
|
||||
/* Structure for holding unix domain socket's address. */
|
||||
struct tomoyo_unix_addr_info {
|
||||
u8 *addr; /* This may not be '\0' terminated string. */
|
||||
unsigned int addr_len;
|
||||
};
|
||||
|
||||
/* Structure for holding socket address. */
|
||||
struct tomoyo_addr_info {
|
||||
u8 protocol;
|
||||
u8 operation;
|
||||
struct tomoyo_inet_addr_info inet;
|
||||
struct tomoyo_unix_addr_info unix0;
|
||||
};
|
||||
|
||||
/* String table for socket's protocols. */
|
||||
const char * const tomoyo_proto_keyword[TOMOYO_SOCK_MAX] = {
|
||||
[SOCK_STREAM] = "stream",
|
||||
[SOCK_DGRAM] = "dgram",
|
||||
[SOCK_RAW] = "raw",
|
||||
[SOCK_SEQPACKET] = "seqpacket",
|
||||
[0] = " ", /* Dummy for avoiding NULL pointer dereference. */
|
||||
[4] = " ", /* Dummy for avoiding NULL pointer dereference. */
|
||||
};
|
||||
|
||||
/**
|
||||
* tomoyo_parse_ipaddr_union - Parse an IP address.
|
||||
*
|
||||
* @param: Pointer to "struct tomoyo_acl_param".
|
||||
* @ptr: Pointer to "struct tomoyo_ipaddr_union".
|
||||
*
|
||||
* Returns true on success, false otherwise.
|
||||
*/
|
||||
bool tomoyo_parse_ipaddr_union(struct tomoyo_acl_param *param,
|
||||
struct tomoyo_ipaddr_union *ptr)
|
||||
{
|
||||
u8 * const min = ptr->ip[0].in6_u.u6_addr8;
|
||||
u8 * const max = ptr->ip[1].in6_u.u6_addr8;
|
||||
char *address = tomoyo_read_token(param);
|
||||
const char *end;
|
||||
|
||||
if (!strchr(address, ':') &&
|
||||
in4_pton(address, -1, min, '-', &end) > 0) {
|
||||
ptr->is_ipv6 = false;
|
||||
if (!*end)
|
||||
ptr->ip[1].s6_addr32[0] = ptr->ip[0].s6_addr32[0];
|
||||
else if (*end++ != '-' ||
|
||||
in4_pton(end, -1, max, '\0', &end) <= 0 || *end)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
if (in6_pton(address, -1, min, '-', &end) > 0) {
|
||||
ptr->is_ipv6 = true;
|
||||
if (!*end)
|
||||
memmove(max, min, sizeof(u16) * 8);
|
||||
else if (*end++ != '-' ||
|
||||
in6_pton(end, -1, max, '\0', &end) <= 0 || *end)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* tomoyo_print_ipv4 - Print an IPv4 address.
|
||||
*
|
||||
* @buffer: Buffer to write to.
|
||||
* @buffer_len: Size of @buffer.
|
||||
* @min_ip: Pointer to __be32.
|
||||
* @max_ip: Pointer to __be32.
|
||||
*
|
||||
* Returns nothing.
|
||||
*/
|
||||
static void tomoyo_print_ipv4(char *buffer, const unsigned int buffer_len,
|
||||
const __be32 *min_ip, const __be32 *max_ip)
|
||||
{
|
||||
snprintf(buffer, buffer_len, "%pI4%c%pI4", min_ip,
|
||||
*min_ip == *max_ip ? '\0' : '-', max_ip);
|
||||
}
|
||||
|
||||
/**
|
||||
* tomoyo_print_ipv6 - Print an IPv6 address.
|
||||
*
|
||||
* @buffer: Buffer to write to.
|
||||
* @buffer_len: Size of @buffer.
|
||||
* @min_ip: Pointer to "struct in6_addr".
|
||||
* @max_ip: Pointer to "struct in6_addr".
|
||||
*
|
||||
* Returns nothing.
|
||||
*/
|
||||
static void tomoyo_print_ipv6(char *buffer, const unsigned int buffer_len,
|
||||
const struct in6_addr *min_ip,
|
||||
const struct in6_addr *max_ip)
|
||||
{
|
||||
snprintf(buffer, buffer_len, "%pI6c%c%pI6c", min_ip,
|
||||
!memcmp(min_ip, max_ip, 16) ? '\0' : '-', max_ip);
|
||||
}
|
||||
|
||||
/**
|
||||
* tomoyo_print_ip - Print an IP address.
|
||||
*
|
||||
* @buf: Buffer to write to.
|
||||
* @size: Size of @buf.
|
||||
* @ptr: Pointer to "struct ipaddr_union".
|
||||
*
|
||||
* Returns nothing.
|
||||
*/
|
||||
void tomoyo_print_ip(char *buf, const unsigned int size,
|
||||
const struct tomoyo_ipaddr_union *ptr)
|
||||
{
|
||||
if (ptr->is_ipv6)
|
||||
tomoyo_print_ipv6(buf, size, &ptr->ip[0], &ptr->ip[1]);
|
||||
else
|
||||
tomoyo_print_ipv4(buf, size, &ptr->ip[0].s6_addr32[0],
|
||||
&ptr->ip[1].s6_addr32[0]);
|
||||
}
|
||||
|
||||
/*
|
||||
* Mapping table from "enum tomoyo_network_acl_index" to
|
||||
* "enum tomoyo_mac_index" for inet domain socket.
|
||||
*/
|
||||
static const u8 tomoyo_inet2mac
|
||||
[TOMOYO_SOCK_MAX][TOMOYO_MAX_NETWORK_OPERATION] = {
|
||||
[SOCK_STREAM] = {
|
||||
[TOMOYO_NETWORK_BIND] = TOMOYO_MAC_NETWORK_INET_STREAM_BIND,
|
||||
[TOMOYO_NETWORK_LISTEN] =
|
||||
TOMOYO_MAC_NETWORK_INET_STREAM_LISTEN,
|
||||
[TOMOYO_NETWORK_CONNECT] =
|
||||
TOMOYO_MAC_NETWORK_INET_STREAM_CONNECT,
|
||||
},
|
||||
[SOCK_DGRAM] = {
|
||||
[TOMOYO_NETWORK_BIND] = TOMOYO_MAC_NETWORK_INET_DGRAM_BIND,
|
||||
[TOMOYO_NETWORK_SEND] = TOMOYO_MAC_NETWORK_INET_DGRAM_SEND,
|
||||
},
|
||||
[SOCK_RAW] = {
|
||||
[TOMOYO_NETWORK_BIND] = TOMOYO_MAC_NETWORK_INET_RAW_BIND,
|
||||
[TOMOYO_NETWORK_SEND] = TOMOYO_MAC_NETWORK_INET_RAW_SEND,
|
||||
},
|
||||
};
|
||||
|
||||
/*
|
||||
* Mapping table from "enum tomoyo_network_acl_index" to
|
||||
* "enum tomoyo_mac_index" for unix domain socket.
|
||||
*/
|
||||
static const u8 tomoyo_unix2mac
|
||||
[TOMOYO_SOCK_MAX][TOMOYO_MAX_NETWORK_OPERATION] = {
|
||||
[SOCK_STREAM] = {
|
||||
[TOMOYO_NETWORK_BIND] = TOMOYO_MAC_NETWORK_UNIX_STREAM_BIND,
|
||||
[TOMOYO_NETWORK_LISTEN] =
|
||||
TOMOYO_MAC_NETWORK_UNIX_STREAM_LISTEN,
|
||||
[TOMOYO_NETWORK_CONNECT] =
|
||||
TOMOYO_MAC_NETWORK_UNIX_STREAM_CONNECT,
|
||||
},
|
||||
[SOCK_DGRAM] = {
|
||||
[TOMOYO_NETWORK_BIND] = TOMOYO_MAC_NETWORK_UNIX_DGRAM_BIND,
|
||||
[TOMOYO_NETWORK_SEND] = TOMOYO_MAC_NETWORK_UNIX_DGRAM_SEND,
|
||||
},
|
||||
[SOCK_SEQPACKET] = {
|
||||
[TOMOYO_NETWORK_BIND] =
|
||||
TOMOYO_MAC_NETWORK_UNIX_SEQPACKET_BIND,
|
||||
[TOMOYO_NETWORK_LISTEN] =
|
||||
TOMOYO_MAC_NETWORK_UNIX_SEQPACKET_LISTEN,
|
||||
[TOMOYO_NETWORK_CONNECT] =
|
||||
TOMOYO_MAC_NETWORK_UNIX_SEQPACKET_CONNECT,
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* tomoyo_same_inet_acl - Check for duplicated "struct tomoyo_inet_acl" entry.
|
||||
*
|
||||
* @a: Pointer to "struct tomoyo_acl_info".
|
||||
* @b: Pointer to "struct tomoyo_acl_info".
|
||||
*
|
||||
* Returns true if @a == @b except permission bits, false otherwise.
|
||||
*/
|
||||
static bool tomoyo_same_inet_acl(const struct tomoyo_acl_info *a,
|
||||
const struct tomoyo_acl_info *b)
|
||||
{
|
||||
const struct tomoyo_inet_acl *p1 = container_of(a, typeof(*p1), head);
|
||||
const struct tomoyo_inet_acl *p2 = container_of(b, typeof(*p2), head);
|
||||
|
||||
return p1->protocol == p2->protocol &&
|
||||
tomoyo_same_ipaddr_union(&p1->address, &p2->address) &&
|
||||
tomoyo_same_number_union(&p1->port, &p2->port);
|
||||
}
|
||||
|
||||
/**
|
||||
* tomoyo_same_unix_acl - Check for duplicated "struct tomoyo_unix_acl" entry.
|
||||
*
|
||||
* @a: Pointer to "struct tomoyo_acl_info".
|
||||
* @b: Pointer to "struct tomoyo_acl_info".
|
||||
*
|
||||
* Returns true if @a == @b except permission bits, false otherwise.
|
||||
*/
|
||||
static bool tomoyo_same_unix_acl(const struct tomoyo_acl_info *a,
|
||||
const struct tomoyo_acl_info *b)
|
||||
{
|
||||
const struct tomoyo_unix_acl *p1 = container_of(a, typeof(*p1), head);
|
||||
const struct tomoyo_unix_acl *p2 = container_of(b, typeof(*p2), head);
|
||||
|
||||
return p1->protocol == p2->protocol &&
|
||||
tomoyo_same_name_union(&p1->name, &p2->name);
|
||||
}
|
||||
|
||||
/**
|
||||
* tomoyo_merge_inet_acl - Merge duplicated "struct tomoyo_inet_acl" entry.
|
||||
*
|
||||
* @a: Pointer to "struct tomoyo_acl_info".
|
||||
* @b: Pointer to "struct tomoyo_acl_info".
|
||||
* @is_delete: True for @a &= ~@b, false for @a |= @b.
|
||||
*
|
||||
* Returns true if @a is empty, false otherwise.
|
||||
*/
|
||||
static bool tomoyo_merge_inet_acl(struct tomoyo_acl_info *a,
|
||||
struct tomoyo_acl_info *b,
|
||||
const bool is_delete)
|
||||
{
|
||||
u8 * const a_perm =
|
||||
&container_of(a, struct tomoyo_inet_acl, head)->perm;
|
||||
u8 perm = *a_perm;
|
||||
const u8 b_perm = container_of(b, struct tomoyo_inet_acl, head)->perm;
|
||||
|
||||
if (is_delete)
|
||||
perm &= ~b_perm;
|
||||
else
|
||||
perm |= b_perm;
|
||||
*a_perm = perm;
|
||||
return !perm;
|
||||
}
|
||||
|
||||
/**
|
||||
* tomoyo_merge_unix_acl - Merge duplicated "struct tomoyo_unix_acl" entry.
|
||||
*
|
||||
* @a: Pointer to "struct tomoyo_acl_info".
|
||||
* @b: Pointer to "struct tomoyo_acl_info".
|
||||
* @is_delete: True for @a &= ~@b, false for @a |= @b.
|
||||
*
|
||||
* Returns true if @a is empty, false otherwise.
|
||||
*/
|
||||
static bool tomoyo_merge_unix_acl(struct tomoyo_acl_info *a,
|
||||
struct tomoyo_acl_info *b,
|
||||
const bool is_delete)
|
||||
{
|
||||
u8 * const a_perm =
|
||||
&container_of(a, struct tomoyo_unix_acl, head)->perm;
|
||||
u8 perm = *a_perm;
|
||||
const u8 b_perm = container_of(b, struct tomoyo_unix_acl, head)->perm;
|
||||
|
||||
if (is_delete)
|
||||
perm &= ~b_perm;
|
||||
else
|
||||
perm |= b_perm;
|
||||
*a_perm = perm;
|
||||
return !perm;
|
||||
}
|
||||
|
||||
/**
|
||||
* tomoyo_write_inet_network - Write "struct tomoyo_inet_acl" list.
|
||||
*
|
||||
* @param: Pointer to "struct tomoyo_acl_param".
|
||||
*
|
||||
* Returns 0 on success, negative value otherwise.
|
||||
*
|
||||
* Caller holds tomoyo_read_lock().
|
||||
*/
|
||||
int tomoyo_write_inet_network(struct tomoyo_acl_param *param)
|
||||
{
|
||||
struct tomoyo_inet_acl e = { .head.type = TOMOYO_TYPE_INET_ACL };
|
||||
int error = -EINVAL;
|
||||
u8 type;
|
||||
const char *protocol = tomoyo_read_token(param);
|
||||
const char *operation = tomoyo_read_token(param);
|
||||
|
||||
for (e.protocol = 0; e.protocol < TOMOYO_SOCK_MAX; e.protocol++)
|
||||
if (!strcmp(protocol, tomoyo_proto_keyword[e.protocol]))
|
||||
break;
|
||||
for (type = 0; type < TOMOYO_MAX_NETWORK_OPERATION; type++)
|
||||
if (tomoyo_permstr(operation, tomoyo_socket_keyword[type]))
|
||||
e.perm |= 1 << type;
|
||||
if (e.protocol == TOMOYO_SOCK_MAX || !e.perm)
|
||||
return -EINVAL;
|
||||
if (param->data[0] == '@') {
|
||||
param->data++;
|
||||
e.address.group =
|
||||
tomoyo_get_group(param, TOMOYO_ADDRESS_GROUP);
|
||||
if (!e.address.group)
|
||||
return -ENOMEM;
|
||||
} else {
|
||||
if (!tomoyo_parse_ipaddr_union(param, &e.address))
|
||||
goto out;
|
||||
}
|
||||
if (!tomoyo_parse_number_union(param, &e.port) ||
|
||||
e.port.values[1] > 65535)
|
||||
goto out;
|
||||
error = tomoyo_update_domain(&e.head, sizeof(e), param,
|
||||
tomoyo_same_inet_acl,
|
||||
tomoyo_merge_inet_acl);
|
||||
out:
|
||||
tomoyo_put_group(e.address.group);
|
||||
tomoyo_put_number_union(&e.port);
|
||||
return error;
|
||||
}
|
||||
|
||||
/**
|
||||
* tomoyo_write_unix_network - Write "struct tomoyo_unix_acl" list.
|
||||
*
|
||||
* @param: Pointer to "struct tomoyo_acl_param".
|
||||
*
|
||||
* Returns 0 on success, negative value otherwise.
|
||||
*/
|
||||
int tomoyo_write_unix_network(struct tomoyo_acl_param *param)
|
||||
{
|
||||
struct tomoyo_unix_acl e = { .head.type = TOMOYO_TYPE_UNIX_ACL };
|
||||
int error;
|
||||
u8 type;
|
||||
const char *protocol = tomoyo_read_token(param);
|
||||
const char *operation = tomoyo_read_token(param);
|
||||
|
||||
for (e.protocol = 0; e.protocol < TOMOYO_SOCK_MAX; e.protocol++)
|
||||
if (!strcmp(protocol, tomoyo_proto_keyword[e.protocol]))
|
||||
break;
|
||||
for (type = 0; type < TOMOYO_MAX_NETWORK_OPERATION; type++)
|
||||
if (tomoyo_permstr(operation, tomoyo_socket_keyword[type]))
|
||||
e.perm |= 1 << type;
|
||||
if (e.protocol == TOMOYO_SOCK_MAX || !e.perm)
|
||||
return -EINVAL;
|
||||
if (!tomoyo_parse_name_union(param, &e.name))
|
||||
return -EINVAL;
|
||||
error = tomoyo_update_domain(&e.head, sizeof(e), param,
|
||||
tomoyo_same_unix_acl,
|
||||
tomoyo_merge_unix_acl);
|
||||
tomoyo_put_name_union(&e.name);
|
||||
return error;
|
||||
}
|
||||
|
||||
/**
|
||||
* tomoyo_audit_net_log - Audit network log.
|
||||
*
|
||||
* @r: Pointer to "struct tomoyo_request_info".
|
||||
* @family: Name of socket family ("inet" or "unix").
|
||||
* @protocol: Name of protocol in @family.
|
||||
* @operation: Name of socket operation.
|
||||
* @address: Name of address.
|
||||
*
|
||||
* Returns 0 on success, negative value otherwise.
|
||||
*/
|
||||
static int tomoyo_audit_net_log(struct tomoyo_request_info *r,
|
||||
const char *family, const u8 protocol,
|
||||
const u8 operation, const char *address)
|
||||
{
|
||||
return tomoyo_supervisor(r, "network %s %s %s %s\n", family,
|
||||
tomoyo_proto_keyword[protocol],
|
||||
tomoyo_socket_keyword[operation], address);
|
||||
}
|
||||
|
||||
/**
|
||||
* tomoyo_audit_inet_log - Audit INET network log.
|
||||
*
|
||||
* @r: Pointer to "struct tomoyo_request_info".
|
||||
*
|
||||
* Returns 0 on success, negative value otherwise.
|
||||
*/
|
||||
static int tomoyo_audit_inet_log(struct tomoyo_request_info *r)
|
||||
{
|
||||
char buf[128];
|
||||
int len;
|
||||
const __be32 *address = r->param.inet_network.address;
|
||||
|
||||
if (r->param.inet_network.is_ipv6)
|
||||
tomoyo_print_ipv6(buf, sizeof(buf), (const struct in6_addr *)
|
||||
address, (const struct in6_addr *) address);
|
||||
else
|
||||
tomoyo_print_ipv4(buf, sizeof(buf), address, address);
|
||||
len = strlen(buf);
|
||||
snprintf(buf + len, sizeof(buf) - len, " %u",
|
||||
r->param.inet_network.port);
|
||||
return tomoyo_audit_net_log(r, "inet", r->param.inet_network.protocol,
|
||||
r->param.inet_network.operation, buf);
|
||||
}
|
||||
|
||||
/**
|
||||
* tomoyo_audit_unix_log - Audit UNIX network log.
|
||||
*
|
||||
* @r: Pointer to "struct tomoyo_request_info".
|
||||
*
|
||||
* Returns 0 on success, negative value otherwise.
|
||||
*/
|
||||
static int tomoyo_audit_unix_log(struct tomoyo_request_info *r)
|
||||
{
|
||||
return tomoyo_audit_net_log(r, "unix", r->param.unix_network.protocol,
|
||||
r->param.unix_network.operation,
|
||||
r->param.unix_network.address->name);
|
||||
}
|
||||
|
||||
/**
|
||||
* tomoyo_check_inet_acl - Check permission for inet domain socket operation.
|
||||
*
|
||||
* @r: Pointer to "struct tomoyo_request_info".
|
||||
* @ptr: Pointer to "struct tomoyo_acl_info".
|
||||
*
|
||||
* Returns true if granted, false otherwise.
|
||||
*/
|
||||
static bool tomoyo_check_inet_acl(struct tomoyo_request_info *r,
|
||||
const struct tomoyo_acl_info *ptr)
|
||||
{
|
||||
const struct tomoyo_inet_acl *acl =
|
||||
container_of(ptr, typeof(*acl), head);
|
||||
const u8 size = r->param.inet_network.is_ipv6 ? 16 : 4;
|
||||
|
||||
if (!(acl->perm & (1 << r->param.inet_network.operation)) ||
|
||||
!tomoyo_compare_number_union(r->param.inet_network.port,
|
||||
&acl->port))
|
||||
return false;
|
||||
if (acl->address.group)
|
||||
return tomoyo_address_matches_group
|
||||
(r->param.inet_network.is_ipv6,
|
||||
r->param.inet_network.address, acl->address.group);
|
||||
return acl->address.is_ipv6 == r->param.inet_network.is_ipv6 &&
|
||||
memcmp(&acl->address.ip[0],
|
||||
r->param.inet_network.address, size) <= 0 &&
|
||||
memcmp(r->param.inet_network.address,
|
||||
&acl->address.ip[1], size) <= 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* tomoyo_check_unix_acl - Check permission for unix domain socket operation.
|
||||
*
|
||||
* @r: Pointer to "struct tomoyo_request_info".
|
||||
* @ptr: Pointer to "struct tomoyo_acl_info".
|
||||
*
|
||||
* Returns true if granted, false otherwise.
|
||||
*/
|
||||
static bool tomoyo_check_unix_acl(struct tomoyo_request_info *r,
|
||||
const struct tomoyo_acl_info *ptr)
|
||||
{
|
||||
const struct tomoyo_unix_acl *acl =
|
||||
container_of(ptr, typeof(*acl), head);
|
||||
|
||||
return (acl->perm & (1 << r->param.unix_network.operation)) &&
|
||||
tomoyo_compare_name_union(r->param.unix_network.address,
|
||||
&acl->name);
|
||||
}
|
||||
|
||||
/**
|
||||
* tomoyo_inet_entry - Check permission for INET network operation.
|
||||
*
|
||||
* @address: Pointer to "struct tomoyo_addr_info".
|
||||
*
|
||||
* Returns 0 on success, negative value otherwise.
|
||||
*/
|
||||
static int tomoyo_inet_entry(const struct tomoyo_addr_info *address)
|
||||
{
|
||||
const int idx = tomoyo_read_lock();
|
||||
struct tomoyo_request_info r;
|
||||
int error = 0;
|
||||
const u8 type = tomoyo_inet2mac[address->protocol][address->operation];
|
||||
|
||||
if (type && tomoyo_init_request_info(&r, NULL, type)
|
||||
!= TOMOYO_CONFIG_DISABLED) {
|
||||
r.param_type = TOMOYO_TYPE_INET_ACL;
|
||||
r.param.inet_network.protocol = address->protocol;
|
||||
r.param.inet_network.operation = address->operation;
|
||||
r.param.inet_network.is_ipv6 = address->inet.is_ipv6;
|
||||
r.param.inet_network.address = address->inet.address;
|
||||
r.param.inet_network.port = ntohs(address->inet.port);
|
||||
do {
|
||||
tomoyo_check_acl(&r, tomoyo_check_inet_acl);
|
||||
error = tomoyo_audit_inet_log(&r);
|
||||
} while (error == TOMOYO_RETRY_REQUEST);
|
||||
}
|
||||
tomoyo_read_unlock(idx);
|
||||
return error;
|
||||
}
|
||||
|
||||
/**
|
||||
* tomoyo_check_inet_address - Check permission for inet domain socket's operation.
|
||||
*
|
||||
* @addr: Pointer to "struct sockaddr".
|
||||
* @addr_len: Size of @addr.
|
||||
* @port: Port number.
|
||||
* @address: Pointer to "struct tomoyo_addr_info".
|
||||
*
|
||||
* Returns 0 on success, negative value otherwise.
|
||||
*/
|
||||
static int tomoyo_check_inet_address(const struct sockaddr *addr,
|
||||
const unsigned int addr_len,
|
||||
const u16 port,
|
||||
struct tomoyo_addr_info *address)
|
||||
{
|
||||
struct tomoyo_inet_addr_info *i = &address->inet;
|
||||
|
||||
switch (addr->sa_family) {
|
||||
case AF_INET6:
|
||||
if (addr_len < SIN6_LEN_RFC2133)
|
||||
goto skip;
|
||||
i->is_ipv6 = true;
|
||||
i->address = (__be32 *)
|
||||
((struct sockaddr_in6 *) addr)->sin6_addr.s6_addr;
|
||||
i->port = ((struct sockaddr_in6 *) addr)->sin6_port;
|
||||
break;
|
||||
case AF_INET:
|
||||
if (addr_len < sizeof(struct sockaddr_in))
|
||||
goto skip;
|
||||
i->is_ipv6 = false;
|
||||
i->address = (__be32 *)
|
||||
&((struct sockaddr_in *) addr)->sin_addr;
|
||||
i->port = ((struct sockaddr_in *) addr)->sin_port;
|
||||
break;
|
||||
default:
|
||||
goto skip;
|
||||
}
|
||||
if (address->protocol == SOCK_RAW)
|
||||
i->port = htons(port);
|
||||
return tomoyo_inet_entry(address);
|
||||
skip:
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* tomoyo_unix_entry - Check permission for UNIX network operation.
|
||||
*
|
||||
* @address: Pointer to "struct tomoyo_addr_info".
|
||||
*
|
||||
* Returns 0 on success, negative value otherwise.
|
||||
*/
|
||||
static int tomoyo_unix_entry(const struct tomoyo_addr_info *address)
|
||||
{
|
||||
const int idx = tomoyo_read_lock();
|
||||
struct tomoyo_request_info r;
|
||||
int error = 0;
|
||||
const u8 type = tomoyo_unix2mac[address->protocol][address->operation];
|
||||
|
||||
if (type && tomoyo_init_request_info(&r, NULL, type)
|
||||
!= TOMOYO_CONFIG_DISABLED) {
|
||||
char *buf = address->unix0.addr;
|
||||
int len = address->unix0.addr_len - sizeof(sa_family_t);
|
||||
|
||||
if (len <= 0) {
|
||||
buf = "anonymous";
|
||||
len = 9;
|
||||
} else if (buf[0]) {
|
||||
len = strnlen(buf, len);
|
||||
}
|
||||
buf = tomoyo_encode2(buf, len);
|
||||
if (buf) {
|
||||
struct tomoyo_path_info addr;
|
||||
|
||||
addr.name = buf;
|
||||
tomoyo_fill_path_info(&addr);
|
||||
r.param_type = TOMOYO_TYPE_UNIX_ACL;
|
||||
r.param.unix_network.protocol = address->protocol;
|
||||
r.param.unix_network.operation = address->operation;
|
||||
r.param.unix_network.address = &addr;
|
||||
do {
|
||||
tomoyo_check_acl(&r, tomoyo_check_unix_acl);
|
||||
error = tomoyo_audit_unix_log(&r);
|
||||
} while (error == TOMOYO_RETRY_REQUEST);
|
||||
kfree(buf);
|
||||
} else
|
||||
error = -ENOMEM;
|
||||
}
|
||||
tomoyo_read_unlock(idx);
|
||||
return error;
|
||||
}
|
||||
|
||||
/**
|
||||
* tomoyo_check_unix_address - Check permission for unix domain socket's operation.
|
||||
*
|
||||
* @addr: Pointer to "struct sockaddr".
|
||||
* @addr_len: Size of @addr.
|
||||
* @address: Pointer to "struct tomoyo_addr_info".
|
||||
*
|
||||
* Returns 0 on success, negative value otherwise.
|
||||
*/
|
||||
static int tomoyo_check_unix_address(struct sockaddr *addr,
|
||||
const unsigned int addr_len,
|
||||
struct tomoyo_addr_info *address)
|
||||
{
|
||||
struct tomoyo_unix_addr_info *u = &address->unix0;
|
||||
|
||||
if (addr->sa_family != AF_UNIX)
|
||||
return 0;
|
||||
u->addr = ((struct sockaddr_un *) addr)->sun_path;
|
||||
u->addr_len = addr_len;
|
||||
return tomoyo_unix_entry(address);
|
||||
}
|
||||
|
||||
/**
|
||||
* tomoyo_kernel_service - Check whether I'm kernel service or not.
|
||||
*
|
||||
* Returns true if I'm kernel service, false otherwise.
|
||||
*/
|
||||
static bool tomoyo_kernel_service(void)
|
||||
{
|
||||
/* Nothing to do if I am a kernel service. */
|
||||
return segment_eq(get_fs(), KERNEL_DS);
|
||||
}
|
||||
|
||||
/**
|
||||
* tomoyo_sock_family - Get socket's family.
|
||||
*
|
||||
* @sk: Pointer to "struct sock".
|
||||
*
|
||||
* Returns one of PF_INET, PF_INET6, PF_UNIX or 0.
|
||||
*/
|
||||
static u8 tomoyo_sock_family(struct sock *sk)
|
||||
{
|
||||
u8 family;
|
||||
|
||||
if (tomoyo_kernel_service())
|
||||
return 0;
|
||||
family = sk->sk_family;
|
||||
switch (family) {
|
||||
case PF_INET:
|
||||
case PF_INET6:
|
||||
case PF_UNIX:
|
||||
return family;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* tomoyo_socket_listen_permission - Check permission for listening a socket.
|
||||
*
|
||||
* @sock: Pointer to "struct socket".
|
||||
*
|
||||
* Returns 0 on success, negative value otherwise.
|
||||
*/
|
||||
int tomoyo_socket_listen_permission(struct socket *sock)
|
||||
{
|
||||
struct tomoyo_addr_info address;
|
||||
const u8 family = tomoyo_sock_family(sock->sk);
|
||||
const unsigned int type = sock->type;
|
||||
struct sockaddr_storage addr;
|
||||
int addr_len;
|
||||
|
||||
if (!family || (type != SOCK_STREAM && type != SOCK_SEQPACKET))
|
||||
return 0;
|
||||
{
|
||||
const int error = sock->ops->getname(sock, (struct sockaddr *)
|
||||
&addr, &addr_len, 0);
|
||||
|
||||
if (error)
|
||||
return error;
|
||||
}
|
||||
address.protocol = type;
|
||||
address.operation = TOMOYO_NETWORK_LISTEN;
|
||||
if (family == PF_UNIX)
|
||||
return tomoyo_check_unix_address((struct sockaddr *) &addr,
|
||||
addr_len, &address);
|
||||
return tomoyo_check_inet_address((struct sockaddr *) &addr, addr_len,
|
||||
0, &address);
|
||||
}
|
||||
|
||||
/**
|
||||
* tomoyo_socket_connect_permission - Check permission for setting the remote address of a socket.
|
||||
*
|
||||
* @sock: Pointer to "struct socket".
|
||||
* @addr: Pointer to "struct sockaddr".
|
||||
* @addr_len: Size of @addr.
|
||||
*
|
||||
* Returns 0 on success, negative value otherwise.
|
||||
*/
|
||||
int tomoyo_socket_connect_permission(struct socket *sock,
|
||||
struct sockaddr *addr, int addr_len)
|
||||
{
|
||||
struct tomoyo_addr_info address;
|
||||
const u8 family = tomoyo_sock_family(sock->sk);
|
||||
const unsigned int type = sock->type;
|
||||
|
||||
if (!family)
|
||||
return 0;
|
||||
address.protocol = type;
|
||||
switch (type) {
|
||||
case SOCK_DGRAM:
|
||||
case SOCK_RAW:
|
||||
address.operation = TOMOYO_NETWORK_SEND;
|
||||
break;
|
||||
case SOCK_STREAM:
|
||||
case SOCK_SEQPACKET:
|
||||
address.operation = TOMOYO_NETWORK_CONNECT;
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
if (family == PF_UNIX)
|
||||
return tomoyo_check_unix_address(addr, addr_len, &address);
|
||||
return tomoyo_check_inet_address(addr, addr_len, sock->sk->sk_protocol,
|
||||
&address);
|
||||
}
|
||||
|
||||
/**
|
||||
* tomoyo_socket_bind_permission - Check permission for setting the local address of a socket.
|
||||
*
|
||||
* @sock: Pointer to "struct socket".
|
||||
* @addr: Pointer to "struct sockaddr".
|
||||
* @addr_len: Size of @addr.
|
||||
*
|
||||
* Returns 0 on success, negative value otherwise.
|
||||
*/
|
||||
int tomoyo_socket_bind_permission(struct socket *sock, struct sockaddr *addr,
|
||||
int addr_len)
|
||||
{
|
||||
struct tomoyo_addr_info address;
|
||||
const u8 family = tomoyo_sock_family(sock->sk);
|
||||
const unsigned int type = sock->type;
|
||||
|
||||
if (!family)
|
||||
return 0;
|
||||
switch (type) {
|
||||
case SOCK_STREAM:
|
||||
case SOCK_DGRAM:
|
||||
case SOCK_RAW:
|
||||
case SOCK_SEQPACKET:
|
||||
address.protocol = type;
|
||||
address.operation = TOMOYO_NETWORK_BIND;
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
if (family == PF_UNIX)
|
||||
return tomoyo_check_unix_address(addr, addr_len, &address);
|
||||
return tomoyo_check_inet_address(addr, addr_len, sock->sk->sk_protocol,
|
||||
&address);
|
||||
}
|
||||
|
||||
/**
|
||||
* tomoyo_socket_sendmsg_permission - Check permission for sending a datagram.
|
||||
*
|
||||
* @sock: Pointer to "struct socket".
|
||||
* @msg: Pointer to "struct msghdr".
|
||||
* @size: Unused.
|
||||
*
|
||||
* Returns 0 on success, negative value otherwise.
|
||||
*/
|
||||
int tomoyo_socket_sendmsg_permission(struct socket *sock, struct msghdr *msg,
|
||||
int size)
|
||||
{
|
||||
struct tomoyo_addr_info address;
|
||||
const u8 family = tomoyo_sock_family(sock->sk);
|
||||
const unsigned int type = sock->type;
|
||||
|
||||
if (!msg->msg_name || !family ||
|
||||
(type != SOCK_DGRAM && type != SOCK_RAW))
|
||||
return 0;
|
||||
address.protocol = type;
|
||||
address.operation = TOMOYO_NETWORK_SEND;
|
||||
if (family == PF_UNIX)
|
||||
return tomoyo_check_unix_address((struct sockaddr *)
|
||||
msg->msg_name,
|
||||
msg->msg_namelen, &address);
|
||||
return tomoyo_check_inet_address((struct sockaddr *) msg->msg_name,
|
||||
msg->msg_namelen,
|
||||
sock->sk->sk_protocol, &address);
|
||||
}
|
||||
|
|
@ -15,17 +15,19 @@
|
|||
#include "../../fs/internal.h"
|
||||
|
||||
/**
|
||||
* tomoyo_encode: Convert binary string to ascii string.
|
||||
* tomoyo_encode2 - Encode binary string to ascii string.
|
||||
*
|
||||
* @str: String in binary format.
|
||||
* @str: String in binary format.
|
||||
* @str_len: Size of @str in byte.
|
||||
*
|
||||
* Returns pointer to @str in ascii format on success, NULL otherwise.
|
||||
*
|
||||
* This function uses kzalloc(), so caller must kfree() if this function
|
||||
* didn't return NULL.
|
||||
*/
|
||||
char *tomoyo_encode(const char *str)
|
||||
char *tomoyo_encode2(const char *str, int str_len)
|
||||
{
|
||||
int i;
|
||||
int len = 0;
|
||||
const char *p = str;
|
||||
char *cp;
|
||||
|
|
@ -33,8 +35,9 @@ char *tomoyo_encode(const char *str)
|
|||
|
||||
if (!p)
|
||||
return NULL;
|
||||
while (*p) {
|
||||
const unsigned char c = *p++;
|
||||
for (i = 0; i < str_len; i++) {
|
||||
const unsigned char c = p[i];
|
||||
|
||||
if (c == '\\')
|
||||
len += 2;
|
||||
else if (c > ' ' && c < 127)
|
||||
|
|
@ -49,8 +52,8 @@ char *tomoyo_encode(const char *str)
|
|||
return NULL;
|
||||
cp0 = cp;
|
||||
p = str;
|
||||
while (*p) {
|
||||
const unsigned char c = *p++;
|
||||
for (i = 0; i < str_len; i++) {
|
||||
const unsigned char c = p[i];
|
||||
|
||||
if (c == '\\') {
|
||||
*cp++ = '\\';
|
||||
|
|
@ -67,6 +70,21 @@ char *tomoyo_encode(const char *str)
|
|||
return cp0;
|
||||
}
|
||||
|
||||
/**
|
||||
* tomoyo_encode - Encode binary string to ascii string.
|
||||
*
|
||||
* @str: String in binary format.
|
||||
*
|
||||
* Returns pointer to @str in ascii format on success, NULL otherwise.
|
||||
*
|
||||
* This function uses kzalloc(), so caller must kfree() if this function
|
||||
* didn't return NULL.
|
||||
*/
|
||||
char *tomoyo_encode(const char *str)
|
||||
{
|
||||
return str ? tomoyo_encode2(str, strlen(str)) : NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* tomoyo_get_absolute_path - Get the path of a dentry but ignores chroot'ed root.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -7,6 +7,124 @@
|
|||
#include <linux/security.h>
|
||||
#include "common.h"
|
||||
|
||||
/**
|
||||
* tomoyo_check_task_acl - Check permission for task operation.
|
||||
*
|
||||
* @r: Pointer to "struct tomoyo_request_info".
|
||||
* @ptr: Pointer to "struct tomoyo_acl_info".
|
||||
*
|
||||
* Returns true if granted, false otherwise.
|
||||
*/
|
||||
static bool tomoyo_check_task_acl(struct tomoyo_request_info *r,
|
||||
const struct tomoyo_acl_info *ptr)
|
||||
{
|
||||
const struct tomoyo_task_acl *acl = container_of(ptr, typeof(*acl),
|
||||
head);
|
||||
return !tomoyo_pathcmp(r->param.task.domainname, acl->domainname);
|
||||
}
|
||||
|
||||
/**
|
||||
* tomoyo_write_self - write() for /sys/kernel/security/tomoyo/self_domain interface.
|
||||
*
|
||||
* @file: Pointer to "struct file".
|
||||
* @buf: Domainname to transit to.
|
||||
* @count: Size of @buf.
|
||||
* @ppos: Unused.
|
||||
*
|
||||
* Returns @count on success, negative value otherwise.
|
||||
*
|
||||
* If domain transition was permitted but the domain transition failed, this
|
||||
* function returns error rather than terminating current thread with SIGKILL.
|
||||
*/
|
||||
static ssize_t tomoyo_write_self(struct file *file, const char __user *buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
char *data;
|
||||
int error;
|
||||
if (!count || count >= TOMOYO_EXEC_TMPSIZE - 10)
|
||||
return -ENOMEM;
|
||||
data = kzalloc(count + 1, GFP_NOFS);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
if (copy_from_user(data, buf, count)) {
|
||||
error = -EFAULT;
|
||||
goto out;
|
||||
}
|
||||
tomoyo_normalize_line(data);
|
||||
if (tomoyo_correct_domain(data)) {
|
||||
const int idx = tomoyo_read_lock();
|
||||
struct tomoyo_path_info name;
|
||||
struct tomoyo_request_info r;
|
||||
name.name = data;
|
||||
tomoyo_fill_path_info(&name);
|
||||
/* Check "task manual_domain_transition" permission. */
|
||||
tomoyo_init_request_info(&r, NULL, TOMOYO_MAC_FILE_EXECUTE);
|
||||
r.param_type = TOMOYO_TYPE_MANUAL_TASK_ACL;
|
||||
r.param.task.domainname = &name;
|
||||
tomoyo_check_acl(&r, tomoyo_check_task_acl);
|
||||
if (!r.granted)
|
||||
error = -EPERM;
|
||||
else {
|
||||
struct tomoyo_domain_info *new_domain =
|
||||
tomoyo_assign_domain(data, true);
|
||||
if (!new_domain) {
|
||||
error = -ENOENT;
|
||||
} else {
|
||||
struct cred *cred = prepare_creds();
|
||||
if (!cred) {
|
||||
error = -ENOMEM;
|
||||
} else {
|
||||
struct tomoyo_domain_info *old_domain =
|
||||
cred->security;
|
||||
cred->security = new_domain;
|
||||
atomic_inc(&new_domain->users);
|
||||
atomic_dec(&old_domain->users);
|
||||
commit_creds(cred);
|
||||
error = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
tomoyo_read_unlock(idx);
|
||||
} else
|
||||
error = -EINVAL;
|
||||
out:
|
||||
kfree(data);
|
||||
return error ? error : count;
|
||||
}
|
||||
|
||||
/**
|
||||
* tomoyo_read_self - read() for /sys/kernel/security/tomoyo/self_domain interface.
|
||||
*
|
||||
* @file: Pointer to "struct file".
|
||||
* @buf: Domainname which current thread belongs to.
|
||||
* @count: Size of @buf.
|
||||
* @ppos: Bytes read by now.
|
||||
*
|
||||
* Returns read size on success, negative value otherwise.
|
||||
*/
|
||||
static ssize_t tomoyo_read_self(struct file *file, char __user *buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
const char *domain = tomoyo_domain()->domainname->name;
|
||||
loff_t len = strlen(domain);
|
||||
loff_t pos = *ppos;
|
||||
if (pos >= len || !count)
|
||||
return 0;
|
||||
len -= pos;
|
||||
if (count < len)
|
||||
len = count;
|
||||
if (copy_to_user(buf, domain + pos, len))
|
||||
return -EFAULT;
|
||||
*ppos += len;
|
||||
return len;
|
||||
}
|
||||
|
||||
/* Operations for /sys/kernel/security/tomoyo/self_domain interface. */
|
||||
static const struct file_operations tomoyo_self_operations = {
|
||||
.write = tomoyo_write_self,
|
||||
.read = tomoyo_read_self,
|
||||
};
|
||||
|
||||
/**
|
||||
* tomoyo_open - open() for /sys/kernel/security/tomoyo/ interface.
|
||||
*
|
||||
|
|
@ -135,8 +253,6 @@ static int __init tomoyo_initerface_init(void)
|
|||
TOMOYO_EXCEPTIONPOLICY);
|
||||
tomoyo_create_entry("audit", 0400, tomoyo_dir,
|
||||
TOMOYO_AUDIT);
|
||||
tomoyo_create_entry("self_domain", 0400, tomoyo_dir,
|
||||
TOMOYO_SELFDOMAIN);
|
||||
tomoyo_create_entry(".process_status", 0600, tomoyo_dir,
|
||||
TOMOYO_PROCESS_STATUS);
|
||||
tomoyo_create_entry("stat", 0644, tomoyo_dir,
|
||||
|
|
@ -147,6 +263,9 @@ static int __init tomoyo_initerface_init(void)
|
|||
TOMOYO_MANAGER);
|
||||
tomoyo_create_entry("version", 0400, tomoyo_dir,
|
||||
TOMOYO_VERSION);
|
||||
securityfs_create_file("self_domain", 0666, tomoyo_dir, NULL,
|
||||
&tomoyo_self_operations);
|
||||
tomoyo_load_builtin_policy();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -442,6 +442,64 @@ static int tomoyo_sb_pivotroot(struct path *old_path, struct path *new_path)
|
|||
return tomoyo_path2_perm(TOMOYO_TYPE_PIVOT_ROOT, new_path, old_path);
|
||||
}
|
||||
|
||||
/**
|
||||
* tomoyo_socket_listen - Check permission for listen().
|
||||
*
|
||||
* @sock: Pointer to "struct socket".
|
||||
* @backlog: Backlog parameter.
|
||||
*
|
||||
* Returns 0 on success, negative value otherwise.
|
||||
*/
|
||||
static int tomoyo_socket_listen(struct socket *sock, int backlog)
|
||||
{
|
||||
return tomoyo_socket_listen_permission(sock);
|
||||
}
|
||||
|
||||
/**
|
||||
* tomoyo_socket_connect - Check permission for connect().
|
||||
*
|
||||
* @sock: Pointer to "struct socket".
|
||||
* @addr: Pointer to "struct sockaddr".
|
||||
* @addr_len: Size of @addr.
|
||||
*
|
||||
* Returns 0 on success, negative value otherwise.
|
||||
*/
|
||||
static int tomoyo_socket_connect(struct socket *sock, struct sockaddr *addr,
|
||||
int addr_len)
|
||||
{
|
||||
return tomoyo_socket_connect_permission(sock, addr, addr_len);
|
||||
}
|
||||
|
||||
/**
|
||||
* tomoyo_socket_bind - Check permission for bind().
|
||||
*
|
||||
* @sock: Pointer to "struct socket".
|
||||
* @addr: Pointer to "struct sockaddr".
|
||||
* @addr_len: Size of @addr.
|
||||
*
|
||||
* Returns 0 on success, negative value otherwise.
|
||||
*/
|
||||
static int tomoyo_socket_bind(struct socket *sock, struct sockaddr *addr,
|
||||
int addr_len)
|
||||
{
|
||||
return tomoyo_socket_bind_permission(sock, addr, addr_len);
|
||||
}
|
||||
|
||||
/**
|
||||
* tomoyo_socket_sendmsg - Check permission for sendmsg().
|
||||
*
|
||||
* @sock: Pointer to "struct socket".
|
||||
* @msg: Pointer to "struct msghdr".
|
||||
* @size: Size of message.
|
||||
*
|
||||
* Returns 0 on success, negative value otherwise.
|
||||
*/
|
||||
static int tomoyo_socket_sendmsg(struct socket *sock, struct msghdr *msg,
|
||||
int size)
|
||||
{
|
||||
return tomoyo_socket_sendmsg_permission(sock, msg, size);
|
||||
}
|
||||
|
||||
/*
|
||||
* tomoyo_security_ops is a "struct security_operations" which is used for
|
||||
* registering TOMOYO.
|
||||
|
|
@ -472,6 +530,10 @@ static struct security_operations tomoyo_security_ops = {
|
|||
.sb_mount = tomoyo_sb_mount,
|
||||
.sb_umount = tomoyo_sb_umount,
|
||||
.sb_pivotroot = tomoyo_sb_pivotroot,
|
||||
.socket_bind = tomoyo_socket_bind,
|
||||
.socket_connect = tomoyo_socket_connect,
|
||||
.socket_listen = tomoyo_socket_listen,
|
||||
.socket_sendmsg = tomoyo_socket_sendmsg,
|
||||
};
|
||||
|
||||
/* Lock for GC. */
|
||||
|
|
|
|||
|
|
@ -42,6 +42,39 @@ const u8 tomoyo_index2category[TOMOYO_MAX_MAC_INDEX] = {
|
|||
[TOMOYO_MAC_FILE_MOUNT] = TOMOYO_MAC_CATEGORY_FILE,
|
||||
[TOMOYO_MAC_FILE_UMOUNT] = TOMOYO_MAC_CATEGORY_FILE,
|
||||
[TOMOYO_MAC_FILE_PIVOT_ROOT] = TOMOYO_MAC_CATEGORY_FILE,
|
||||
/* CONFIG::network group */
|
||||
[TOMOYO_MAC_NETWORK_INET_STREAM_BIND] =
|
||||
TOMOYO_MAC_CATEGORY_NETWORK,
|
||||
[TOMOYO_MAC_NETWORK_INET_STREAM_LISTEN] =
|
||||
TOMOYO_MAC_CATEGORY_NETWORK,
|
||||
[TOMOYO_MAC_NETWORK_INET_STREAM_CONNECT] =
|
||||
TOMOYO_MAC_CATEGORY_NETWORK,
|
||||
[TOMOYO_MAC_NETWORK_INET_DGRAM_BIND] =
|
||||
TOMOYO_MAC_CATEGORY_NETWORK,
|
||||
[TOMOYO_MAC_NETWORK_INET_DGRAM_SEND] =
|
||||
TOMOYO_MAC_CATEGORY_NETWORK,
|
||||
[TOMOYO_MAC_NETWORK_INET_RAW_BIND] =
|
||||
TOMOYO_MAC_CATEGORY_NETWORK,
|
||||
[TOMOYO_MAC_NETWORK_INET_RAW_SEND] =
|
||||
TOMOYO_MAC_CATEGORY_NETWORK,
|
||||
[TOMOYO_MAC_NETWORK_UNIX_STREAM_BIND] =
|
||||
TOMOYO_MAC_CATEGORY_NETWORK,
|
||||
[TOMOYO_MAC_NETWORK_UNIX_STREAM_LISTEN] =
|
||||
TOMOYO_MAC_CATEGORY_NETWORK,
|
||||
[TOMOYO_MAC_NETWORK_UNIX_STREAM_CONNECT] =
|
||||
TOMOYO_MAC_CATEGORY_NETWORK,
|
||||
[TOMOYO_MAC_NETWORK_UNIX_DGRAM_BIND] =
|
||||
TOMOYO_MAC_CATEGORY_NETWORK,
|
||||
[TOMOYO_MAC_NETWORK_UNIX_DGRAM_SEND] =
|
||||
TOMOYO_MAC_CATEGORY_NETWORK,
|
||||
[TOMOYO_MAC_NETWORK_UNIX_SEQPACKET_BIND] =
|
||||
TOMOYO_MAC_CATEGORY_NETWORK,
|
||||
[TOMOYO_MAC_NETWORK_UNIX_SEQPACKET_LISTEN] =
|
||||
TOMOYO_MAC_CATEGORY_NETWORK,
|
||||
[TOMOYO_MAC_NETWORK_UNIX_SEQPACKET_CONNECT] =
|
||||
TOMOYO_MAC_CATEGORY_NETWORK,
|
||||
/* CONFIG::misc group */
|
||||
[TOMOYO_MAC_ENVIRON] = TOMOYO_MAC_CATEGORY_MISC,
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -125,6 +158,31 @@ char *tomoyo_read_token(struct tomoyo_acl_param *param)
|
|||
return pos;
|
||||
}
|
||||
|
||||
/**
|
||||
* tomoyo_get_domainname - Read a domainname from a line.
|
||||
*
|
||||
* @param: Pointer to "struct tomoyo_acl_param".
|
||||
*
|
||||
* Returns a domainname on success, NULL otherwise.
|
||||
*/
|
||||
const struct tomoyo_path_info *tomoyo_get_domainname
|
||||
(struct tomoyo_acl_param *param)
|
||||
{
|
||||
char *start = param->data;
|
||||
char *pos = start;
|
||||
while (*pos) {
|
||||
if (*pos++ != ' ' || *pos++ == '/')
|
||||
continue;
|
||||
pos -= 2;
|
||||
*pos++ = '\0';
|
||||
break;
|
||||
}
|
||||
param->data = pos;
|
||||
if (tomoyo_correct_domain(start))
|
||||
return tomoyo_get_name(start);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* tomoyo_parse_ulong - Parse an "unsigned long" value.
|
||||
*
|
||||
|
|
@ -920,14 +978,17 @@ int tomoyo_get_mode(const struct tomoyo_policy_namespace *ns, const u8 profile,
|
|||
const u8 index)
|
||||
{
|
||||
u8 mode;
|
||||
const u8 category = TOMOYO_MAC_CATEGORY_FILE;
|
||||
struct tomoyo_profile *p;
|
||||
|
||||
if (!tomoyo_policy_loaded)
|
||||
return TOMOYO_CONFIG_DISABLED;
|
||||
mode = tomoyo_profile(ns, profile)->config[index];
|
||||
p = tomoyo_profile(ns, profile);
|
||||
mode = p->config[index];
|
||||
if (mode == TOMOYO_CONFIG_USE_DEFAULT)
|
||||
mode = tomoyo_profile(ns, profile)->config[category];
|
||||
mode = p->config[tomoyo_index2category[index]
|
||||
+ TOMOYO_MAX_MAC_INDEX];
|
||||
if (mode == TOMOYO_CONFIG_USE_DEFAULT)
|
||||
mode = tomoyo_profile(ns, profile)->default_config;
|
||||
mode = p->default_config;
|
||||
return mode & 3;
|
||||
}
|
||||
|
||||
|
|
@ -996,6 +1057,17 @@ bool tomoyo_domain_quota_is_ok(struct tomoyo_request_info *r)
|
|||
perm = container_of(ptr, struct tomoyo_mkdev_acl,
|
||||
head)->perm;
|
||||
break;
|
||||
case TOMOYO_TYPE_INET_ACL:
|
||||
perm = container_of(ptr, struct tomoyo_inet_acl,
|
||||
head)->perm;
|
||||
break;
|
||||
case TOMOYO_TYPE_UNIX_ACL:
|
||||
perm = container_of(ptr, struct tomoyo_unix_acl,
|
||||
head)->perm;
|
||||
break;
|
||||
case TOMOYO_TYPE_MANUAL_TASK_ACL:
|
||||
perm = 0;
|
||||
break;
|
||||
default:
|
||||
perm = 1;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue