TOMOYO: Allow using UID/GID etc. of current thread as conditions.
This patch adds support for permission checks using current thread's UID/GID etc. in addition to pathnames. Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp> Signed-off-by: James Morris <jmorris@namei.org>
This commit is contained in:
Родитель
5c4274f138
Коммит
2066a36125
|
@ -1,4 +1,4 @@
|
|||
obj-y = audit.o common.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 file.o gc.o group.o load_policy.o memory.o mount.o realpath.o securityfs_if.o tomoyo.o util.o
|
||||
|
||||
$(obj)/policy/profile.conf:
|
||||
@mkdir -p $(obj)/policy/
|
||||
|
|
|
@ -25,7 +25,7 @@ static char *tomoyo_print_header(struct tomoyo_request_info *r)
|
|||
const pid_t gpid = task_pid_nr(current);
|
||||
static const int tomoyo_buffer_len = 4096;
|
||||
char *buffer = kmalloc(tomoyo_buffer_len, GFP_NOFS);
|
||||
pid_t ppid;
|
||||
int pos;
|
||||
if (!buffer)
|
||||
return NULL;
|
||||
{
|
||||
|
@ -33,21 +33,21 @@ static char *tomoyo_print_header(struct tomoyo_request_info *r)
|
|||
do_gettimeofday(&tv);
|
||||
tomoyo_convert_time(tv.tv_sec, &stamp);
|
||||
}
|
||||
rcu_read_lock();
|
||||
ppid = task_tgid_vnr(current->real_parent);
|
||||
rcu_read_unlock();
|
||||
snprintf(buffer, tomoyo_buffer_len - 1,
|
||||
"#%04u/%02u/%02u %02u:%02u:%02u# profile=%u mode=%s "
|
||||
"granted=%s (global-pid=%u) task={ pid=%u ppid=%u "
|
||||
"uid=%u gid=%u euid=%u egid=%u suid=%u sgid=%u "
|
||||
"fsuid=%u fsgid=%u }",
|
||||
stamp.year, stamp.month, stamp.day, stamp.hour,
|
||||
stamp.min, stamp.sec, r->profile, tomoyo_mode[r->mode],
|
||||
tomoyo_yesno(r->granted), gpid, task_tgid_vnr(current), ppid,
|
||||
current_uid(), current_gid(), current_euid(), current_egid(),
|
||||
current_suid(), current_sgid(), current_fsuid(),
|
||||
current_fsgid());
|
||||
return buffer;
|
||||
pos = snprintf(buffer, tomoyo_buffer_len - 1,
|
||||
"#%04u/%02u/%02u %02u:%02u:%02u# profile=%u mode=%s "
|
||||
"granted=%s (global-pid=%u) task={ pid=%u ppid=%u "
|
||||
"uid=%u gid=%u euid=%u egid=%u suid=%u sgid=%u "
|
||||
"fsuid=%u fsgid=%u }", stamp.year, stamp.month,
|
||||
stamp.day, stamp.hour, stamp.min, stamp.sec, r->profile,
|
||||
tomoyo_mode[r->mode], tomoyo_yesno(r->granted), gpid,
|
||||
tomoyo_sys_getpid(), tomoyo_sys_getppid(),
|
||||
current_uid(), current_gid(), current_euid(),
|
||||
current_egid(), current_suid(), current_sgid(),
|
||||
current_fsuid(), current_fsgid());
|
||||
if (pos < tomoyo_buffer_len - 1)
|
||||
return buffer;
|
||||
kfree(buffer);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -48,6 +48,20 @@ const char * const tomoyo_mac_keywords[TOMOYO_MAX_MAC_INDEX
|
|||
[TOMOYO_MAX_MAC_INDEX + TOMOYO_MAC_CATEGORY_FILE] = "file",
|
||||
};
|
||||
|
||||
/* String table for conditions. */
|
||||
const char * const tomoyo_condition_keyword[TOMOYO_MAX_CONDITION_KEYWORD] = {
|
||||
[TOMOYO_TASK_UID] = "task.uid",
|
||||
[TOMOYO_TASK_EUID] = "task.euid",
|
||||
[TOMOYO_TASK_SUID] = "task.suid",
|
||||
[TOMOYO_TASK_FSUID] = "task.fsuid",
|
||||
[TOMOYO_TASK_GID] = "task.gid",
|
||||
[TOMOYO_TASK_EGID] = "task.egid",
|
||||
[TOMOYO_TASK_SGID] = "task.sgid",
|
||||
[TOMOYO_TASK_FSGID] = "task.fsgid",
|
||||
[TOMOYO_TASK_PID] = "task.pid",
|
||||
[TOMOYO_TASK_PPID] = "task.ppid",
|
||||
};
|
||||
|
||||
/* String table for PREFERENCE keyword. */
|
||||
static const char * const tomoyo_pref_keywords[TOMOYO_MAX_PREF] = {
|
||||
[TOMOYO_PREF_MAX_AUDIT_LOG] = "max_audit_log",
|
||||
|
@ -294,15 +308,16 @@ static void tomoyo_print_name_union(struct tomoyo_io_buffer *head,
|
|||
}
|
||||
|
||||
/**
|
||||
* tomoyo_print_number_union - Print a tomoyo_number_union.
|
||||
* tomoyo_print_number_union_nospace - Print a tomoyo_number_union without a space.
|
||||
*
|
||||
* @head: Pointer to "struct tomoyo_io_buffer".
|
||||
* @ptr: Pointer to "struct tomoyo_number_union".
|
||||
* @head: Pointer to "struct tomoyo_io_buffer".
|
||||
* @ptr: Pointer to "struct tomoyo_number_union".
|
||||
*
|
||||
* Returns nothing.
|
||||
*/
|
||||
static void tomoyo_print_number_union(struct tomoyo_io_buffer *head,
|
||||
const struct tomoyo_number_union *ptr)
|
||||
static void tomoyo_print_number_union_nospace
|
||||
(struct tomoyo_io_buffer *head, const struct tomoyo_number_union *ptr)
|
||||
{
|
||||
tomoyo_set_space(head);
|
||||
if (ptr->group) {
|
||||
tomoyo_set_string(head, "@");
|
||||
tomoyo_set_string(head, ptr->group->group_name->name);
|
||||
|
@ -325,8 +340,8 @@ static void tomoyo_print_number_union(struct tomoyo_io_buffer *head,
|
|||
"0%lo", min);
|
||||
break;
|
||||
default:
|
||||
tomoyo_addprintf(buffer, sizeof(buffer),
|
||||
"%lu", min);
|
||||
tomoyo_addprintf(buffer, sizeof(buffer), "%lu",
|
||||
min);
|
||||
break;
|
||||
}
|
||||
if (min == max && min_type == max_type)
|
||||
|
@ -339,6 +354,21 @@ static void tomoyo_print_number_union(struct tomoyo_io_buffer *head,
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* tomoyo_print_number_union - Print a tomoyo_number_union.
|
||||
*
|
||||
* @head: Pointer to "struct tomoyo_io_buffer".
|
||||
* @ptr: Pointer to "struct tomoyo_number_union".
|
||||
*
|
||||
* Returns nothing.
|
||||
*/
|
||||
static void tomoyo_print_number_union(struct tomoyo_io_buffer *head,
|
||||
const struct tomoyo_number_union *ptr)
|
||||
{
|
||||
tomoyo_set_space(head);
|
||||
tomoyo_print_number_union_nospace(head, ptr);
|
||||
}
|
||||
|
||||
/**
|
||||
* tomoyo_assign_profile - Create a new profile.
|
||||
*
|
||||
|
@ -1003,6 +1033,91 @@ static int tomoyo_write_domain(struct tomoyo_io_buffer *head)
|
|||
is_delete);
|
||||
}
|
||||
|
||||
/**
|
||||
* tomoyo_print_condition - Print condition part.
|
||||
*
|
||||
* @head: Pointer to "struct tomoyo_io_buffer".
|
||||
* @cond: Pointer to "struct tomoyo_condition".
|
||||
*
|
||||
* Returns true on success, false otherwise.
|
||||
*/
|
||||
static bool tomoyo_print_condition(struct tomoyo_io_buffer *head,
|
||||
const struct tomoyo_condition *cond)
|
||||
{
|
||||
switch (head->r.cond_step) {
|
||||
case 0:
|
||||
head->r.cond_index = 0;
|
||||
head->r.cond_step++;
|
||||
/* fall through */
|
||||
case 1:
|
||||
{
|
||||
const u16 condc = cond->condc;
|
||||
const struct tomoyo_condition_element *condp =
|
||||
(typeof(condp)) (cond + 1);
|
||||
const struct tomoyo_number_union *numbers_p =
|
||||
(typeof(numbers_p)) (condp + condc);
|
||||
u16 skip;
|
||||
for (skip = 0; skip < head->r.cond_index; skip++) {
|
||||
const u8 left = condp->left;
|
||||
const u8 right = condp->right;
|
||||
condp++;
|
||||
switch (left) {
|
||||
case TOMOYO_NUMBER_UNION:
|
||||
numbers_p++;
|
||||
break;
|
||||
}
|
||||
switch (right) {
|
||||
case TOMOYO_NUMBER_UNION:
|
||||
numbers_p++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
while (head->r.cond_index < condc) {
|
||||
const u8 match = condp->equals;
|
||||
const u8 left = condp->left;
|
||||
const u8 right = condp->right;
|
||||
if (!tomoyo_flush(head))
|
||||
return false;
|
||||
condp++;
|
||||
head->r.cond_index++;
|
||||
tomoyo_set_space(head);
|
||||
switch (left) {
|
||||
case TOMOYO_NUMBER_UNION:
|
||||
tomoyo_print_number_union_nospace
|
||||
(head, numbers_p++);
|
||||
break;
|
||||
default:
|
||||
tomoyo_set_string(head,
|
||||
tomoyo_condition_keyword[left]);
|
||||
break;
|
||||
}
|
||||
tomoyo_set_string(head, match ? "=" : "!=");
|
||||
switch (right) {
|
||||
case TOMOYO_NUMBER_UNION:
|
||||
tomoyo_print_number_union_nospace
|
||||
(head, numbers_p++);
|
||||
break;
|
||||
default:
|
||||
tomoyo_set_string(head,
|
||||
tomoyo_condition_keyword[right]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
head->r.cond_step++;
|
||||
/* fall through */
|
||||
case 2:
|
||||
if (!tomoyo_flush(head))
|
||||
break;
|
||||
head->r.cond_step++;
|
||||
/* fall through */
|
||||
case 3:
|
||||
tomoyo_set_lf(head);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* tomoyo_set_group - Print "acl_group " header keyword and category name.
|
||||
*
|
||||
|
@ -1037,6 +1152,8 @@ static bool tomoyo_print_entry(struct tomoyo_io_buffer *head,
|
|||
bool first = true;
|
||||
u8 bit;
|
||||
|
||||
if (head->r.print_cond_part)
|
||||
goto print_cond_part;
|
||||
if (acl->is_deleted)
|
||||
return true;
|
||||
if (!tomoyo_flush(head))
|
||||
|
@ -1135,7 +1252,18 @@ static bool tomoyo_print_entry(struct tomoyo_io_buffer *head,
|
|||
tomoyo_print_name_union(head, &ptr->fs_type);
|
||||
tomoyo_print_number_union(head, &ptr->flags);
|
||||
}
|
||||
tomoyo_set_lf(head);
|
||||
if (acl->cond) {
|
||||
head->r.print_cond_part = true;
|
||||
head->r.cond_step = 0;
|
||||
if (!tomoyo_flush(head))
|
||||
return false;
|
||||
print_cond_part:
|
||||
if (!tomoyo_print_condition(head, acl->cond))
|
||||
return false;
|
||||
head->r.print_cond_part = false;
|
||||
} else {
|
||||
tomoyo_set_lf(head);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -21,7 +21,8 @@
|
|||
#include <linux/list.h>
|
||||
#include <linux/cred.h>
|
||||
#include <linux/poll.h>
|
||||
struct linux_binprm;
|
||||
#include <linux/binfmts.h>
|
||||
#include <linux/highmem.h>
|
||||
|
||||
/********** Constants definitions. **********/
|
||||
|
||||
|
@ -41,6 +42,22 @@ struct linux_binprm;
|
|||
/* Group number is an integer between 0 and 255. */
|
||||
#define TOMOYO_MAX_ACL_GROUPS 256
|
||||
|
||||
/* Index numbers for "struct tomoyo_condition". */
|
||||
enum tomoyo_conditions_index {
|
||||
TOMOYO_TASK_UID, /* current_uid() */
|
||||
TOMOYO_TASK_EUID, /* current_euid() */
|
||||
TOMOYO_TASK_SUID, /* current_suid() */
|
||||
TOMOYO_TASK_FSUID, /* current_fsuid() */
|
||||
TOMOYO_TASK_GID, /* current_gid() */
|
||||
TOMOYO_TASK_EGID, /* current_egid() */
|
||||
TOMOYO_TASK_SGID, /* current_sgid() */
|
||||
TOMOYO_TASK_FSGID, /* current_fsgid() */
|
||||
TOMOYO_TASK_PID, /* sys_getpid() */
|
||||
TOMOYO_TASK_PPID, /* sys_getppid() */
|
||||
TOMOYO_MAX_CONDITION_KEYWORD,
|
||||
TOMOYO_NUMBER_UNION,
|
||||
};
|
||||
|
||||
/* Index numbers for operation mode. */
|
||||
enum tomoyo_mode_index {
|
||||
TOMOYO_CONFIG_DISABLED,
|
||||
|
@ -61,6 +78,7 @@ enum tomoyo_policy_id {
|
|||
TOMOYO_ID_TRANSITION_CONTROL,
|
||||
TOMOYO_ID_AGGREGATOR,
|
||||
TOMOYO_ID_MANAGER,
|
||||
TOMOYO_ID_CONDITION,
|
||||
TOMOYO_ID_NAME,
|
||||
TOMOYO_ID_ACL,
|
||||
TOMOYO_ID_DOMAIN,
|
||||
|
@ -370,9 +388,32 @@ struct tomoyo_number_group {
|
|||
struct tomoyo_number_union number;
|
||||
};
|
||||
|
||||
/* Structure for entries which follows "struct tomoyo_condition". */
|
||||
struct tomoyo_condition_element {
|
||||
/* Left hand operand. */
|
||||
u8 left;
|
||||
/* Right hand operand. */
|
||||
u8 right;
|
||||
/* Equation operator. True if equals or overlaps, false otherwise. */
|
||||
bool equals;
|
||||
};
|
||||
|
||||
/* Structure for optional arguments. */
|
||||
struct tomoyo_condition {
|
||||
struct tomoyo_shared_acl_head head;
|
||||
u32 size; /* Memory size allocated for this entry. */
|
||||
u16 condc; /* Number of conditions in this struct. */
|
||||
u16 numbers_count; /* Number of "struct tomoyo_number_union values". */
|
||||
/*
|
||||
* struct tomoyo_condition_element condition[condc];
|
||||
* struct tomoyo_number_union values[numbers_count];
|
||||
*/
|
||||
};
|
||||
|
||||
/* Common header for individual entries. */
|
||||
struct tomoyo_acl_info {
|
||||
struct list_head list;
|
||||
struct tomoyo_condition *cond; /* Maybe NULL. */
|
||||
bool is_deleted;
|
||||
u8 type; /* One of values in "enum tomoyo_acl_entry_type_index". */
|
||||
} __packed;
|
||||
|
@ -475,12 +516,15 @@ struct tomoyo_io_buffer {
|
|||
unsigned int step;
|
||||
unsigned int query_index;
|
||||
u16 index;
|
||||
u16 cond_index;
|
||||
u8 acl_group_index;
|
||||
u8 cond_step;
|
||||
u8 bit;
|
||||
u8 w_pos;
|
||||
bool eof;
|
||||
bool print_this_domain_only;
|
||||
bool print_transition_related_only;
|
||||
bool print_cond_part;
|
||||
const char *w[TOMOYO_MAX_IO_READ_QUEUE];
|
||||
} r;
|
||||
struct {
|
||||
|
@ -586,6 +630,8 @@ struct tomoyo_policy_namespace {
|
|||
|
||||
bool tomoyo_compare_number_union(const unsigned long value,
|
||||
const struct tomoyo_number_union *ptr);
|
||||
bool tomoyo_condition(struct tomoyo_request_info *r,
|
||||
const struct tomoyo_condition *cond);
|
||||
bool tomoyo_correct_domain(const unsigned char *domainname);
|
||||
bool tomoyo_correct_path(const char *filename);
|
||||
bool tomoyo_correct_word(const char *string);
|
||||
|
@ -664,6 +710,7 @@ 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,
|
||||
const char __user *buffer, const int buffer_len);
|
||||
struct tomoyo_condition *tomoyo_get_condition(struct tomoyo_acl_param *param);
|
||||
struct tomoyo_domain_info *tomoyo_assign_domain(const char *domainname,
|
||||
const bool transit);
|
||||
struct tomoyo_domain_info *tomoyo_find_domain(const char *domainname);
|
||||
|
@ -675,6 +722,7 @@ struct tomoyo_profile *tomoyo_profile(const struct tomoyo_policy_namespace *ns,
|
|||
const u8 profile);
|
||||
unsigned int tomoyo_check_flags(const struct tomoyo_domain_info *domain,
|
||||
const u8 index);
|
||||
u8 tomoyo_parse_ulong(unsigned long *result, char **str);
|
||||
void *tomoyo_commit_ok(void *data, const unsigned int size);
|
||||
void __init tomoyo_load_builtin_policy(void);
|
||||
void __init tomoyo_mm_init(void);
|
||||
|
@ -683,6 +731,7 @@ void tomoyo_check_acl(struct tomoyo_request_info *r,
|
|||
const struct tomoyo_acl_info *));
|
||||
void tomoyo_check_profile(void);
|
||||
void tomoyo_convert_time(time_t time, struct tomoyo_time *stamp);
|
||||
void tomoyo_del_condition(struct list_head *element);
|
||||
void tomoyo_fill_path_info(struct tomoyo_path_info *ptr);
|
||||
void tomoyo_init_policy_namespace(struct tomoyo_policy_namespace *ns);
|
||||
void tomoyo_io_printf(struct tomoyo_io_buffer *head, const char *fmt, ...)
|
||||
|
@ -706,6 +755,8 @@ void tomoyo_write_log2(struct tomoyo_request_info *r, int len, const char *fmt,
|
|||
/********** External variable definitions. **********/
|
||||
|
||||
extern bool tomoyo_policy_loaded;
|
||||
extern const char * const tomoyo_condition_keyword
|
||||
[TOMOYO_MAX_CONDITION_KEYWORD];
|
||||
extern const char * const tomoyo_dif[TOMOYO_MAX_DOMAIN_INFO_FLAGS];
|
||||
extern const char * const tomoyo_mac_keywords[TOMOYO_MAX_MAC_INDEX
|
||||
+ TOMOYO_MAX_MAC_CATEGORY_INDEX];
|
||||
|
@ -715,6 +766,7 @@ 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];
|
||||
extern const u8 tomoyo_pp2mac[TOMOYO_MAX_PATH2_OPERATION];
|
||||
extern struct list_head tomoyo_condition_list;
|
||||
extern struct list_head tomoyo_domain_list;
|
||||
extern struct list_head tomoyo_name_list[TOMOYO_MAX_HASH];
|
||||
extern struct list_head tomoyo_namespace_list;
|
||||
|
@ -749,6 +801,36 @@ static inline void tomoyo_read_unlock(int idx)
|
|||
srcu_read_unlock(&tomoyo_ss, idx);
|
||||
}
|
||||
|
||||
/**
|
||||
* tomoyo_sys_getppid - Copy of getppid().
|
||||
*
|
||||
* Returns parent process's PID.
|
||||
*
|
||||
* Alpha does not have getppid() defined. To be able to build this module on
|
||||
* Alpha, I have to copy getppid() from kernel/timer.c.
|
||||
*/
|
||||
static inline pid_t tomoyo_sys_getppid(void)
|
||||
{
|
||||
pid_t pid;
|
||||
rcu_read_lock();
|
||||
pid = task_tgid_vnr(current->real_parent);
|
||||
rcu_read_unlock();
|
||||
return pid;
|
||||
}
|
||||
|
||||
/**
|
||||
* tomoyo_sys_getpid - Copy of getpid().
|
||||
*
|
||||
* Returns current thread's PID.
|
||||
*
|
||||
* Alpha does not have getpid() defined. To be able to build this module on
|
||||
* Alpha, I have to copy getpid() from kernel/timer.c.
|
||||
*/
|
||||
static inline pid_t tomoyo_sys_getpid(void)
|
||||
{
|
||||
return task_tgid_vnr(current);
|
||||
}
|
||||
|
||||
/**
|
||||
* tomoyo_pathcmp - strcmp() for "struct tomoyo_path_info" structure.
|
||||
*
|
||||
|
@ -779,6 +861,19 @@ static inline void tomoyo_put_name(const struct tomoyo_path_info *name)
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* tomoyo_put_condition - Drop reference on "struct tomoyo_condition".
|
||||
*
|
||||
* @cond: Pointer to "struct tomoyo_condition". Maybe NULL.
|
||||
*
|
||||
* Returns nothing.
|
||||
*/
|
||||
static inline void tomoyo_put_condition(struct tomoyo_condition *cond)
|
||||
{
|
||||
if (cond)
|
||||
atomic_dec(&cond->head.users);
|
||||
}
|
||||
|
||||
/**
|
||||
* tomoyo_put_group - Drop reference on "struct tomoyo_group".
|
||||
*
|
||||
|
|
|
@ -0,0 +1,349 @@
|
|||
/*
|
||||
* security/tomoyo/condition.c
|
||||
*
|
||||
* Copyright (C) 2005-2011 NTT DATA CORPORATION
|
||||
*/
|
||||
|
||||
#include "common.h"
|
||||
#include <linux/slab.h>
|
||||
|
||||
/* List of "struct tomoyo_condition". */
|
||||
LIST_HEAD(tomoyo_condition_list);
|
||||
|
||||
/**
|
||||
* tomoyo_same_condition - Check for duplicated "struct tomoyo_condition" entry.
|
||||
*
|
||||
* @a: Pointer to "struct tomoyo_condition".
|
||||
* @b: Pointer to "struct tomoyo_condition".
|
||||
*
|
||||
* Returns true if @a == @b, false otherwise.
|
||||
*/
|
||||
static inline bool tomoyo_same_condition(const struct tomoyo_condition *a,
|
||||
const struct tomoyo_condition *b)
|
||||
{
|
||||
return a->size == b->size && a->condc == b->condc &&
|
||||
a->numbers_count == b->numbers_count &&
|
||||
!memcmp(a + 1, b + 1, a->size - sizeof(*a));
|
||||
}
|
||||
|
||||
/**
|
||||
* tomoyo_condition_type - Get condition type.
|
||||
*
|
||||
* @word: Keyword string.
|
||||
*
|
||||
* Returns one of values in "enum tomoyo_conditions_index" on success,
|
||||
* TOMOYO_MAX_CONDITION_KEYWORD otherwise.
|
||||
*/
|
||||
static u8 tomoyo_condition_type(const char *word)
|
||||
{
|
||||
u8 i;
|
||||
for (i = 0; i < TOMOYO_MAX_CONDITION_KEYWORD; i++) {
|
||||
if (!strcmp(word, tomoyo_condition_keyword[i]))
|
||||
break;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
/* Define this to enable debug mode. */
|
||||
/* #define DEBUG_CONDITION */
|
||||
|
||||
#ifdef DEBUG_CONDITION
|
||||
#define dprintk printk
|
||||
#else
|
||||
#define dprintk(...) do { } while (0)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* tomoyo_commit_condition - Commit "struct tomoyo_condition".
|
||||
*
|
||||
* @entry: Pointer to "struct tomoyo_condition".
|
||||
*
|
||||
* Returns pointer to "struct tomoyo_condition" on success, NULL otherwise.
|
||||
*
|
||||
* This function merges duplicated entries. This function returns NULL if
|
||||
* @entry is not duplicated but memory quota for policy has exceeded.
|
||||
*/
|
||||
static struct tomoyo_condition *tomoyo_commit_condition
|
||||
(struct tomoyo_condition *entry)
|
||||
{
|
||||
struct tomoyo_condition *ptr;
|
||||
bool found = false;
|
||||
if (mutex_lock_interruptible(&tomoyo_policy_lock)) {
|
||||
dprintk(KERN_WARNING "%u: %s failed\n", __LINE__, __func__);
|
||||
ptr = NULL;
|
||||
found = true;
|
||||
goto out;
|
||||
}
|
||||
list_for_each_entry_rcu(ptr, &tomoyo_condition_list, head.list) {
|
||||
if (!tomoyo_same_condition(ptr, entry))
|
||||
continue;
|
||||
/* Same entry found. Share this entry. */
|
||||
atomic_inc(&ptr->head.users);
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
if (!found) {
|
||||
if (tomoyo_memory_ok(entry)) {
|
||||
atomic_set(&entry->head.users, 1);
|
||||
list_add_rcu(&entry->head.list,
|
||||
&tomoyo_condition_list);
|
||||
} else {
|
||||
found = true;
|
||||
ptr = NULL;
|
||||
}
|
||||
}
|
||||
mutex_unlock(&tomoyo_policy_lock);
|
||||
out:
|
||||
if (found) {
|
||||
tomoyo_del_condition(&entry->head.list);
|
||||
kfree(entry);
|
||||
entry = ptr;
|
||||
}
|
||||
return entry;
|
||||
}
|
||||
|
||||
/**
|
||||
* tomoyo_get_condition - Parse condition part.
|
||||
*
|
||||
* @param: Pointer to "struct tomoyo_acl_param".
|
||||
*
|
||||
* Returns pointer to "struct tomoyo_condition" on success, NULL otherwise.
|
||||
*/
|
||||
struct tomoyo_condition *tomoyo_get_condition(struct tomoyo_acl_param *param)
|
||||
{
|
||||
struct tomoyo_condition *entry = NULL;
|
||||
struct tomoyo_condition_element *condp = NULL;
|
||||
struct tomoyo_number_union *numbers_p = NULL;
|
||||
struct tomoyo_condition e = { };
|
||||
char * const start_of_string = param->data;
|
||||
char * const end_of_string = start_of_string + strlen(start_of_string);
|
||||
char *pos;
|
||||
rerun:
|
||||
pos = start_of_string;
|
||||
while (1) {
|
||||
u8 left = -1;
|
||||
u8 right = -1;
|
||||
char *left_word = pos;
|
||||
char *cp;
|
||||
char *right_word;
|
||||
bool is_not;
|
||||
if (!*left_word)
|
||||
break;
|
||||
/*
|
||||
* Since left-hand condition does not allow use of "path_group"
|
||||
* or "number_group" and environment variable's names do not
|
||||
* accept '=', it is guaranteed that the original line consists
|
||||
* of one or more repetition of $left$operator$right blocks
|
||||
* where "$left is free from '=' and ' '" and "$operator is
|
||||
* either '=' or '!='" and "$right is free from ' '".
|
||||
* Therefore, we can reconstruct the original line at the end
|
||||
* of dry run even if we overwrite $operator with '\0'.
|
||||
*/
|
||||
cp = strchr(pos, ' ');
|
||||
if (cp) {
|
||||
*cp = '\0'; /* Will restore later. */
|
||||
pos = cp + 1;
|
||||
} else {
|
||||
pos = "";
|
||||
}
|
||||
right_word = strchr(left_word, '=');
|
||||
if (!right_word || right_word == left_word)
|
||||
goto out;
|
||||
is_not = *(right_word - 1) == '!';
|
||||
if (is_not)
|
||||
*(right_word++ - 1) = '\0'; /* Will restore later. */
|
||||
else if (*(right_word + 1) != '=')
|
||||
*right_word++ = '\0'; /* Will restore later. */
|
||||
else
|
||||
goto out;
|
||||
dprintk(KERN_WARNING "%u: <%s>%s=<%s>\n", __LINE__, left_word,
|
||||
is_not ? "!" : "", right_word);
|
||||
left = tomoyo_condition_type(left_word);
|
||||
dprintk(KERN_WARNING "%u: <%s> left=%u\n", __LINE__, left_word,
|
||||
left);
|
||||
if (left == TOMOYO_MAX_CONDITION_KEYWORD) {
|
||||
if (!numbers_p) {
|
||||
e.numbers_count++;
|
||||
} else {
|
||||
e.numbers_count--;
|
||||
left = TOMOYO_NUMBER_UNION;
|
||||
param->data = left_word;
|
||||
if (*left_word == '@' ||
|
||||
!tomoyo_parse_number_union(param,
|
||||
numbers_p++))
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
if (!condp)
|
||||
e.condc++;
|
||||
else
|
||||
e.condc--;
|
||||
right = tomoyo_condition_type(right_word);
|
||||
if (right == TOMOYO_MAX_CONDITION_KEYWORD) {
|
||||
if (!numbers_p) {
|
||||
e.numbers_count++;
|
||||
} else {
|
||||
e.numbers_count--;
|
||||
right = TOMOYO_NUMBER_UNION;
|
||||
param->data = right_word;
|
||||
if (!tomoyo_parse_number_union(param,
|
||||
numbers_p++))
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
if (!condp) {
|
||||
dprintk(KERN_WARNING "%u: dry_run left=%u right=%u "
|
||||
"match=%u\n", __LINE__, left, right, !is_not);
|
||||
continue;
|
||||
}
|
||||
condp->left = left;
|
||||
condp->right = right;
|
||||
condp->equals = !is_not;
|
||||
dprintk(KERN_WARNING "%u: left=%u right=%u match=%u\n",
|
||||
__LINE__, condp->left, condp->right,
|
||||
condp->equals);
|
||||
condp++;
|
||||
}
|
||||
dprintk(KERN_INFO "%u: cond=%u numbers=%u\n",
|
||||
__LINE__, e.condc, e.numbers_count);
|
||||
if (entry) {
|
||||
BUG_ON(e.numbers_count | e.condc);
|
||||
return tomoyo_commit_condition(entry);
|
||||
}
|
||||
e.size = sizeof(*entry)
|
||||
+ e.condc * sizeof(struct tomoyo_condition_element)
|
||||
+ e.numbers_count * sizeof(struct tomoyo_number_union);
|
||||
entry = kzalloc(e.size, GFP_NOFS);
|
||||
if (!entry)
|
||||
return NULL;
|
||||
*entry = e;
|
||||
condp = (struct tomoyo_condition_element *) (entry + 1);
|
||||
numbers_p = (struct tomoyo_number_union *) (condp + e.condc);
|
||||
{
|
||||
bool flag = false;
|
||||
for (pos = start_of_string; pos < end_of_string; pos++) {
|
||||
if (*pos)
|
||||
continue;
|
||||
if (flag) /* Restore " ". */
|
||||
*pos = ' ';
|
||||
else if (*(pos + 1) == '=') /* Restore "!=". */
|
||||
*pos = '!';
|
||||
else /* Restore "=". */
|
||||
*pos = '=';
|
||||
flag = !flag;
|
||||
}
|
||||
}
|
||||
goto rerun;
|
||||
out:
|
||||
dprintk(KERN_WARNING "%u: %s failed\n", __LINE__, __func__);
|
||||
if (entry) {
|
||||
tomoyo_del_condition(&entry->head.list);
|
||||
kfree(entry);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* tomoyo_condition - Check condition part.
|
||||
*
|
||||
* @r: Pointer to "struct tomoyo_request_info".
|
||||
* @cond: Pointer to "struct tomoyo_condition". Maybe NULL.
|
||||
*
|
||||
* Returns true on success, false otherwise.
|
||||
*
|
||||
* Caller holds tomoyo_read_lock().
|
||||
*/
|
||||
bool tomoyo_condition(struct tomoyo_request_info *r,
|
||||
const struct tomoyo_condition *cond)
|
||||
{
|
||||
u32 i;
|
||||
unsigned long min_v[2] = { 0, 0 };
|
||||
unsigned long max_v[2] = { 0, 0 };
|
||||
const struct tomoyo_condition_element *condp;
|
||||
const struct tomoyo_number_union *numbers_p;
|
||||
u16 condc;
|
||||
if (!cond)
|
||||
return true;
|
||||
condc = cond->condc;
|
||||
condp = (struct tomoyo_condition_element *) (cond + 1);
|
||||
numbers_p = (const struct tomoyo_number_union *) (condp + condc);
|
||||
for (i = 0; i < condc; i++) {
|
||||
const bool match = condp->equals;
|
||||
const u8 left = condp->left;
|
||||
const u8 right = condp->right;
|
||||
u8 j;
|
||||
condp++;
|
||||
/* Check numeric or bit-op expressions. */
|
||||
for (j = 0; j < 2; j++) {
|
||||
const u8 index = j ? right : left;
|
||||
unsigned long value = 0;
|
||||
switch (index) {
|
||||
case TOMOYO_TASK_UID:
|
||||
value = current_uid();
|
||||
break;
|
||||
case TOMOYO_TASK_EUID:
|
||||
value = current_euid();
|
||||
break;
|
||||
case TOMOYO_TASK_SUID:
|
||||
value = current_suid();
|
||||
break;
|
||||
case TOMOYO_TASK_FSUID:
|
||||
value = current_fsuid();
|
||||
break;
|
||||
case TOMOYO_TASK_GID:
|
||||
value = current_gid();
|
||||
break;
|
||||
case TOMOYO_TASK_EGID:
|
||||
value = current_egid();
|
||||
break;
|
||||
case TOMOYO_TASK_SGID:
|
||||
value = current_sgid();
|
||||
break;
|
||||
case TOMOYO_TASK_FSGID:
|
||||
value = current_fsgid();
|
||||
break;
|
||||
case TOMOYO_TASK_PID:
|
||||
value = tomoyo_sys_getpid();
|
||||
break;
|
||||
case TOMOYO_TASK_PPID:
|
||||
value = tomoyo_sys_getppid();
|
||||
break;
|
||||
case TOMOYO_NUMBER_UNION:
|
||||
/* Fetch values later. */
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
max_v[j] = value;
|
||||
min_v[j] = value;
|
||||
}
|
||||
if (left == TOMOYO_NUMBER_UNION) {
|
||||
/* Fetch values now. */
|
||||
const struct tomoyo_number_union *ptr = numbers_p++;
|
||||
min_v[0] = ptr->values[0];
|
||||
max_v[0] = ptr->values[1];
|
||||
}
|
||||
if (right == TOMOYO_NUMBER_UNION) {
|
||||
/* Fetch values now. */
|
||||
const struct tomoyo_number_union *ptr = numbers_p++;
|
||||
if (ptr->group) {
|
||||
if (tomoyo_number_matches_group(min_v[0],
|
||||
max_v[0],
|
||||
ptr->group)
|
||||
== match)
|
||||
continue;
|
||||
} else {
|
||||
if ((min_v[0] <= ptr->values[1] &&
|
||||
max_v[0] >= ptr->values[0]) == match)
|
||||
continue;
|
||||
}
|
||||
goto out;
|
||||
}
|
||||
/* Normal value range comparison. */
|
||||
if ((min_v[0] <= max_v[1] && max_v[0] >= min_v[1]) == match)
|
||||
continue;
|
||||
out:
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
|
@ -69,7 +69,7 @@ int tomoyo_update_policy(struct tomoyo_acl_head *new_entry, const int size,
|
|||
static inline bool tomoyo_same_acl_head(const struct tomoyo_acl_info *a,
|
||||
const struct tomoyo_acl_info *b)
|
||||
{
|
||||
return a->type == b->type;
|
||||
return a->type == b->type && a->cond == b->cond;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -100,8 +100,13 @@ int tomoyo_update_domain(struct tomoyo_acl_info *new_entry, const int size,
|
|||
struct tomoyo_acl_info *entry;
|
||||
struct list_head * const list = param->list;
|
||||
|
||||
if (param->data[0]) {
|
||||
new_entry->cond = tomoyo_get_condition(param);
|
||||
if (!new_entry->cond)
|
||||
return -EINVAL;
|
||||
}
|
||||
if (mutex_lock_interruptible(&tomoyo_policy_lock))
|
||||
return error;
|
||||
goto out;
|
||||
list_for_each_entry_rcu(entry, list, list) {
|
||||
if (!tomoyo_same_acl_head(entry, new_entry) ||
|
||||
!check_duplicate(entry, new_entry))
|
||||
|
@ -122,6 +127,8 @@ int tomoyo_update_domain(struct tomoyo_acl_info *new_entry, const int size,
|
|||
}
|
||||
}
|
||||
mutex_unlock(&tomoyo_policy_lock);
|
||||
out:
|
||||
tomoyo_put_condition(new_entry->cond);
|
||||
return error;
|
||||
}
|
||||
|
||||
|
@ -148,10 +155,12 @@ retry:
|
|||
list_for_each_entry_rcu(ptr, list, list) {
|
||||
if (ptr->is_deleted || ptr->type != r->param_type)
|
||||
continue;
|
||||
if (check_entry(r, ptr)) {
|
||||
r->granted = true;
|
||||
return;
|
||||
}
|
||||
if (!check_entry(r, ptr))
|
||||
continue;
|
||||
if (!tomoyo_condition(r, ptr->cond))
|
||||
continue;
|
||||
r->granted = true;
|
||||
return;
|
||||
}
|
||||
if (!retried) {
|
||||
retried = true;
|
||||
|
|
|
@ -25,6 +25,7 @@ static const u8 tomoyo_element_size[TOMOYO_MAX_POLICY] = {
|
|||
[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], */
|
||||
|
@ -162,6 +163,10 @@ static bool tomoyo_add_to_gc(const int type, struct list_head *element)
|
|||
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;
|
||||
|
@ -246,6 +251,7 @@ static void tomoyo_del_acl(struct list_head *element)
|
|||
{
|
||||
struct tomoyo_acl_info *acl =
|
||||
container_of(element, typeof(*acl), list);
|
||||
tomoyo_put_condition(acl->cond);
|
||||
switch (acl->type) {
|
||||
case TOMOYO_TYPE_PATH_ACL:
|
||||
{
|
||||
|
@ -338,6 +344,27 @@ static bool tomoyo_del_domain(struct list_head *element)
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* tomoyo_del_condition - Delete members in "struct tomoyo_condition".
|
||||
*
|
||||
* @element: Pointer to "struct list_head".
|
||||
*
|
||||
* Returns nothing.
|
||||
*/
|
||||
void tomoyo_del_condition(struct list_head *element)
|
||||
{
|
||||
struct tomoyo_condition *cond = container_of(element, typeof(*cond),
|
||||
head.list);
|
||||
const u16 condc = cond->condc;
|
||||
const u16 numbers_count = cond->numbers_count;
|
||||
unsigned int i;
|
||||
const struct tomoyo_condition_element *condp
|
||||
= (const struct tomoyo_condition_element *) (cond + 1);
|
||||
struct tomoyo_number_union *numbers_p
|
||||
= (struct tomoyo_number_union *) (condp + condc);
|
||||
for (i = 0; i < numbers_count; i++)
|
||||
tomoyo_put_number_union(numbers_p++);
|
||||
}
|
||||
|
||||
/**
|
||||
* tomoyo_del_name - Delete members in "struct tomoyo_name".
|
||||
|
@ -494,15 +521,18 @@ static void tomoyo_collect_entry(void)
|
|||
}
|
||||
}
|
||||
}
|
||||
for (i = 0; i < TOMOYO_MAX_HASH; i++) {
|
||||
struct list_head *list = &tomoyo_name_list[i];
|
||||
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];
|
||||
struct tomoyo_shared_acl_head *ptr;
|
||||
list_for_each_entry(ptr, list, list) {
|
||||
if (atomic_read(&ptr->users))
|
||||
continue;
|
||||
if (!tomoyo_add_to_gc(TOMOYO_ID_NAME, &ptr->list))
|
||||
if (!tomoyo_add_to_gc(id, &ptr->list))
|
||||
goto unlock;
|
||||
}
|
||||
id = TOMOYO_ID_NAME;
|
||||
}
|
||||
unlock:
|
||||
tomoyo_read_unlock(idx);
|
||||
|
@ -557,6 +587,9 @@ static bool tomoyo_kfree_entry(void)
|
|||
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"
|
||||
|
|
|
@ -138,7 +138,7 @@ char *tomoyo_read_token(struct tomoyo_acl_param *param)
|
|||
* The @src is updated to point the first character after the value
|
||||
* on success.
|
||||
*/
|
||||
static u8 tomoyo_parse_ulong(unsigned long *result, char **str)
|
||||
u8 tomoyo_parse_ulong(unsigned long *result, char **str)
|
||||
{
|
||||
const char *cp = *str;
|
||||
char *ep;
|
||||
|
|
Загрузка…
Ссылка в новой задаче