diff options
author | Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp> | 2010-05-17 10:09:15 +0900 |
---|---|---|
committer | James Morris <jmorris@namei.org> | 2010-08-02 15:33:37 +1000 |
commit | a1f9bb6a375a8dbf7797ffbd6739c46b338a77f7 (patch) | |
tree | 44df8f05e6ad6bd7cf9ce398c99efbd7cff24c20 /security/tomoyo/file.c | |
parent | cb0abe6a5b58499bd4bc1403f4987af9ead0642c (diff) | |
download | linux-a1f9bb6a375a8dbf7797ffbd6739c46b338a77f7.tar.gz |
TOMOYO: Split file access control functions by type of parameters.
Check numeric parameters for operations that deal them
(e.g. chmod/chown/ioctl).
Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
Signed-off-by: James Morris <jmorris@namei.org>
Diffstat (limited to 'security/tomoyo/file.c')
-rw-r--r-- | security/tomoyo/file.c | 588 |
1 files changed, 501 insertions, 87 deletions
diff --git a/security/tomoyo/file.c b/security/tomoyo/file.c index f1d2adfd33bc..727cc723f87d 100644 --- a/security/tomoyo/file.c +++ b/security/tomoyo/file.c @@ -12,39 +12,49 @@ #include "common.h" #include <linux/slab.h> -/* Keyword array for single path operations. */ +/* Keyword array for operations with one pathname. */ static const char *tomoyo_path_keyword[TOMOYO_MAX_PATH_OPERATION] = { [TOMOYO_TYPE_READ_WRITE] = "read/write", [TOMOYO_TYPE_EXECUTE] = "execute", [TOMOYO_TYPE_READ] = "read", [TOMOYO_TYPE_WRITE] = "write", - [TOMOYO_TYPE_CREATE] = "create", [TOMOYO_TYPE_UNLINK] = "unlink", - [TOMOYO_TYPE_MKDIR] = "mkdir", [TOMOYO_TYPE_RMDIR] = "rmdir", - [TOMOYO_TYPE_MKFIFO] = "mkfifo", - [TOMOYO_TYPE_MKSOCK] = "mksock", - [TOMOYO_TYPE_MKBLOCK] = "mkblock", - [TOMOYO_TYPE_MKCHAR] = "mkchar", [TOMOYO_TYPE_TRUNCATE] = "truncate", [TOMOYO_TYPE_SYMLINK] = "symlink", [TOMOYO_TYPE_REWRITE] = "rewrite", - [TOMOYO_TYPE_IOCTL] = "ioctl", - [TOMOYO_TYPE_CHMOD] = "chmod", - [TOMOYO_TYPE_CHOWN] = "chown", - [TOMOYO_TYPE_CHGRP] = "chgrp", [TOMOYO_TYPE_CHROOT] = "chroot", [TOMOYO_TYPE_MOUNT] = "mount", [TOMOYO_TYPE_UMOUNT] = "unmount", }; -/* Keyword array for double path operations. */ +/* Keyword array for operations with one pathname and three numbers. */ +static const char *tomoyo_path_number3_keyword +[TOMOYO_MAX_PATH_NUMBER3_OPERATION] = { + [TOMOYO_TYPE_MKBLOCK] = "mkblock", + [TOMOYO_TYPE_MKCHAR] = "mkchar", +}; + +/* Keyword array for operations with two pathnames. */ static const char *tomoyo_path2_keyword[TOMOYO_MAX_PATH2_OPERATION] = { - [TOMOYO_TYPE_LINK] = "link", - [TOMOYO_TYPE_RENAME] = "rename", + [TOMOYO_TYPE_LINK] = "link", + [TOMOYO_TYPE_RENAME] = "rename", [TOMOYO_TYPE_PIVOT_ROOT] = "pivot_root", }; +/* Keyword array for operations with one pathname and one number. */ +static const char *tomoyo_path_number_keyword +[TOMOYO_MAX_PATH_NUMBER_OPERATION] = { + [TOMOYO_TYPE_CREATE] = "create", + [TOMOYO_TYPE_MKDIR] = "mkdir", + [TOMOYO_TYPE_MKFIFO] = "mkfifo", + [TOMOYO_TYPE_MKSOCK] = "mksock", + [TOMOYO_TYPE_IOCTL] = "ioctl", + [TOMOYO_TYPE_CHMOD] = "chmod", + [TOMOYO_TYPE_CHOWN] = "chown", + [TOMOYO_TYPE_CHGRP] = "chgrp", +}; + void tomoyo_put_name_union(struct tomoyo_name_union *ptr) { if (!ptr) @@ -159,6 +169,19 @@ const char *tomoyo_path2keyword(const u8 operation) } /** + * tomoyo_path_number32keyword - Get the name of path/number/number/number operations. + * + * @operation: Type of operation. + * + * Returns the name of path/number/number/number operation. + */ +const char *tomoyo_path_number32keyword(const u8 operation) +{ + return (operation < TOMOYO_MAX_PATH_NUMBER3_OPERATION) + ? tomoyo_path_number3_keyword[operation] : NULL; +} + +/** * tomoyo_path22keyword - Get the name of double path operation. * * @operation: Type of operation. @@ -172,6 +195,19 @@ const char *tomoyo_path22keyword(const u8 operation) } /** + * tomoyo_path_number2keyword - Get the name of path/number operations. + * + * @operation: Type of operation. + * + * Returns the name of path/number operation. + */ +const char *tomoyo_path_number2keyword(const u8 operation) +{ + return (operation < TOMOYO_MAX_PATH_NUMBER_OPERATION) + ? tomoyo_path_number_keyword[operation] : NULL; +} + +/** * tomoyo_strendswith - Check whether the token ends with the given token. * * @name: The token to check. @@ -665,8 +701,8 @@ bool tomoyo_read_no_rewrite_policy(struct tomoyo_io_buffer *head) /** * tomoyo_update_file_acl - Update file's read/write/execute ACL. * - * @filename: Filename. * @perm: Permission (between 1 to 7). + * @filename: Filename. * @domain: Pointer to "struct tomoyo_domain_info". * @is_delete: True if it is a delete request. * @@ -679,7 +715,7 @@ bool tomoyo_read_no_rewrite_policy(struct tomoyo_io_buffer *head) * * Caller holds tomoyo_read_lock(). */ -static int tomoyo_update_file_acl(const char *filename, u8 perm, +static int tomoyo_update_file_acl(u8 perm, const char *filename, struct tomoyo_domain_info * const domain, const bool is_delete) { @@ -731,14 +767,8 @@ static int tomoyo_path_acl(const struct tomoyo_request_info *r, if (ptr->type != TOMOYO_TYPE_PATH_ACL) continue; acl = container_of(ptr, struct tomoyo_path_acl, head); - if (perm <= 0xFFFF) { - if (!(acl->perm & perm)) - continue; - } else { - if (!(acl->perm_high & (perm >> 16))) - continue; - } - if (!tomoyo_compare_name_union_pattern(filename, &acl->name, + if (!(acl->perm & perm) || + !tomoyo_compare_name_union_pattern(filename, &acl->name, may_use_pattern)) continue; error = 0; @@ -796,61 +826,13 @@ static int tomoyo_file_perm(struct tomoyo_request_info *r, /* Don't use patterns for execute permission. */ const struct tomoyo_path_info *patterned_file = (mode != 1) ? tomoyo_get_file_pattern(filename) : filename; - tomoyo_update_file_acl(patterned_file->name, mode, - r->domain, false); + tomoyo_update_file_acl(mode, patterned_file->name, r->domain, + false); } return 0; } /** - * tomoyo_write_file_policy - Update file related list. - * - * @data: String to parse. - * @domain: Pointer to "struct tomoyo_domain_info". - * @is_delete: True if it is a delete request. - * - * Returns 0 on success, negative value otherwise. - * - * Caller holds tomoyo_read_lock(). - */ -int tomoyo_write_file_policy(char *data, struct tomoyo_domain_info *domain, - const bool is_delete) -{ - char *filename = strchr(data, ' '); - char *filename2; - unsigned int perm; - u8 type; - - if (!filename) - return -EINVAL; - *filename++ = '\0'; - if (sscanf(data, "%u", &perm) == 1) - return tomoyo_update_file_acl(filename, (u8) perm, domain, - is_delete); - if (strncmp(data, "allow_", 6)) - goto out; - data += 6; - for (type = 0; type < TOMOYO_MAX_PATH_OPERATION; type++) { - if (strcmp(data, tomoyo_path_keyword[type])) - continue; - return tomoyo_update_path_acl(type, filename, domain, - is_delete); - } - filename2 = strchr(filename, ' '); - if (!filename2) - goto out; - *filename2++ = '\0'; - for (type = 0; type < TOMOYO_MAX_PATH2_OPERATION; type++) { - if (strcmp(data, tomoyo_path2_keyword[type])) - continue; - return tomoyo_update_path2_acl(type, filename, filename2, - domain, is_delete); - } - out: - return -EINVAL; -} - -/** * tomoyo_update_path_acl - Update "struct tomoyo_path_acl" list. * * @type: Type of operation. @@ -866,13 +848,12 @@ static int tomoyo_update_path_acl(const u8 type, const char *filename, struct tomoyo_domain_info *const domain, const bool is_delete) { - static const u32 tomoyo_rw_mask = + static const u16 tomoyo_rw_mask = (1 << TOMOYO_TYPE_READ) | (1 << TOMOYO_TYPE_WRITE); - const u32 perm = 1 << type; + const u16 perm = 1 << type; struct tomoyo_acl_info *ptr; struct tomoyo_path_acl e = { .head.type = TOMOYO_TYPE_PATH_ACL, - .perm_high = perm >> 16, .perm = perm }; int error = is_delete ? -ENOENT : -ENOMEM; @@ -891,19 +872,13 @@ static int tomoyo_update_path_acl(const u8 type, const char *filename, if (!tomoyo_is_same_path_acl(acl, &e)) continue; if (is_delete) { - if (perm <= 0xFFFF) - acl->perm &= ~perm; - else - acl->perm_high &= ~(perm >> 16); + acl->perm &= ~perm; if ((acl->perm & tomoyo_rw_mask) != tomoyo_rw_mask) acl->perm &= ~(1 << TOMOYO_TYPE_READ_WRITE); else if (!(acl->perm & (1 << TOMOYO_TYPE_READ_WRITE))) acl->perm &= ~tomoyo_rw_mask; } else { - if (perm <= 0xFFFF) - acl->perm |= perm; - else - acl->perm_high |= (perm >> 16); + acl->perm |= perm; if ((acl->perm & tomoyo_rw_mask) == tomoyo_rw_mask) acl->perm |= 1 << TOMOYO_TYPE_READ_WRITE; else if (acl->perm & (1 << TOMOYO_TYPE_READ_WRITE)) @@ -928,6 +903,71 @@ static int tomoyo_update_path_acl(const u8 type, const char *filename, } /** + * tomoyo_update_path_number3_acl - Update "struct tomoyo_path_number3_acl" list. + * + * @type: Type of operation. + * @filename: Filename. + * @mode: Create mode. + * @major: Device major number. + * @minor: Device minor number. + * @domain: Pointer to "struct tomoyo_domain_info". + * @is_delete: True if it is a delete request. + * + * Returns 0 on success, negative value otherwise. + */ +static inline int tomoyo_update_path_number3_acl(const u8 type, + const char *filename, + char *mode, + char *major, char *minor, + struct tomoyo_domain_info * + const domain, + const bool is_delete) +{ + const u8 perm = 1 << type; + struct tomoyo_acl_info *ptr; + struct tomoyo_path_number3_acl e = { + .head.type = TOMOYO_TYPE_PATH_NUMBER3_ACL, + .perm = perm + }; + int error = is_delete ? -ENOENT : -ENOMEM; + if (!tomoyo_parse_name_union(filename, &e.name) || + !tomoyo_parse_number_union(mode, &e.mode) || + !tomoyo_parse_number_union(major, &e.major) || + !tomoyo_parse_number_union(minor, &e.minor)) + goto out; + if (mutex_lock_interruptible(&tomoyo_policy_lock)) + goto out; + list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { + struct tomoyo_path_number3_acl *acl = + container_of(ptr, struct tomoyo_path_number3_acl, head); + if (!tomoyo_is_same_path_number3_acl(acl, &e)) + continue; + if (is_delete) + acl->perm &= ~perm; + else + acl->perm |= perm; + error = 0; + break; + } + if (!is_delete && error) { + struct tomoyo_path_number3_acl *entry = + tomoyo_commit_ok(&e, sizeof(e)); + if (entry) { + list_add_tail_rcu(&entry->head.list, + &domain->acl_info_list); + error = 0; + } + } + mutex_unlock(&tomoyo_policy_lock); + out: + tomoyo_put_name_union(&e.name); + tomoyo_put_number_union(&e.mode); + tomoyo_put_number_union(&e.major); + tomoyo_put_number_union(&e.minor); + return error; +} + +/** * tomoyo_update_path2_acl - Update "struct tomoyo_path2_acl" list. * * @type: Type of operation. @@ -989,6 +1029,50 @@ static int tomoyo_update_path2_acl(const u8 type, const char *filename1, } /** + * tomoyo_path_number3_acl - Check permission for path/number/number/number operation. + * + * @r: Pointer to "struct tomoyo_request_info". + * @filename: Filename to check. + * @perm: Permission. + * @mode: Create mode. + * @major: Device major number. + * @minor: Device minor number. + * + * Returns 0 on success, -EPERM otherwise. + * + * Caller holds tomoyo_read_lock(). + */ +static int tomoyo_path_number3_acl(struct tomoyo_request_info *r, + const struct tomoyo_path_info *filename, + const u16 perm, const unsigned int mode, + const unsigned int major, + const unsigned int minor) +{ + struct tomoyo_domain_info *domain = r->domain; + struct tomoyo_acl_info *ptr; + int error = -EPERM; + list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { + struct tomoyo_path_number3_acl *acl; + if (ptr->type != TOMOYO_TYPE_PATH_NUMBER3_ACL) + continue; + acl = container_of(ptr, struct tomoyo_path_number3_acl, head); + if (!tomoyo_compare_number_union(mode, &acl->mode)) + continue; + if (!tomoyo_compare_number_union(major, &acl->major)) + continue; + if (!tomoyo_compare_number_union(minor, &acl->minor)) + continue; + if (!(acl->perm & perm)) + continue; + if (!tomoyo_compare_name_union(filename, &acl->name)) + continue; + error = 0; + break; + } + return error; +} + +/** * tomoyo_path2_acl - Check permission for double path operation. * * @r: Pointer to "struct tomoyo_request_info". @@ -1069,6 +1153,195 @@ static int tomoyo_path_permission(struct tomoyo_request_info *r, u8 operation, } /** + * tomoyo_path_number_acl - Check permission for ioctl/chmod/chown/chgrp operation. + * + * @r: Pointer to "struct tomoyo_request_info". + * @type: Operation. + * @filename: Filename to check. + * @number: Number. + * + * Returns 0 on success, -EPERM otherwise. + * + * Caller holds tomoyo_read_lock(). + */ +static int tomoyo_path_number_acl(struct tomoyo_request_info *r, const u8 type, + const struct tomoyo_path_info *filename, + const unsigned long number) +{ + struct tomoyo_domain_info *domain = r->domain; + struct tomoyo_acl_info *ptr; + const u8 perm = 1 << type; + int error = -EPERM; + list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { + struct tomoyo_path_number_acl *acl; + if (ptr->type != TOMOYO_TYPE_PATH_NUMBER_ACL) + continue; + acl = container_of(ptr, struct tomoyo_path_number_acl, + head); + if (!(acl->perm & perm) || + !tomoyo_compare_number_union(number, &acl->number) || + !tomoyo_compare_name_union(filename, &acl->name)) + continue; + error = 0; + break; + } + return error; +} + +/** + * tomoyo_update_path_number_acl - Update ioctl/chmod/chown/chgrp ACL. + * + * @type: Type of operation. + * @filename: Filename. + * @number: Number. + * @domain: Pointer to "struct tomoyo_domain_info". + * @is_delete: True if it is a delete request. + * + * Returns 0 on success, negative value otherwise. + */ +static inline int tomoyo_update_path_number_acl(const u8 type, + const char *filename, + char *number, + struct tomoyo_domain_info * + const domain, + const bool is_delete) +{ + const u8 perm = 1 << type; + struct tomoyo_acl_info *ptr; + struct tomoyo_path_number_acl e = { + .head.type = TOMOYO_TYPE_PATH_NUMBER_ACL, + .perm = perm + }; + int error = is_delete ? -ENOENT : -ENOMEM; + if (!domain) + return -EINVAL; + if (!tomoyo_parse_name_union(filename, &e.name)) + return -EINVAL; + if (!tomoyo_parse_number_union(number, &e.number)) + goto out; + if (mutex_lock_interruptible(&tomoyo_policy_lock)) + goto out; + list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { + struct tomoyo_path_number_acl *acl = + container_of(ptr, struct tomoyo_path_number_acl, head); + if (!tomoyo_is_same_path_number_acl(acl, &e)) + continue; + if (is_delete) + acl->perm &= ~perm; + else + acl->perm |= perm; + error = 0; + break; + } + if (!is_delete && error) { + struct tomoyo_path_number_acl *entry = + tomoyo_commit_ok(&e, sizeof(e)); + if (entry) { + list_add_tail_rcu(&entry->head.list, + &domain->acl_info_list); + error = 0; + } + } + mutex_unlock(&tomoyo_policy_lock); + out: + tomoyo_put_name_union(&e.name); + tomoyo_put_number_union(&e.number); + return error; +} + +/** + * tomoyo_path_number_perm2 - Check permission for "create", "mkdir", "mkfifo", "mksock", "ioctl", "chmod", "chown", "chgrp". + * + * @r: Pointer to "strct tomoyo_request_info". + * @filename: Filename to check. + * @number: Number. + * + * Returns 0 on success, negative value otherwise. + * + * Caller holds tomoyo_read_lock(). + */ +static int tomoyo_path_number_perm2(struct tomoyo_request_info *r, + const u8 type, + const struct tomoyo_path_info *filename, + const unsigned long number) +{ + char buffer[64]; + int error; + u8 radix; + + if (!filename) + return 0; + switch (type) { + case TOMOYO_TYPE_CREATE: + case TOMOYO_TYPE_MKDIR: + case TOMOYO_TYPE_MKFIFO: + case TOMOYO_TYPE_MKSOCK: + case TOMOYO_TYPE_CHMOD: + radix = TOMOYO_VALUE_TYPE_OCTAL; + break; + case TOMOYO_TYPE_IOCTL: + radix = TOMOYO_VALUE_TYPE_HEXADECIMAL; + break; + default: + radix = TOMOYO_VALUE_TYPE_DECIMAL; + break; + } + tomoyo_print_ulong(buffer, sizeof(buffer), number, radix); + error = tomoyo_path_number_acl(r, type, filename, number); + if (!error) + return 0; + tomoyo_warn_log(r, "%s %s %s", tomoyo_path_number2keyword(type), + filename->name, buffer); + if (tomoyo_domain_quota_is_ok(r)) + tomoyo_update_path_number_acl(type, + tomoyo_get_file_pattern(filename) + ->name, buffer, r->domain, false); + if (r->mode != TOMOYO_CONFIG_ENFORCING) + error = 0; + return error; +} + +/** + * tomoyo_path_number_perm - Check permission for "create", "mkdir", "mkfifo", "mksock", "ioctl", "chmod", "chown", "chgrp". + * + * @type: Type of operation. + * @path: Pointer to "struct path". + * @number: Number. + * + * Returns 0 on success, negative value otherwise. + */ +int tomoyo_path_number_perm(const u8 type, struct path *path, + unsigned long number) +{ + struct tomoyo_request_info r; + int error = -ENOMEM; + 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) + 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); + out: + kfree(buf); + tomoyo_read_unlock(idx); + if (r.mode != TOMOYO_CONFIG_ENFORCING) + error = 0; + return error; +} + +/** * tomoyo_check_exec_perm - Check permission for "execute". * * @domain: Pointer to "struct tomoyo_domain_info". @@ -1145,7 +1418,7 @@ int tomoyo_check_open_permission(struct tomoyo_domain_info *domain, } /** - * tomoyo_path_perm - Check permission for "create", "unlink", "mkdir", "rmdir", "mkfifo", "mksock", "mkblock", "mkchar", "truncate", "symlink", "rewrite", "ioctl", "chmod", "chown", "chgrp", "chroot", "mount" and "unmount". + * tomoyo_path_perm - Check permission for "unlink", "rmdir", "truncate", "symlink", "rewrite", "chroot", "mount" and "unmount". * * @operation: Type of operation. * @path: Pointer to "struct path". @@ -1173,7 +1446,6 @@ int tomoyo_path_perm(const u8 operation, struct path *path) goto out; } break; - case TOMOYO_TYPE_MKDIR: case TOMOYO_TYPE_RMDIR: case TOMOYO_TYPE_CHROOT: if (!buf->is_dir) { @@ -1194,6 +1466,91 @@ int tomoyo_path_perm(const u8 operation, struct path *path) } /** + * tomoyo_path_number3_perm2 - Check permission for path/number/number/number operation. + * + * @r: Pointer to "struct tomoyo_request_info". + * @operation: Type of operation. + * @filename: Filename to check. + * @mode: Create mode. + * @dev: Device number. + * + * Returns 0 on success, negative value otherwise. + * + * Caller holds tomoyo_read_lock(). + */ +static int tomoyo_path_number3_perm2(struct tomoyo_request_info *r, + const u8 operation, + const struct tomoyo_path_info *filename, + const unsigned int mode, + const unsigned int dev) +{ + int error; + const unsigned int major = MAJOR(dev); + const unsigned int minor = MINOR(dev); + + error = tomoyo_path_number3_acl(r, filename, 1 << operation, mode, + major, minor); + if (!error) + return 0; + tomoyo_warn_log(r, "%s %s 0%o %u %u", + tomoyo_path_number32keyword(operation), + filename->name, mode, major, minor); + if (tomoyo_domain_quota_is_ok(r)) { + char mode_buf[64]; + char major_buf[64]; + char minor_buf[64]; + memset(mode_buf, 0, sizeof(mode_buf)); + memset(major_buf, 0, sizeof(major_buf)); + memset(minor_buf, 0, sizeof(minor_buf)); + snprintf(mode_buf, sizeof(mode_buf) - 1, "0%o", mode); + snprintf(major_buf, sizeof(major_buf) - 1, "%u", major); + snprintf(minor_buf, sizeof(minor_buf) - 1, "%u", minor); + tomoyo_update_path_number3_acl(operation, + tomoyo_get_file_pattern(filename) + ->name, mode_buf, major_buf, + minor_buf, r->domain, false); + } + if (r->mode != TOMOYO_CONFIG_ENFORCING) + error = 0; + return error; +} + +/** + * tomoyo_path_number3_perm - Check permission for "mkblock" and "mkchar". + * + * @operation: Type of operation. (TOMOYO_TYPE_MKCHAR or TOMOYO_TYPE_MKBLOCK) + * @path: Pointer to "struct path". + * @mode: Create mode. + * @dev: Device number. + * + * Returns 0 on success, negative value otherwise. + */ +int tomoyo_path_number3_perm(const u8 operation, struct path *path, + const unsigned int mode, unsigned int dev) +{ + struct tomoyo_request_info r; + int error = -ENOMEM; + struct tomoyo_path_info *buf; + int idx; + + if (tomoyo_init_request_info(&r, NULL) == TOMOYO_CONFIG_DISABLED || + !path->mnt) + return 0; + idx = tomoyo_read_lock(); + error = -ENOMEM; + buf = tomoyo_get_path(path); + if (buf) { + error = tomoyo_path_number3_perm2(&r, operation, buf, mode, + new_decode_dev(dev)); + kfree(buf); + } + tomoyo_read_unlock(idx); + if (r.mode != TOMOYO_CONFIG_ENFORCING) + error = 0; + return error; +} + +/** * tomoyo_path2_perm - Check permission for "rename", "link" and "pivot_root". * * @operation: Type of operation. @@ -1254,3 +1611,60 @@ int tomoyo_path2_perm(const u8 operation, struct path *path1, error = 0; return error; } + +/** + * tomoyo_write_file_policy - Update file related list. + * + * @data: String to parse. + * @domain: Pointer to "struct tomoyo_domain_info". + * @is_delete: True if it is a delete request. + * + * Returns 0 on success, negative value otherwise. + * + * Caller holds tomoyo_read_lock(). + */ +int tomoyo_write_file_policy(char *data, struct tomoyo_domain_info *domain, + const bool is_delete) +{ + char *w[5]; + u8 type; + if (!tomoyo_tokenize(data, w, sizeof(w)) || !w[1][0]) + return -EINVAL; + if (strncmp(w[0], "allow_", 6)) { + unsigned int perm; + if (sscanf(w[0], "%u", &perm) == 1) + return tomoyo_update_file_acl((u8) perm, w[1], domain, + is_delete); + goto out; + } + w[0] += 6; + for (type = 0; type < TOMOYO_MAX_PATH_OPERATION; type++) { + if (strcmp(w[0], tomoyo_path_keyword[type])) + continue; + return tomoyo_update_path_acl(type, w[1], domain, is_delete); + } + if (!w[2][0]) + goto out; + for (type = 0; type < TOMOYO_MAX_PATH2_OPERATION; type++) { + if (strcmp(w[0], tomoyo_path2_keyword[type])) + continue; + return tomoyo_update_path2_acl(type, w[1], w[2], domain, + is_delete); + } + for (type = 0; type < TOMOYO_MAX_PATH_NUMBER_OPERATION; type++) { + if (strcmp(w[0], tomoyo_path_number_keyword[type])) + continue; + return tomoyo_update_path_number_acl(type, w[1], w[2], domain, + is_delete); + } + if (!w[3][0] || !w[4][0]) + goto out; + for (type = 0; type < TOMOYO_MAX_PATH_NUMBER3_OPERATION; type++) { + if (strcmp(w[0], tomoyo_path_number3_keyword[type])) + continue; + return tomoyo_update_path_number3_acl(type, w[1], w[2], w[3], + w[4], domain, is_delete); + } + out: + return -EINVAL; +} |