Commit 57c2590f authored by Tetsuo Handa's avatar Tetsuo Handa Committed by James Morris

TOMOYO: Update profile structure.

This patch allows users to change access control mode for per-operation basis.
This feature comes from non LSM version of TOMOYO which is designed for
permitting users to use SELinux and TOMOYO at the same time.

SELinux does not care filename in a directory whereas TOMOYO does. Change of
filename can change how the file is used. For example, renaming index.txt to
.htaccess will change how the file is used. Thus, letting SELinux to enforce
read()/write()/mmap() etc. restriction and letting TOMOYO to enforce rename()
restriction is an example usage of this feature.

What is unfortunate for me is that currently LSM does not allow users to use
SELinux and LSM version of TOMOYO at the same time...
Signed-off-by: default avatarTetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
Signed-off-by: default avatarJames Morris <jmorris@namei.org>
parent 1084307c
This diff is collapsed.
......@@ -42,7 +42,8 @@ enum tomoyo_mode_index {
TOMOYO_CONFIG_DISABLED,
TOMOYO_CONFIG_LEARNING,
TOMOYO_CONFIG_PERMISSIVE,
TOMOYO_CONFIG_ENFORCING
TOMOYO_CONFIG_ENFORCING,
TOMOYO_CONFIG_USE_DEFAULT = 255
};
/* Keywords for ACLs. */
......@@ -74,14 +75,6 @@ enum tomoyo_mode_index {
#define TOMOYO_VALUE_TYPE_OCTAL 2
#define TOMOYO_VALUE_TYPE_HEXADECIMAL 3
/* Index numbers for Access Controls. */
enum tomoyo_mac_index {
TOMOYO_MAC_FOR_FILE, /* domain_policy.conf */
TOMOYO_MAX_ACCEPT_ENTRY,
TOMOYO_VERBOSE,
TOMOYO_MAX_CONTROL_INDEX
};
/* Index numbers for Access Controls. */
enum tomoyo_acl_entry_type_index {
TOMOYO_TYPE_PATH_ACL,
......@@ -157,6 +150,38 @@ enum tomoyo_securityfs_interface_index {
TOMOYO_MANAGER
};
enum tomoyo_mac_index {
TOMOYO_MAC_FILE_EXECUTE,
TOMOYO_MAC_FILE_OPEN,
TOMOYO_MAC_FILE_CREATE,
TOMOYO_MAC_FILE_UNLINK,
TOMOYO_MAC_FILE_MKDIR,
TOMOYO_MAC_FILE_RMDIR,
TOMOYO_MAC_FILE_MKFIFO,
TOMOYO_MAC_FILE_MKSOCK,
TOMOYO_MAC_FILE_TRUNCATE,
TOMOYO_MAC_FILE_SYMLINK,
TOMOYO_MAC_FILE_REWRITE,
TOMOYO_MAC_FILE_MKBLOCK,
TOMOYO_MAC_FILE_MKCHAR,
TOMOYO_MAC_FILE_LINK,
TOMOYO_MAC_FILE_RENAME,
TOMOYO_MAC_FILE_CHMOD,
TOMOYO_MAC_FILE_CHOWN,
TOMOYO_MAC_FILE_CHGRP,
TOMOYO_MAC_FILE_IOCTL,
TOMOYO_MAC_FILE_CHROOT,
TOMOYO_MAC_FILE_MOUNT,
TOMOYO_MAC_FILE_UMOUNT,
TOMOYO_MAC_FILE_PIVOT_ROOT,
TOMOYO_MAX_MAC_INDEX
};
enum tomoyo_mac_category_index {
TOMOYO_MAC_CATEGORY_FILE,
TOMOYO_MAX_MAC_CATEGORY_INDEX
};
#define TOMOYO_RETRY_REQUEST 1 /* Retry this request. */
/********** Structure definitions. **********/
......@@ -174,6 +199,7 @@ struct tomoyo_request_info {
u8 retry;
u8 profile;
u8 mode; /* One of tomoyo_mode_index . */
u8 type;
};
/*
......@@ -649,6 +675,23 @@ struct tomoyo_policy_manager_entry {
bool is_deleted; /* True if this entry is deleted. */
};
struct tomoyo_preference {
unsigned int learning_max_entry;
bool enforcing_verbose;
bool learning_verbose;
bool permissive_verbose;
};
struct tomoyo_profile {
const struct tomoyo_path_info *comment;
struct tomoyo_preference *learning;
struct tomoyo_preference *permissive;
struct tomoyo_preference *enforcing;
struct tomoyo_preference preference;
u8 default_config;
u8 config[TOMOYO_MAX_MAC_INDEX + TOMOYO_MAX_MAC_CATEGORY_INDEX];
};
/********** Function prototypes. **********/
extern asmlinkage long sys_getpid(void);
......@@ -685,6 +728,7 @@ bool tomoyo_compare_name_union(const struct tomoyo_path_info *name,
/* Check whether the given number matches the given number_union. */
bool tomoyo_compare_number_union(const unsigned long value,
const struct tomoyo_number_union *ptr);
int tomoyo_get_mode(const u8 profile, const u8 index);
/* Transactional sprintf() for policy dump. */
bool tomoyo_io_printf(struct tomoyo_io_buffer *head, const char *fmt, ...)
__attribute__ ((format(printf, 2, 3)));
......@@ -747,7 +791,8 @@ const char *tomoyo_get_last_name(const struct tomoyo_domain_info *domain);
const char *tomoyo_path2keyword(const u8 operation);
/* Fill "struct tomoyo_request_info". */
int tomoyo_init_request_info(struct tomoyo_request_info *r,
struct tomoyo_domain_info *domain);
struct tomoyo_domain_info *domain,
const u8 index);
/* Check permission for mount operation. */
int tomoyo_mount_permission(char *dev_name, struct path *path, char *type,
unsigned long flags, void *data_page);
......@@ -794,6 +839,7 @@ struct tomoyo_domain_info *tomoyo_find_domain(const char *domainname);
struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char *
domainname,
const u8 profile);
struct tomoyo_profile *tomoyo_profile(const u8 profile);
/* Allocate memory for "struct tomoyo_path_group". */
struct tomoyo_path_group *tomoyo_get_path_group(const char *group_name);
struct tomoyo_number_group *tomoyo_get_number_group(const char *group_name);
......@@ -844,7 +890,7 @@ int tomoyo_write_memory_quota(struct tomoyo_io_buffer *head);
/* Initialize mm related code. */
void __init tomoyo_mm_init(void);
int tomoyo_check_exec_perm(struct tomoyo_domain_info *domain,
int tomoyo_check_exec_perm(struct tomoyo_request_info *r,
const struct tomoyo_path_info *filename);
int tomoyo_check_open_permission(struct tomoyo_domain_info *domain,
struct path *path, const int flag);
......
......@@ -812,8 +812,8 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm)
struct tomoyo_domain_info *domain = NULL;
const char *old_domain_name = old_domain->domainname->name;
const char *original_name = bprm->filename;
const u8 mode = tomoyo_check_flags(old_domain, TOMOYO_MAC_FOR_FILE);
const bool is_enforce = (mode == TOMOYO_CONFIG_ENFORCING);
u8 mode;
bool is_enforce;
int retval = -ENOMEM;
bool need_kfree = false;
struct tomoyo_path_info rn = { }; /* real name */
......@@ -822,7 +822,8 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm)
ln.name = tomoyo_get_last_name(old_domain);
tomoyo_fill_path_info(&ln);
tomoyo_init_request_info(&r, NULL);
mode = tomoyo_init_request_info(&r, NULL, TOMOYO_MAC_FILE_EXECUTE);
is_enforce = (mode == TOMOYO_CONFIG_ENFORCING);
if (!tmp)
goto out;
......@@ -880,7 +881,7 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm)
}
/* Check execute permission. */
retval = tomoyo_check_exec_perm(old_domain, &rn);
retval = tomoyo_check_exec_perm(&r, &rn);
if (retval == TOMOYO_RETRY_REQUEST)
goto retry;
if (retval < 0)
......
......@@ -51,6 +51,42 @@ static const char *tomoyo_path_number_keyword
[TOMOYO_TYPE_CHGRP] = "chgrp",
};
static const u8 tomoyo_p2mac[TOMOYO_MAX_PATH_OPERATION] = {
[TOMOYO_TYPE_READ_WRITE] = TOMOYO_MAC_FILE_OPEN,
[TOMOYO_TYPE_EXECUTE] = TOMOYO_MAC_FILE_EXECUTE,
[TOMOYO_TYPE_READ] = TOMOYO_MAC_FILE_OPEN,
[TOMOYO_TYPE_WRITE] = TOMOYO_MAC_FILE_OPEN,
[TOMOYO_TYPE_UNLINK] = TOMOYO_MAC_FILE_UNLINK,
[TOMOYO_TYPE_RMDIR] = TOMOYO_MAC_FILE_RMDIR,
[TOMOYO_TYPE_TRUNCATE] = TOMOYO_MAC_FILE_TRUNCATE,
[TOMOYO_TYPE_SYMLINK] = TOMOYO_MAC_FILE_SYMLINK,
[TOMOYO_TYPE_REWRITE] = TOMOYO_MAC_FILE_REWRITE,
[TOMOYO_TYPE_CHROOT] = TOMOYO_MAC_FILE_CHROOT,
[TOMOYO_TYPE_UMOUNT] = TOMOYO_MAC_FILE_UMOUNT,
};
static const u8 tomoyo_pnnn2mac[TOMOYO_MAX_PATH_NUMBER3_OPERATION] = {
[TOMOYO_TYPE_MKBLOCK] = TOMOYO_MAC_FILE_MKBLOCK,
[TOMOYO_TYPE_MKCHAR] = TOMOYO_MAC_FILE_MKCHAR,
};
static const u8 tomoyo_pp2mac[TOMOYO_MAX_PATH2_OPERATION] = {
[TOMOYO_TYPE_LINK] = TOMOYO_MAC_FILE_LINK,
[TOMOYO_TYPE_RENAME] = TOMOYO_MAC_FILE_RENAME,
[TOMOYO_TYPE_PIVOT_ROOT] = TOMOYO_MAC_FILE_PIVOT_ROOT,
};
static const u8 tomoyo_pn2mac[TOMOYO_MAX_PATH_NUMBER_OPERATION] = {
[TOMOYO_TYPE_CREATE] = TOMOYO_MAC_FILE_CREATE,
[TOMOYO_TYPE_MKDIR] = TOMOYO_MAC_FILE_MKDIR,
[TOMOYO_TYPE_MKFIFO] = TOMOYO_MAC_FILE_MKFIFO,
[TOMOYO_TYPE_MKSOCK] = TOMOYO_MAC_FILE_MKSOCK,
[TOMOYO_TYPE_IOCTL] = TOMOYO_MAC_FILE_IOCTL,
[TOMOYO_TYPE_CHMOD] = TOMOYO_MAC_FILE_CHMOD,
[TOMOYO_TYPE_CHOWN] = TOMOYO_MAC_FILE_CHOWN,
[TOMOYO_TYPE_CHGRP] = TOMOYO_MAC_FILE_CHGRP,
};
void tomoyo_put_name_union(struct tomoyo_name_union *ptr)
{
if (!ptr)
......@@ -1057,6 +1093,10 @@ static int tomoyo_path_permission(struct tomoyo_request_info *r, u8 operation,
int error;
next:
r->type = tomoyo_p2mac[operation];
r->mode = tomoyo_get_mode(r->profile, r->type);
if (r->mode == TOMOYO_CONFIG_DISABLED)
return 0;
do {
error = tomoyo_path_acl(r, filename, 1 << operation);
if (!error)
......@@ -1249,8 +1289,8 @@ int tomoyo_path_number_perm(const u8 type, struct path *path,
struct tomoyo_path_info buf;
int idx;
if (tomoyo_init_request_info(&r, NULL) == TOMOYO_CONFIG_DISABLED ||
!path->mnt || !path->dentry)
if (tomoyo_init_request_info(&r, NULL, tomoyo_pn2mac[type])
== TOMOYO_CONFIG_DISABLED || !path->mnt || !path->dentry)
return 0;
idx = tomoyo_read_lock();
if (!tomoyo_get_realpath(&buf, path))
......@@ -1269,21 +1309,19 @@ int tomoyo_path_number_perm(const u8 type, struct path *path,
/**
* tomoyo_check_exec_perm - Check permission for "execute".
*
* @domain: Pointer to "struct tomoyo_domain_info".
* @r: Pointer to "struct tomoyo_request_info".
* @filename: Check permission for "execute".
*
* Returns 0 on success, negativevalue otherwise.
*
* Caller holds tomoyo_read_lock().
*/
int tomoyo_check_exec_perm(struct tomoyo_domain_info *domain,
int tomoyo_check_exec_perm(struct tomoyo_request_info *r,
const struct tomoyo_path_info *filename)
{
struct tomoyo_request_info r;
if (tomoyo_init_request_info(&r, NULL) == TOMOYO_CONFIG_DISABLED)
if (r->mode == TOMOYO_CONFIG_DISABLED)
return 0;
return tomoyo_file_perm(&r, filename, 1);
return tomoyo_file_perm(r, filename, 1);
}
/**
......@@ -1304,17 +1342,11 @@ int tomoyo_check_open_permission(struct tomoyo_domain_info *domain,
struct tomoyo_request_info r;
int idx;
if (tomoyo_init_request_info(&r, domain) == TOMOYO_CONFIG_DISABLED ||
!path->mnt)
return 0;
if (acc_mode == 0)
return 0;
if (path->dentry->d_inode && S_ISDIR(path->dentry->d_inode->i_mode))
/*
* I don't check directories here because mkdir() and rmdir()
* don't call me.
*/
if (!path->mnt ||
(path->dentry->d_inode && S_ISDIR(path->dentry->d_inode->i_mode)))
return 0;
buf.name = NULL;
r.mode = TOMOYO_CONFIG_DISABLED;
idx = tomoyo_read_lock();
if (!tomoyo_get_realpath(&buf, path))
goto out;
......@@ -1324,15 +1356,26 @@ int tomoyo_check_open_permission(struct tomoyo_domain_info *domain,
* we need to check "allow_rewrite" permission when the filename is not
* opened for append mode or the filename is truncated at open time.
*/
if ((acc_mode & MAY_WRITE) &&
((flag & O_TRUNC) || !(flag & O_APPEND)) &&
(tomoyo_is_no_rewrite_file(&buf))) {
error = tomoyo_path_permission(&r, TOMOYO_TYPE_REWRITE, &buf);
if ((acc_mode & MAY_WRITE) && !(flag & O_APPEND)
&& tomoyo_init_request_info(&r, domain, TOMOYO_MAC_FILE_REWRITE)
!= TOMOYO_CONFIG_DISABLED) {
if (!tomoyo_get_realpath(&buf, path)) {
error = -ENOMEM;
goto out;
}
if (tomoyo_is_no_rewrite_file(&buf))
error = tomoyo_path_permission(&r, TOMOYO_TYPE_REWRITE,
&buf);
}
if (!error)
if (!error && acc_mode &&
tomoyo_init_request_info(&r, domain, TOMOYO_MAC_FILE_OPEN)
!= TOMOYO_CONFIG_DISABLED) {
if (!buf.name && !tomoyo_get_realpath(&buf, path)) {
error = -ENOMEM;
goto out;
}
error = tomoyo_file_perm(&r, &buf, acc_mode);
if (!error && (flag & O_TRUNC))
error = tomoyo_path_permission(&r, TOMOYO_TYPE_TRUNCATE, &buf);
}
out:
kfree(buf.name);
tomoyo_read_unlock(idx);
......@@ -1356,9 +1399,12 @@ int tomoyo_path_perm(const u8 operation, struct path *path)
struct tomoyo_request_info r;
int idx;
if (tomoyo_init_request_info(&r, NULL) == TOMOYO_CONFIG_DISABLED ||
!path->mnt)
if (!path->mnt)
return 0;
if (tomoyo_init_request_info(&r, NULL, tomoyo_p2mac[operation])
== TOMOYO_CONFIG_DISABLED)
return 0;
buf.name = NULL;
idx = tomoyo_read_lock();
if (!tomoyo_get_realpath(&buf, path))
goto out;
......@@ -1371,6 +1417,7 @@ int tomoyo_path_perm(const u8 operation, struct path *path)
break;
case TOMOYO_TYPE_RMDIR:
case TOMOYO_TYPE_CHROOT:
case TOMOYO_TYPE_UMOUNT:
tomoyo_add_slash(&buf);
break;
}
......@@ -1442,8 +1489,9 @@ int tomoyo_path_number3_perm(const u8 operation, struct path *path,
struct tomoyo_path_info buf;
int idx;
if (tomoyo_init_request_info(&r, NULL) == TOMOYO_CONFIG_DISABLED ||
!path->mnt)
if (!path->mnt ||
tomoyo_init_request_info(&r, NULL, tomoyo_pnnn2mac[operation])
== TOMOYO_CONFIG_DISABLED)
return 0;
idx = tomoyo_read_lock();
error = -ENOMEM;
......@@ -1477,8 +1525,9 @@ int tomoyo_path2_perm(const u8 operation, struct path *path1,
struct tomoyo_request_info r;
int idx;
if (tomoyo_init_request_info(&r, NULL) == TOMOYO_CONFIG_DISABLED ||
!path1->mnt || !path2->mnt)
if (!path1->mnt || !path2->mnt ||
tomoyo_init_request_info(&r, NULL, tomoyo_pp2mac[operation])
== TOMOYO_CONFIG_DISABLED)
return 0;
buf1.name = NULL;
buf2.name = NULL;
......@@ -1486,13 +1535,19 @@ int tomoyo_path2_perm(const u8 operation, struct path *path1,
if (!tomoyo_get_realpath(&buf1, path1) ||
!tomoyo_get_realpath(&buf2, path2))
goto out;
{
struct dentry *dentry = path1->dentry;
if (dentry->d_inode && S_ISDIR(dentry->d_inode->i_mode)) {
tomoyo_add_slash(&buf1);
tomoyo_add_slash(&buf2);
}
}
switch (operation) {
struct dentry *dentry;
case TOMOYO_TYPE_RENAME:
case TOMOYO_TYPE_LINK:
dentry = path1->dentry;
if (!dentry->d_inode || !S_ISDIR(dentry->d_inode->i_mode))
break;
/* fall through */
case TOMOYO_TYPE_PIVOT_ROOT:
tomoyo_add_slash(&buf1);
tomoyo_add_slash(&buf2);
break;
}
do {
error = tomoyo_path2_acl(&r, operation, &buf1, &buf2);
if (!error)
......
......@@ -248,7 +248,8 @@ int tomoyo_mount_permission(char *dev_name, struct path *path, char *type,
int error;
int idx;
if (tomoyo_init_request_info(&r, NULL) == TOMOYO_CONFIG_DISABLED)
if (tomoyo_init_request_info(&r, NULL, TOMOYO_MAC_FILE_MOUNT)
== TOMOYO_CONFIG_DISABLED)
return 0;
if (!type)
type = "<NULL>";
......
......@@ -791,25 +791,67 @@ const char *tomoyo_get_exe(void)
return cp;
}
/**
* tomoyo_get_mode - Get MAC mode.
*
* @profile: Profile number.
* @index: Index number of functionality.
*
* Returns mode.
*/
int tomoyo_get_mode(const u8 profile, const u8 index)
{
u8 mode;
const u8 category = TOMOYO_MAC_CATEGORY_FILE;
if (!tomoyo_policy_loaded)
return TOMOYO_CONFIG_DISABLED;
mode = tomoyo_profile(profile)->config[index];
if (mode == TOMOYO_CONFIG_USE_DEFAULT)
mode = tomoyo_profile(profile)->config[category];
if (mode == TOMOYO_CONFIG_USE_DEFAULT)
mode = tomoyo_profile(profile)->default_config;
return mode & 3;
}
/**
* tomoyo_init_request_info - Initialize "struct tomoyo_request_info" members.
*
* @r: Pointer to "struct tomoyo_request_info" to initialize.
* @domain: Pointer to "struct tomoyo_domain_info". NULL for tomoyo_domain().
* @index: Index number of functionality.
*
* Returns mode.
*/
int tomoyo_init_request_info(struct tomoyo_request_info *r,
struct tomoyo_domain_info *domain)
struct tomoyo_domain_info *domain, const u8 index)
{
u8 profile;
memset(r, 0, sizeof(*r));
if (!domain)
domain = tomoyo_domain();
r->domain = domain;
r->mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE);
profile = domain->profile;
r->profile = profile;
r->type = index;
r->mode = tomoyo_get_mode(profile, index);
return r->mode;
}
/**
* tomoyo_last_word - Get last component of a line.
*
* @line: A line.
*
* Returns the last word of a line.
*/
static const char *tomoyo_last_word(const char *name)
{
const char *cp = strrchr(name, ' ');
if (cp)
return cp + 1;
return name;
}
/**
* tomoyo_warn_log - Print warning or error message on console.
*
......@@ -818,29 +860,34 @@ int tomoyo_init_request_info(struct tomoyo_request_info *r,
*/
void tomoyo_warn_log(struct tomoyo_request_info *r, const char *fmt, ...)
{
int len = PAGE_SIZE;
va_list args;
char *buffer;
if (!tomoyo_verbose_mode(r->domain))
return;
while (1) {
int len2;
buffer = kmalloc(len, GFP_NOFS);
if (!buffer)
const struct tomoyo_domain_info * const domain = r->domain;
const struct tomoyo_profile *profile = tomoyo_profile(domain->profile);
switch (r->mode) {
case TOMOYO_CONFIG_ENFORCING:
if (!profile->enforcing->enforcing_verbose)
return;
va_start(args, fmt);
len2 = vsnprintf(buffer, len - 1, fmt, args);
va_end(args);
if (len2 <= len - 1) {
buffer[len2] = '\0';
break;
}
len = len2 + 1;
kfree(buffer);
break;
case TOMOYO_CONFIG_PERMISSIVE:
if (!profile->permissive->permissive_verbose)
return;
break;
case TOMOYO_CONFIG_LEARNING:
if (!profile->learning->learning_verbose)
return;
break;
}
printk(KERN_WARNING "TOMOYO-%s: Access %s denied for %s\n",
r->mode == TOMOYO_CONFIG_ENFORCING ? "ERROR" : "WARNING",
buffer, tomoyo_get_last_name(r->domain));
buffer = kmalloc(4096, GFP_NOFS);
if (!buffer)
return;
va_start(args, fmt);
vsnprintf(buffer, 4095, fmt, args);
va_end(args);
buffer[4095] = '\0';
printk(KERN_WARNING "%s: Access %s denied for %s\n",
r->mode == TOMOYO_CONFIG_ENFORCING ? "ERROR" : "WARNING", buffer,
tomoyo_last_word(domain->domainname->name));
kfree(buffer);
}
......@@ -903,7 +950,8 @@ bool tomoyo_domain_quota_is_ok(struct tomoyo_request_info *r)
count++;
}
}
if (count < tomoyo_check_flags(domain, TOMOYO_MAX_ACCEPT_ENTRY))
if (count < tomoyo_profile(domain->profile)->learning->
learning_max_entry)
return true;
if (!domain->quota_warned) {
domain->quota_warned = true;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment