TOMOYO: Support longer pathname.
Allow pathnames longer than 4000 bytes. 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:
parent
9b244373da
commit
c8c57e8427
|
@ -33,14 +33,7 @@ struct linux_binprm;
|
|||
#define TOMOYO_HASH_BITS 8
|
||||
#define TOMOYO_MAX_HASH (1u<<TOMOYO_HASH_BITS)
|
||||
|
||||
/*
|
||||
* This is the max length of a token.
|
||||
*
|
||||
* A token consists of only ASCII printable characters.
|
||||
* Non printable characters in a token is represented in \ooo style
|
||||
* octal string. Thus, \ itself is represented as \\.
|
||||
*/
|
||||
#define TOMOYO_MAX_PATHNAME_LEN 4000
|
||||
#define TOMOYO_EXEC_TMPSIZE 4096
|
||||
|
||||
/* Profile number is an integer between 0 and 255. */
|
||||
#define TOMOYO_MAX_PROFILES 256
|
||||
|
@ -167,17 +160,6 @@ enum tomoyo_securityfs_interface_index {
|
|||
|
||||
/********** Structure definitions. **********/
|
||||
|
||||
/*
|
||||
* tomoyo_page_buffer is a structure which is used for holding a pathname
|
||||
* obtained from "struct dentry" and "struct vfsmount" pair.
|
||||
* As of now, it is 4096 bytes. If users complain that 4096 bytes is too small
|
||||
* (because TOMOYO escapes non ASCII printable characters using \ooo format),
|
||||
* we will make the buffer larger.
|
||||
*/
|
||||
struct tomoyo_page_buffer {
|
||||
char buffer[4096];
|
||||
};
|
||||
|
||||
/*
|
||||
* tomoyo_request_info is a structure which is used for holding
|
||||
*
|
||||
|
@ -231,28 +213,6 @@ struct tomoyo_name_entry {
|
|||
struct tomoyo_path_info entry;
|
||||
};
|
||||
|
||||
/*
|
||||
* tomoyo_path_info_with_data is a structure which is used for holding a
|
||||
* pathname obtained from "struct dentry" and "struct vfsmount" pair.
|
||||
*
|
||||
* "struct tomoyo_path_info_with_data" consists of "struct tomoyo_path_info"
|
||||
* and buffer for the pathname, while "struct tomoyo_page_buffer" consists of
|
||||
* buffer for the pathname only.
|
||||
*
|
||||
* "struct tomoyo_path_info_with_data" is intended to allow TOMOYO to release
|
||||
* both "struct tomoyo_path_info" and buffer for the pathname by single kfree()
|
||||
* so that we don't need to return two pointers to the caller. If the caller
|
||||
* puts "struct tomoyo_path_info" on stack memory, we will be able to remove
|
||||
* "struct tomoyo_path_info_with_data".
|
||||
*/
|
||||
struct tomoyo_path_info_with_data {
|
||||
/* Keep "head" first, for this pointer is passed to kfree(). */
|
||||
struct tomoyo_path_info head;
|
||||
char barrier1[16]; /* Safeguard for overrun. */
|
||||
char body[TOMOYO_MAX_PATHNAME_LEN];
|
||||
char barrier2[16]; /* Safeguard for overrun. */
|
||||
};
|
||||
|
||||
struct tomoyo_name_union {
|
||||
const struct tomoyo_path_info *filename;
|
||||
struct tomoyo_path_group *group;
|
||||
|
@ -827,11 +787,7 @@ void tomoyo_load_policy(const char *filename);
|
|||
void tomoyo_put_number_union(struct tomoyo_number_union *ptr);
|
||||
|
||||
/* Convert binary string to ascii string. */
|
||||
int tomoyo_encode(char *buffer, int buflen, const char *str);
|
||||
|
||||
/* Returns realpath(3) of the given pathname but ignores chroot'ed root. */
|
||||
int tomoyo_realpath_from_path2(struct path *path, char *newname,
|
||||
int newname_len);
|
||||
char *tomoyo_encode(const char *str);
|
||||
|
||||
/*
|
||||
* Returns realpath(3) of the given pathname but ignores chroot'ed root.
|
||||
|
|
|
@ -676,47 +676,43 @@ struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char *
|
|||
int tomoyo_find_next_domain(struct linux_binprm *bprm)
|
||||
{
|
||||
struct tomoyo_request_info r;
|
||||
/*
|
||||
* This function assumes that the size of buffer returned by
|
||||
* tomoyo_realpath() = TOMOYO_MAX_PATHNAME_LEN.
|
||||
*/
|
||||
struct tomoyo_page_buffer *tmp = kzalloc(sizeof(*tmp), GFP_NOFS);
|
||||
char *tmp = kzalloc(TOMOYO_EXEC_TMPSIZE, GFP_NOFS);
|
||||
struct tomoyo_domain_info *old_domain = tomoyo_domain();
|
||||
struct tomoyo_domain_info *domain = NULL;
|
||||
const char *old_domain_name = old_domain->domainname->name;
|
||||
const char *original_name = bprm->filename;
|
||||
char *new_domain_name = NULL;
|
||||
char *real_program_name = NULL;
|
||||
char *symlink_program_name = NULL;
|
||||
const u8 mode = tomoyo_check_flags(old_domain, TOMOYO_MAC_FOR_FILE);
|
||||
const bool is_enforce = (mode == TOMOYO_CONFIG_ENFORCING);
|
||||
int retval = -ENOMEM;
|
||||
struct tomoyo_path_info rn; /* real name */
|
||||
struct tomoyo_path_info sn; /* symlink name */
|
||||
bool need_kfree = false;
|
||||
struct tomoyo_path_info rn = { }; /* real name */
|
||||
struct tomoyo_path_info sn = { }; /* symlink name */
|
||||
struct tomoyo_path_info ln; /* last name */
|
||||
|
||||
ln.name = tomoyo_get_last_name(old_domain);
|
||||
tomoyo_fill_path_info(&ln);
|
||||
tomoyo_init_request_info(&r, NULL);
|
||||
if (!tmp)
|
||||
goto out;
|
||||
|
||||
retry:
|
||||
if (need_kfree) {
|
||||
kfree(rn.name);
|
||||
need_kfree = false;
|
||||
}
|
||||
/* Get tomoyo_realpath of program. */
|
||||
retval = -ENOENT;
|
||||
/* I hope tomoyo_realpath() won't fail with -ENOMEM. */
|
||||
real_program_name = tomoyo_realpath(original_name);
|
||||
if (!real_program_name)
|
||||
rn.name = tomoyo_realpath(original_name);
|
||||
if (!rn.name)
|
||||
goto out;
|
||||
/* Get tomoyo_realpath of symbolic link. */
|
||||
symlink_program_name = tomoyo_realpath_nofollow(original_name);
|
||||
if (!symlink_program_name)
|
||||
goto out;
|
||||
|
||||
rn.name = real_program_name;
|
||||
tomoyo_fill_path_info(&rn);
|
||||
sn.name = symlink_program_name;
|
||||
need_kfree = true;
|
||||
|
||||
/* Get tomoyo_realpath of symbolic link. */
|
||||
sn.name = tomoyo_realpath_nofollow(original_name);
|
||||
if (!sn.name)
|
||||
goto out;
|
||||
tomoyo_fill_path_info(&sn);
|
||||
ln.name = tomoyo_get_last_name(old_domain);
|
||||
tomoyo_fill_path_info(&ln);
|
||||
|
||||
/* Check 'alias' directive. */
|
||||
if (tomoyo_pathcmp(&rn, &sn)) {
|
||||
|
@ -727,10 +723,10 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm)
|
|||
tomoyo_pathcmp(&rn, ptr->original_name) ||
|
||||
tomoyo_pathcmp(&sn, ptr->aliased_name))
|
||||
continue;
|
||||
memset(real_program_name, 0, TOMOYO_MAX_PATHNAME_LEN);
|
||||
strncpy(real_program_name, ptr->aliased_name->name,
|
||||
TOMOYO_MAX_PATHNAME_LEN - 1);
|
||||
tomoyo_fill_path_info(&rn);
|
||||
kfree(rn.name);
|
||||
need_kfree = false;
|
||||
/* This is OK because it is read only. */
|
||||
rn = *ptr->aliased_name;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -742,11 +738,10 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm)
|
|||
if (retval < 0)
|
||||
goto out;
|
||||
|
||||
new_domain_name = tmp->buffer;
|
||||
if (tomoyo_is_domain_initializer(old_domain->domainname, &rn, &ln)) {
|
||||
/* Transit to the child of tomoyo_kernel_domain domain. */
|
||||
snprintf(new_domain_name, TOMOYO_MAX_PATHNAME_LEN + 1,
|
||||
TOMOYO_ROOT_NAME " " "%s", real_program_name);
|
||||
snprintf(tmp, TOMOYO_EXEC_TMPSIZE - 1,
|
||||
TOMOYO_ROOT_NAME " " "%s", rn.name);
|
||||
} else if (old_domain == &tomoyo_kernel_domain &&
|
||||
!tomoyo_policy_loaded) {
|
||||
/*
|
||||
|
@ -760,29 +755,27 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm)
|
|||
domain = old_domain;
|
||||
} else {
|
||||
/* Normal domain transition. */
|
||||
snprintf(new_domain_name, TOMOYO_MAX_PATHNAME_LEN + 1,
|
||||
"%s %s", old_domain_name, real_program_name);
|
||||
snprintf(tmp, TOMOYO_EXEC_TMPSIZE - 1,
|
||||
"%s %s", old_domain_name, rn.name);
|
||||
}
|
||||
if (domain || strlen(new_domain_name) >= TOMOYO_MAX_PATHNAME_LEN)
|
||||
if (domain || strlen(tmp) >= TOMOYO_EXEC_TMPSIZE - 10)
|
||||
goto done;
|
||||
domain = tomoyo_find_domain(new_domain_name);
|
||||
domain = tomoyo_find_domain(tmp);
|
||||
if (domain)
|
||||
goto done;
|
||||
if (is_enforce) {
|
||||
int error = tomoyo_supervisor(&r, "# wants to create domain\n"
|
||||
"%s\n", new_domain_name);
|
||||
"%s\n", tmp);
|
||||
if (error == TOMOYO_RETRY_REQUEST)
|
||||
goto retry;
|
||||
if (error < 0)
|
||||
goto done;
|
||||
}
|
||||
domain = tomoyo_find_or_assign_new_domain(new_domain_name,
|
||||
old_domain->profile);
|
||||
domain = tomoyo_find_or_assign_new_domain(tmp, old_domain->profile);
|
||||
done:
|
||||
if (domain)
|
||||
goto out;
|
||||
printk(KERN_WARNING "TOMOYO-ERROR: Domain '%s' not defined.\n",
|
||||
new_domain_name);
|
||||
printk(KERN_WARNING "TOMOYO-ERROR: Domain '%s' not defined.\n", tmp);
|
||||
if (is_enforce)
|
||||
retval = -EPERM;
|
||||
else
|
||||
|
@ -793,8 +786,9 @@ 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;
|
||||
kfree(real_program_name);
|
||||
kfree(symlink_program_name);
|
||||
if (need_kfree)
|
||||
kfree(rn.name);
|
||||
kfree(sn.name);
|
||||
kfree(tmp);
|
||||
return retval;
|
||||
}
|
||||
|
|
|
@ -148,6 +148,17 @@ const char *tomoyo_path_number2keyword(const u8 operation)
|
|||
? tomoyo_path_number_keyword[operation] : NULL;
|
||||
}
|
||||
|
||||
static void tomoyo_add_slash(struct tomoyo_path_info *buf)
|
||||
{
|
||||
if (buf->is_dir)
|
||||
return;
|
||||
/*
|
||||
* This is OK because tomoyo_encode() reserves space for appending "/".
|
||||
*/
|
||||
strcat((char *) buf->name, "/");
|
||||
tomoyo_fill_path_info(buf);
|
||||
}
|
||||
|
||||
/**
|
||||
* tomoyo_strendswith - Check whether the token ends with the given token.
|
||||
*
|
||||
|
@ -167,30 +178,21 @@ static bool tomoyo_strendswith(const char *name, const char *tail)
|
|||
}
|
||||
|
||||
/**
|
||||
* tomoyo_get_path - Get realpath.
|
||||
* tomoyo_get_realpath - Get realpath.
|
||||
*
|
||||
* @buf: Pointer to "struct tomoyo_path_info".
|
||||
* @path: Pointer to "struct path".
|
||||
*
|
||||
* Returns pointer to "struct tomoyo_path_info" on success, NULL otherwise.
|
||||
* Returns true on success, false otherwise.
|
||||
*/
|
||||
static struct tomoyo_path_info *tomoyo_get_path(struct path *path)
|
||||
static bool tomoyo_get_realpath(struct tomoyo_path_info *buf, struct path *path)
|
||||
{
|
||||
int error;
|
||||
struct tomoyo_path_info_with_data *buf = kzalloc(sizeof(*buf),
|
||||
GFP_NOFS);
|
||||
|
||||
if (!buf)
|
||||
return NULL;
|
||||
/* Reserve one byte for appending "/". */
|
||||
error = tomoyo_realpath_from_path2(path, buf->body,
|
||||
sizeof(buf->body) - 2);
|
||||
if (!error) {
|
||||
buf->head.name = buf->body;
|
||||
tomoyo_fill_path_info(&buf->head);
|
||||
return &buf->head;
|
||||
buf->name = tomoyo_realpath_from_path(path);
|
||||
if (buf->name) {
|
||||
tomoyo_fill_path_info(buf);
|
||||
return true;
|
||||
}
|
||||
kfree(buf);
|
||||
return NULL;
|
||||
return false;
|
||||
}
|
||||
|
||||
static int tomoyo_update_path2_acl(const u8 type, const char *filename1,
|
||||
|
@ -1259,26 +1261,20 @@ int tomoyo_path_number_perm(const u8 type, struct path *path,
|
|||
{
|
||||
struct tomoyo_request_info r;
|
||||
int error = -ENOMEM;
|
||||
struct tomoyo_path_info *buf;
|
||||
struct tomoyo_path_info buf;
|
||||
int idx;
|
||||
|
||||
if (tomoyo_init_request_info(&r, NULL) == TOMOYO_CONFIG_DISABLED ||
|
||||
!path->mnt || !path->dentry)
|
||||
return 0;
|
||||
idx = tomoyo_read_lock();
|
||||
buf = tomoyo_get_path(path);
|
||||
if (!buf)
|
||||
if (!tomoyo_get_realpath(&buf, path))
|
||||
goto out;
|
||||
if (type == TOMOYO_TYPE_MKDIR && !buf->is_dir) {
|
||||
/*
|
||||
* tomoyo_get_path() reserves space for appending "/."
|
||||
*/
|
||||
strcat((char *) buf->name, "/");
|
||||
tomoyo_fill_path_info(buf);
|
||||
}
|
||||
error = tomoyo_path_number_perm2(&r, type, buf, number);
|
||||
if (type == TOMOYO_TYPE_MKDIR)
|
||||
tomoyo_add_slash(&buf);
|
||||
error = tomoyo_path_number_perm2(&r, type, &buf, number);
|
||||
out:
|
||||
kfree(buf);
|
||||
kfree(buf.name);
|
||||
tomoyo_read_unlock(idx);
|
||||
if (r.mode != TOMOYO_CONFIG_ENFORCING)
|
||||
error = 0;
|
||||
|
@ -1319,7 +1315,7 @@ int tomoyo_check_open_permission(struct tomoyo_domain_info *domain,
|
|||
{
|
||||
const u8 acc_mode = ACC_MODE(flag);
|
||||
int error = -ENOMEM;
|
||||
struct tomoyo_path_info *buf;
|
||||
struct tomoyo_path_info buf;
|
||||
struct tomoyo_request_info r;
|
||||
int idx;
|
||||
|
||||
|
@ -1335,8 +1331,7 @@ int tomoyo_check_open_permission(struct tomoyo_domain_info *domain,
|
|||
*/
|
||||
return 0;
|
||||
idx = tomoyo_read_lock();
|
||||
buf = tomoyo_get_path(path);
|
||||
if (!buf)
|
||||
if (!tomoyo_get_realpath(&buf, path))
|
||||
goto out;
|
||||
error = 0;
|
||||
/*
|
||||
|
@ -1346,15 +1341,15 @@ int tomoyo_check_open_permission(struct tomoyo_domain_info *domain,
|
|||
*/
|
||||
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);
|
||||
(tomoyo_is_no_rewrite_file(&buf))) {
|
||||
error = tomoyo_path_permission(&r, TOMOYO_TYPE_REWRITE, &buf);
|
||||
}
|
||||
if (!error)
|
||||
error = tomoyo_file_perm(&r, buf, acc_mode);
|
||||
error = tomoyo_file_perm(&r, &buf, acc_mode);
|
||||
if (!error && (flag & O_TRUNC))
|
||||
error = tomoyo_path_permission(&r, TOMOYO_TYPE_TRUNCATE, buf);
|
||||
error = tomoyo_path_permission(&r, TOMOYO_TYPE_TRUNCATE, &buf);
|
||||
out:
|
||||
kfree(buf);
|
||||
kfree(buf.name);
|
||||
tomoyo_read_unlock(idx);
|
||||
if (r.mode != TOMOYO_CONFIG_ENFORCING)
|
||||
error = 0;
|
||||
|
@ -1372,7 +1367,7 @@ int tomoyo_check_open_permission(struct tomoyo_domain_info *domain,
|
|||
int tomoyo_path_perm(const u8 operation, struct path *path)
|
||||
{
|
||||
int error = -ENOMEM;
|
||||
struct tomoyo_path_info *buf;
|
||||
struct tomoyo_path_info buf;
|
||||
struct tomoyo_request_info r;
|
||||
int idx;
|
||||
|
||||
|
@ -1380,29 +1375,23 @@ int tomoyo_path_perm(const u8 operation, struct path *path)
|
|||
!path->mnt)
|
||||
return 0;
|
||||
idx = tomoyo_read_lock();
|
||||
buf = tomoyo_get_path(path);
|
||||
if (!buf)
|
||||
if (!tomoyo_get_realpath(&buf, path))
|
||||
goto out;
|
||||
switch (operation) {
|
||||
case TOMOYO_TYPE_REWRITE:
|
||||
if (!tomoyo_is_no_rewrite_file(buf)) {
|
||||
if (!tomoyo_is_no_rewrite_file(&buf)) {
|
||||
error = 0;
|
||||
goto out;
|
||||
}
|
||||
break;
|
||||
case TOMOYO_TYPE_RMDIR:
|
||||
case TOMOYO_TYPE_CHROOT:
|
||||
if (!buf->is_dir) {
|
||||
/*
|
||||
* tomoyo_get_path() reserves space for appending "/."
|
||||
*/
|
||||
strcat((char *) buf->name, "/");
|
||||
tomoyo_fill_path_info(buf);
|
||||
}
|
||||
tomoyo_add_slash(&buf);
|
||||
break;
|
||||
}
|
||||
error = tomoyo_path_permission(&r, operation, buf);
|
||||
error = tomoyo_path_permission(&r, operation, &buf);
|
||||
out:
|
||||
kfree(buf);
|
||||
kfree(buf.name);
|
||||
tomoyo_read_unlock(idx);
|
||||
if (r.mode != TOMOYO_CONFIG_ENFORCING)
|
||||
error = 0;
|
||||
|
@ -1465,7 +1454,7 @@ int tomoyo_path_number3_perm(const u8 operation, struct path *path,
|
|||
{
|
||||
struct tomoyo_request_info r;
|
||||
int error = -ENOMEM;
|
||||
struct tomoyo_path_info *buf;
|
||||
struct tomoyo_path_info buf;
|
||||
int idx;
|
||||
|
||||
if (tomoyo_init_request_info(&r, NULL) == TOMOYO_CONFIG_DISABLED ||
|
||||
|
@ -1473,11 +1462,10 @@ int tomoyo_path_number3_perm(const u8 operation, struct path *path,
|
|||
return 0;
|
||||
idx = tomoyo_read_lock();
|
||||
error = -ENOMEM;
|
||||
buf = tomoyo_get_path(path);
|
||||
if (buf) {
|
||||
error = tomoyo_path_number3_perm2(&r, operation, buf, mode,
|
||||
if (tomoyo_get_realpath(&buf, path)) {
|
||||
error = tomoyo_path_number3_perm2(&r, operation, &buf, mode,
|
||||
new_decode_dev(dev));
|
||||
kfree(buf);
|
||||
kfree(buf.name);
|
||||
}
|
||||
tomoyo_read_unlock(idx);
|
||||
if (r.mode != TOMOYO_CONFIG_ENFORCING)
|
||||
|
@ -1499,48 +1487,40 @@ int tomoyo_path2_perm(const u8 operation, struct path *path1,
|
|||
{
|
||||
int error = -ENOMEM;
|
||||
const char *msg;
|
||||
struct tomoyo_path_info *buf1;
|
||||
struct tomoyo_path_info *buf2;
|
||||
struct tomoyo_path_info buf1;
|
||||
struct tomoyo_path_info buf2;
|
||||
struct tomoyo_request_info r;
|
||||
int idx;
|
||||
|
||||
if (tomoyo_init_request_info(&r, NULL) == TOMOYO_CONFIG_DISABLED ||
|
||||
!path1->mnt || !path2->mnt)
|
||||
return 0;
|
||||
buf1.name = NULL;
|
||||
buf2.name = NULL;
|
||||
idx = tomoyo_read_lock();
|
||||
buf1 = tomoyo_get_path(path1);
|
||||
buf2 = tomoyo_get_path(path2);
|
||||
if (!buf1 || !buf2)
|
||||
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_get_path() reserves space for appending "/."
|
||||
*/
|
||||
if (!buf1->is_dir) {
|
||||
strcat((char *) buf1->name, "/");
|
||||
tomoyo_fill_path_info(buf1);
|
||||
}
|
||||
if (!buf2->is_dir) {
|
||||
strcat((char *) buf2->name, "/");
|
||||
tomoyo_fill_path_info(buf2);
|
||||
}
|
||||
tomoyo_add_slash(&buf1);
|
||||
tomoyo_add_slash(&buf2);
|
||||
}
|
||||
}
|
||||
do {
|
||||
error = tomoyo_path2_acl(&r, operation, buf1, buf2);
|
||||
error = tomoyo_path2_acl(&r, operation, &buf1, &buf2);
|
||||
if (!error)
|
||||
break;
|
||||
msg = tomoyo_path22keyword(operation);
|
||||
tomoyo_warn_log(&r, "%s %s %s", msg, buf1->name, buf2->name);
|
||||
tomoyo_warn_log(&r, "%s %s %s", msg, buf1.name, buf2.name);
|
||||
error = tomoyo_supervisor(&r, "allow_%s %s %s\n", msg,
|
||||
tomoyo_file_pattern(buf1),
|
||||
tomoyo_file_pattern(buf2));
|
||||
tomoyo_file_pattern(&buf1),
|
||||
tomoyo_file_pattern(&buf2));
|
||||
} while (error == TOMOYO_RETRY_REQUEST);
|
||||
out:
|
||||
kfree(buf1);
|
||||
kfree(buf2);
|
||||
kfree(buf1.name);
|
||||
kfree(buf2.name);
|
||||
tomoyo_read_unlock(idx);
|
||||
if (r.mode != TOMOYO_CONFIG_ENFORCING)
|
||||
error = 0;
|
||||
|
|
|
@ -153,7 +153,6 @@ void __init tomoyo_mm_init(void)
|
|||
{
|
||||
int idx;
|
||||
|
||||
BUILD_BUG_ON(TOMOYO_MAX_PATHNAME_LEN > PATH_MAX);
|
||||
for (idx = 0; idx < TOMOYO_MAX_HASH; idx++)
|
||||
INIT_LIST_HEAD(&tomoyo_name_list[idx]);
|
||||
INIT_LIST_HEAD(&tomoyo_kernel_domain.acl_info_list);
|
||||
|
|
|
@ -24,57 +24,6 @@
|
|||
/* Allow to call 'mount --make-shared /dir' */
|
||||
#define TOMOYO_MOUNT_MAKE_SHARED_KEYWORD "--make-shared"
|
||||
|
||||
/**
|
||||
* tomoyo_encode2: 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.
|
||||
*/
|
||||
static char *tomoyo_encode2(const char *str)
|
||||
{
|
||||
int len = 0;
|
||||
const char *p = str;
|
||||
char *cp;
|
||||
char *cp0;
|
||||
if (!p)
|
||||
return NULL;
|
||||
while (*p) {
|
||||
const unsigned char c = *p++;
|
||||
if (c == '\\')
|
||||
len += 2;
|
||||
else if (c > ' ' && c < 127)
|
||||
len++;
|
||||
else
|
||||
len += 4;
|
||||
}
|
||||
len++;
|
||||
/* Reserve space for appending "/". */
|
||||
cp = kzalloc(len + 10, GFP_NOFS);
|
||||
if (!cp)
|
||||
return NULL;
|
||||
cp0 = cp;
|
||||
p = str;
|
||||
while (*p) {
|
||||
const unsigned char c = *p++;
|
||||
if (c == '\\') {
|
||||
*cp++ = '\\';
|
||||
*cp++ = '\\';
|
||||
} else if (c > ' ' && c < 127) {
|
||||
*cp++ = c;
|
||||
} else {
|
||||
*cp++ = '\\';
|
||||
*cp++ = (c >> 6) + '0';
|
||||
*cp++ = ((c >> 3) & 7) + '0';
|
||||
*cp++ = (c & 7) + '0';
|
||||
}
|
||||
}
|
||||
return cp0;
|
||||
}
|
||||
|
||||
/**
|
||||
* tomoyo_mount_acl2 - Check permission for mount() operation.
|
||||
*
|
||||
|
@ -104,7 +53,7 @@ static int tomoyo_mount_acl2(struct tomoyo_request_info *r, char *dev_name,
|
|||
int error = -ENOMEM;
|
||||
|
||||
/* Get fstype. */
|
||||
requested_type = tomoyo_encode2(type);
|
||||
requested_type = tomoyo_encode(type);
|
||||
if (!requested_type)
|
||||
goto out;
|
||||
rtype.name = requested_type;
|
||||
|
@ -155,7 +104,7 @@ static int tomoyo_mount_acl2(struct tomoyo_request_info *r, char *dev_name,
|
|||
/* Map dev_name to "<NULL>" if no dev_name given. */
|
||||
if (!dev_name)
|
||||
dev_name = "<NULL>";
|
||||
requested_dev_name = tomoyo_encode2(dev_name);
|
||||
requested_dev_name = tomoyo_encode(dev_name);
|
||||
if (!requested_dev_name) {
|
||||
error = -ENOMEM;
|
||||
goto out;
|
||||
|
|
|
@ -12,115 +12,60 @@
|
|||
#include <linux/fs_struct.h>
|
||||
#include <linux/magic.h>
|
||||
#include <linux/slab.h>
|
||||
#include <net/sock.h>
|
||||
#include "common.h"
|
||||
|
||||
/**
|
||||
* tomoyo_encode: Convert binary string to ascii string.
|
||||
*
|
||||
* @buffer: Buffer for ASCII string.
|
||||
* @buflen: Size of @buffer.
|
||||
* @str: Binary string.
|
||||
* @str: String in binary format.
|
||||
*
|
||||
* Returns 0 on success, -ENOMEM otherwise.
|
||||
* 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.
|
||||
*/
|
||||
int tomoyo_encode(char *buffer, int buflen, const char *str)
|
||||
char *tomoyo_encode(const char *str)
|
||||
{
|
||||
while (1) {
|
||||
const unsigned char c = *(unsigned char *) str++;
|
||||
int len = 0;
|
||||
const char *p = str;
|
||||
char *cp;
|
||||
char *cp0;
|
||||
|
||||
if (tomoyo_is_valid(c)) {
|
||||
if (--buflen <= 0)
|
||||
break;
|
||||
*buffer++ = (char) c;
|
||||
if (c != '\\')
|
||||
continue;
|
||||
if (--buflen <= 0)
|
||||
break;
|
||||
*buffer++ = (char) c;
|
||||
continue;
|
||||
}
|
||||
if (!c) {
|
||||
if (--buflen <= 0)
|
||||
break;
|
||||
*buffer = '\0';
|
||||
return 0;
|
||||
}
|
||||
buflen -= 4;
|
||||
if (buflen <= 0)
|
||||
break;
|
||||
*buffer++ = '\\';
|
||||
*buffer++ = (c >> 6) + '0';
|
||||
*buffer++ = ((c >> 3) & 7) + '0';
|
||||
*buffer++ = (c & 7) + '0';
|
||||
if (!p)
|
||||
return NULL;
|
||||
while (*p) {
|
||||
const unsigned char c = *p++;
|
||||
if (c == '\\')
|
||||
len += 2;
|
||||
else if (c > ' ' && c < 127)
|
||||
len++;
|
||||
else
|
||||
len += 4;
|
||||
}
|
||||
return -ENOMEM;
|
||||
}
|
||||
len++;
|
||||
/* Reserve space for appending "/". */
|
||||
cp = kzalloc(len + 10, GFP_NOFS);
|
||||
if (!cp)
|
||||
return NULL;
|
||||
cp0 = cp;
|
||||
p = str;
|
||||
while (*p) {
|
||||
const unsigned char c = *p++;
|
||||
|
||||
/**
|
||||
* tomoyo_realpath_from_path2 - Returns realpath(3) of the given dentry but ignores chroot'ed root.
|
||||
*
|
||||
* @path: Pointer to "struct path".
|
||||
* @newname: Pointer to buffer to return value in.
|
||||
* @newname_len: Size of @newname.
|
||||
*
|
||||
* Returns 0 on success, negative value otherwise.
|
||||
*
|
||||
* If dentry is a directory, trailing '/' is appended.
|
||||
* Characters out of 0x20 < c < 0x7F range are converted to
|
||||
* \ooo style octal string.
|
||||
* Character \ is converted to \\ string.
|
||||
*/
|
||||
int tomoyo_realpath_from_path2(struct path *path, char *newname,
|
||||
int newname_len)
|
||||
{
|
||||
int error = -ENOMEM;
|
||||
struct dentry *dentry = path->dentry;
|
||||
char *sp;
|
||||
|
||||
if (!dentry || !path->mnt || !newname || newname_len <= 2048)
|
||||
return -EINVAL;
|
||||
if (dentry->d_op && dentry->d_op->d_dname) {
|
||||
/* For "socket:[\$]" and "pipe:[\$]". */
|
||||
static const int offset = 1536;
|
||||
sp = dentry->d_op->d_dname(dentry, newname + offset,
|
||||
newname_len - offset);
|
||||
} else {
|
||||
struct path ns_root = {.mnt = NULL, .dentry = NULL};
|
||||
|
||||
spin_lock(&dcache_lock);
|
||||
/* go to whatever namespace root we are under */
|
||||
sp = __d_path(path, &ns_root, newname, newname_len);
|
||||
spin_unlock(&dcache_lock);
|
||||
/* Prepend "/proc" prefix if using internal proc vfs mount. */
|
||||
if (!IS_ERR(sp) && (path->mnt->mnt_flags & MNT_INTERNAL) &&
|
||||
(path->mnt->mnt_sb->s_magic == PROC_SUPER_MAGIC)) {
|
||||
sp -= 5;
|
||||
if (sp >= newname)
|
||||
memcpy(sp, "/proc", 5);
|
||||
else
|
||||
sp = ERR_PTR(-ENOMEM);
|
||||
if (c == '\\') {
|
||||
*cp++ = '\\';
|
||||
*cp++ = '\\';
|
||||
} else if (c > ' ' && c < 127) {
|
||||
*cp++ = c;
|
||||
} else {
|
||||
*cp++ = '\\';
|
||||
*cp++ = (c >> 6) + '0';
|
||||
*cp++ = ((c >> 3) & 7) + '0';
|
||||
*cp++ = (c & 7) + '0';
|
||||
}
|
||||
}
|
||||
if (IS_ERR(sp))
|
||||
error = PTR_ERR(sp);
|
||||
else
|
||||
error = tomoyo_encode(newname, sp - newname, sp);
|
||||
/* Append trailing '/' if dentry is a directory. */
|
||||
if (!error && dentry->d_inode && S_ISDIR(dentry->d_inode->i_mode)
|
||||
&& *newname) {
|
||||
sp = newname + strlen(newname);
|
||||
if (*(sp - 1) != '/') {
|
||||
if (sp < newname + newname_len - 4) {
|
||||
*sp++ = '/';
|
||||
*sp = '\0';
|
||||
} else {
|
||||
error = -ENOMEM;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (error)
|
||||
tomoyo_warn_oom(__func__);
|
||||
return error;
|
||||
return cp0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -130,23 +75,90 @@ int tomoyo_realpath_from_path2(struct path *path, char *newname,
|
|||
*
|
||||
* Returns the realpath of the given @path on success, NULL otherwise.
|
||||
*
|
||||
* If dentry is a directory, trailing '/' is appended.
|
||||
* Characters out of 0x20 < c < 0x7F range are converted to
|
||||
* \ooo style octal string.
|
||||
* Character \ is converted to \\ string.
|
||||
*
|
||||
* These functions use kzalloc(), so the caller must call kfree()
|
||||
* if these functions didn't return NULL.
|
||||
*/
|
||||
char *tomoyo_realpath_from_path(struct path *path)
|
||||
{
|
||||
char *buf = kzalloc(sizeof(struct tomoyo_page_buffer), GFP_NOFS);
|
||||
|
||||
BUILD_BUG_ON(TOMOYO_MAX_PATHNAME_LEN > PATH_MAX);
|
||||
BUILD_BUG_ON(sizeof(struct tomoyo_page_buffer)
|
||||
<= TOMOYO_MAX_PATHNAME_LEN - 1);
|
||||
if (!buf)
|
||||
char *buf = NULL;
|
||||
char *name = NULL;
|
||||
unsigned int buf_len = PAGE_SIZE / 2;
|
||||
struct dentry *dentry = path->dentry;
|
||||
bool is_dir;
|
||||
if (!dentry)
|
||||
return NULL;
|
||||
if (tomoyo_realpath_from_path2(path, buf,
|
||||
TOMOYO_MAX_PATHNAME_LEN - 1) == 0)
|
||||
return buf;
|
||||
is_dir = dentry->d_inode && S_ISDIR(dentry->d_inode->i_mode);
|
||||
while (1) {
|
||||
struct path ns_root = { .mnt = NULL, .dentry = NULL };
|
||||
char *pos;
|
||||
buf_len <<= 1;
|
||||
kfree(buf);
|
||||
buf = kmalloc(buf_len, GFP_NOFS);
|
||||
if (!buf)
|
||||
break;
|
||||
/* Get better name for socket. */
|
||||
if (dentry->d_sb && dentry->d_sb->s_magic == SOCKFS_MAGIC) {
|
||||
struct inode *inode = dentry->d_inode;
|
||||
struct socket *sock = inode ? SOCKET_I(inode) : NULL;
|
||||
struct sock *sk = sock ? sock->sk : NULL;
|
||||
if (sk) {
|
||||
snprintf(buf, buf_len - 1, "socket:[family=%u:"
|
||||
"type=%u:protocol=%u]", sk->sk_family,
|
||||
sk->sk_type, sk->sk_protocol);
|
||||
} else {
|
||||
snprintf(buf, buf_len - 1, "socket:[unknown]");
|
||||
}
|
||||
name = tomoyo_encode(buf);
|
||||
break;
|
||||
}
|
||||
/* For "socket:[\$]" and "pipe:[\$]". */
|
||||
if (dentry->d_op && dentry->d_op->d_dname) {
|
||||
pos = dentry->d_op->d_dname(dentry, buf, buf_len - 1);
|
||||
if (IS_ERR(pos))
|
||||
continue;
|
||||
name = tomoyo_encode(pos);
|
||||
break;
|
||||
}
|
||||
/* If we don't have a vfsmount, we can't calculate. */
|
||||
if (!path->mnt)
|
||||
break;
|
||||
spin_lock(&dcache_lock);
|
||||
/* go to whatever namespace root we are under */
|
||||
pos = __d_path(path, &ns_root, buf, buf_len);
|
||||
spin_unlock(&dcache_lock);
|
||||
/* Prepend "/proc" prefix if using internal proc vfs mount. */
|
||||
if (!IS_ERR(pos) && (path->mnt->mnt_flags & MNT_INTERNAL) &&
|
||||
(path->mnt->mnt_sb->s_magic == PROC_SUPER_MAGIC)) {
|
||||
pos -= 5;
|
||||
if (pos >= buf)
|
||||
memcpy(pos, "/proc", 5);
|
||||
else
|
||||
pos = ERR_PTR(-ENOMEM);
|
||||
}
|
||||
if (IS_ERR(pos))
|
||||
continue;
|
||||
name = tomoyo_encode(pos);
|
||||
break;
|
||||
}
|
||||
kfree(buf);
|
||||
return NULL;
|
||||
if (!name)
|
||||
tomoyo_warn_oom(__func__);
|
||||
else if (is_dir && *name) {
|
||||
/* Append trailing '/' if dentry is a directory. */
|
||||
char *pos = name + strlen(name) - 1;
|
||||
if (*pos != '/')
|
||||
/*
|
||||
* This is OK because tomoyo_encode() reserves space
|
||||
* for appending "/".
|
||||
*/
|
||||
*++pos = '/';
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
Loading…
Reference in New Issue