From 9f59f90bf57cff8be07faddc608c400b6e7c5d05 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sun, 6 Dec 2009 10:16:51 +0100 Subject: [PATCH 01/38] security/selinux/ss: correct size computation The size argument to kcalloc should be the size of desired structure, not the pointer to it. The semantic patch that makes this change is as follows: (http://coccinelle.lip6.fr/) // @expression@ expression *x; @@ x = <+... -sizeof(x) +sizeof(*x) ...+>// Signed-off-by: Julia Lawall Acked-by: Eric Paris Signed-off-by: James Morris --- security/selinux/ss/services.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index d6bb20cbad6..07ddc81d7b5 100644 --- a/security/selinux/ss/services.c +++ b/security/selinux/ss/services.c @@ -2555,7 +2555,7 @@ int security_get_classes(char ***classes, int *nclasses) read_lock(&policy_rwlock); *nclasses = policydb.p_classes.nprim; - *classes = kcalloc(*nclasses, sizeof(*classes), GFP_ATOMIC); + *classes = kcalloc(*nclasses, sizeof(**classes), GFP_ATOMIC); if (!*classes) goto out; @@ -2602,7 +2602,7 @@ int security_get_permissions(char *class, char ***perms, int *nperms) } *nperms = match->permissions.nprim; - *perms = kcalloc(*nperms, sizeof(*perms), GFP_ATOMIC); + *perms = kcalloc(*nperms, sizeof(**perms), GFP_ATOMIC); if (!*perms) goto out; From 5d0901a3a0c39c97ca504f73d24030f63cfc9fa2 Mon Sep 17 00:00:00 2001 From: Tetsuo Handa Date: Thu, 26 Nov 2009 15:24:49 +0900 Subject: [PATCH 02/38] LSM: Rename security_path_ functions argument names. include/linux/security.h and security/capability.c are using "struct path *dir" but security/security.c was using "struct path *path" by error. This patch renames "struct path *path" to "struct path *dir". Signed-off-by: Tetsuo Handa Signed-off-by: James Morris --- security/security.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/security/security.c b/security/security.c index 24e060be9fa..f2d8aa94932 100644 --- a/security/security.c +++ b/security/security.c @@ -389,42 +389,42 @@ int security_inode_init_security(struct inode *inode, struct inode *dir, EXPORT_SYMBOL(security_inode_init_security); #ifdef CONFIG_SECURITY_PATH -int security_path_mknod(struct path *path, struct dentry *dentry, int mode, +int security_path_mknod(struct path *dir, struct dentry *dentry, int mode, unsigned int dev) { - if (unlikely(IS_PRIVATE(path->dentry->d_inode))) + if (unlikely(IS_PRIVATE(dir->dentry->d_inode))) return 0; - return security_ops->path_mknod(path, dentry, mode, dev); + return security_ops->path_mknod(dir, dentry, mode, dev); } EXPORT_SYMBOL(security_path_mknod); -int security_path_mkdir(struct path *path, struct dentry *dentry, int mode) +int security_path_mkdir(struct path *dir, struct dentry *dentry, int mode) { - if (unlikely(IS_PRIVATE(path->dentry->d_inode))) + if (unlikely(IS_PRIVATE(dir->dentry->d_inode))) return 0; - return security_ops->path_mkdir(path, dentry, mode); + return security_ops->path_mkdir(dir, dentry, mode); } -int security_path_rmdir(struct path *path, struct dentry *dentry) +int security_path_rmdir(struct path *dir, struct dentry *dentry) { - if (unlikely(IS_PRIVATE(path->dentry->d_inode))) + if (unlikely(IS_PRIVATE(dir->dentry->d_inode))) return 0; - return security_ops->path_rmdir(path, dentry); + return security_ops->path_rmdir(dir, dentry); } -int security_path_unlink(struct path *path, struct dentry *dentry) +int security_path_unlink(struct path *dir, struct dentry *dentry) { - if (unlikely(IS_PRIVATE(path->dentry->d_inode))) + if (unlikely(IS_PRIVATE(dir->dentry->d_inode))) return 0; - return security_ops->path_unlink(path, dentry); + return security_ops->path_unlink(dir, dentry); } -int security_path_symlink(struct path *path, struct dentry *dentry, +int security_path_symlink(struct path *dir, struct dentry *dentry, const char *old_name) { - if (unlikely(IS_PRIVATE(path->dentry->d_inode))) + if (unlikely(IS_PRIVATE(dir->dentry->d_inode))) return 0; - return security_ops->path_symlink(path, dentry, old_name); + return security_ops->path_symlink(dir, dentry, old_name); } int security_path_link(struct dentry *old_dentry, struct path *new_dir, From 937bf6133b21b16965f75223085f4314ae32b8eb Mon Sep 17 00:00:00 2001 From: Tetsuo Handa Date: Wed, 2 Dec 2009 21:09:48 +0900 Subject: [PATCH 03/38] TOMOYO: Add rest of file operation restrictions. LSM hooks for chmod()/chown()/chroot() are now ready. This patch utilizes these hooks. Signed-off-by: Tetsuo Handa Signed-off-by: James Morris --- security/tomoyo/common.c | 61 ++++++++++++---------------------------- security/tomoyo/common.h | 12 +++++--- security/tomoyo/file.c | 47 +++++++++++++++++++++++-------- security/tomoyo/tomoyo.c | 61 ++++++++++++++++++++++++++++++++++++++++ security/tomoyo/tomoyo.h | 12 ++++++-- 5 files changed, 132 insertions(+), 61 deletions(-) diff --git a/security/tomoyo/common.c b/security/tomoyo/common.c index e0d0354008b..6c606168243 100644 --- a/security/tomoyo/common.c +++ b/security/tomoyo/common.c @@ -842,52 +842,27 @@ bool tomoyo_domain_quota_is_ok(struct tomoyo_domain_info * const domain) if (ptr->type & TOMOYO_ACL_DELETED) continue; switch (tomoyo_acl_type2(ptr)) { - struct tomoyo_single_path_acl_record *acl1; - struct tomoyo_double_path_acl_record *acl2; - u16 perm; + struct tomoyo_single_path_acl_record *acl; + u32 perm; + u8 i; case TOMOYO_TYPE_SINGLE_PATH_ACL: - acl1 = container_of(ptr, - struct tomoyo_single_path_acl_record, - head); - perm = acl1->perm; - if (perm & (1 << TOMOYO_TYPE_EXECUTE_ACL)) - count++; - if (perm & - ((1 << TOMOYO_TYPE_READ_ACL) | - (1 << TOMOYO_TYPE_WRITE_ACL))) - count++; - if (perm & (1 << TOMOYO_TYPE_CREATE_ACL)) - count++; - if (perm & (1 << TOMOYO_TYPE_UNLINK_ACL)) - count++; - if (perm & (1 << TOMOYO_TYPE_MKDIR_ACL)) - count++; - if (perm & (1 << TOMOYO_TYPE_RMDIR_ACL)) - count++; - if (perm & (1 << TOMOYO_TYPE_MKFIFO_ACL)) - count++; - if (perm & (1 << TOMOYO_TYPE_MKSOCK_ACL)) - count++; - if (perm & (1 << TOMOYO_TYPE_MKBLOCK_ACL)) - count++; - if (perm & (1 << TOMOYO_TYPE_MKCHAR_ACL)) - count++; - if (perm & (1 << TOMOYO_TYPE_TRUNCATE_ACL)) - count++; - if (perm & (1 << TOMOYO_TYPE_SYMLINK_ACL)) - count++; - if (perm & (1 << TOMOYO_TYPE_REWRITE_ACL)) - count++; + acl = container_of(ptr, + struct tomoyo_single_path_acl_record, + head); + perm = acl->perm | (((u32) acl->perm_high) << 16); + for (i = 0; i < TOMOYO_MAX_SINGLE_PATH_OPERATION; i++) + if (perm & (1 << i)) + count++; + if (perm & (1 << TOMOYO_TYPE_READ_WRITE_ACL)) + count -= 2; break; case TOMOYO_TYPE_DOUBLE_PATH_ACL: - acl2 = container_of(ptr, + perm = container_of(ptr, struct tomoyo_double_path_acl_record, - head); - perm = acl2->perm; - if (perm & (1 << TOMOYO_TYPE_LINK_ACL)) - count++; - if (perm & (1 << TOMOYO_TYPE_RENAME_ACL)) - count++; + head)->perm; + for (i = 0; i < TOMOYO_MAX_DOUBLE_PATH_OPERATION; i++) + if (perm & (1 << i)) + count++; break; } } @@ -1426,7 +1401,7 @@ static bool tomoyo_print_single_path_acl(struct tomoyo_io_buffer *head, u8 bit; const char *atmark = ""; const char *filename; - const u16 perm = ptr->perm; + const u32 perm = ptr->perm | (((u32) ptr->perm_high) << 16); filename = ptr->filename->name; for (bit = head->read_bit; bit < TOMOYO_MAX_SINGLE_PATH_OPERATION; diff --git a/security/tomoyo/common.h b/security/tomoyo/common.h index 92169d29b2d..bd10f9fa351 100644 --- a/security/tomoyo/common.h +++ b/security/tomoyo/common.h @@ -108,7 +108,7 @@ struct tomoyo_path_info_with_data { * (b) type & 0x80 : whether the entry is marked as "deleted". * * Packing "struct tomoyo_acl_info" allows - * "struct tomoyo_single_path_acl_record" to embed "u16" and + * "struct tomoyo_single_path_acl_record" to embed "u8" + "u16" and * "struct tomoyo_double_path_acl_record" to embed "u8" * without enlarging their structure size. */ @@ -184,10 +184,13 @@ struct tomoyo_domain_info { * Directives held by this structure are "allow_read/write", "allow_execute", * "allow_read", "allow_write", "allow_create", "allow_unlink", "allow_mkdir", * "allow_rmdir", "allow_mkfifo", "allow_mksock", "allow_mkblock", - * "allow_mkchar", "allow_truncate", "allow_symlink" and "allow_rewrite". + * "allow_mkchar", "allow_truncate", "allow_symlink", "allow_rewrite", + * "allow_chmod", "allow_chown", "allow_chgrp", "allow_chroot", "allow_mount" + * and "allow_unmount". */ struct tomoyo_single_path_acl_record { struct tomoyo_acl_info head; /* type = TOMOYO_TYPE_SINGLE_PATH_ACL */ + u8 perm_high; u16 perm; /* Pointer to single pathname. */ const struct tomoyo_path_info *filename; @@ -195,7 +198,7 @@ struct tomoyo_single_path_acl_record { /* * tomoyo_double_path_acl_record is a structure which is used for holding an - * entry with two pathnames operation (i.e. link() and rename()). + * entry with two pathnames operation (i.e. link(), rename() and pivot_root()). * It has following fields. * * (1) "head" which is a "struct tomoyo_acl_info". @@ -203,7 +206,8 @@ struct tomoyo_single_path_acl_record { * (3) "filename1" is the source/old pathname. * (4) "filename2" is the destination/new pathname. * - * Directives held by this structure are "allow_rename" and "allow_link". + * Directives held by this structure are "allow_rename", "allow_link" and + * "allow_pivot_root". */ struct tomoyo_double_path_acl_record { struct tomoyo_acl_info head; /* type = TOMOYO_TYPE_DOUBLE_PATH_ACL */ diff --git a/security/tomoyo/file.c b/security/tomoyo/file.c index 5ae3a571559..2d10f98fc55 100644 --- a/security/tomoyo/file.c +++ b/security/tomoyo/file.c @@ -81,12 +81,20 @@ static const char *tomoyo_sp_keyword[TOMOYO_MAX_SINGLE_PATH_OPERATION] = { [TOMOYO_TYPE_TRUNCATE_ACL] = "truncate", [TOMOYO_TYPE_SYMLINK_ACL] = "symlink", [TOMOYO_TYPE_REWRITE_ACL] = "rewrite", + [TOMOYO_TYPE_IOCTL_ACL] = "ioctl", + [TOMOYO_TYPE_CHMOD_ACL] = "chmod", + [TOMOYO_TYPE_CHOWN_ACL] = "chown", + [TOMOYO_TYPE_CHGRP_ACL] = "chgrp", + [TOMOYO_TYPE_CHROOT_ACL] = "chroot", + [TOMOYO_TYPE_MOUNT_ACL] = "mount", + [TOMOYO_TYPE_UMOUNT_ACL] = "unmount", }; /* Keyword array for double path operations. */ static const char *tomoyo_dp_keyword[TOMOYO_MAX_DOUBLE_PATH_OPERATION] = { [TOMOYO_TYPE_LINK_ACL] = "link", [TOMOYO_TYPE_RENAME_ACL] = "rename", + [TOMOYO_TYPE_PIVOT_ROOT_ACL] = "pivot_root", }; /** @@ -655,7 +663,7 @@ static int tomoyo_check_single_path_acl2(const struct tomoyo_domain_info * domain, const struct tomoyo_path_info * filename, - const u16 perm, + const u32 perm, const bool may_use_pattern) { struct tomoyo_acl_info *ptr; @@ -668,8 +676,13 @@ static int tomoyo_check_single_path_acl2(const struct tomoyo_domain_info * continue; acl = container_of(ptr, struct tomoyo_single_path_acl_record, head); - if (!(acl->perm & perm)) - continue; + if (perm <= 0xFFFF) { + if (!(acl->perm & perm)) + continue; + } else { + if (!(acl->perm_high & (perm >> 16))) + continue; + } if (may_use_pattern || !acl->filename->is_patterned) { if (!tomoyo_path_matches_pattern(filename, acl->filename)) @@ -697,7 +710,7 @@ static int tomoyo_check_file_acl(const struct tomoyo_domain_info *domain, const struct tomoyo_path_info *filename, const u8 operation) { - u16 perm = 0; + u32 perm = 0; if (!tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE)) return 0; @@ -830,13 +843,13 @@ static int tomoyo_update_single_path_acl(const u8 type, const char *filename, struct tomoyo_domain_info * const domain, const bool is_delete) { - static const u16 rw_mask = + static const u32 rw_mask = (1 << TOMOYO_TYPE_READ_ACL) | (1 << TOMOYO_TYPE_WRITE_ACL); const struct tomoyo_path_info *saved_filename; struct tomoyo_acl_info *ptr; struct tomoyo_single_path_acl_record *acl; int error = -ENOMEM; - const u16 perm = 1 << type; + const u32 perm = 1 << type; if (!domain) return -EINVAL; @@ -858,7 +871,10 @@ static int tomoyo_update_single_path_acl(const u8 type, const char *filename, /* Special case. Clear all bits if marked as deleted. */ if (ptr->type & TOMOYO_ACL_DELETED) acl->perm = 0; - acl->perm |= perm; + if (perm <= 0xFFFF) + acl->perm |= perm; + else + acl->perm_high |= (perm >> 16); if ((acl->perm & rw_mask) == rw_mask) acl->perm |= 1 << TOMOYO_TYPE_READ_WRITE_ACL; else if (acl->perm & (1 << TOMOYO_TYPE_READ_WRITE_ACL)) @@ -871,7 +887,10 @@ static int tomoyo_update_single_path_acl(const u8 type, const char *filename, acl = tomoyo_alloc_acl_element(TOMOYO_TYPE_SINGLE_PATH_ACL); if (!acl) goto out; - acl->perm = perm; + if (perm <= 0xFFFF) + acl->perm = perm; + else + acl->perm_high = (perm >> 16); if (perm == (1 << TOMOYO_TYPE_READ_WRITE_ACL)) acl->perm |= rw_mask; acl->filename = saved_filename; @@ -887,12 +906,15 @@ static int tomoyo_update_single_path_acl(const u8 type, const char *filename, head); if (acl->filename != saved_filename) continue; - acl->perm &= ~perm; + if (perm <= 0xFFFF) + acl->perm &= ~perm; + else + acl->perm_high &= ~(perm >> 16); if ((acl->perm & rw_mask) != rw_mask) acl->perm &= ~(1 << TOMOYO_TYPE_READ_WRITE_ACL); else if (!(acl->perm & (1 << TOMOYO_TYPE_READ_WRITE_ACL))) acl->perm &= ~rw_mask; - if (!acl->perm) + if (!acl->perm && !acl->perm_high) ptr->type |= TOMOYO_ACL_DELETED; error = 0; break; @@ -1193,7 +1215,7 @@ int tomoyo_check_open_permission(struct tomoyo_domain_info *domain, } /** - * tomoyo_check_1path_perm - Check permission for "create", "unlink", "mkdir", "rmdir", "mkfifo", "mksock", "mkblock", "mkchar", "truncate" and "symlink". + * tomoyo_check_1path_perm - Check permission for "create", "unlink", "mkdir", "rmdir", "mkfifo", "mksock", "mkblock", "mkchar", "truncate", "symlink", "ioctl", "chmod", "chown", "chgrp", "chroot", "mount" and "unmount". * * @domain: Pointer to "struct tomoyo_domain_info". * @operation: Type of operation. @@ -1217,6 +1239,7 @@ int tomoyo_check_1path_perm(struct tomoyo_domain_info *domain, switch (operation) { case TOMOYO_TYPE_MKDIR_ACL: case TOMOYO_TYPE_RMDIR_ACL: + case TOMOYO_TYPE_CHROOT_ACL: if (!buf->is_dir) { /* * tomoyo_get_path() reserves space for appending "/." @@ -1270,7 +1293,7 @@ int tomoyo_check_rewrite_permission(struct tomoyo_domain_info *domain, } /** - * tomoyo_check_2path_perm - Check permission for "rename" and "link". + * tomoyo_check_2path_perm - Check permission for "rename", "link" and "pivot_root". * * @domain: Pointer to "struct tomoyo_domain_info". * @operation: Type of operation. diff --git a/security/tomoyo/tomoyo.c b/security/tomoyo/tomoyo.c index 9548a0984cc..3fb5f6ea4fc 100644 --- a/security/tomoyo/tomoyo.c +++ b/security/tomoyo/tomoyo.c @@ -271,6 +271,60 @@ static int tomoyo_dentry_open(struct file *f, const struct cred *cred) return tomoyo_check_open_permission(tomoyo_domain(), &f->f_path, flags); } +static int tomoyo_file_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) +{ + return tomoyo_check_1path_perm(tomoyo_domain(), TOMOYO_TYPE_IOCTL_ACL, + &file->f_path); +} + +static int tomoyo_path_chmod(struct dentry *dentry, struct vfsmount *mnt, + mode_t mode) +{ + struct path path = { mnt, dentry }; + return tomoyo_check_1path_perm(tomoyo_domain(), TOMOYO_TYPE_CHMOD_ACL, + &path); +} + +static int tomoyo_path_chown(struct path *path, uid_t uid, gid_t gid) +{ + int error = 0; + if (uid != (uid_t) -1) + error = tomoyo_check_1path_perm(tomoyo_domain(), + TOMOYO_TYPE_CHOWN_ACL, path); + if (!error && gid != (gid_t) -1) + error = tomoyo_check_1path_perm(tomoyo_domain(), + TOMOYO_TYPE_CHGRP_ACL, path); + return error; +} + +static int tomoyo_path_chroot(struct path *path) +{ + return tomoyo_check_1path_perm(tomoyo_domain(), TOMOYO_TYPE_CHROOT_ACL, + path); +} + +static int tomoyo_sb_mount(char *dev_name, struct path *path, + char *type, unsigned long flags, void *data) +{ + return tomoyo_check_1path_perm(tomoyo_domain(), TOMOYO_TYPE_MOUNT_ACL, + path); +} + +static int tomoyo_sb_umount(struct vfsmount *mnt, int flags) +{ + struct path path = { mnt, mnt->mnt_root }; + return tomoyo_check_1path_perm(tomoyo_domain(), TOMOYO_TYPE_UMOUNT_ACL, + &path); +} + +static int tomoyo_sb_pivotroot(struct path *old_path, struct path *new_path) +{ + return tomoyo_check_2path_perm(tomoyo_domain(), + TOMOYO_TYPE_PIVOT_ROOT_ACL, + new_path, old_path); +} + /* * tomoyo_security_ops is a "struct security_operations" which is used for * registering TOMOYO. @@ -295,6 +349,13 @@ static struct security_operations tomoyo_security_ops = { .path_mknod = tomoyo_path_mknod, .path_link = tomoyo_path_link, .path_rename = tomoyo_path_rename, + .file_ioctl = tomoyo_file_ioctl, + .path_chmod = tomoyo_path_chmod, + .path_chown = tomoyo_path_chown, + .path_chroot = tomoyo_path_chroot, + .sb_mount = tomoyo_sb_mount, + .sb_umount = tomoyo_sb_umount, + .sb_pivotroot = tomoyo_sb_pivotroot, }; static int __init tomoyo_init(void) diff --git a/security/tomoyo/tomoyo.h b/security/tomoyo/tomoyo.h index cd6ba0bf706..fac02655ea4 100644 --- a/security/tomoyo/tomoyo.h +++ b/security/tomoyo/tomoyo.h @@ -64,11 +64,19 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm); #define TOMOYO_TYPE_TRUNCATE_ACL 12 #define TOMOYO_TYPE_SYMLINK_ACL 13 #define TOMOYO_TYPE_REWRITE_ACL 14 -#define TOMOYO_MAX_SINGLE_PATH_OPERATION 15 +#define TOMOYO_TYPE_IOCTL_ACL 15 +#define TOMOYO_TYPE_CHMOD_ACL 16 +#define TOMOYO_TYPE_CHOWN_ACL 17 +#define TOMOYO_TYPE_CHGRP_ACL 18 +#define TOMOYO_TYPE_CHROOT_ACL 19 +#define TOMOYO_TYPE_MOUNT_ACL 20 +#define TOMOYO_TYPE_UMOUNT_ACL 21 +#define TOMOYO_MAX_SINGLE_PATH_OPERATION 22 #define TOMOYO_TYPE_LINK_ACL 0 #define TOMOYO_TYPE_RENAME_ACL 1 -#define TOMOYO_MAX_DOUBLE_PATH_OPERATION 2 +#define TOMOYO_TYPE_PIVOT_ROOT_ACL 2 +#define TOMOYO_MAX_DOUBLE_PATH_OPERATION 3 #define TOMOYO_DOMAINPOLICY 0 #define TOMOYO_EXCEPTIONPOLICY 1 From 08e3daff217059c84c360cc71212686e0a7995af Mon Sep 17 00:00:00 2001 From: Amerigo Wang Date: Thu, 3 Dec 2009 03:48:28 -0500 Subject: [PATCH 04/38] selinux: remove a useless return The last return is unreachable, remove the 'return' in default, let it fall through. Signed-off-by: WANG Cong Acked-by: Eric Paris Signed-off-by: James Morris --- security/selinux/ss/mls.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/security/selinux/ss/mls.c b/security/selinux/ss/mls.c index 3f2b2706b5b..e6654b543ae 100644 --- a/security/selinux/ss/mls.c +++ b/security/selinux/ss/mls.c @@ -541,8 +541,8 @@ int mls_compute_sid(struct context *scontext, case AVTAB_MEMBER: /* Use the process effective MLS attributes. */ return mls_context_cpy_low(newcontext, scontext); - default: - return -EINVAL; + + /* fall through */ } return -EINVAL; } From 67fa4880c5e059428392ca6f7c2f9c38e8546fea Mon Sep 17 00:00:00 2001 From: Tetsuo Handa Date: Wed, 9 Dec 2009 15:36:04 +0900 Subject: [PATCH 05/38] TOMOYO: Compare filesystem by magic number rather than by name. Please apply below one after merging 1557d33007f63dd96e5d15f33af389378e5f2e54 (Merge git://git.kernel.org/pub/scm/linux/kernel/git/ebiederm/sysctl-2.6). ---------- [PATCH for 2.6.33] TOMOYO: Compare filesystem by magic number rather than by name. We can use magic number for checking whether the filesystem is procfs or not. Signed-off-by: Tetsuo Handa Signed-off-by: James Morris --- security/tomoyo/realpath.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/security/tomoyo/realpath.c b/security/tomoyo/realpath.c index 18369d497eb..e3c7aa0fb70 100644 --- a/security/tomoyo/realpath.c +++ b/security/tomoyo/realpath.c @@ -14,6 +14,7 @@ #include #include #include +#include #include "common.h" #include "realpath.h" @@ -112,7 +113,7 @@ int tomoyo_realpath_from_path2(struct path *path, char *newname, path_put(&ns_root); /* Prepend "/proc" prefix if using internal proc vfs mount. */ if (!IS_ERR(sp) && (path->mnt->mnt_parent == path->mnt) && - (strcmp(path->mnt->mnt_sb->s_type->name, "proc") == 0)) { + (path->mnt->mnt_sb->s_magic == PROC_SUPER_MAGIC)) { sp -= 5; if (sp >= newname) memcpy(sp, "/proc", 5); From 86fc80f16e8a2449d5827bf1a9838b7fd9f70097 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Wed, 9 Dec 2009 17:13:31 +0100 Subject: [PATCH 06/38] capabilities: Use RCU to protect task lookup in sys_capget cap_get_target_pid() protects the task lookup with tasklist_lock. security_capget() is called under tasklist_lock as well but tasklist_lock does not protect anything there. The capabilities are protected by RCU already. So tasklist_lock only protects the lookup and prevents the task going away, which can be done with rcu_read_lock() as well. Signed-off-by: Thomas Gleixner Signed-off-by: James Morris --- kernel/capability.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kernel/capability.c b/kernel/capability.c index 7f876e60521..9e4697e9b27 100644 --- a/kernel/capability.c +++ b/kernel/capability.c @@ -135,7 +135,7 @@ static inline int cap_get_target_pid(pid_t pid, kernel_cap_t *pEp, if (pid && (pid != task_pid_vnr(current))) { struct task_struct *target; - read_lock(&tasklist_lock); + rcu_read_lock(); target = find_task_by_vpid(pid); if (!target) @@ -143,7 +143,7 @@ static inline int cap_get_target_pid(pid_t pid, kernel_cap_t *pEp, else ret = security_capget(target, pEp, pIp, pPp); - read_unlock(&tasklist_lock); + rcu_read_unlock(); } else ret = security_capget(current, pEp, pIp, pPp); From fdb8ebb729bbb640e64028a4f579a02ebc405727 Mon Sep 17 00:00:00 2001 From: Tetsuo Handa Date: Tue, 8 Dec 2009 09:34:43 +0900 Subject: [PATCH 07/38] TOMOYO: Use RCU primitives for list operation Replace list operation with RCU primitives and replace down_read()/up_read() with srcu_read_lock()/srcu_read_unlock(). Signed-off-by: Tetsuo Handa Acked-by: Serge Hallyn Signed-off-by: James Morris --- security/tomoyo/common.c | 90 ++++++++++++++++-------------- security/tomoyo/common.h | 28 +++++++--- security/tomoyo/domain.c | 63 ++++++++++++--------- security/tomoyo/file.c | 110 ++++++++++++++++++++++++++----------- security/tomoyo/realpath.c | 8 ++- security/tomoyo/tomoyo.c | 20 ++++++- 6 files changed, 207 insertions(+), 112 deletions(-) diff --git a/security/tomoyo/common.c b/security/tomoyo/common.c index 6c606168243..f01b9364db2 100644 --- a/security/tomoyo/common.c +++ b/security/tomoyo/common.c @@ -365,10 +365,9 @@ bool tomoyo_is_domain_def(const unsigned char *buffer) * * @domainname: The domainname to find. * - * Caller must call down_read(&tomoyo_domain_list_lock); or - * down_write(&tomoyo_domain_list_lock); . - * * Returns pointer to "struct tomoyo_domain_info" if found, NULL otherwise. + * + * Caller holds tomoyo_read_lock(). */ struct tomoyo_domain_info *tomoyo_find_domain(const char *domainname) { @@ -377,7 +376,7 @@ struct tomoyo_domain_info *tomoyo_find_domain(const char *domainname) name.name = domainname; tomoyo_fill_path_info(&name); - list_for_each_entry(domain, &tomoyo_domain_list, list) { + list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) { if (!domain->is_deleted && !tomoyo_pathcmp(&name, domain->domainname)) return domain; @@ -829,6 +828,8 @@ bool tomoyo_verbose_mode(const struct tomoyo_domain_info *domain) * @domain: Pointer to "struct tomoyo_domain_info". * * Returns true if the domain is not exceeded quota, false otherwise. + * + * Caller holds tomoyo_read_lock(). */ bool tomoyo_domain_quota_is_ok(struct tomoyo_domain_info * const domain) { @@ -837,8 +838,7 @@ bool tomoyo_domain_quota_is_ok(struct tomoyo_domain_info * const domain) if (!domain) return true; - down_read(&tomoyo_domain_acl_info_list_lock); - list_for_each_entry(ptr, &domain->acl_info_list, list) { + list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { if (ptr->type & TOMOYO_ACL_DELETED) continue; switch (tomoyo_acl_type2(ptr)) { @@ -866,7 +866,6 @@ bool tomoyo_domain_quota_is_ok(struct tomoyo_domain_info * const domain) break; } } - up_read(&tomoyo_domain_acl_info_list_lock); if (count < tomoyo_check_flags(domain, TOMOYO_MAX_ACCEPT_ENTRY)) return true; if (!domain->quota_warned) { @@ -1096,6 +1095,8 @@ static DECLARE_RWSEM(tomoyo_policy_manager_list_lock); * @is_delete: True if it is a delete request. * * Returns 0 on success, negative value otherwise. + * + * Caller holds tomoyo_read_lock(). */ static int tomoyo_update_manager_entry(const char *manager, const bool is_delete) @@ -1118,7 +1119,7 @@ static int tomoyo_update_manager_entry(const char *manager, if (!saved_manager) return -ENOMEM; down_write(&tomoyo_policy_manager_list_lock); - list_for_each_entry(ptr, &tomoyo_policy_manager_list, list) { + list_for_each_entry_rcu(ptr, &tomoyo_policy_manager_list, list) { if (ptr->manager != saved_manager) continue; ptr->is_deleted = is_delete; @@ -1134,7 +1135,7 @@ static int tomoyo_update_manager_entry(const char *manager, goto out; new_entry->manager = saved_manager; new_entry->is_domain = is_domain; - list_add_tail(&new_entry->list, &tomoyo_policy_manager_list); + list_add_tail_rcu(&new_entry->list, &tomoyo_policy_manager_list); error = 0; out: up_write(&tomoyo_policy_manager_list_lock); @@ -1147,6 +1148,8 @@ static int tomoyo_update_manager_entry(const char *manager, * @head: Pointer to "struct tomoyo_io_buffer". * * Returns 0 on success, negative value otherwise. + * + * Caller holds tomoyo_read_lock(). */ static int tomoyo_write_manager_policy(struct tomoyo_io_buffer *head) { @@ -1166,6 +1169,8 @@ static int tomoyo_write_manager_policy(struct tomoyo_io_buffer *head) * @head: Pointer to "struct tomoyo_io_buffer". * * Returns 0. + * + * Caller holds tomoyo_read_lock(). */ static int tomoyo_read_manager_policy(struct tomoyo_io_buffer *head) { @@ -1174,7 +1179,6 @@ static int tomoyo_read_manager_policy(struct tomoyo_io_buffer *head) if (head->read_eof) return 0; - down_read(&tomoyo_policy_manager_list_lock); list_for_each_cookie(pos, head->read_var2, &tomoyo_policy_manager_list) { struct tomoyo_policy_manager_entry *ptr; @@ -1186,7 +1190,6 @@ static int tomoyo_read_manager_policy(struct tomoyo_io_buffer *head) if (!done) break; } - up_read(&tomoyo_policy_manager_list_lock); head->read_eof = done; return 0; } @@ -1196,6 +1199,8 @@ static int tomoyo_read_manager_policy(struct tomoyo_io_buffer *head) * * Returns true if the current process is permitted to modify policy * via /sys/kernel/security/tomoyo/ interface. + * + * Caller holds tomoyo_read_lock(). */ static bool tomoyo_is_policy_manager(void) { @@ -1209,29 +1214,25 @@ static bool tomoyo_is_policy_manager(void) return true; if (!tomoyo_manage_by_non_root && (task->cred->uid || task->cred->euid)) return false; - down_read(&tomoyo_policy_manager_list_lock); - list_for_each_entry(ptr, &tomoyo_policy_manager_list, list) { + list_for_each_entry_rcu(ptr, &tomoyo_policy_manager_list, list) { if (!ptr->is_deleted && ptr->is_domain && !tomoyo_pathcmp(domainname, ptr->manager)) { found = true; break; } } - up_read(&tomoyo_policy_manager_list_lock); if (found) return true; exe = tomoyo_get_exe(); if (!exe) return false; - down_read(&tomoyo_policy_manager_list_lock); - list_for_each_entry(ptr, &tomoyo_policy_manager_list, list) { + list_for_each_entry_rcu(ptr, &tomoyo_policy_manager_list, list) { if (!ptr->is_deleted && !ptr->is_domain && !strcmp(exe, ptr->manager->name)) { found = true; break; } } - up_read(&tomoyo_policy_manager_list_lock); if (!found) { /* Reduce error messages. */ static pid_t last_pid; const pid_t pid = current->pid; @@ -1252,6 +1253,8 @@ static bool tomoyo_is_policy_manager(void) * @data: String to parse. * * Returns true on success, false otherwise. + * + * Caller holds tomoyo_read_lock(). */ static bool tomoyo_is_select_one(struct tomoyo_io_buffer *head, const char *data) @@ -1267,11 +1270,8 @@ static bool tomoyo_is_select_one(struct tomoyo_io_buffer *head, domain = tomoyo_real_domain(p); read_unlock(&tasklist_lock); } else if (!strncmp(data, "domain=", 7)) { - if (tomoyo_is_domain_def(data + 7)) { - down_read(&tomoyo_domain_list_lock); + if (tomoyo_is_domain_def(data + 7)) domain = tomoyo_find_domain(data + 7); - up_read(&tomoyo_domain_list_lock); - } } else return false; head->write_var1 = domain; @@ -1285,13 +1285,11 @@ static bool tomoyo_is_select_one(struct tomoyo_io_buffer *head, if (domain) { struct tomoyo_domain_info *d; head->read_var1 = NULL; - down_read(&tomoyo_domain_list_lock); - list_for_each_entry(d, &tomoyo_domain_list, list) { + list_for_each_entry_rcu(d, &tomoyo_domain_list, list) { if (d == domain) break; head->read_var1 = &d->list; } - up_read(&tomoyo_domain_list_lock); head->read_var2 = NULL; head->read_bit = 0; head->read_step = 0; @@ -1307,6 +1305,8 @@ static bool tomoyo_is_select_one(struct tomoyo_io_buffer *head, * @domainname: The name of domain. * * Returns 0. + * + * Caller holds tomoyo_read_lock(). */ static int tomoyo_delete_domain(char *domainname) { @@ -1317,7 +1317,7 @@ static int tomoyo_delete_domain(char *domainname) tomoyo_fill_path_info(&name); down_write(&tomoyo_domain_list_lock); /* Is there an active domain? */ - list_for_each_entry(domain, &tomoyo_domain_list, list) { + list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) { /* Never delete tomoyo_kernel_domain */ if (domain == &tomoyo_kernel_domain) continue; @@ -1337,6 +1337,8 @@ static int tomoyo_delete_domain(char *domainname) * @head: Pointer to "struct tomoyo_io_buffer". * * Returns 0 on success, negative value otherwise. + * + * Caller holds tomoyo_read_lock(). */ static int tomoyo_write_domain_policy(struct tomoyo_io_buffer *head) { @@ -1359,11 +1361,9 @@ static int tomoyo_write_domain_policy(struct tomoyo_io_buffer *head) domain = NULL; if (is_delete) tomoyo_delete_domain(data); - else if (is_select) { - down_read(&tomoyo_domain_list_lock); + else if (is_select) domain = tomoyo_find_domain(data); - up_read(&tomoyo_domain_list_lock); - } else + else domain = tomoyo_find_or_assign_new_domain(data, 0); head->write_var1 = domain; return 0; @@ -1508,6 +1508,8 @@ static bool tomoyo_print_entry(struct tomoyo_io_buffer *head, * @head: Pointer to "struct tomoyo_io_buffer". * * Returns 0. + * + * Caller holds tomoyo_read_lock(). */ static int tomoyo_read_domain_policy(struct tomoyo_io_buffer *head) { @@ -1519,7 +1521,6 @@ static int tomoyo_read_domain_policy(struct tomoyo_io_buffer *head) return 0; if (head->read_step == 0) head->read_step = 1; - down_read(&tomoyo_domain_list_lock); list_for_each_cookie(dpos, head->read_var1, &tomoyo_domain_list) { struct tomoyo_domain_info *domain; const char *quota_exceeded = ""; @@ -1552,7 +1553,6 @@ acl_loop: if (head->read_step == 3) goto tail_mark; /* Print ACL entries in the domain. */ - down_read(&tomoyo_domain_acl_info_list_lock); list_for_each_cookie(apos, head->read_var2, &domain->acl_info_list) { struct tomoyo_acl_info *ptr @@ -1562,7 +1562,6 @@ acl_loop: if (!done) break; } - up_read(&tomoyo_domain_acl_info_list_lock); if (!done) break; head->read_step = 3; @@ -1574,7 +1573,6 @@ tail_mark: if (head->read_single_domain) break; } - up_read(&tomoyo_domain_list_lock); head->read_eof = done; return 0; } @@ -1590,6 +1588,8 @@ tail_mark: * * ( echo "select " $domainname; echo "use_profile " $profile ) | * /usr/lib/ccs/loadpolicy -d + * + * Caller holds tomoyo_read_lock(). */ static int tomoyo_write_domain_profile(struct tomoyo_io_buffer *head) { @@ -1601,9 +1601,7 @@ static int tomoyo_write_domain_profile(struct tomoyo_io_buffer *head) if (!cp) return -EINVAL; *cp = '\0'; - down_read(&tomoyo_domain_list_lock); domain = tomoyo_find_domain(cp + 1); - up_read(&tomoyo_domain_list_lock); if (strict_strtoul(data, 10, &profile)) return -EINVAL; if (domain && profile < TOMOYO_MAX_PROFILES @@ -1625,6 +1623,8 @@ static int tomoyo_write_domain_profile(struct tomoyo_io_buffer *head) * awk ' { if ( domainname == "" ) { if ( $1 == "" ) * domainname = $0; } else if ( $1 == "use_profile" ) { * print $2 " " domainname; domainname = ""; } } ; ' + * + * Caller holds tomoyo_read_lock(). */ static int tomoyo_read_domain_profile(struct tomoyo_io_buffer *head) { @@ -1633,7 +1633,6 @@ static int tomoyo_read_domain_profile(struct tomoyo_io_buffer *head) if (head->read_eof) return 0; - down_read(&tomoyo_domain_list_lock); list_for_each_cookie(pos, head->read_var1, &tomoyo_domain_list) { struct tomoyo_domain_info *domain; domain = list_entry(pos, struct tomoyo_domain_info, list); @@ -1644,7 +1643,6 @@ static int tomoyo_read_domain_profile(struct tomoyo_io_buffer *head) if (!done) break; } - up_read(&tomoyo_domain_list_lock); head->read_eof = done; return 0; } @@ -1701,6 +1699,8 @@ static int tomoyo_read_pid(struct tomoyo_io_buffer *head) * @head: Pointer to "struct tomoyo_io_buffer". * * Returns 0 on success, negative value otherwise. + * + * Caller holds tomoyo_read_lock(). */ static int tomoyo_write_exception_policy(struct tomoyo_io_buffer *head) { @@ -1735,6 +1735,8 @@ static int tomoyo_write_exception_policy(struct tomoyo_io_buffer *head) * @head: Pointer to "struct tomoyo_io_buffer". * * Returns 0 on success, -EINVAL otherwise. + * + * Caller holds tomoyo_read_lock(). */ static int tomoyo_read_exception_policy(struct tomoyo_io_buffer *head) { @@ -1864,15 +1866,13 @@ void tomoyo_load_policy(const char *filename) tomoyo_policy_loaded = true; { /* Check all profiles currently assigned to domains are defined. */ struct tomoyo_domain_info *domain; - down_read(&tomoyo_domain_list_lock); - list_for_each_entry(domain, &tomoyo_domain_list, list) { + list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) { const u8 profile = domain->profile; if (tomoyo_profile_ptr[profile]) continue; panic("Profile %u (used by '%s') not defined.\n", profile, domain->domainname->name); } - up_read(&tomoyo_domain_list_lock); } } @@ -1920,6 +1920,8 @@ static int tomoyo_read_self_domain(struct tomoyo_io_buffer *head) * @file: Pointer to "struct file". * * Associates policy handler and returns 0 on success, -ENOMEM otherwise. + * + * Caller acquires tomoyo_read_lock(). */ static int tomoyo_open_control(const u8 type, struct file *file) { @@ -2005,6 +2007,7 @@ static int tomoyo_open_control(const u8 type, struct file *file) return -ENOMEM; } } + head->reader_idx = tomoyo_read_lock(); file->private_data = head; /* * Call the handler now if the file is @@ -2026,6 +2029,8 @@ static int tomoyo_open_control(const u8 type, struct file *file) * @buffer_len: Size of @buffer. * * Returns bytes read on success, negative value otherwise. + * + * Caller holds tomoyo_read_lock(). */ static int tomoyo_read_control(struct file *file, char __user *buffer, const int buffer_len) @@ -2069,6 +2074,8 @@ static int tomoyo_read_control(struct file *file, char __user *buffer, * @buffer_len: Size of @buffer. * * Returns @buffer_len on success, negative value otherwise. + * + * Caller holds tomoyo_read_lock(). */ static int tomoyo_write_control(struct file *file, const char __user *buffer, const int buffer_len) @@ -2119,11 +2126,14 @@ static int tomoyo_write_control(struct file *file, const char __user *buffer, * @file: Pointer to "struct file". * * Releases memory and returns 0. + * + * Caller looses tomoyo_read_lock(). */ static int tomoyo_close_control(struct file *file) { struct tomoyo_io_buffer *head = file->private_data; + tomoyo_read_unlock(head->reader_idx); /* Release memory used for policy I/O. */ tomoyo_free(head->read_buf); head->read_buf = NULL; diff --git a/security/tomoyo/common.h b/security/tomoyo/common.h index bd10f9fa351..c6f13925472 100644 --- a/security/tomoyo/common.h +++ b/security/tomoyo/common.h @@ -269,6 +269,8 @@ struct tomoyo_io_buffer { int (*write) (struct tomoyo_io_buffer *); /* Exclusive lock for this structure. */ struct mutex io_sem; + /* Index returned by tomoyo_read_lock(). */ + int reader_idx; /* The position currently reading from. */ struct list_head *read_var1; /* Extra variables for reading. */ @@ -446,16 +448,28 @@ extern struct tomoyo_domain_info tomoyo_kernel_domain; * @cookie: the &struct list_head to use as a cookie. * @head: the head for your list. * - * Same with list_for_each() except that this primitive uses @cookie + * Same with list_for_each_rcu() except that this primitive uses @cookie * so that we can continue iteration. * @cookie must be NULL when iteration starts, and @cookie will become * NULL when iteration finishes. */ -#define list_for_each_cookie(pos, cookie, head) \ - for (({ if (!cookie) \ - cookie = head; }), \ - pos = (cookie)->next; \ - prefetch(pos->next), pos != (head) || ((cookie) = NULL); \ - (cookie) = pos, pos = pos->next) +#define list_for_each_cookie(pos, cookie, head) \ + for (({ if (!cookie) \ + cookie = head; }), \ + pos = rcu_dereference((cookie)->next); \ + prefetch(pos->next), pos != (head) || ((cookie) = NULL); \ + (cookie) = pos, pos = rcu_dereference(pos->next)) + +extern struct srcu_struct tomoyo_ss; + +static inline int tomoyo_read_lock(void) +{ + return srcu_read_lock(&tomoyo_ss); +} + +static inline void tomoyo_read_unlock(int idx) +{ + srcu_read_unlock(&tomoyo_ss, idx); +} #endif /* !defined(_SECURITY_TOMOYO_COMMON_H) */ diff --git a/security/tomoyo/domain.c b/security/tomoyo/domain.c index fcf52accce2..2fd190168b7 100644 --- a/security/tomoyo/domain.c +++ b/security/tomoyo/domain.c @@ -217,6 +217,8 @@ static DECLARE_RWSEM(tomoyo_domain_initializer_list_lock); * @is_delete: True if it is a delete request. * * Returns 0 on success, negative value otherwise. + * + * Caller holds tomoyo_read_lock(). */ static int tomoyo_update_domain_initializer_entry(const char *domainname, const char *program, @@ -246,7 +248,7 @@ static int tomoyo_update_domain_initializer_entry(const char *domainname, if (!saved_program) return -ENOMEM; down_write(&tomoyo_domain_initializer_list_lock); - list_for_each_entry(ptr, &tomoyo_domain_initializer_list, list) { + list_for_each_entry_rcu(ptr, &tomoyo_domain_initializer_list, list) { if (ptr->is_not != is_not || ptr->domainname != saved_domainname || ptr->program != saved_program) @@ -266,7 +268,7 @@ static int tomoyo_update_domain_initializer_entry(const char *domainname, new_entry->program = saved_program; new_entry->is_not = is_not; new_entry->is_last_name = is_last_name; - list_add_tail(&new_entry->list, &tomoyo_domain_initializer_list); + list_add_tail_rcu(&new_entry->list, &tomoyo_domain_initializer_list); error = 0; out: up_write(&tomoyo_domain_initializer_list_lock); @@ -279,13 +281,14 @@ static int tomoyo_update_domain_initializer_entry(const char *domainname, * @head: Pointer to "struct tomoyo_io_buffer". * * Returns true on success, false otherwise. + * + * Caller holds tomoyo_read_lock(). */ bool tomoyo_read_domain_initializer_policy(struct tomoyo_io_buffer *head) { struct list_head *pos; bool done = true; - down_read(&tomoyo_domain_initializer_list_lock); list_for_each_cookie(pos, head->read_var2, &tomoyo_domain_initializer_list) { const char *no; @@ -308,7 +311,6 @@ bool tomoyo_read_domain_initializer_policy(struct tomoyo_io_buffer *head) if (!done) break; } - up_read(&tomoyo_domain_initializer_list_lock); return done; } @@ -320,6 +322,8 @@ bool tomoyo_read_domain_initializer_policy(struct tomoyo_io_buffer *head) * @is_delete: True if it is a delete request. * * Returns 0 on success, negative value otherwise. + * + * Caller holds tomoyo_read_lock(). */ int tomoyo_write_domain_initializer_policy(char *data, const bool is_not, const bool is_delete) @@ -345,6 +349,8 @@ int tomoyo_write_domain_initializer_policy(char *data, const bool is_not, * * Returns true if executing @program reinitializes domain transition, * false otherwise. + * + * Caller holds tomoyo_read_lock(). */ static bool tomoyo_is_domain_initializer(const struct tomoyo_path_info * domainname, @@ -355,8 +361,7 @@ static bool tomoyo_is_domain_initializer(const struct tomoyo_path_info * struct tomoyo_domain_initializer_entry *ptr; bool flag = false; - down_read(&tomoyo_domain_initializer_list_lock); - list_for_each_entry(ptr, &tomoyo_domain_initializer_list, list) { + list_for_each_entry_rcu(ptr, &tomoyo_domain_initializer_list, list) { if (ptr->is_deleted) continue; if (ptr->domainname) { @@ -376,7 +381,6 @@ static bool tomoyo_is_domain_initializer(const struct tomoyo_path_info * } flag = true; } - up_read(&tomoyo_domain_initializer_list_lock); return flag; } @@ -430,6 +434,8 @@ static DECLARE_RWSEM(tomoyo_domain_keeper_list_lock); * @is_delete: True if it is a delete request. * * Returns 0 on success, negative value otherwise. + * + * Caller holds tomoyo_read_lock(). */ static int tomoyo_update_domain_keeper_entry(const char *domainname, const char *program, @@ -459,7 +465,7 @@ static int tomoyo_update_domain_keeper_entry(const char *domainname, if (!saved_domainname) return -ENOMEM; down_write(&tomoyo_domain_keeper_list_lock); - list_for_each_entry(ptr, &tomoyo_domain_keeper_list, list) { + list_for_each_entry_rcu(ptr, &tomoyo_domain_keeper_list, list) { if (ptr->is_not != is_not || ptr->domainname != saved_domainname || ptr->program != saved_program) @@ -479,7 +485,7 @@ static int tomoyo_update_domain_keeper_entry(const char *domainname, new_entry->program = saved_program; new_entry->is_not = is_not; new_entry->is_last_name = is_last_name; - list_add_tail(&new_entry->list, &tomoyo_domain_keeper_list); + list_add_tail_rcu(&new_entry->list, &tomoyo_domain_keeper_list); error = 0; out: up_write(&tomoyo_domain_keeper_list_lock); @@ -493,6 +499,7 @@ static int tomoyo_update_domain_keeper_entry(const char *domainname, * @is_not: True if it is "no_keep_domain" entry. * @is_delete: True if it is a delete request. * + * Caller holds tomoyo_read_lock(). */ int tomoyo_write_domain_keeper_policy(char *data, const bool is_not, const bool is_delete) @@ -513,13 +520,14 @@ int tomoyo_write_domain_keeper_policy(char *data, const bool is_not, * @head: Pointer to "struct tomoyo_io_buffer". * * Returns true on success, false otherwise. + * + * Caller holds tomoyo_read_lock(). */ bool tomoyo_read_domain_keeper_policy(struct tomoyo_io_buffer *head) { struct list_head *pos; bool done = true; - down_read(&tomoyo_domain_keeper_list_lock); list_for_each_cookie(pos, head->read_var2, &tomoyo_domain_keeper_list) { struct tomoyo_domain_keeper_entry *ptr; @@ -542,7 +550,6 @@ bool tomoyo_read_domain_keeper_policy(struct tomoyo_io_buffer *head) if (!done) break; } - up_read(&tomoyo_domain_keeper_list_lock); return done; } @@ -555,6 +562,8 @@ bool tomoyo_read_domain_keeper_policy(struct tomoyo_io_buffer *head) * * Returns true if executing @program supresses domain transition, * false otherwise. + * + * Caller holds tomoyo_read_lock(). */ static bool tomoyo_is_domain_keeper(const struct tomoyo_path_info *domainname, const struct tomoyo_path_info *program, @@ -563,8 +572,7 @@ static bool tomoyo_is_domain_keeper(const struct tomoyo_path_info *domainname, struct tomoyo_domain_keeper_entry *ptr; bool flag = false; - down_read(&tomoyo_domain_keeper_list_lock); - list_for_each_entry(ptr, &tomoyo_domain_keeper_list, list) { + list_for_each_entry_rcu(ptr, &tomoyo_domain_keeper_list, list) { if (ptr->is_deleted) continue; if (!ptr->is_last_name) { @@ -582,7 +590,6 @@ static bool tomoyo_is_domain_keeper(const struct tomoyo_path_info *domainname, } flag = true; } - up_read(&tomoyo_domain_keeper_list_lock); return flag; } @@ -627,6 +634,8 @@ static DECLARE_RWSEM(tomoyo_alias_list_lock); * @is_delete: True if it is a delete request. * * Returns 0 on success, negative value otherwise. + * + * Caller holds tomoyo_read_lock(). */ static int tomoyo_update_alias_entry(const char *original_name, const char *aliased_name, @@ -646,7 +655,7 @@ static int tomoyo_update_alias_entry(const char *original_name, if (!saved_original_name || !saved_aliased_name) return -ENOMEM; down_write(&tomoyo_alias_list_lock); - list_for_each_entry(ptr, &tomoyo_alias_list, list) { + list_for_each_entry_rcu(ptr, &tomoyo_alias_list, list) { if (ptr->original_name != saved_original_name || ptr->aliased_name != saved_aliased_name) continue; @@ -663,7 +672,7 @@ static int tomoyo_update_alias_entry(const char *original_name, goto out; new_entry->original_name = saved_original_name; new_entry->aliased_name = saved_aliased_name; - list_add_tail(&new_entry->list, &tomoyo_alias_list); + list_add_tail_rcu(&new_entry->list, &tomoyo_alias_list); error = 0; out: up_write(&tomoyo_alias_list_lock); @@ -676,13 +685,14 @@ static int tomoyo_update_alias_entry(const char *original_name, * @head: Pointer to "struct tomoyo_io_buffer". * * Returns true on success, false otherwise. + * + * Caller holds tomoyo_read_lock(). */ bool tomoyo_read_alias_policy(struct tomoyo_io_buffer *head) { struct list_head *pos; bool done = true; - down_read(&tomoyo_alias_list_lock); list_for_each_cookie(pos, head->read_var2, &tomoyo_alias_list) { struct tomoyo_alias_entry *ptr; @@ -695,7 +705,6 @@ bool tomoyo_read_alias_policy(struct tomoyo_io_buffer *head) if (!done) break; } - up_read(&tomoyo_alias_list_lock); return done; } @@ -706,6 +715,8 @@ bool tomoyo_read_alias_policy(struct tomoyo_io_buffer *head) * @is_delete: True if it is a delete request. * * Returns 0 on success, negative value otherwise. + * + * Caller holds tomoyo_read_lock(). */ int tomoyo_write_alias_policy(char *data, const bool is_delete) { @@ -724,6 +735,8 @@ int tomoyo_write_alias_policy(char *data, const bool is_delete) * @profile: Profile number to assign if the domain was newly created. * * Returns pointer to "struct tomoyo_domain_info" on success, NULL otherwise. + * + * Caller holds tomoyo_read_lock(). */ struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char * domainname, @@ -742,7 +755,7 @@ struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char * if (!saved_domainname) goto out; /* Can I reuse memory of deleted domain? */ - list_for_each_entry(domain, &tomoyo_domain_list, list) { + list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) { struct task_struct *p; struct tomoyo_acl_info *ptr; bool flag; @@ -760,7 +773,7 @@ struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char * read_unlock(&tasklist_lock); if (flag) continue; - list_for_each_entry(ptr, &domain->acl_info_list, list) { + list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { ptr->type |= TOMOYO_ACL_DELETED; } tomoyo_set_domain_flag(domain, true, domain->flags); @@ -776,7 +789,7 @@ struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char * INIT_LIST_HEAD(&domain->acl_info_list); domain->domainname = saved_domainname; domain->profile = profile; - list_add_tail(&domain->list, &tomoyo_domain_list); + list_add_tail_rcu(&domain->list, &tomoyo_domain_list); } out: up_write(&tomoyo_domain_list_lock); @@ -789,6 +802,8 @@ struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char * * @bprm: Pointer to "struct linux_binprm". * * Returns 0 on success, negative value otherwise. + * + * Caller holds tomoyo_read_lock(). */ int tomoyo_find_next_domain(struct linux_binprm *bprm) { @@ -849,8 +864,7 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm) if (tomoyo_pathcmp(&r, &s)) { struct tomoyo_alias_entry *ptr; /* Is this program allowed to be called via symbolic links? */ - down_read(&tomoyo_alias_list_lock); - list_for_each_entry(ptr, &tomoyo_alias_list, list) { + list_for_each_entry_rcu(ptr, &tomoyo_alias_list, list) { if (ptr->is_deleted || tomoyo_pathcmp(&r, ptr->original_name) || tomoyo_pathcmp(&s, ptr->aliased_name)) @@ -861,7 +875,6 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm) tomoyo_fill_path_info(&r); break; } - up_read(&tomoyo_alias_list_lock); } /* Check execute permission. */ @@ -892,9 +905,7 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm) } if (domain || strlen(new_domain_name) >= TOMOYO_MAX_PATHNAME_LEN) goto done; - down_read(&tomoyo_domain_list_lock); domain = tomoyo_find_domain(new_domain_name); - up_read(&tomoyo_domain_list_lock); if (domain) goto done; if (is_enforce) diff --git a/security/tomoyo/file.c b/security/tomoyo/file.c index 482f0e7ed99..3c472867634 100644 --- a/security/tomoyo/file.c +++ b/security/tomoyo/file.c @@ -213,6 +213,8 @@ static DECLARE_RWSEM(tomoyo_globally_readable_list_lock); * @is_delete: True if it is a delete request. * * Returns 0 on success, negative value otherwise. + * + * Caller holds tomoyo_read_lock(). */ static int tomoyo_update_globally_readable_entry(const char *filename, const bool is_delete) @@ -228,7 +230,7 @@ static int tomoyo_update_globally_readable_entry(const char *filename, if (!saved_filename) return -ENOMEM; down_write(&tomoyo_globally_readable_list_lock); - list_for_each_entry(ptr, &tomoyo_globally_readable_list, list) { + list_for_each_entry_rcu(ptr, &tomoyo_globally_readable_list, list) { if (ptr->filename != saved_filename) continue; ptr->is_deleted = is_delete; @@ -243,7 +245,7 @@ static int tomoyo_update_globally_readable_entry(const char *filename, if (!new_entry) goto out; new_entry->filename = saved_filename; - list_add_tail(&new_entry->list, &tomoyo_globally_readable_list); + list_add_tail_rcu(&new_entry->list, &tomoyo_globally_readable_list); error = 0; out: up_write(&tomoyo_globally_readable_list_lock); @@ -256,21 +258,22 @@ static int tomoyo_update_globally_readable_entry(const char *filename, * @filename: The filename to check. * * Returns true if any domain can open @filename for reading, false otherwise. + * + * Caller holds tomoyo_read_lock(). */ static bool tomoyo_is_globally_readable_file(const struct tomoyo_path_info * filename) { struct tomoyo_globally_readable_file_entry *ptr; bool found = false; - down_read(&tomoyo_globally_readable_list_lock); - list_for_each_entry(ptr, &tomoyo_globally_readable_list, list) { + + list_for_each_entry_rcu(ptr, &tomoyo_globally_readable_list, list) { if (!ptr->is_deleted && tomoyo_path_matches_pattern(filename, ptr->filename)) { found = true; break; } } - up_read(&tomoyo_globally_readable_list_lock); return found; } @@ -281,6 +284,8 @@ static bool tomoyo_is_globally_readable_file(const struct tomoyo_path_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_globally_readable_policy(char *data, const bool is_delete) { @@ -293,13 +298,14 @@ int tomoyo_write_globally_readable_policy(char *data, const bool is_delete) * @head: Pointer to "struct tomoyo_io_buffer". * * Returns true on success, false otherwise. + * + * Caller holds tomoyo_read_lock(). */ bool tomoyo_read_globally_readable_policy(struct tomoyo_io_buffer *head) { struct list_head *pos; bool done = true; - down_read(&tomoyo_globally_readable_list_lock); list_for_each_cookie(pos, head->read_var2, &tomoyo_globally_readable_list) { struct tomoyo_globally_readable_file_entry *ptr; @@ -313,7 +319,6 @@ bool tomoyo_read_globally_readable_policy(struct tomoyo_io_buffer *head) if (!done) break; } - up_read(&tomoyo_globally_readable_list_lock); return done; } @@ -356,6 +361,8 @@ static DECLARE_RWSEM(tomoyo_pattern_list_lock); * @is_delete: True if it is a delete request. * * Returns 0 on success, negative value otherwise. + * + * Caller holds tomoyo_read_lock(). */ static int tomoyo_update_file_pattern_entry(const char *pattern, const bool is_delete) @@ -371,7 +378,7 @@ static int tomoyo_update_file_pattern_entry(const char *pattern, if (!saved_pattern) return -ENOMEM; down_write(&tomoyo_pattern_list_lock); - list_for_each_entry(ptr, &tomoyo_pattern_list, list) { + list_for_each_entry_rcu(ptr, &tomoyo_pattern_list, list) { if (saved_pattern != ptr->pattern) continue; ptr->is_deleted = is_delete; @@ -386,7 +393,7 @@ static int tomoyo_update_file_pattern_entry(const char *pattern, if (!new_entry) goto out; new_entry->pattern = saved_pattern; - list_add_tail(&new_entry->list, &tomoyo_pattern_list); + list_add_tail_rcu(&new_entry->list, &tomoyo_pattern_list); error = 0; out: up_write(&tomoyo_pattern_list_lock); @@ -399,6 +406,8 @@ static int tomoyo_update_file_pattern_entry(const char *pattern, * @filename: The filename to find patterned pathname. * * Returns pointer to pathname pattern if matched, @filename otherwise. + * + * Caller holds tomoyo_read_lock(). */ static const struct tomoyo_path_info * tomoyo_get_file_pattern(const struct tomoyo_path_info *filename) @@ -406,8 +415,7 @@ tomoyo_get_file_pattern(const struct tomoyo_path_info *filename) struct tomoyo_pattern_entry *ptr; const struct tomoyo_path_info *pattern = NULL; - down_read(&tomoyo_pattern_list_lock); - list_for_each_entry(ptr, &tomoyo_pattern_list, list) { + list_for_each_entry_rcu(ptr, &tomoyo_pattern_list, list) { if (ptr->is_deleted) continue; if (!tomoyo_path_matches_pattern(filename, ptr->pattern)) @@ -420,7 +428,6 @@ tomoyo_get_file_pattern(const struct tomoyo_path_info *filename) break; } } - up_read(&tomoyo_pattern_list_lock); if (pattern) filename = pattern; return filename; @@ -433,6 +440,8 @@ tomoyo_get_file_pattern(const struct tomoyo_path_info *filename) * @is_delete: True if it is a delete request. * * Returns 0 on success, negative value otherwise. + * + * Caller holds tomoyo_read_lock(). */ int tomoyo_write_pattern_policy(char *data, const bool is_delete) { @@ -445,13 +454,14 @@ int tomoyo_write_pattern_policy(char *data, const bool is_delete) * @head: Pointer to "struct tomoyo_io_buffer". * * Returns true on success, false otherwise. + * + * Caller holds tomoyo_read_lock(). */ bool tomoyo_read_file_pattern(struct tomoyo_io_buffer *head) { struct list_head *pos; bool done = true; - down_read(&tomoyo_pattern_list_lock); list_for_each_cookie(pos, head->read_var2, &tomoyo_pattern_list) { struct tomoyo_pattern_entry *ptr; ptr = list_entry(pos, struct tomoyo_pattern_entry, list); @@ -462,7 +472,6 @@ bool tomoyo_read_file_pattern(struct tomoyo_io_buffer *head) if (!done) break; } - up_read(&tomoyo_pattern_list_lock); return done; } @@ -505,6 +514,8 @@ static DECLARE_RWSEM(tomoyo_no_rewrite_list_lock); * @is_delete: True if it is a delete request. * * Returns 0 on success, negative value otherwise. + * + * Caller holds tomoyo_read_lock(). */ static int tomoyo_update_no_rewrite_entry(const char *pattern, const bool is_delete) @@ -519,7 +530,7 @@ static int tomoyo_update_no_rewrite_entry(const char *pattern, if (!saved_pattern) return -ENOMEM; down_write(&tomoyo_no_rewrite_list_lock); - list_for_each_entry(ptr, &tomoyo_no_rewrite_list, list) { + list_for_each_entry_rcu(ptr, &tomoyo_no_rewrite_list, list) { if (ptr->pattern != saved_pattern) continue; ptr->is_deleted = is_delete; @@ -534,7 +545,7 @@ static int tomoyo_update_no_rewrite_entry(const char *pattern, if (!new_entry) goto out; new_entry->pattern = saved_pattern; - list_add_tail(&new_entry->list, &tomoyo_no_rewrite_list); + list_add_tail_rcu(&new_entry->list, &tomoyo_no_rewrite_list); error = 0; out: up_write(&tomoyo_no_rewrite_list_lock); @@ -548,14 +559,15 @@ static int tomoyo_update_no_rewrite_entry(const char *pattern, * * Returns true if @filename is specified by "deny_rewrite" directive, * false otherwise. + * + * Caller holds tomoyo_read_lock(). */ static bool tomoyo_is_no_rewrite_file(const struct tomoyo_path_info *filename) { struct tomoyo_no_rewrite_entry *ptr; bool found = false; - down_read(&tomoyo_no_rewrite_list_lock); - list_for_each_entry(ptr, &tomoyo_no_rewrite_list, list) { + list_for_each_entry_rcu(ptr, &tomoyo_no_rewrite_list, list) { if (ptr->is_deleted) continue; if (!tomoyo_path_matches_pattern(filename, ptr->pattern)) @@ -563,7 +575,6 @@ static bool tomoyo_is_no_rewrite_file(const struct tomoyo_path_info *filename) found = true; break; } - up_read(&tomoyo_no_rewrite_list_lock); return found; } @@ -574,6 +585,8 @@ static bool tomoyo_is_no_rewrite_file(const struct tomoyo_path_info *filename) * @is_delete: True if it is a delete request. * * Returns 0 on success, negative value otherwise. + * + * Caller holds tomoyo_read_lock(). */ int tomoyo_write_no_rewrite_policy(char *data, const bool is_delete) { @@ -586,13 +599,14 @@ int tomoyo_write_no_rewrite_policy(char *data, const bool is_delete) * @head: Pointer to "struct tomoyo_io_buffer". * * Returns true on success, false otherwise. + * + * Caller holds tomoyo_read_lock(). */ bool tomoyo_read_no_rewrite_policy(struct tomoyo_io_buffer *head) { struct list_head *pos; bool done = true; - down_read(&tomoyo_no_rewrite_list_lock); list_for_each_cookie(pos, head->read_var2, &tomoyo_no_rewrite_list) { struct tomoyo_no_rewrite_entry *ptr; ptr = list_entry(pos, struct tomoyo_no_rewrite_entry, list); @@ -603,7 +617,6 @@ bool tomoyo_read_no_rewrite_policy(struct tomoyo_io_buffer *head) if (!done) break; } - up_read(&tomoyo_no_rewrite_list_lock); return done; } @@ -621,6 +634,8 @@ bool tomoyo_read_no_rewrite_policy(struct tomoyo_io_buffer *head) * Current policy syntax uses "allow_read/write" instead of "6", * "allow_read" instead of "4", "allow_write" instead of "2", * "allow_execute" instead of "1". + * + * Caller holds tomoyo_read_lock(). */ static int tomoyo_update_file_acl(const char *filename, u8 perm, struct tomoyo_domain_info * const domain, @@ -658,6 +673,8 @@ static int tomoyo_update_file_acl(const char *filename, u8 perm, * @may_use_pattern: True if patterned ACL is permitted. * * Returns 0 on success, -EPERM otherwise. + * + * Caller holds tomoyo_read_lock(). */ static int tomoyo_check_single_path_acl2(const struct tomoyo_domain_info * domain, @@ -669,8 +686,7 @@ static int tomoyo_check_single_path_acl2(const struct tomoyo_domain_info * struct tomoyo_acl_info *ptr; int error = -EPERM; - down_read(&tomoyo_domain_acl_info_list_lock); - list_for_each_entry(ptr, &domain->acl_info_list, list) { + list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { struct tomoyo_single_path_acl_record *acl; if (tomoyo_acl_type2(ptr) != TOMOYO_TYPE_SINGLE_PATH_ACL) continue; @@ -693,7 +709,6 @@ static int tomoyo_check_single_path_acl2(const struct tomoyo_domain_info * error = 0; break; } - up_read(&tomoyo_domain_acl_info_list_lock); return error; } @@ -705,6 +720,8 @@ static int tomoyo_check_single_path_acl2(const struct tomoyo_domain_info * * @operation: Mode ("read" or "write" or "read/write" or "execute"). * * Returns 0 on success, -EPERM otherwise. + * + * Caller holds tomoyo_read_lock(). */ static int tomoyo_check_file_acl(const struct tomoyo_domain_info *domain, const struct tomoyo_path_info *filename, @@ -738,6 +755,8 @@ static int tomoyo_check_file_acl(const struct tomoyo_domain_info *domain, * @mode: Access control mode. * * Returns 0 on success, negative value otherwise. + * + * Caller holds tomoyo_read_lock(). */ static int tomoyo_check_file_perm2(struct tomoyo_domain_info * const domain, const struct tomoyo_path_info *filename, @@ -791,6 +810,8 @@ static int tomoyo_check_file_perm2(struct tomoyo_domain_info * const domain, * @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) @@ -838,6 +859,8 @@ int tomoyo_write_file_policy(char *data, struct tomoyo_domain_info *domain, * @is_delete: True if it is a delete request. * * Returns 0 on success, negative value otherwise. + * + * Caller holds tomoyo_read_lock(). */ static int tomoyo_update_single_path_acl(const u8 type, const char *filename, struct tomoyo_domain_info * @@ -861,7 +884,7 @@ static int tomoyo_update_single_path_acl(const u8 type, const char *filename, down_write(&tomoyo_domain_acl_info_list_lock); if (is_delete) goto delete; - list_for_each_entry(ptr, &domain->acl_info_list, list) { + list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { if (tomoyo_acl_type1(ptr) != TOMOYO_TYPE_SINGLE_PATH_ACL) continue; acl = container_of(ptr, struct tomoyo_single_path_acl_record, @@ -894,12 +917,12 @@ static int tomoyo_update_single_path_acl(const u8 type, const char *filename, if (perm == (1 << TOMOYO_TYPE_READ_WRITE_ACL)) acl->perm |= rw_mask; acl->filename = saved_filename; - list_add_tail(&acl->head.list, &domain->acl_info_list); + list_add_tail_rcu(&acl->head.list, &domain->acl_info_list); error = 0; goto out; delete: error = -ENOENT; - list_for_each_entry(ptr, &domain->acl_info_list, list) { + list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { if (tomoyo_acl_type2(ptr) != TOMOYO_TYPE_SINGLE_PATH_ACL) continue; acl = container_of(ptr, struct tomoyo_single_path_acl_record, @@ -934,6 +957,8 @@ static int tomoyo_update_single_path_acl(const u8 type, const char *filename, * @is_delete: True if it is a delete request. * * Returns 0 on success, negative value otherwise. + * + * Caller holds tomoyo_read_lock(). */ static int tomoyo_update_double_path_acl(const u8 type, const char *filename1, const char *filename2, @@ -959,7 +984,7 @@ static int tomoyo_update_double_path_acl(const u8 type, const char *filename1, down_write(&tomoyo_domain_acl_info_list_lock); if (is_delete) goto delete; - list_for_each_entry(ptr, &domain->acl_info_list, list) { + list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { if (tomoyo_acl_type1(ptr) != TOMOYO_TYPE_DOUBLE_PATH_ACL) continue; acl = container_of(ptr, struct tomoyo_double_path_acl_record, @@ -982,12 +1007,12 @@ static int tomoyo_update_double_path_acl(const u8 type, const char *filename1, acl->perm = perm; acl->filename1 = saved_filename1; acl->filename2 = saved_filename2; - list_add_tail(&acl->head.list, &domain->acl_info_list); + list_add_tail_rcu(&acl->head.list, &domain->acl_info_list); error = 0; goto out; delete: error = -ENOENT; - list_for_each_entry(ptr, &domain->acl_info_list, list) { + list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { if (tomoyo_acl_type2(ptr) != TOMOYO_TYPE_DOUBLE_PATH_ACL) continue; acl = container_of(ptr, struct tomoyo_double_path_acl_record, @@ -1014,6 +1039,8 @@ static int tomoyo_update_double_path_acl(const u8 type, const char *filename1, * @filename: Filename to check. * * Returns 0 on success, negative value otherwise. + * + * Caller holds tomoyo_read_lock(). */ static int tomoyo_check_single_path_acl(struct tomoyo_domain_info *domain, const u8 type, @@ -1033,6 +1060,8 @@ static int tomoyo_check_single_path_acl(struct tomoyo_domain_info *domain, * @filename2: Second filename to check. * * Returns 0 on success, -EPERM otherwise. + * + * Caller holds tomoyo_read_lock(). */ static int tomoyo_check_double_path_acl(const struct tomoyo_domain_info *domain, const u8 type, @@ -1047,8 +1076,7 @@ static int tomoyo_check_double_path_acl(const struct tomoyo_domain_info *domain, if (!tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE)) return 0; - down_read(&tomoyo_domain_acl_info_list_lock); - list_for_each_entry(ptr, &domain->acl_info_list, list) { + list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { struct tomoyo_double_path_acl_record *acl; if (tomoyo_acl_type2(ptr) != TOMOYO_TYPE_DOUBLE_PATH_ACL) continue; @@ -1063,7 +1091,6 @@ static int tomoyo_check_double_path_acl(const struct tomoyo_domain_info *domain, error = 0; break; } - up_read(&tomoyo_domain_acl_info_list_lock); return error; } @@ -1076,6 +1103,8 @@ static int tomoyo_check_double_path_acl(const struct tomoyo_domain_info *domain, * @mode: Access control mode. * * Returns 0 on success, negative value otherwise. + * + * Caller holds tomoyo_read_lock(). */ static int tomoyo_check_single_path_permission2(struct tomoyo_domain_info * const domain, u8 operation, @@ -1124,6 +1153,8 @@ static int tomoyo_check_single_path_permission2(struct tomoyo_domain_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, const struct tomoyo_path_info *filename) @@ -1152,6 +1183,7 @@ int tomoyo_check_open_permission(struct tomoyo_domain_info *domain, struct tomoyo_path_info *buf; const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE); const bool is_enforce = (mode == 3); + int idx; if (!mode || !path->mnt) return 0; @@ -1163,6 +1195,7 @@ int tomoyo_check_open_permission(struct tomoyo_domain_info *domain, * don't call me. */ return 0; + idx = tomoyo_read_lock(); buf = tomoyo_get_path(path); if (!buf) goto out; @@ -1188,6 +1221,7 @@ int tomoyo_check_open_permission(struct tomoyo_domain_info *domain, buf, mode); out: tomoyo_free(buf); + tomoyo_read_unlock(idx); if (!is_enforce) error = 0; return error; @@ -1209,9 +1243,11 @@ int tomoyo_check_1path_perm(struct tomoyo_domain_info *domain, struct tomoyo_path_info *buf; const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE); const bool is_enforce = (mode == 3); + int idx; if (!mode || !path->mnt) return 0; + idx = tomoyo_read_lock(); buf = tomoyo_get_path(path); if (!buf) goto out; @@ -1231,6 +1267,7 @@ int tomoyo_check_1path_perm(struct tomoyo_domain_info *domain, mode); out: tomoyo_free(buf); + tomoyo_read_unlock(idx); if (!is_enforce) error = 0; return error; @@ -1251,9 +1288,12 @@ int tomoyo_check_rewrite_permission(struct tomoyo_domain_info *domain, const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE); const bool is_enforce = (mode == 3); struct tomoyo_path_info *buf; + int idx; if (!mode || !filp->f_path.mnt) return 0; + + idx = tomoyo_read_lock(); buf = tomoyo_get_path(&filp->f_path); if (!buf) goto out; @@ -1266,6 +1306,7 @@ int tomoyo_check_rewrite_permission(struct tomoyo_domain_info *domain, buf, mode); out: tomoyo_free(buf); + tomoyo_read_unlock(idx); if (!is_enforce) error = 0; return error; @@ -1290,9 +1331,11 @@ int tomoyo_check_2path_perm(struct tomoyo_domain_info * const domain, const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE); const bool is_enforce = (mode == 3); const char *msg; + int idx; if (!mode || !path1->mnt || !path2->mnt) return 0; + idx = tomoyo_read_lock(); buf1 = tomoyo_get_path(path1); buf2 = tomoyo_get_path(path2); if (!buf1 || !buf2) @@ -1331,6 +1374,7 @@ int tomoyo_check_2path_perm(struct tomoyo_domain_info * const domain, out: tomoyo_free(buf1); tomoyo_free(buf2); + tomoyo_read_unlock(idx); if (!is_enforce) error = 0; return error; diff --git a/security/tomoyo/realpath.c b/security/tomoyo/realpath.c index e3c7aa0fb70..62363b3bc71 100644 --- a/security/tomoyo/realpath.c +++ b/security/tomoyo/realpath.c @@ -402,11 +402,13 @@ void __init tomoyo_realpath_init(void) INIT_LIST_HEAD(&tomoyo_name_list[i]); INIT_LIST_HEAD(&tomoyo_kernel_domain.acl_info_list); tomoyo_kernel_domain.domainname = tomoyo_save_name(TOMOYO_ROOT_NAME); - list_add_tail(&tomoyo_kernel_domain.list, &tomoyo_domain_list); - down_read(&tomoyo_domain_list_lock); + /* + * tomoyo_read_lock() is not needed because this function is + * called before the first "delete" request. + */ + list_add_tail_rcu(&tomoyo_kernel_domain.list, &tomoyo_domain_list); if (tomoyo_find_domain(TOMOYO_ROOT_NAME) != &tomoyo_kernel_domain) panic("Can't register tomoyo_kernel_domain"); - up_read(&tomoyo_domain_list_lock); } /* Memory allocated for temporary purpose. */ diff --git a/security/tomoyo/tomoyo.c b/security/tomoyo/tomoyo.c index ad9555fc376..714daa34d49 100644 --- a/security/tomoyo/tomoyo.c +++ b/security/tomoyo/tomoyo.c @@ -76,8 +76,18 @@ static int tomoyo_bprm_check_security(struct linux_binprm *bprm) * Execute permission is checked against pathname passed to do_execve() * using current domain. */ - if (!domain) - return tomoyo_find_next_domain(bprm); + if (!domain) { + /* + * We will need to protect whole execve() operation when GC + * starts kfree()ing "struct tomoyo_domain_info" because + * bprm->cred->security points to "struct tomoyo_domain_info" + * but "struct tomoyo_domain_info" does not have a refcounter. + */ + const int idx = tomoyo_read_lock(); + const int err = tomoyo_find_next_domain(bprm); + tomoyo_read_unlock(idx); + return err; + } /* * Read permission is checked against interpreters using next domain. * '1' is the result of open_to_namei_flags(O_RDONLY). @@ -278,6 +288,9 @@ static struct security_operations tomoyo_security_ops = { .sb_pivotroot = tomoyo_sb_pivotroot, }; +/* Lock for GC. */ +struct srcu_struct tomoyo_ss; + static int __init tomoyo_init(void) { struct cred *cred = (struct cred *) current_cred(); @@ -285,7 +298,8 @@ static int __init tomoyo_init(void) if (!security_module_enable(&tomoyo_security_ops)) return 0; /* register ourselves with the security framework */ - if (register_security(&tomoyo_security_ops)) + if (register_security(&tomoyo_security_ops) || + init_srcu_struct(&tomoyo_ss)) panic("Failure registering TOMOYO Linux"); printk(KERN_INFO "TOMOYO Linux initialized\n"); cred->security = &tomoyo_kernel_domain; From f737d95ddfea4df68a36ffc9231db4bf34b06d13 Mon Sep 17 00:00:00 2001 From: Tetsuo Handa Date: Sun, 3 Jan 2010 21:16:32 +0900 Subject: [PATCH 08/38] TOMOYO: Replace rw_semaphore by mutex. Since readers no longer use down_read(), writers no longer need to use rw_semaphore. Replace individual rw_semaphore by single mutex. Signed-off-by: Tetsuo Handa Acked-by: Serge Hallyn Signed-off-by: James Morris --- security/tomoyo/common.c | 12 +++++++----- security/tomoyo/common.h | 5 ++--- security/tomoyo/domain.c | 20 ++++++++------------ security/tomoyo/file.c | 26 ++++++++++---------------- 4 files changed, 27 insertions(+), 36 deletions(-) diff --git a/security/tomoyo/common.c b/security/tomoyo/common.c index f01b9364db2..642e0e565df 100644 --- a/security/tomoyo/common.c +++ b/security/tomoyo/common.c @@ -16,6 +16,9 @@ #include "common.h" #include "tomoyo.h" +/* Lock for protecting policy. */ +DEFINE_MUTEX(tomoyo_policy_lock); + /* Has loading policy done? */ bool tomoyo_policy_loaded; @@ -1086,7 +1089,6 @@ struct tomoyo_policy_manager_entry { * # cat /sys/kernel/security/tomoyo/manager */ static LIST_HEAD(tomoyo_policy_manager_list); -static DECLARE_RWSEM(tomoyo_policy_manager_list_lock); /** * tomoyo_update_manager_entry - Add a manager entry. @@ -1118,7 +1120,7 @@ static int tomoyo_update_manager_entry(const char *manager, saved_manager = tomoyo_save_name(manager); if (!saved_manager) return -ENOMEM; - down_write(&tomoyo_policy_manager_list_lock); + mutex_lock(&tomoyo_policy_lock); list_for_each_entry_rcu(ptr, &tomoyo_policy_manager_list, list) { if (ptr->manager != saved_manager) continue; @@ -1138,7 +1140,7 @@ static int tomoyo_update_manager_entry(const char *manager, list_add_tail_rcu(&new_entry->list, &tomoyo_policy_manager_list); error = 0; out: - up_write(&tomoyo_policy_manager_list_lock); + mutex_unlock(&tomoyo_policy_lock); return error; } @@ -1315,7 +1317,7 @@ static int tomoyo_delete_domain(char *domainname) name.name = domainname; tomoyo_fill_path_info(&name); - down_write(&tomoyo_domain_list_lock); + mutex_lock(&tomoyo_policy_lock); /* Is there an active domain? */ list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) { /* Never delete tomoyo_kernel_domain */ @@ -1327,7 +1329,7 @@ static int tomoyo_delete_domain(char *domainname) domain->is_deleted = true; break; } - up_write(&tomoyo_domain_list_lock); + mutex_unlock(&tomoyo_policy_lock); return 0; } diff --git a/security/tomoyo/common.h b/security/tomoyo/common.h index c6f13925472..874abf8df43 100644 --- a/security/tomoyo/common.h +++ b/security/tomoyo/common.h @@ -431,10 +431,9 @@ static inline bool tomoyo_is_invalid(const unsigned char c) /* The list for "struct tomoyo_domain_info". */ extern struct list_head tomoyo_domain_list; -extern struct rw_semaphore tomoyo_domain_list_lock; -/* Lock for domain->acl_info_list. */ -extern struct rw_semaphore tomoyo_domain_acl_info_list_lock; +/* Lock for protecting policy. */ +extern struct mutex tomoyo_policy_lock; /* Has /sbin/init started? */ extern bool tomoyo_policy_loaded; diff --git a/security/tomoyo/domain.c b/security/tomoyo/domain.c index 2fd190168b7..7d0b0bc4820 100644 --- a/security/tomoyo/domain.c +++ b/security/tomoyo/domain.c @@ -58,7 +58,6 @@ struct tomoyo_domain_info tomoyo_kernel_domain; * exceptions. */ LIST_HEAD(tomoyo_domain_list); -DECLARE_RWSEM(tomoyo_domain_list_lock); /* * tomoyo_domain_initializer_entry is a structure which is used for holding @@ -206,7 +205,6 @@ const char *tomoyo_get_last_name(const struct tomoyo_domain_info *domain) * unless executed from " /etc/rc.d/init.d/httpd" domain. */ static LIST_HEAD(tomoyo_domain_initializer_list); -static DECLARE_RWSEM(tomoyo_domain_initializer_list_lock); /** * tomoyo_update_domain_initializer_entry - Update "struct tomoyo_domain_initializer_entry" list. @@ -247,7 +245,7 @@ static int tomoyo_update_domain_initializer_entry(const char *domainname, saved_program = tomoyo_save_name(program); if (!saved_program) return -ENOMEM; - down_write(&tomoyo_domain_initializer_list_lock); + mutex_lock(&tomoyo_policy_lock); list_for_each_entry_rcu(ptr, &tomoyo_domain_initializer_list, list) { if (ptr->is_not != is_not || ptr->domainname != saved_domainname || @@ -271,7 +269,7 @@ static int tomoyo_update_domain_initializer_entry(const char *domainname, list_add_tail_rcu(&new_entry->list, &tomoyo_domain_initializer_list); error = 0; out: - up_write(&tomoyo_domain_initializer_list_lock); + mutex_unlock(&tomoyo_policy_lock); return error; } @@ -423,7 +421,6 @@ static bool tomoyo_is_domain_initializer(const struct tomoyo_path_info * * explicitly specified by "initialize_domain". */ static LIST_HEAD(tomoyo_domain_keeper_list); -static DECLARE_RWSEM(tomoyo_domain_keeper_list_lock); /** * tomoyo_update_domain_keeper_entry - Update "struct tomoyo_domain_keeper_entry" list. @@ -464,7 +461,7 @@ static int tomoyo_update_domain_keeper_entry(const char *domainname, saved_domainname = tomoyo_save_name(domainname); if (!saved_domainname) return -ENOMEM; - down_write(&tomoyo_domain_keeper_list_lock); + mutex_lock(&tomoyo_policy_lock); list_for_each_entry_rcu(ptr, &tomoyo_domain_keeper_list, list) { if (ptr->is_not != is_not || ptr->domainname != saved_domainname || @@ -488,7 +485,7 @@ static int tomoyo_update_domain_keeper_entry(const char *domainname, list_add_tail_rcu(&new_entry->list, &tomoyo_domain_keeper_list); error = 0; out: - up_write(&tomoyo_domain_keeper_list_lock); + mutex_unlock(&tomoyo_policy_lock); return error; } @@ -624,7 +621,6 @@ static bool tomoyo_is_domain_keeper(const struct tomoyo_path_info *domainname, * execve() succeeds is calculated using /bin/cat rather than /bin/busybox . */ static LIST_HEAD(tomoyo_alias_list); -static DECLARE_RWSEM(tomoyo_alias_list_lock); /** * tomoyo_update_alias_entry - Update "struct tomoyo_alias_entry" list. @@ -654,7 +650,7 @@ static int tomoyo_update_alias_entry(const char *original_name, saved_aliased_name = tomoyo_save_name(aliased_name); if (!saved_original_name || !saved_aliased_name) return -ENOMEM; - down_write(&tomoyo_alias_list_lock); + mutex_lock(&tomoyo_policy_lock); list_for_each_entry_rcu(ptr, &tomoyo_alias_list, list) { if (ptr->original_name != saved_original_name || ptr->aliased_name != saved_aliased_name) @@ -675,7 +671,7 @@ static int tomoyo_update_alias_entry(const char *original_name, list_add_tail_rcu(&new_entry->list, &tomoyo_alias_list); error = 0; out: - up_write(&tomoyo_alias_list_lock); + mutex_unlock(&tomoyo_policy_lock); return error; } @@ -745,7 +741,7 @@ struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char * struct tomoyo_domain_info *domain = NULL; const struct tomoyo_path_info *saved_domainname; - down_write(&tomoyo_domain_list_lock); + mutex_lock(&tomoyo_policy_lock); domain = tomoyo_find_domain(domainname); if (domain) goto out; @@ -792,7 +788,7 @@ struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char * list_add_tail_rcu(&domain->list, &tomoyo_domain_list); } out: - up_write(&tomoyo_domain_list_lock); + mutex_unlock(&tomoyo_policy_lock); return domain; } diff --git a/security/tomoyo/file.c b/security/tomoyo/file.c index 3c472867634..5d1689d6e16 100644 --- a/security/tomoyo/file.c +++ b/security/tomoyo/file.c @@ -167,9 +167,6 @@ static struct tomoyo_path_info *tomoyo_get_path(struct path *path) return NULL; } -/* Lock for domain->acl_info_list. */ -DECLARE_RWSEM(tomoyo_domain_acl_info_list_lock); - static int tomoyo_update_double_path_acl(const u8 type, const char *filename1, const char *filename2, struct tomoyo_domain_info * @@ -204,7 +201,6 @@ static int tomoyo_update_single_path_acl(const u8 type, const char *filename, * belongs to. */ static LIST_HEAD(tomoyo_globally_readable_list); -static DECLARE_RWSEM(tomoyo_globally_readable_list_lock); /** * tomoyo_update_globally_readable_entry - Update "struct tomoyo_globally_readable_file_entry" list. @@ -229,7 +225,7 @@ static int tomoyo_update_globally_readable_entry(const char *filename, saved_filename = tomoyo_save_name(filename); if (!saved_filename) return -ENOMEM; - down_write(&tomoyo_globally_readable_list_lock); + mutex_lock(&tomoyo_policy_lock); list_for_each_entry_rcu(ptr, &tomoyo_globally_readable_list, list) { if (ptr->filename != saved_filename) continue; @@ -248,7 +244,7 @@ static int tomoyo_update_globally_readable_entry(const char *filename, list_add_tail_rcu(&new_entry->list, &tomoyo_globally_readable_list); error = 0; out: - up_write(&tomoyo_globally_readable_list_lock); + mutex_unlock(&tomoyo_policy_lock); return error; } @@ -352,7 +348,6 @@ bool tomoyo_read_globally_readable_policy(struct tomoyo_io_buffer *head) * current process from accessing other process's information. */ static LIST_HEAD(tomoyo_pattern_list); -static DECLARE_RWSEM(tomoyo_pattern_list_lock); /** * tomoyo_update_file_pattern_entry - Update "struct tomoyo_pattern_entry" list. @@ -377,7 +372,7 @@ static int tomoyo_update_file_pattern_entry(const char *pattern, saved_pattern = tomoyo_save_name(pattern); if (!saved_pattern) return -ENOMEM; - down_write(&tomoyo_pattern_list_lock); + mutex_lock(&tomoyo_policy_lock); list_for_each_entry_rcu(ptr, &tomoyo_pattern_list, list) { if (saved_pattern != ptr->pattern) continue; @@ -396,7 +391,7 @@ static int tomoyo_update_file_pattern_entry(const char *pattern, list_add_tail_rcu(&new_entry->list, &tomoyo_pattern_list); error = 0; out: - up_write(&tomoyo_pattern_list_lock); + mutex_unlock(&tomoyo_policy_lock); return error; } @@ -505,7 +500,6 @@ bool tomoyo_read_file_pattern(struct tomoyo_io_buffer *head) * need to worry whether the file is already unlink()ed or not. */ static LIST_HEAD(tomoyo_no_rewrite_list); -static DECLARE_RWSEM(tomoyo_no_rewrite_list_lock); /** * tomoyo_update_no_rewrite_entry - Update "struct tomoyo_no_rewrite_entry" list. @@ -529,7 +523,7 @@ static int tomoyo_update_no_rewrite_entry(const char *pattern, saved_pattern = tomoyo_save_name(pattern); if (!saved_pattern) return -ENOMEM; - down_write(&tomoyo_no_rewrite_list_lock); + mutex_lock(&tomoyo_policy_lock); list_for_each_entry_rcu(ptr, &tomoyo_no_rewrite_list, list) { if (ptr->pattern != saved_pattern) continue; @@ -548,7 +542,7 @@ static int tomoyo_update_no_rewrite_entry(const char *pattern, list_add_tail_rcu(&new_entry->list, &tomoyo_no_rewrite_list); error = 0; out: - up_write(&tomoyo_no_rewrite_list_lock); + mutex_unlock(&tomoyo_policy_lock); return error; } @@ -881,7 +875,7 @@ static int tomoyo_update_single_path_acl(const u8 type, const char *filename, saved_filename = tomoyo_save_name(filename); if (!saved_filename) return -ENOMEM; - down_write(&tomoyo_domain_acl_info_list_lock); + mutex_lock(&tomoyo_policy_lock); if (is_delete) goto delete; list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { @@ -943,7 +937,7 @@ static int tomoyo_update_single_path_acl(const u8 type, const char *filename, break; } out: - up_write(&tomoyo_domain_acl_info_list_lock); + mutex_unlock(&tomoyo_policy_lock); return error; } @@ -981,7 +975,7 @@ static int tomoyo_update_double_path_acl(const u8 type, const char *filename1, saved_filename2 = tomoyo_save_name(filename2); if (!saved_filename1 || !saved_filename2) return -ENOMEM; - down_write(&tomoyo_domain_acl_info_list_lock); + mutex_lock(&tomoyo_policy_lock); if (is_delete) goto delete; list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { @@ -1027,7 +1021,7 @@ static int tomoyo_update_double_path_acl(const u8 type, const char *filename1, break; } out: - up_write(&tomoyo_domain_acl_info_list_lock); + mutex_unlock(&tomoyo_policy_lock); return error; } From 0ed731859e24cd6e3ec058cf2b49b2a0df80e86b Mon Sep 17 00:00:00 2001 From: Tetsuo Handa Date: Wed, 6 Jan 2010 09:23:54 +0900 Subject: [PATCH 09/38] LSM: Update comment on security_sock_rcv_skb It is not permitted to do sleeping operation inside security_sock_rcv_skb(). Signed-off-by: Tetsuo Handa Acked-by: Serge Hallyn -- Signed-off-by: James Morris --- include/linux/security.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/linux/security.h b/include/linux/security.h index 466cbadbd1e..3696ca34574 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -978,6 +978,7 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts) * Check permissions on incoming network packets. This hook is distinct * from Netfilter's IP input hooks since it is the first time that the * incoming sk_buff @skb has been associated with a particular socket, @sk. + * Must not sleep inside this hook because some callers hold spinlocks. * @sk contains the sock (not socket) associated with the incoming sk_buff. * @skb contains the incoming network data. * @socket_getpeersec_stream: From e41035a996356c257183e53a70abfb46fa84908b Mon Sep 17 00:00:00 2001 From: Tetsuo Handa Date: Tue, 5 Jan 2010 06:39:00 +0900 Subject: [PATCH 10/38] TOMOYO: Remove memory pool for string data. Currently, TOMOYO allocates memory for string data from memory pool allocated by kmalloc(PAGE_SIZE). But that makes it difficult to kfree() when garbage collector is added. Thus, remove memory pool and use kmalloc(strlen()). Signed-off-by: Tetsuo Handa Signed-off-by: James Morris --- security/tomoyo/realpath.c | 60 +++++++------------------------------- 1 file changed, 10 insertions(+), 50 deletions(-) diff --git a/security/tomoyo/realpath.c b/security/tomoyo/realpath.c index 62363b3bc71..9105e5e29da 100644 --- a/security/tomoyo/realpath.c +++ b/security/tomoyo/realpath.c @@ -293,13 +293,6 @@ struct tomoyo_name_entry { struct tomoyo_path_info entry; }; -/* Structure for available memory region. */ -struct tomoyo_free_memory_block_list { - struct list_head list; - char *ptr; /* Pointer to a free area. */ - int len; /* Length of the area. */ -}; - /* * tomoyo_name_list is used for holding string data used by TOMOYO. * Since same string data is likely used for multiple times (e.g. @@ -314,52 +307,32 @@ static struct list_head tomoyo_name_list[TOMOYO_MAX_HASH]; * @name: The string to store into the permernent memory. * * Returns pointer to "struct tomoyo_path_info" on success, NULL otherwise. - * - * The RAM is shared, so NEVER try to modify or kfree() the returned name. */ const struct tomoyo_path_info *tomoyo_save_name(const char *name) { - static LIST_HEAD(fmb_list); static DEFINE_MUTEX(lock); struct tomoyo_name_entry *ptr; unsigned int hash; - /* fmb contains available size in bytes. - fmb is removed from the fmb_list when fmb->len becomes 0. */ - struct tomoyo_free_memory_block_list *fmb; int len; - char *cp; + int allocated_len; struct list_head *head; if (!name) return NULL; len = strlen(name) + 1; - if (len > TOMOYO_MAX_PATHNAME_LEN) { - printk(KERN_WARNING "ERROR: Name too long " - "for tomoyo_save_name().\n"); - return NULL; - } hash = full_name_hash((const unsigned char *) name, len - 1); head = &tomoyo_name_list[hash_long(hash, TOMOYO_HASH_BITS)]; - mutex_lock(&lock); list_for_each_entry(ptr, head, list) { if (hash == ptr->entry.hash && !strcmp(name, ptr->entry.name)) goto out; } - list_for_each_entry(fmb, &fmb_list, list) { - if (len <= fmb->len) - goto ready; - } - if (!tomoyo_quota_for_savename || - tomoyo_allocated_memory_for_savename + PATH_MAX - <= tomoyo_quota_for_savename) - cp = kzalloc(PATH_MAX, GFP_KERNEL); - else - cp = NULL; - fmb = kzalloc(sizeof(*fmb), GFP_KERNEL); - if (!cp || !fmb) { - kfree(cp); - kfree(fmb); + ptr = kzalloc(sizeof(*ptr) + len, GFP_KERNEL); + allocated_len = ptr ? ksize(ptr) : 0; + if (!ptr || (tomoyo_quota_for_savename && + tomoyo_allocated_memory_for_savename + allocated_len + > tomoyo_quota_for_savename)) { + kfree(ptr); printk(KERN_WARNING "ERROR: Out of memory " "for tomoyo_save_name().\n"); if (!tomoyo_policy_loaded) @@ -367,24 +340,11 @@ const struct tomoyo_path_info *tomoyo_save_name(const char *name) ptr = NULL; goto out; } - tomoyo_allocated_memory_for_savename += PATH_MAX; - list_add(&fmb->list, &fmb_list); - fmb->ptr = cp; - fmb->len = PATH_MAX; - ready: - ptr = tomoyo_alloc_element(sizeof(*ptr)); - if (!ptr) - goto out; - ptr->entry.name = fmb->ptr; - memmove(fmb->ptr, name, len); + tomoyo_allocated_memory_for_savename += allocated_len; + ptr->entry.name = ((char *) ptr) + sizeof(*ptr); + memmove((char *) ptr->entry.name, name, len); tomoyo_fill_path_info(&ptr->entry); - fmb->ptr += len; - fmb->len -= len; list_add_tail(&ptr->list, head); - if (fmb->len == 0) { - list_del(&fmb->list); - kfree(fmb); - } out: mutex_unlock(&lock); return ptr ? &ptr->entry : NULL; From cd7bec6ad80188394a8ea857ff1aa3512fc2282a Mon Sep 17 00:00:00 2001 From: Tetsuo Handa Date: Tue, 5 Jan 2010 06:39:37 +0900 Subject: [PATCH 11/38] TOMOYO: Remove memory pool for list elements. Currently, TOMOYO allocates memory for list elements from memory pool allocated by kmalloc(PAGE_SIZE). But that makes it difficult to kfree() when garbage collector is added. Thus, remove memory pool and use kmalloc(sizeof()). Signed-off-by: Tetsuo Handa Signed-off-by: James Morris --- security/tomoyo/common.c | 41 +++++------------------- security/tomoyo/common.h | 2 -- security/tomoyo/domain.c | 58 +++++++++++----------------------- security/tomoyo/file.c | 34 ++++++++++++++------ security/tomoyo/realpath.c | 65 ++++++++++++-------------------------- security/tomoyo/realpath.h | 7 ++-- 6 files changed, 73 insertions(+), 134 deletions(-) diff --git a/security/tomoyo/common.c b/security/tomoyo/common.c index 642e0e565df..e331e699cf5 100644 --- a/security/tomoyo/common.c +++ b/security/tomoyo/common.c @@ -900,9 +900,11 @@ static struct tomoyo_profile *tomoyo_find_or_assign_new_profile(const unsigned ptr = tomoyo_profile_ptr[profile]; if (ptr) goto ok; - ptr = tomoyo_alloc_element(sizeof(*ptr)); - if (!ptr) + ptr = kmalloc(sizeof(*ptr), GFP_KERNEL); + if (!tomoyo_memory_ok(ptr)) { + kfree(ptr); goto ok; + } for (i = 0; i < TOMOYO_MAX_CONTROL_INDEX; i++) ptr->value[i] = tomoyo_control_array[i].current_value; mb(); /* Avoid out-of-order execution. */ @@ -1120,6 +1122,7 @@ static int tomoyo_update_manager_entry(const char *manager, saved_manager = tomoyo_save_name(manager); if (!saved_manager) return -ENOMEM; + new_entry = kmalloc(sizeof(*new_entry), GFP_KERNEL); mutex_lock(&tomoyo_policy_lock); list_for_each_entry_rcu(ptr, &tomoyo_policy_manager_list, list) { if (ptr->manager != saved_manager) @@ -1132,15 +1135,16 @@ static int tomoyo_update_manager_entry(const char *manager, error = -ENOENT; goto out; } - new_entry = tomoyo_alloc_element(sizeof(*new_entry)); - if (!new_entry) + if (!tomoyo_memory_ok(new_entry)) goto out; new_entry->manager = saved_manager; new_entry->is_domain = is_domain; list_add_tail_rcu(&new_entry->list, &tomoyo_policy_manager_list); + new_entry = NULL; error = 0; out: mutex_unlock(&tomoyo_policy_lock); + kfree(new_entry); return error; } @@ -2147,35 +2151,6 @@ static int tomoyo_close_control(struct file *file) return 0; } -/** - * tomoyo_alloc_acl_element - Allocate permanent memory for ACL entry. - * - * @acl_type: Type of ACL entry. - * - * Returns pointer to the ACL entry on success, NULL otherwise. - */ -void *tomoyo_alloc_acl_element(const u8 acl_type) -{ - int len; - struct tomoyo_acl_info *ptr; - - switch (acl_type) { - case TOMOYO_TYPE_SINGLE_PATH_ACL: - len = sizeof(struct tomoyo_single_path_acl_record); - break; - case TOMOYO_TYPE_DOUBLE_PATH_ACL: - len = sizeof(struct tomoyo_double_path_acl_record); - break; - default: - return NULL; - } - ptr = tomoyo_alloc_element(len); - if (!ptr) - return NULL; - ptr->type = acl_type; - return ptr; -} - /** * tomoyo_open - open() for /sys/kernel/security/tomoyo/ interface. * diff --git a/security/tomoyo/common.h b/security/tomoyo/common.h index 874abf8df43..610a6a05682 100644 --- a/security/tomoyo/common.h +++ b/security/tomoyo/common.h @@ -376,8 +376,6 @@ struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char * /* Check mode for specified functionality. */ unsigned int tomoyo_check_flags(const struct tomoyo_domain_info *domain, const u8 index); -/* Allocate memory for structures. */ -void *tomoyo_alloc_acl_element(const u8 acl_type); /* Fill in "struct tomoyo_path_info" members. */ void tomoyo_fill_path_info(struct tomoyo_path_info *ptr); /* Run policy loader when /sbin/init starts. */ diff --git a/security/tomoyo/domain.c b/security/tomoyo/domain.c index 7d0b0bc4820..a55a1cced58 100644 --- a/security/tomoyo/domain.c +++ b/security/tomoyo/domain.c @@ -245,6 +245,7 @@ static int tomoyo_update_domain_initializer_entry(const char *domainname, saved_program = tomoyo_save_name(program); if (!saved_program) return -ENOMEM; + new_entry = kmalloc(sizeof(*new_entry), GFP_KERNEL); mutex_lock(&tomoyo_policy_lock); list_for_each_entry_rcu(ptr, &tomoyo_domain_initializer_list, list) { if (ptr->is_not != is_not || @@ -259,17 +260,18 @@ static int tomoyo_update_domain_initializer_entry(const char *domainname, error = -ENOENT; goto out; } - new_entry = tomoyo_alloc_element(sizeof(*new_entry)); - if (!new_entry) + if (!tomoyo_memory_ok(new_entry)) goto out; new_entry->domainname = saved_domainname; new_entry->program = saved_program; new_entry->is_not = is_not; new_entry->is_last_name = is_last_name; list_add_tail_rcu(&new_entry->list, &tomoyo_domain_initializer_list); + new_entry = NULL; error = 0; out: mutex_unlock(&tomoyo_policy_lock); + kfree(new_entry); return error; } @@ -461,6 +463,7 @@ static int tomoyo_update_domain_keeper_entry(const char *domainname, saved_domainname = tomoyo_save_name(domainname); if (!saved_domainname) return -ENOMEM; + new_entry = kmalloc(sizeof(*new_entry), GFP_KERNEL); mutex_lock(&tomoyo_policy_lock); list_for_each_entry_rcu(ptr, &tomoyo_domain_keeper_list, list) { if (ptr->is_not != is_not || @@ -475,17 +478,18 @@ static int tomoyo_update_domain_keeper_entry(const char *domainname, error = -ENOENT; goto out; } - new_entry = tomoyo_alloc_element(sizeof(*new_entry)); - if (!new_entry) + if (!tomoyo_memory_ok(new_entry)) goto out; new_entry->domainname = saved_domainname; new_entry->program = saved_program; new_entry->is_not = is_not; new_entry->is_last_name = is_last_name; list_add_tail_rcu(&new_entry->list, &tomoyo_domain_keeper_list); + new_entry = NULL; error = 0; out: mutex_unlock(&tomoyo_policy_lock); + kfree(new_entry); return error; } @@ -650,6 +654,7 @@ static int tomoyo_update_alias_entry(const char *original_name, saved_aliased_name = tomoyo_save_name(aliased_name); if (!saved_original_name || !saved_aliased_name) return -ENOMEM; + new_entry = kmalloc(sizeof(*new_entry), GFP_KERNEL); mutex_lock(&tomoyo_policy_lock); list_for_each_entry_rcu(ptr, &tomoyo_alias_list, list) { if (ptr->original_name != saved_original_name || @@ -663,15 +668,16 @@ static int tomoyo_update_alias_entry(const char *original_name, error = -ENOENT; goto out; } - new_entry = tomoyo_alloc_element(sizeof(*new_entry)); - if (!new_entry) + if (!tomoyo_memory_ok(new_entry)) goto out; new_entry->original_name = saved_original_name; new_entry->aliased_name = saved_aliased_name; list_add_tail_rcu(&new_entry->list, &tomoyo_alias_list); + new_entry = NULL; error = 0; out: mutex_unlock(&tomoyo_policy_lock); + kfree(new_entry); return error; } @@ -738,7 +744,7 @@ struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char * domainname, const u8 profile) { - struct tomoyo_domain_info *domain = NULL; + struct tomoyo_domain_info *domain; const struct tomoyo_path_info *saved_domainname; mutex_lock(&tomoyo_policy_lock); @@ -750,43 +756,17 @@ struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char * saved_domainname = tomoyo_save_name(domainname); if (!saved_domainname) goto out; - /* Can I reuse memory of deleted domain? */ - list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) { - struct task_struct *p; - struct tomoyo_acl_info *ptr; - bool flag; - if (!domain->is_deleted || - domain->domainname != saved_domainname) - continue; - flag = false; - read_lock(&tasklist_lock); - for_each_process(p) { - if (tomoyo_real_domain(p) != domain) - continue; - flag = true; - break; - } - read_unlock(&tasklist_lock); - if (flag) - continue; - list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { - ptr->type |= TOMOYO_ACL_DELETED; - } - tomoyo_set_domain_flag(domain, true, domain->flags); - domain->profile = profile; - domain->quota_warned = false; - mb(); /* Avoid out-of-order execution. */ - domain->is_deleted = false; - goto out; - } - /* No memory reusable. Create using new memory. */ - domain = tomoyo_alloc_element(sizeof(*domain)); - if (domain) { + domain = kmalloc(sizeof(*domain), GFP_KERNEL); + if (tomoyo_memory_ok(domain)) { INIT_LIST_HEAD(&domain->acl_info_list); domain->domainname = saved_domainname; domain->profile = profile; list_add_tail_rcu(&domain->list, &tomoyo_domain_list); + } else { + kfree(domain); + domain = NULL; } + out: mutex_unlock(&tomoyo_policy_lock); return domain; diff --git a/security/tomoyo/file.c b/security/tomoyo/file.c index 5d1689d6e16..075392c052b 100644 --- a/security/tomoyo/file.c +++ b/security/tomoyo/file.c @@ -225,6 +225,7 @@ static int tomoyo_update_globally_readable_entry(const char *filename, saved_filename = tomoyo_save_name(filename); if (!saved_filename) return -ENOMEM; + new_entry = kmalloc(sizeof(*new_entry), GFP_KERNEL); mutex_lock(&tomoyo_policy_lock); list_for_each_entry_rcu(ptr, &tomoyo_globally_readable_list, list) { if (ptr->filename != saved_filename) @@ -237,14 +238,15 @@ static int tomoyo_update_globally_readable_entry(const char *filename, error = -ENOENT; goto out; } - new_entry = tomoyo_alloc_element(sizeof(*new_entry)); - if (!new_entry) + if (!tomoyo_memory_ok(new_entry)) goto out; new_entry->filename = saved_filename; list_add_tail_rcu(&new_entry->list, &tomoyo_globally_readable_list); + new_entry = NULL; error = 0; out: mutex_unlock(&tomoyo_policy_lock); + kfree(new_entry); return error; } @@ -372,6 +374,7 @@ static int tomoyo_update_file_pattern_entry(const char *pattern, saved_pattern = tomoyo_save_name(pattern); if (!saved_pattern) return -ENOMEM; + new_entry = kmalloc(sizeof(*new_entry), GFP_KERNEL); mutex_lock(&tomoyo_policy_lock); list_for_each_entry_rcu(ptr, &tomoyo_pattern_list, list) { if (saved_pattern != ptr->pattern) @@ -384,14 +387,15 @@ static int tomoyo_update_file_pattern_entry(const char *pattern, error = -ENOENT; goto out; } - new_entry = tomoyo_alloc_element(sizeof(*new_entry)); - if (!new_entry) + if (!tomoyo_memory_ok(new_entry)) goto out; new_entry->pattern = saved_pattern; list_add_tail_rcu(&new_entry->list, &tomoyo_pattern_list); + new_entry = NULL; error = 0; out: mutex_unlock(&tomoyo_policy_lock); + kfree(new_entry); return error; } @@ -523,6 +527,7 @@ static int tomoyo_update_no_rewrite_entry(const char *pattern, saved_pattern = tomoyo_save_name(pattern); if (!saved_pattern) return -ENOMEM; + new_entry = kmalloc(sizeof(*new_entry), GFP_KERNEL); mutex_lock(&tomoyo_policy_lock); list_for_each_entry_rcu(ptr, &tomoyo_no_rewrite_list, list) { if (ptr->pattern != saved_pattern) @@ -535,14 +540,15 @@ static int tomoyo_update_no_rewrite_entry(const char *pattern, error = -ENOENT; goto out; } - new_entry = tomoyo_alloc_element(sizeof(*new_entry)); - if (!new_entry) + if (!tomoyo_memory_ok(new_entry)) goto out; new_entry->pattern = saved_pattern; list_add_tail_rcu(&new_entry->list, &tomoyo_no_rewrite_list); + new_entry = NULL; error = 0; out: mutex_unlock(&tomoyo_policy_lock); + kfree(new_entry); return error; } @@ -901,9 +907,13 @@ static int tomoyo_update_single_path_acl(const u8 type, const char *filename, goto out; } /* Not found. Append it to the tail. */ - acl = tomoyo_alloc_acl_element(TOMOYO_TYPE_SINGLE_PATH_ACL); - if (!acl) + acl = kmalloc(sizeof(*acl), GFP_KERNEL); + if (!tomoyo_memory_ok(acl)) { + kfree(acl); + acl = NULL; goto out; + } + acl->head.type = TOMOYO_TYPE_SINGLE_PATH_ACL; if (perm <= 0xFFFF) acl->perm = perm; else @@ -995,9 +1005,13 @@ static int tomoyo_update_double_path_acl(const u8 type, const char *filename1, goto out; } /* Not found. Append it to the tail. */ - acl = tomoyo_alloc_acl_element(TOMOYO_TYPE_DOUBLE_PATH_ACL); - if (!acl) + acl = kmalloc(sizeof(*acl), GFP_KERNEL); + if (!tomoyo_memory_ok(acl)) { + kfree(acl); + acl = NULL; goto out; + } + acl->head.type = TOMOYO_TYPE_DOUBLE_PATH_ACL; acl->perm = perm; acl->filename1 = saved_filename1; acl->filename2 = saved_filename2; diff --git a/security/tomoyo/realpath.c b/security/tomoyo/realpath.c index 9105e5e29da..54226d5be49 100644 --- a/security/tomoyo/realpath.c +++ b/security/tomoyo/realpath.c @@ -212,57 +212,32 @@ static unsigned int tomoyo_allocated_memory_for_elements; static unsigned int tomoyo_quota_for_elements; /** - * tomoyo_alloc_element - Allocate permanent memory for structures. + * tomoyo_memory_ok - Check memory quota. * - * @size: Size in bytes. + * @ptr: Pointer to allocated memory. * - * Returns pointer to allocated memory on success, NULL otherwise. + * Returns true on success, false otherwise. * - * Memory has to be zeroed. - * The RAM is chunked, so NEVER try to kfree() the returned pointer. + * Caller holds tomoyo_policy_lock. + * Memory pointed by @ptr will be zeroed on success. */ -void *tomoyo_alloc_element(const unsigned int size) +bool tomoyo_memory_ok(void *ptr) { - static char *buf; - static DEFINE_MUTEX(lock); - static unsigned int buf_used_len = PATH_MAX; - char *ptr = NULL; - /*Assumes sizeof(void *) >= sizeof(long) is true. */ - const unsigned int word_aligned_size - = roundup(size, max(sizeof(void *), sizeof(long))); - if (word_aligned_size > PATH_MAX) - return NULL; - mutex_lock(&lock); - if (buf_used_len + word_aligned_size > PATH_MAX) { - if (!tomoyo_quota_for_elements || - tomoyo_allocated_memory_for_elements - + PATH_MAX <= tomoyo_quota_for_elements) - ptr = kzalloc(PATH_MAX, GFP_KERNEL); - if (!ptr) { - printk(KERN_WARNING "ERROR: Out of memory " - "for tomoyo_alloc_element().\n"); - if (!tomoyo_policy_loaded) - panic("MAC Initialization failed.\n"); - } else { - buf = ptr; - tomoyo_allocated_memory_for_elements += PATH_MAX; - buf_used_len = word_aligned_size; - ptr = buf; - } - } else if (word_aligned_size) { - int i; - ptr = buf + buf_used_len; - buf_used_len += word_aligned_size; - for (i = 0; i < word_aligned_size; i++) { - if (!ptr[i]) - continue; - printk(KERN_ERR "WARNING: Reserved memory was tainted! " - "The system might go wrong.\n"); - ptr[i] = '\0'; - } + int allocated_len = ptr ? ksize(ptr) : 0; + bool result = false; + if (!ptr || (tomoyo_quota_for_elements && + tomoyo_allocated_memory_for_elements + + allocated_len > tomoyo_quota_for_elements)) { + printk(KERN_WARNING "ERROR: Out of memory " + "for tomoyo_alloc_element().\n"); + if (!tomoyo_policy_loaded) + panic("MAC Initialization failed.\n"); + } else { + result = true; + tomoyo_allocated_memory_for_elements += allocated_len; + memset(ptr, 0, allocated_len); } - mutex_unlock(&lock); - return ptr; + return result; } /* Memory allocated for string data in bytes. */ diff --git a/security/tomoyo/realpath.h b/security/tomoyo/realpath.h index 78217a37960..47b4f59dad6 100644 --- a/security/tomoyo/realpath.h +++ b/security/tomoyo/realpath.h @@ -36,11 +36,8 @@ char *tomoyo_realpath_nofollow(const char *pathname); /* Same with tomoyo_realpath() except that the pathname is already solved. */ char *tomoyo_realpath_from_path(struct path *path); -/* - * Allocate memory for ACL entry. - * The RAM is chunked, so NEVER try to kfree() the returned pointer. - */ -void *tomoyo_alloc_element(const unsigned int size); +/* Check memory quota. */ +bool tomoyo_memory_ok(void *ptr); /* * Keep the given name on the RAM. From 8d9525048c74786205b99f3fcd05a839721edfb7 Mon Sep 17 00:00:00 2001 From: James Morris Date: Thu, 14 Jan 2010 09:33:28 +1100 Subject: [PATCH 12/38] security: correct error returns for get/set security with private inodes Currently, the getsecurity and setsecurity operations return zero for kernel private inodes, where xattrs are not available directly to userspace. This confuses some applications, and does not conform to the man page for getxattr(2) etc., which state that these syscalls should return ENOTSUP if xattrs are not supported or disabled. Note that in the listsecurity case, we still need to return zero as we don't know which other xattr handlers may be active. For discussion of userland confusion, see: http://www.mail-archive.com/bug-coreutils@gnu.org/msg17988.html This patch corrects the error returns so that ENOTSUP is reported to userspace as required. Signed-off-by: James Morris Acked-by: Stephen Smalley Acked-by: Serge Hallyn --- security/security.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/security/security.c b/security/security.c index f2d8aa94932..440afe5eb54 100644 --- a/security/security.c +++ b/security/security.c @@ -630,14 +630,14 @@ int security_inode_killpriv(struct dentry *dentry) int security_inode_getsecurity(const struct inode *inode, const char *name, void **buffer, bool alloc) { if (unlikely(IS_PRIVATE(inode))) - return 0; + return -EOPNOTSUPP; return security_ops->inode_getsecurity(inode, name, buffer, alloc); } int security_inode_setsecurity(struct inode *inode, const char *name, const void *value, size_t size, int flags) { if (unlikely(IS_PRIVATE(inode))) - return 0; + return -EOPNOTSUPP; return security_ops->inode_setsecurity(inode, name, value, size, flags); } From 19439d05b88dafc4e55d9ffce84ccc27cf8b2bcc Mon Sep 17 00:00:00 2001 From: Stephen Smalley Date: Thu, 14 Jan 2010 17:28:10 -0500 Subject: [PATCH 13/38] selinux: change the handling of unknown classes If allow_unknown==deny, SELinux treats an undefined kernel security class as an error condition rather than as a typical permission denial and thus does not allow permissions on undefined classes even when in permissive mode. Change the SELinux logic so that this case is handled as a typical permission denial, subject to the usual permissive mode and permissive domain handling. Also drop the 'requested' argument from security_compute_av() and helpers as it is a legacy of the original security server interface and is unused. Changes: - Handle permissive domains consistently by moving up the test for a permissive domain. - Make security_compute_av_user() consistent with security_compute_av(); the only difference now is that security_compute_av() performs mapping between the kernel-private class and permission indices and the policy values. In the userspace case, this mapping is handled by libselinux. - Moved avd_init inside the policy lock. Based in part on a patch by Paul Moore . Reported-by: Andrew Worsley Signed-off-by: Stephen D. Smalley Reviewed-by: Paul Moore Signed-off-by: James Morris --- security/selinux/avc.c | 5 +- security/selinux/include/security.h | 10 +- security/selinux/selinuxfs.c | 7 +- security/selinux/ss/services.c | 188 ++++++++++++---------------- 4 files changed, 89 insertions(+), 121 deletions(-) diff --git a/security/selinux/avc.c b/security/selinux/avc.c index f2dde268165..3ee9b6a8beb 100644 --- a/security/selinux/avc.c +++ b/security/selinux/avc.c @@ -746,9 +746,7 @@ int avc_has_perm_noaudit(u32 ssid, u32 tsid, else avd = &avd_entry; - rc = security_compute_av(ssid, tsid, tclass, requested, avd); - if (rc) - goto out; + security_compute_av(ssid, tsid, tclass, avd); rcu_read_lock(); node = avc_insert(ssid, tsid, tclass, avd); } else { @@ -770,7 +768,6 @@ int avc_has_perm_noaudit(u32 ssid, u32 tsid, } rcu_read_unlock(); -out: return rc; } diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h index 2553266ad79..022cf067aa3 100644 --- a/security/selinux/include/security.h +++ b/security/selinux/include/security.h @@ -96,13 +96,11 @@ struct av_decision { /* definitions of av_decision.flags */ #define AVD_FLAGS_PERMISSIVE 0x0001 -int security_compute_av(u32 ssid, u32 tsid, - u16 tclass, u32 requested, - struct av_decision *avd); +void security_compute_av(u32 ssid, u32 tsid, + u16 tclass, struct av_decision *avd); -int security_compute_av_user(u32 ssid, u32 tsid, - u16 tclass, u32 requested, - struct av_decision *avd); +void security_compute_av_user(u32 ssid, u32 tsid, + u16 tclass, struct av_decision *avd); int security_transition_sid(u32 ssid, u32 tsid, u16 tclass, u32 *out_sid); diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c index fab36fdf276..b7bb0f5ec07 100644 --- a/security/selinux/selinuxfs.c +++ b/security/selinux/selinuxfs.c @@ -494,7 +494,6 @@ static ssize_t sel_write_access(struct file *file, char *buf, size_t size) char *scon, *tcon; u32 ssid, tsid; u16 tclass; - u32 req; struct av_decision avd; ssize_t length; @@ -512,7 +511,7 @@ static ssize_t sel_write_access(struct file *file, char *buf, size_t size) goto out; length = -EINVAL; - if (sscanf(buf, "%s %s %hu %x", scon, tcon, &tclass, &req) != 4) + if (sscanf(buf, "%s %s %hu", scon, tcon, &tclass) != 3) goto out2; length = security_context_to_sid(scon, strlen(scon)+1, &ssid); @@ -522,9 +521,7 @@ static ssize_t sel_write_access(struct file *file, char *buf, size_t size) if (length < 0) goto out2; - length = security_compute_av_user(ssid, tsid, tclass, req, &avd); - if (length < 0) - goto out2; + security_compute_av_user(ssid, tsid, tclass, &avd); length = scnprintf(buf, SIMPLE_TRANSACTION_LIMIT, "%x %x %x %x %u %x", diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index 07ddc81d7b5..9ec24169ccd 100644 --- a/security/selinux/ss/services.c +++ b/security/selinux/ss/services.c @@ -87,11 +87,10 @@ static u32 latest_granting; static int context_struct_to_string(struct context *context, char **scontext, u32 *scontext_len); -static int context_struct_compute_av(struct context *scontext, - struct context *tcontext, - u16 tclass, - u32 requested, - struct av_decision *avd); +static void context_struct_compute_av(struct context *scontext, + struct context *tcontext, + u16 tclass, + struct av_decision *avd); struct selinux_mapping { u16 value; /* policy value */ @@ -196,23 +195,6 @@ static u16 unmap_class(u16 tclass) return tclass; } -static u32 unmap_perm(u16 tclass, u32 tperm) -{ - if (tclass < current_mapping_size) { - unsigned i; - u32 kperm = 0; - - for (i = 0; i < current_mapping[tclass].num_perms; i++) - if (tperm & (1<allowed) == avd->allowed) return; /* no masked permission */ @@ -569,7 +549,6 @@ static void type_attribute_bounds_av(struct context *scontext, context_struct_compute_av(scontext, &lo_tcontext, tclass, - requested, &lo_avd); if ((lo_avd.allowed & avd->allowed) == avd->allowed) return; /* no masked permission */ @@ -586,7 +565,6 @@ static void type_attribute_bounds_av(struct context *scontext, context_struct_compute_av(&lo_scontext, &lo_tcontext, tclass, - requested, &lo_avd); if ((lo_avd.allowed & avd->allowed) == avd->allowed) return; /* no masked permission */ @@ -607,11 +585,10 @@ static void type_attribute_bounds_av(struct context *scontext, * Compute access vectors based on a context structure pair for * the permissions in a particular class. */ -static int context_struct_compute_av(struct context *scontext, - struct context *tcontext, - u16 tclass, - u32 requested, - struct av_decision *avd) +static void context_struct_compute_av(struct context *scontext, + struct context *tcontext, + u16 tclass, + struct av_decision *avd) { struct constraint_node *constraint; struct role_allow *ra; @@ -622,19 +599,14 @@ static int context_struct_compute_av(struct context *scontext, struct ebitmap_node *snode, *tnode; unsigned int i, j; - /* - * Initialize the access vectors to the default values. - */ avd->allowed = 0; avd->auditallow = 0; avd->auditdeny = 0xffffffff; - avd->seqno = latest_granting; - avd->flags = 0; if (unlikely(!tclass || tclass > policydb.p_classes.nprim)) { if (printk_ratelimit()) printk(KERN_WARNING "SELinux: Invalid class %hu\n", tclass); - return -EINVAL; + return; } tclass_datum = policydb.class_val_to_struct[tclass - 1]; @@ -705,9 +677,7 @@ static int context_struct_compute_av(struct context *scontext, * permission and notice it to userspace via audit. */ type_attribute_bounds_av(scontext, tcontext, - tclass, requested, avd); - - return 0; + tclass, avd); } static int security_validtrans_handle_fail(struct context *ocontext, @@ -886,110 +856,116 @@ out: return rc; } - -static int security_compute_av_core(u32 ssid, - u32 tsid, - u16 tclass, - u32 requested, - struct av_decision *avd) +static void avd_init(struct av_decision *avd) { - struct context *scontext = NULL, *tcontext = NULL; - int rc = 0; - - scontext = sidtab_search(&sidtab, ssid); - if (!scontext) { - printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", - __func__, ssid); - return -EINVAL; - } - tcontext = sidtab_search(&sidtab, tsid); - if (!tcontext) { - printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", - __func__, tsid); - return -EINVAL; - } - - rc = context_struct_compute_av(scontext, tcontext, tclass, - requested, avd); - - /* permissive domain? */ - if (ebitmap_get_bit(&policydb.permissive_map, scontext->type)) - avd->flags |= AVD_FLAGS_PERMISSIVE; - - return rc; + avd->allowed = 0; + avd->auditallow = 0; + avd->auditdeny = 0xffffffff; + avd->seqno = latest_granting; + avd->flags = 0; } + /** * security_compute_av - Compute access vector decisions. * @ssid: source security identifier * @tsid: target security identifier * @tclass: target security class - * @requested: requested permissions * @avd: access vector decisions * * Compute a set of access vector decisions based on the * SID pair (@ssid, @tsid) for the permissions in @tclass. - * Return -%EINVAL if any of the parameters are invalid or %0 - * if the access vector decisions were computed successfully. */ -int security_compute_av(u32 ssid, - u32 tsid, - u16 orig_tclass, - u32 orig_requested, - struct av_decision *avd) +void security_compute_av(u32 ssid, + u32 tsid, + u16 orig_tclass, + struct av_decision *avd) { u16 tclass; - u32 requested; - int rc; + struct context *scontext = NULL, *tcontext = NULL; read_lock(&policy_rwlock); - + avd_init(avd); if (!ss_initialized) goto allow; - requested = unmap_perm(orig_tclass, orig_requested); + scontext = sidtab_search(&sidtab, ssid); + if (!scontext) { + printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", + __func__, ssid); + goto out; + } + + /* permissive domain? */ + if (ebitmap_get_bit(&policydb.permissive_map, scontext->type)) + avd->flags |= AVD_FLAGS_PERMISSIVE; + + tcontext = sidtab_search(&sidtab, tsid); + if (!tcontext) { + printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", + __func__, tsid); + goto out; + } + tclass = unmap_class(orig_tclass); if (unlikely(orig_tclass && !tclass)) { if (policydb.allow_unknown) goto allow; - rc = -EINVAL; goto out; } - rc = security_compute_av_core(ssid, tsid, tclass, requested, avd); + context_struct_compute_av(scontext, tcontext, tclass, avd); map_decision(orig_tclass, avd, policydb.allow_unknown); out: read_unlock(&policy_rwlock); - return rc; + return; allow: avd->allowed = 0xffffffff; - avd->auditallow = 0; - avd->auditdeny = 0xffffffff; - avd->seqno = latest_granting; - avd->flags = 0; - rc = 0; goto out; } -int security_compute_av_user(u32 ssid, - u32 tsid, - u16 tclass, - u32 requested, - struct av_decision *avd) +void security_compute_av_user(u32 ssid, + u32 tsid, + u16 tclass, + struct av_decision *avd) { - int rc; - - if (!ss_initialized) { - avd->allowed = 0xffffffff; - avd->auditallow = 0; - avd->auditdeny = 0xffffffff; - avd->seqno = latest_granting; - return 0; - } + struct context *scontext = NULL, *tcontext = NULL; read_lock(&policy_rwlock); - rc = security_compute_av_core(ssid, tsid, tclass, requested, avd); + avd_init(avd); + if (!ss_initialized) + goto allow; + + scontext = sidtab_search(&sidtab, ssid); + if (!scontext) { + printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", + __func__, ssid); + goto out; + } + + /* permissive domain? */ + if (ebitmap_get_bit(&policydb.permissive_map, scontext->type)) + avd->flags |= AVD_FLAGS_PERMISSIVE; + + tcontext = sidtab_search(&sidtab, tsid); + if (!tcontext) { + printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", + __func__, tsid); + goto out; + } + + if (unlikely(!tclass)) { + if (policydb.allow_unknown) + goto allow; + goto out; + } + + context_struct_compute_av(scontext, tcontext, tclass, avd); + out: read_unlock(&policy_rwlock); - return rc; + return; +allow: + avd->allowed = 0xffffffff; + goto out; } /* From 2f3e82d694d3d7a2db019db1bb63385fbc1066f3 Mon Sep 17 00:00:00 2001 From: Stephen Smalley Date: Thu, 7 Jan 2010 15:55:16 -0500 Subject: [PATCH 14/38] selinux: convert range transition list to a hashtab Per https://bugzilla.redhat.com/show_bug.cgi?id=548145 there are sufficient range transition rules in modern (Fedora) policy to make mls_compute_sid a significant factor on the shmem file setup path due to the length of the range_tr list. Replace the simple range_tr list with a hashtab inside the security server to help mitigate this problem. Signed-off-by: Stephen D. Smalley Signed-off-by: James Morris --- security/selinux/ss/mls.c | 18 +++--- security/selinux/ss/policydb.c | 107 ++++++++++++++++++++++++--------- security/selinux/ss/policydb.h | 6 +- 3 files changed, 88 insertions(+), 43 deletions(-) diff --git a/security/selinux/ss/mls.c b/security/selinux/ss/mls.c index e6654b543ae..443ae737014 100644 --- a/security/selinux/ss/mls.c +++ b/security/selinux/ss/mls.c @@ -513,7 +513,8 @@ int mls_compute_sid(struct context *scontext, u32 specified, struct context *newcontext) { - struct range_trans *rtr; + struct range_trans rtr; + struct mls_range *r; if (!selinux_mls_enabled) return 0; @@ -521,15 +522,12 @@ int mls_compute_sid(struct context *scontext, switch (specified) { case AVTAB_TRANSITION: /* Look for a range transition rule. */ - for (rtr = policydb.range_tr; rtr; rtr = rtr->next) { - if (rtr->source_type == scontext->type && - rtr->target_type == tcontext->type && - rtr->target_class == tclass) { - /* Set the range from the rule */ - return mls_range_set(newcontext, - &rtr->target_range); - } - } + rtr.source_type = scontext->type; + rtr.target_type = tcontext->type; + rtr.target_class = tclass; + r = hashtab_search(policydb.range_tr, &rtr); + if (r) + return mls_range_set(newcontext, r); /* Fallthrough */ case AVTAB_CHANGE: if (tclass == policydb.process_class) diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c index f03667213ea..5b92c021920 100644 --- a/security/selinux/ss/policydb.c +++ b/security/selinux/ss/policydb.c @@ -177,6 +177,21 @@ out_free_role: goto out; } +static u32 rangetr_hash(struct hashtab *h, const void *k) +{ + const struct range_trans *key = k; + return (key->source_type + (key->target_type << 3) + + (key->target_class << 5)) & (h->size - 1); +} + +static int rangetr_cmp(struct hashtab *h, const void *k1, const void *k2) +{ + const struct range_trans *key1 = k1, *key2 = k2; + return (key1->source_type != key2->source_type || + key1->target_type != key2->target_type || + key1->target_class != key2->target_class); +} + /* * Initialize a policy database structure. */ @@ -204,6 +219,10 @@ static int policydb_init(struct policydb *p) if (rc) goto out_free_symtab; + p->range_tr = hashtab_create(rangetr_hash, rangetr_cmp, 256); + if (!p->range_tr) + goto out_free_symtab; + ebitmap_init(&p->policycaps); ebitmap_init(&p->permissive_map); @@ -408,6 +427,20 @@ static void symtab_hash_eval(struct symtab *s) info.slots_used, h->size, info.max_chain_len); } } + +static void rangetr_hash_eval(struct hashtab *h) +{ + struct hashtab_info info; + + hashtab_stat(h, &info); + printk(KERN_DEBUG "SELinux: rangetr: %d entries and %d/%d buckets used, " + "longest chain length %d\n", h->nel, + info.slots_used, h->size, info.max_chain_len); +} +#else +static inline void rangetr_hash_eval(struct hashtab *h) +{ +} #endif /* @@ -612,6 +645,17 @@ static int (*destroy_f[SYM_NUM]) (void *key, void *datum, void *datap) = cat_destroy, }; +static int range_tr_destroy(void *key, void *datum, void *p) +{ + struct mls_range *rt = datum; + kfree(key); + ebitmap_destroy(&rt->level[0].cat); + ebitmap_destroy(&rt->level[1].cat); + kfree(datum); + cond_resched(); + return 0; +} + static void ocontext_destroy(struct ocontext *c, int i) { context_destroy(&c->context[0]); @@ -632,7 +676,6 @@ void policydb_destroy(struct policydb *p) int i; struct role_allow *ra, *lra = NULL; struct role_trans *tr, *ltr = NULL; - struct range_trans *rt, *lrt = NULL; for (i = 0; i < SYM_NUM; i++) { cond_resched(); @@ -693,20 +736,8 @@ void policydb_destroy(struct policydb *p) } kfree(lra); - for (rt = p->range_tr; rt; rt = rt->next) { - cond_resched(); - if (lrt) { - ebitmap_destroy(&lrt->target_range.level[0].cat); - ebitmap_destroy(&lrt->target_range.level[1].cat); - kfree(lrt); - } - lrt = rt; - } - if (lrt) { - ebitmap_destroy(&lrt->target_range.level[0].cat); - ebitmap_destroy(&lrt->target_range.level[1].cat); - kfree(lrt); - } + hashtab_map(p->range_tr, range_tr_destroy, NULL); + hashtab_destroy(p->range_tr); if (p->type_attr_map) { for (i = 0; i < p->p_types.nprim; i++) @@ -1689,7 +1720,8 @@ int policydb_read(struct policydb *p, void *fp) u32 len, len2, config, nprim, nel, nel2; char *policydb_str; struct policydb_compat_info *info; - struct range_trans *rt, *lrt; + struct range_trans *rt; + struct mls_range *r; config = 0; @@ -2122,44 +2154,61 @@ int policydb_read(struct policydb *p, void *fp) if (rc < 0) goto bad; nel = le32_to_cpu(buf[0]); - lrt = NULL; for (i = 0; i < nel; i++) { rt = kzalloc(sizeof(*rt), GFP_KERNEL); if (!rt) { rc = -ENOMEM; goto bad; } - if (lrt) - lrt->next = rt; - else - p->range_tr = rt; rc = next_entry(buf, fp, (sizeof(u32) * 2)); - if (rc < 0) + if (rc < 0) { + kfree(rt); goto bad; + } rt->source_type = le32_to_cpu(buf[0]); rt->target_type = le32_to_cpu(buf[1]); if (new_rangetr) { rc = next_entry(buf, fp, sizeof(u32)); - if (rc < 0) + if (rc < 0) { + kfree(rt); goto bad; + } rt->target_class = le32_to_cpu(buf[0]); } else rt->target_class = p->process_class; if (!policydb_type_isvalid(p, rt->source_type) || !policydb_type_isvalid(p, rt->target_type) || !policydb_class_isvalid(p, rt->target_class)) { + kfree(rt); rc = -EINVAL; goto bad; } - rc = mls_read_range_helper(&rt->target_range, fp); - if (rc) - goto bad; - if (!mls_range_isvalid(p, &rt->target_range)) { - printk(KERN_WARNING "SELinux: rangetrans: invalid range\n"); + r = kzalloc(sizeof(*r), GFP_KERNEL); + if (!r) { + kfree(rt); + rc = -ENOMEM; + goto bad; + } + rc = mls_read_range_helper(r, fp); + if (rc) { + kfree(rt); + kfree(r); + goto bad; + } + if (!mls_range_isvalid(p, r)) { + printk(KERN_WARNING "SELinux: rangetrans: invalid range\n"); + kfree(rt); + kfree(r); + goto bad; + } + rc = hashtab_insert(p->range_tr, rt, r); + if (rc) { + kfree(rt); + kfree(r); goto bad; } - lrt = rt; } + rangetr_hash_eval(p->range_tr); } p->type_attr_map = kmalloc(p->p_types.nprim*sizeof(struct ebitmap), GFP_KERNEL); diff --git a/security/selinux/ss/policydb.h b/security/selinux/ss/policydb.h index cdcc5700946..193736b64de 100644 --- a/security/selinux/ss/policydb.h +++ b/security/selinux/ss/policydb.h @@ -113,8 +113,6 @@ struct range_trans { u32 source_type; u32 target_type; u32 target_class; - struct mls_range target_range; - struct range_trans *next; }; /* Boolean data type */ @@ -240,8 +238,8 @@ struct policydb { fixed labeling behavior. */ struct genfs *genfs; - /* range transitions */ - struct range_trans *range_tr; + /* range transitions table (range_trans_key -> mls_range) */ + struct hashtab *range_tr; /* type -> attribute reverse mapping */ struct ebitmap *type_attr_map; From 7d52a155e38d5a165759dbbee656455861bf7801 Mon Sep 17 00:00:00 2001 From: KaiGai Kohei Date: Thu, 21 Jan 2010 15:00:15 +0900 Subject: [PATCH 15/38] selinux: remove dead code in type_attribute_bounds_av() This patch removes dead code in type_attribute_bounds_av(). Due to the historical reason, the type boundary feature is delivered from hierarchical types in libsepol, it has supported boundary features both of subject type (domain; in most cases) and target type. However, we don't have any actual use cases in bounded target types, and it tended to make conceptual confusion. So, this patch removes the dead code to apply boundary checks on the target types. I makes clear the TYPEBOUNDS restricts privileges of a certain domain bounded to any other domain. Signed-off-by: KaiGai Kohei Acked-by: Stephen Smalley -- security/selinux/ss/services.c | 43 +++------------------------------------ 1 files changed, 4 insertions(+), 39 deletions(-) Signed-off-by: James Morris --- security/selinux/ss/services.c | 43 ++++------------------------------ 1 file changed, 4 insertions(+), 39 deletions(-) diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index 3b42b154d87..4a2bf212057 100644 --- a/security/selinux/ss/services.c +++ b/security/selinux/ss/services.c @@ -516,16 +516,14 @@ static void type_attribute_bounds_av(struct context *scontext, u16 tclass, struct av_decision *avd) { - struct context lo_scontext; - struct context lo_tcontext; - struct av_decision lo_avd; struct type_datum *source = policydb.type_val_to_struct[scontext->type - 1]; - struct type_datum *target - = policydb.type_val_to_struct[tcontext->type - 1]; - u32 masked = 0; if (source->bounds) { + struct context lo_scontext; + struct av_decision lo_avd; + u32 masked; + memset(&lo_avd, 0, sizeof(lo_avd)); memcpy(&lo_scontext, scontext, sizeof(lo_scontext)); @@ -538,40 +536,7 @@ static void type_attribute_bounds_av(struct context *scontext, if ((lo_avd.allowed & avd->allowed) == avd->allowed) return; /* no masked permission */ masked = ~lo_avd.allowed & avd->allowed; - } - if (target->bounds) { - memset(&lo_avd, 0, sizeof(lo_avd)); - - memcpy(&lo_tcontext, tcontext, sizeof(lo_tcontext)); - lo_tcontext.type = target->bounds; - - context_struct_compute_av(scontext, - &lo_tcontext, - tclass, - &lo_avd); - if ((lo_avd.allowed & avd->allowed) == avd->allowed) - return; /* no masked permission */ - masked = ~lo_avd.allowed & avd->allowed; - } - - if (source->bounds && target->bounds) { - memset(&lo_avd, 0, sizeof(lo_avd)); - /* - * lo_scontext and lo_tcontext are already - * set up. - */ - - context_struct_compute_av(&lo_scontext, - &lo_tcontext, - tclass, - &lo_avd); - if ((lo_avd.allowed & avd->allowed) == avd->allowed) - return; /* no masked permission */ - masked = ~lo_avd.allowed & avd->allowed; - } - - if (masked) { /* mask violated permissions */ avd->allowed &= ~masked; From 8e2d39a1665e680c095545993aac2fcac6916eb9 Mon Sep 17 00:00:00 2001 From: Tetsuo Handa Date: Tue, 26 Jan 2010 20:45:27 +0900 Subject: [PATCH 16/38] TOMOYO: Remove usage counter for temporary memory. TOMOYO was using own memory usage counter for detecting memory leak. But as kernel 2.6.31 introduced memory leak detection mechanism ( CONFIG_DEBUG_KMEMLEAK ), we no longer need to have own counter. We remove usage counter for memory used for permission checks, but we keep usage counter for memory used for policy so that we can apply quota. Signed-off-by: Tetsuo Handa Signed-off-by: James Morris --- security/tomoyo/common.c | 22 +++++++++---------- security/tomoyo/common.h | 2 +- security/tomoyo/domain.c | 8 +++---- security/tomoyo/file.c | 15 +++++++------ security/tomoyo/realpath.c | 45 ++++---------------------------------- security/tomoyo/realpath.h | 8 +------ 6 files changed, 29 insertions(+), 71 deletions(-) diff --git a/security/tomoyo/common.c b/security/tomoyo/common.c index e331e699cf5..ef6622300a8 100644 --- a/security/tomoyo/common.c +++ b/security/tomoyo/common.c @@ -750,7 +750,7 @@ bool tomoyo_io_printf(struct tomoyo_io_buffer *head, const char *fmt, ...) * * Returns the tomoyo_realpath() of current process on success, NULL otherwise. * - * This function uses tomoyo_alloc(), so the caller must call tomoyo_free() + * This function uses kzalloc(), so the caller must call kfree() * if this function didn't return NULL. */ static const char *tomoyo_get_exe(void) @@ -1248,7 +1248,7 @@ static bool tomoyo_is_policy_manager(void) last_pid = pid; } } - tomoyo_free(exe); + kfree(exe); return found; } @@ -1931,7 +1931,7 @@ static int tomoyo_read_self_domain(struct tomoyo_io_buffer *head) */ static int tomoyo_open_control(const u8 type, struct file *file) { - struct tomoyo_io_buffer *head = tomoyo_alloc(sizeof(*head)); + struct tomoyo_io_buffer *head = kzalloc(sizeof(*head), GFP_KERNEL); if (!head) return -ENOMEM; @@ -1992,9 +1992,9 @@ static int tomoyo_open_control(const u8 type, struct file *file) } else { if (!head->readbuf_size) head->readbuf_size = 4096 * 2; - head->read_buf = tomoyo_alloc(head->readbuf_size); + head->read_buf = kzalloc(head->readbuf_size, GFP_KERNEL); if (!head->read_buf) { - tomoyo_free(head); + kfree(head); return -ENOMEM; } } @@ -2006,10 +2006,10 @@ static int tomoyo_open_control(const u8 type, struct file *file) head->write = NULL; } else if (head->write) { head->writebuf_size = 4096 * 2; - head->write_buf = tomoyo_alloc(head->writebuf_size); + head->write_buf = kzalloc(head->writebuf_size, GFP_KERNEL); if (!head->write_buf) { - tomoyo_free(head->read_buf); - tomoyo_free(head); + kfree(head->read_buf); + kfree(head); return -ENOMEM; } } @@ -2141,11 +2141,11 @@ static int tomoyo_close_control(struct file *file) tomoyo_read_unlock(head->reader_idx); /* Release memory used for policy I/O. */ - tomoyo_free(head->read_buf); + kfree(head->read_buf); head->read_buf = NULL; - tomoyo_free(head->write_buf); + kfree(head->write_buf); head->write_buf = NULL; - tomoyo_free(head); + kfree(head); head = NULL; file->private_data = NULL; return 0; diff --git a/security/tomoyo/common.h b/security/tomoyo/common.h index 610a6a05682..8b59ec8fe11 100644 --- a/security/tomoyo/common.h +++ b/security/tomoyo/common.h @@ -89,7 +89,7 @@ struct tomoyo_path_info { * "struct tomoyo_path_info_with_data". */ struct tomoyo_path_info_with_data { - /* Keep "head" first, for this pointer is passed to tomoyo_free(). */ + /* 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]; diff --git a/security/tomoyo/domain.c b/security/tomoyo/domain.c index a55a1cced58..34843971cc6 100644 --- a/security/tomoyo/domain.c +++ b/security/tomoyo/domain.c @@ -787,7 +787,7 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm) * This function assumes that the size of buffer returned by * tomoyo_realpath() = TOMOYO_MAX_PATHNAME_LEN. */ - struct tomoyo_page_buffer *tmp = tomoyo_alloc(sizeof(*tmp)); + struct tomoyo_page_buffer *tmp = kzalloc(sizeof(*tmp), GFP_KERNEL); struct tomoyo_domain_info *old_domain = tomoyo_domain(); struct tomoyo_domain_info *domain = NULL; const char *old_domain_name = old_domain->domainname->name; @@ -902,8 +902,8 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm) if (!domain) domain = old_domain; bprm->cred->security = domain; - tomoyo_free(real_program_name); - tomoyo_free(symlink_program_name); - tomoyo_free(tmp); + kfree(real_program_name); + kfree(symlink_program_name); + kfree(tmp); return retval; } diff --git a/security/tomoyo/file.c b/security/tomoyo/file.c index cfcb096ee97..24af081f1af 100644 --- a/security/tomoyo/file.c +++ b/security/tomoyo/file.c @@ -150,7 +150,8 @@ static bool tomoyo_strendswith(const char *name, const char *tail) static struct tomoyo_path_info *tomoyo_get_path(struct path *path) { int error; - struct tomoyo_path_info_with_data *buf = tomoyo_alloc(sizeof(*buf)); + struct tomoyo_path_info_with_data *buf = kzalloc(sizeof(*buf), + GFP_KERNEL); if (!buf) return NULL; @@ -162,7 +163,7 @@ static struct tomoyo_path_info *tomoyo_get_path(struct path *path) tomoyo_fill_path_info(&buf->head); return &buf->head; } - tomoyo_free(buf); + kfree(buf); return NULL; } @@ -1227,7 +1228,7 @@ int tomoyo_check_open_permission(struct tomoyo_domain_info *domain, TOMOYO_TYPE_TRUNCATE_ACL, buf, mode); out: - tomoyo_free(buf); + kfree(buf); tomoyo_read_unlock(idx); if (!is_enforce) error = 0; @@ -1273,7 +1274,7 @@ int tomoyo_check_1path_perm(struct tomoyo_domain_info *domain, error = tomoyo_check_single_path_permission2(domain, operation, buf, mode); out: - tomoyo_free(buf); + kfree(buf); tomoyo_read_unlock(idx); if (!is_enforce) error = 0; @@ -1312,7 +1313,7 @@ int tomoyo_check_rewrite_permission(struct tomoyo_domain_info *domain, TOMOYO_TYPE_REWRITE_ACL, buf, mode); out: - tomoyo_free(buf); + kfree(buf); tomoyo_read_unlock(idx); if (!is_enforce) error = 0; @@ -1379,8 +1380,8 @@ int tomoyo_check_2path_perm(struct tomoyo_domain_info * const domain, false); } out: - tomoyo_free(buf1); - tomoyo_free(buf2); + kfree(buf1); + kfree(buf2); tomoyo_read_unlock(idx); if (!is_enforce) error = 0; diff --git a/security/tomoyo/realpath.c b/security/tomoyo/realpath.c index 54226d5be49..92460c7ded6 100644 --- a/security/tomoyo/realpath.c +++ b/security/tomoyo/realpath.c @@ -150,12 +150,12 @@ int tomoyo_realpath_from_path2(struct path *path, char *newname, * * Returns the realpath of the given @path on success, NULL otherwise. * - * These functions use tomoyo_alloc(), so the caller must call tomoyo_free() + * 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 = tomoyo_alloc(sizeof(struct tomoyo_page_buffer)); + char *buf = kzalloc(sizeof(struct tomoyo_page_buffer), GFP_KERNEL); BUILD_BUG_ON(sizeof(struct tomoyo_page_buffer) <= TOMOYO_MAX_PATHNAME_LEN - 1); @@ -164,7 +164,7 @@ char *tomoyo_realpath_from_path(struct path *path) if (tomoyo_realpath_from_path2(path, buf, TOMOYO_MAX_PATHNAME_LEN - 1) == 0) return buf; - tomoyo_free(buf); + kfree(buf); return NULL; } @@ -346,39 +346,6 @@ void __init tomoyo_realpath_init(void) panic("Can't register tomoyo_kernel_domain"); } -/* Memory allocated for temporary purpose. */ -static atomic_t tomoyo_dynamic_memory_size; - -/** - * tomoyo_alloc - Allocate memory for temporary purpose. - * - * @size: Size in bytes. - * - * Returns pointer to allocated memory on success, NULL otherwise. - */ -void *tomoyo_alloc(const size_t size) -{ - void *p = kzalloc(size, GFP_KERNEL); - if (p) - atomic_add(ksize(p), &tomoyo_dynamic_memory_size); - return p; -} - -/** - * tomoyo_free - Release memory allocated by tomoyo_alloc(). - * - * @p: Pointer returned by tomoyo_alloc(). May be NULL. - * - * Returns nothing. - */ -void tomoyo_free(const void *p) -{ - if (p) { - atomic_sub(ksize(p), &tomoyo_dynamic_memory_size); - kfree(p); - } -} - /** * tomoyo_read_memory_counter - Check for memory usage in bytes. * @@ -393,8 +360,6 @@ int tomoyo_read_memory_counter(struct tomoyo_io_buffer *head) = tomoyo_allocated_memory_for_savename; const unsigned int private = tomoyo_allocated_memory_for_elements; - const unsigned int dynamic - = atomic_read(&tomoyo_dynamic_memory_size); char buffer[64]; memset(buffer, 0, sizeof(buffer)); @@ -412,9 +377,7 @@ int tomoyo_read_memory_counter(struct tomoyo_io_buffer *head) else buffer[0] = '\0'; tomoyo_io_printf(head, "Private: %10u%s\n", private, buffer); - tomoyo_io_printf(head, "Dynamic: %10u\n", dynamic); - tomoyo_io_printf(head, "Total: %10u\n", - shared + private + dynamic); + tomoyo_io_printf(head, "Total: %10u\n", shared + private); head->read_eof = true; } return 0; diff --git a/security/tomoyo/realpath.h b/security/tomoyo/realpath.h index 47b4f59dad6..da4f06ff6f8 100644 --- a/security/tomoyo/realpath.h +++ b/security/tomoyo/realpath.h @@ -25,7 +25,7 @@ int tomoyo_realpath_from_path2(struct path *path, char *newname, /* * Returns realpath(3) of the given pathname but ignores chroot'ed root. - * These functions use tomoyo_alloc(), so the caller must call tomoyo_free() + * These functions use kzalloc(), so the caller must call kfree() * if these functions didn't return NULL. */ char *tomoyo_realpath(const char *pathname); @@ -45,12 +45,6 @@ bool tomoyo_memory_ok(void *ptr); */ const struct tomoyo_path_info *tomoyo_save_name(const char *name); -/* Allocate memory for temporary use (e.g. permission checks). */ -void *tomoyo_alloc(const size_t size); - -/* Free memory allocated by tomoyo_alloc(). */ -void tomoyo_free(const void *p); - /* Check for memory usage. */ int tomoyo_read_memory_counter(struct tomoyo_io_buffer *head); From b6cac5a30b325e14cda425670bb3568d3cad0aa8 Mon Sep 17 00:00:00 2001 From: Stephen Smalley Date: Tue, 2 Feb 2010 11:31:51 -0500 Subject: [PATCH 17/38] selinux: Only audit permissions specified in policy Only audit the permissions specified by the policy rules. Before: type=AVC msg=audit(01/28/2010 14:30:46.690:3250) : avc: denied { read append } for pid=14092 comm=foo name=test_file dev=dm-1 ino=132932 scontext=unconfined_u:unconfined_r:load_policy_t:s0-s0:c0.c1023 tcontext=unconfined_u:object_r:rpm_tmp_t:s0 tclass=file After: type=AVC msg=audit(01/28/2010 14:52:37.448:26) : avc: denied { append } for pid=1917 comm=foo name=test_file dev=dm-1 ino=132932 scontext=unconfined_u:unconfined_r:load_policy_t:s0-s0:c0.c1023 tcontext=unconfined_u:object_r:rpm_tmp_t:s0 tclass=file Reference: https://bugzilla.redhat.com/show_bug.cgi?id=558499 Reported-by: Tom London Signed-off-by: Stephen D. Smalley Signed-off-by: James Morris --- security/selinux/avc.c | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/security/selinux/avc.c b/security/selinux/avc.c index 3ee9b6a8beb..db0fd9f3349 100644 --- a/security/selinux/avc.c +++ b/security/selinux/avc.c @@ -489,17 +489,14 @@ void avc_audit(u32 ssid, u32 tsid, struct common_audit_data stack_data; u32 denied, audited; denied = requested & ~avd->allowed; - if (denied) { - audited = denied; - if (!(audited & avd->auditdeny)) - return; - } else if (result) { + if (denied) + audited = denied & avd->auditdeny; + else if (result) audited = denied = requested; - } else { - audited = requested; - if (!(audited & avd->auditallow)) - return; - } + else + audited = requested & avd->auditallow; + if (!audited) + return; if (!a) { a = &stack_data; memset(a, 0, sizeof(*a)); From 42596eafdd75257a640f64701b9b07090bcd84b0 Mon Sep 17 00:00:00 2001 From: Guido Trentalancia Date: Wed, 3 Feb 2010 17:06:01 +0100 Subject: [PATCH 18/38] selinux: load the initial SIDs upon every policy load Always load the initial SIDs, even in the case of a policy reload and not just at the initial policy load. This comes particularly handy after the introduction of a recent patch for enabling runtime switching between different policy types, although this patch is in theory independent from that feature. Signed-off-by: Guido Trentalancia Acked-by: Stephen Smalley Signed-off-by: James Morris --- security/selinux/ss/services.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index 4a2bf212057..2abbc49914e 100644 --- a/security/selinux/ss/services.c +++ b/security/selinux/ss/services.c @@ -1506,7 +1506,10 @@ static int clone_sid(u32 sid, { struct sidtab *s = arg; - return sidtab_insert(s, sid, context); + if (sid > SECINITSID_NUM) + return sidtab_insert(s, sid, context); + else + return 0; } static inline int convert_context_handle_invalid_context(struct context *context) @@ -1552,7 +1555,10 @@ static int convert_context(u32 key, struct user_datum *usrdatum; char *s; u32 len; - int rc; + int rc = 0; + + if (key <= SECINITSID_NUM) + goto out; args = p; @@ -1712,9 +1718,11 @@ int security_load_policy(void *data, size_t len) if (policydb_read(&newpolicydb, fp)) return -EINVAL; - if (sidtab_init(&newsidtab)) { + rc = policydb_load_isids(&newpolicydb, &newsidtab); + if (rc) { + printk(KERN_ERR "SELinux: unable to load the initial SIDs\n"); policydb_destroy(&newpolicydb); - return -ENOMEM; + return rc; } if (selinux_set_mapping(&newpolicydb, secclass_map, From 0719aaf5ead7555b7b7a4a080ebf2826a871384e Mon Sep 17 00:00:00 2001 From: Guido Trentalancia Date: Wed, 3 Feb 2010 16:40:20 +0100 Subject: [PATCH 19/38] selinux: allow MLS->non-MLS and vice versa upon policy reload Allow runtime switching between different policy types (e.g. from a MLS/MCS policy to a non-MLS/non-MCS policy or viceversa). Signed-off-by: Guido Trentalancia Acked-by: Stephen Smalley Signed-off-by: James Morris --- security/selinux/include/security.h | 3 +- security/selinux/selinuxfs.c | 3 +- security/selinux/ss/context.h | 12 ------ security/selinux/ss/mls.c | 26 ++++++------ security/selinux/ss/mls.h | 2 + security/selinux/ss/mls_types.h | 7 +--- security/selinux/ss/policydb.c | 24 ++--------- security/selinux/ss/policydb.h | 4 ++ security/selinux/ss/services.c | 62 ++++++++++++++++++++++++++--- 9 files changed, 84 insertions(+), 59 deletions(-) diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h index 022cf067aa3..1f7c2491d3d 100644 --- a/security/selinux/include/security.h +++ b/security/selinux/include/security.h @@ -57,7 +57,6 @@ struct netlbl_lsm_secattr; extern int selinux_enabled; -extern int selinux_mls_enabled; /* Policy capabilities */ enum { @@ -80,6 +79,8 @@ extern int selinux_policycap_openperm; /* limitation of boundary depth */ #define POLICYDB_BOUNDS_MAXDEPTH 4 +int security_mls_enabled(void); + int security_load_policy(void *data, size_t len); int security_policycap_supported(unsigned int req_cap); diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c index b7bb0f5ec07..a1cfc464bbb 100644 --- a/security/selinux/selinuxfs.c +++ b/security/selinux/selinuxfs.c @@ -282,7 +282,8 @@ static ssize_t sel_read_mls(struct file *filp, char __user *buf, char tmpbuf[TMPBUFLEN]; ssize_t length; - length = scnprintf(tmpbuf, TMPBUFLEN, "%d", selinux_mls_enabled); + length = scnprintf(tmpbuf, TMPBUFLEN, "%d", + security_mls_enabled()); return simple_read_from_buffer(buf, count, ppos, tmpbuf, length); } diff --git a/security/selinux/ss/context.h b/security/selinux/ss/context.h index d9dd7a2f6a8..45e8fb0515f 100644 --- a/security/selinux/ss/context.h +++ b/security/selinux/ss/context.h @@ -41,9 +41,6 @@ static inline int mls_context_cpy(struct context *dst, struct context *src) { int rc; - if (!selinux_mls_enabled) - return 0; - dst->range.level[0].sens = src->range.level[0].sens; rc = ebitmap_cpy(&dst->range.level[0].cat, &src->range.level[0].cat); if (rc) @@ -64,9 +61,6 @@ static inline int mls_context_cpy_low(struct context *dst, struct context *src) { int rc; - if (!selinux_mls_enabled) - return 0; - dst->range.level[0].sens = src->range.level[0].sens; rc = ebitmap_cpy(&dst->range.level[0].cat, &src->range.level[0].cat); if (rc) @@ -82,9 +76,6 @@ out: static inline int mls_context_cmp(struct context *c1, struct context *c2) { - if (!selinux_mls_enabled) - return 1; - return ((c1->range.level[0].sens == c2->range.level[0].sens) && ebitmap_cmp(&c1->range.level[0].cat, &c2->range.level[0].cat) && (c1->range.level[1].sens == c2->range.level[1].sens) && @@ -93,9 +84,6 @@ static inline int mls_context_cmp(struct context *c1, struct context *c2) static inline void mls_context_destroy(struct context *c) { - if (!selinux_mls_enabled) - return; - ebitmap_destroy(&c->range.level[0].cat); ebitmap_destroy(&c->range.level[1].cat); mls_context_init(c); diff --git a/security/selinux/ss/mls.c b/security/selinux/ss/mls.c index 443ae737014..372b773f821 100644 --- a/security/selinux/ss/mls.c +++ b/security/selinux/ss/mls.c @@ -39,7 +39,7 @@ int mls_compute_context_len(struct context *context) struct ebitmap *e; struct ebitmap_node *node; - if (!selinux_mls_enabled) + if (!policydb.mls_enabled) return 0; len = 1; /* for the beginning ":" */ @@ -93,7 +93,7 @@ void mls_sid_to_context(struct context *context, struct ebitmap *e; struct ebitmap_node *node; - if (!selinux_mls_enabled) + if (!policydb.mls_enabled) return; scontextp = *scontext; @@ -200,7 +200,7 @@ int mls_context_isvalid(struct policydb *p, struct context *c) { struct user_datum *usrdatum; - if (!selinux_mls_enabled) + if (!p->mls_enabled) return 1; if (!mls_range_isvalid(p, &c->range)) @@ -253,7 +253,7 @@ int mls_context_to_sid(struct policydb *pol, struct cat_datum *catdatum, *rngdatum; int l, rc = -EINVAL; - if (!selinux_mls_enabled) { + if (!pol->mls_enabled) { if (def_sid != SECSID_NULL && oldc) *scontext += strlen(*scontext)+1; return 0; @@ -387,7 +387,7 @@ int mls_from_string(char *str, struct context *context, gfp_t gfp_mask) char *tmpstr, *freestr; int rc; - if (!selinux_mls_enabled) + if (!policydb.mls_enabled) return -EINVAL; /* we need freestr because mls_context_to_sid will change @@ -407,7 +407,7 @@ int mls_from_string(char *str, struct context *context, gfp_t gfp_mask) /* * Copies the MLS range `range' into `context'. */ -static inline int mls_range_set(struct context *context, +int mls_range_set(struct context *context, struct mls_range *range) { int l, rc = 0; @@ -427,7 +427,7 @@ static inline int mls_range_set(struct context *context, int mls_setup_user_range(struct context *fromcon, struct user_datum *user, struct context *usercon) { - if (selinux_mls_enabled) { + if (policydb.mls_enabled) { struct mls_level *fromcon_sen = &(fromcon->range.level[0]); struct mls_level *fromcon_clr = &(fromcon->range.level[1]); struct mls_level *user_low = &(user->range.level[0]); @@ -477,7 +477,7 @@ int mls_convert_context(struct policydb *oldp, struct ebitmap_node *node; int l, i; - if (!selinux_mls_enabled) + if (!policydb.mls_enabled) return 0; for (l = 0; l < 2; l++) { @@ -516,7 +516,7 @@ int mls_compute_sid(struct context *scontext, struct range_trans rtr; struct mls_range *r; - if (!selinux_mls_enabled) + if (!policydb.mls_enabled) return 0; switch (specified) { @@ -559,7 +559,7 @@ int mls_compute_sid(struct context *scontext, void mls_export_netlbl_lvl(struct context *context, struct netlbl_lsm_secattr *secattr) { - if (!selinux_mls_enabled) + if (!policydb.mls_enabled) return; secattr->attr.mls.lvl = context->range.level[0].sens - 1; @@ -579,7 +579,7 @@ void mls_export_netlbl_lvl(struct context *context, void mls_import_netlbl_lvl(struct context *context, struct netlbl_lsm_secattr *secattr) { - if (!selinux_mls_enabled) + if (!policydb.mls_enabled) return; context->range.level[0].sens = secattr->attr.mls.lvl + 1; @@ -601,7 +601,7 @@ int mls_export_netlbl_cat(struct context *context, { int rc; - if (!selinux_mls_enabled) + if (!policydb.mls_enabled) return 0; rc = ebitmap_netlbl_export(&context->range.level[0].cat, @@ -629,7 +629,7 @@ int mls_import_netlbl_cat(struct context *context, { int rc; - if (!selinux_mls_enabled) + if (!policydb.mls_enabled) return 0; rc = ebitmap_netlbl_import(&context->range.level[0].cat, diff --git a/security/selinux/ss/mls.h b/security/selinux/ss/mls.h index 1276715aaa8..cd9152632e5 100644 --- a/security/selinux/ss/mls.h +++ b/security/selinux/ss/mls.h @@ -39,6 +39,8 @@ int mls_context_to_sid(struct policydb *p, int mls_from_string(char *str, struct context *context, gfp_t gfp_mask); +int mls_range_set(struct context *context, struct mls_range *range); + int mls_convert_context(struct policydb *oldp, struct policydb *newp, struct context *context); diff --git a/security/selinux/ss/mls_types.h b/security/selinux/ss/mls_types.h index b6e943a2106..03bed52a805 100644 --- a/security/selinux/ss/mls_types.h +++ b/security/selinux/ss/mls_types.h @@ -15,6 +15,7 @@ #define _SS_MLS_TYPES_H_ #include "security.h" +#include "ebitmap.h" struct mls_level { u32 sens; /* sensitivity */ @@ -27,18 +28,12 @@ struct mls_range { static inline int mls_level_eq(struct mls_level *l1, struct mls_level *l2) { - if (!selinux_mls_enabled) - return 1; - return ((l1->sens == l2->sens) && ebitmap_cmp(&l1->cat, &l2->cat)); } static inline int mls_level_dom(struct mls_level *l1, struct mls_level *l2) { - if (!selinux_mls_enabled) - return 1; - return ((l1->sens >= l2->sens) && ebitmap_contains(&l1->cat, &l2->cat)); } diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c index 5b92c021920..23c6e53c102 100644 --- a/security/selinux/ss/policydb.c +++ b/security/selinux/ss/policydb.c @@ -52,8 +52,6 @@ static char *symtab_name[SYM_NUM] = { }; #endif -int selinux_mls_enabled; - static unsigned int symtab_sizes[SYM_NUM] = { 2, 32, @@ -455,7 +453,7 @@ static int policydb_index_others(struct policydb *p) printk(KERN_DEBUG "SELinux: %d users, %d roles, %d types, %d bools", p->p_users.nprim, p->p_roles.nprim, p->p_types.nprim, p->p_bools.nprim); - if (selinux_mls_enabled) + if (p->mls_enabled) printk(", %d sens, %d cats", p->p_levels.nprim, p->p_cats.nprim); printk("\n"); @@ -1717,14 +1715,12 @@ int policydb_read(struct policydb *p, void *fp) int i, j, rc; __le32 buf[4]; u32 nodebuf[8]; - u32 len, len2, config, nprim, nel, nel2; + u32 len, len2, nprim, nel, nel2; char *policydb_str; struct policydb_compat_info *info; struct range_trans *rt; struct mls_range *r; - config = 0; - rc = policydb_init(p); if (rc) goto out; @@ -1772,7 +1768,7 @@ int policydb_read(struct policydb *p, void *fp) kfree(policydb_str); policydb_str = NULL; - /* Read the version, config, and table sizes. */ + /* Read the version and table sizes. */ rc = next_entry(buf, fp, sizeof(u32)*4); if (rc < 0) goto bad; @@ -1787,13 +1783,7 @@ int policydb_read(struct policydb *p, void *fp) } if ((le32_to_cpu(buf[1]) & POLICYDB_CONFIG_MLS)) { - if (ss_initialized && !selinux_mls_enabled) { - printk(KERN_ERR "SELinux: Cannot switch between non-MLS" - " and MLS policies\n"); - goto bad; - } - selinux_mls_enabled = 1; - config |= POLICYDB_CONFIG_MLS; + p->mls_enabled = 1; if (p->policyvers < POLICYDB_VERSION_MLS) { printk(KERN_ERR "SELinux: security policydb version %d " @@ -1801,12 +1791,6 @@ int policydb_read(struct policydb *p, void *fp) p->policyvers); goto bad; } - } else { - if (ss_initialized && selinux_mls_enabled) { - printk(KERN_ERR "SELinux: Cannot switch between MLS and" - " non-MLS policies\n"); - goto bad; - } } p->reject_unknown = !!(le32_to_cpu(buf[1]) & REJECT_UNKNOWN); p->allow_unknown = !!(le32_to_cpu(buf[1]) & ALLOW_UNKNOWN); diff --git a/security/selinux/ss/policydb.h b/security/selinux/ss/policydb.h index 193736b64de..26d9adf8542 100644 --- a/security/selinux/ss/policydb.h +++ b/security/selinux/ss/policydb.h @@ -27,6 +27,8 @@ #include "symtab.h" #include "avtab.h" #include "sidtab.h" +#include "ebitmap.h" +#include "mls_types.h" #include "context.h" #include "constraint.h" @@ -185,6 +187,8 @@ struct genfs { /* The policy database */ struct policydb { + int mls_enabled; + /* symbol tables */ struct symtab symtab[SYM_NUM]; #define p_commons symtab[SYM_COMMONS] diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index 2abbc49914e..4e976f58b98 100644 --- a/security/selinux/ss/services.c +++ b/security/selinux/ss/services.c @@ -26,6 +26,10 @@ * * Added support for bounds domain and audit messaged on masked permissions * + * Updated: Guido Trentalancia + * + * Added support for runtime switching of the policy type + * * Copyright (C) 2008, 2009 NEC Corporation * Copyright (C) 2006, 2007 Hewlett-Packard Development Company, L.P. * Copyright (C) 2004-2006 Trusted Computer Solutions, Inc. @@ -232,6 +236,10 @@ static void map_decision(u16 tclass, struct av_decision *avd, } } +int security_mls_enabled(void) +{ + return policydb.mls_enabled; +} /* * Return the boolean value of a constraint expression @@ -1550,6 +1558,8 @@ static int convert_context(u32 key, { struct convert_context_args *args; struct context oldc; + struct ocontext *oc; + struct mls_range *range; struct role_datum *role; struct type_datum *typdatum; struct user_datum *usrdatum; @@ -1620,9 +1630,39 @@ static int convert_context(u32 key, goto bad; c->type = typdatum->value; - rc = mls_convert_context(args->oldp, args->newp, c); - if (rc) - goto bad; + /* Convert the MLS fields if dealing with MLS policies */ + if (args->oldp->mls_enabled && args->newp->mls_enabled) { + rc = mls_convert_context(args->oldp, args->newp, c); + if (rc) + goto bad; + } else if (args->oldp->mls_enabled && !args->newp->mls_enabled) { + /* + * Switching between MLS and non-MLS policy: + * free any storage used by the MLS fields in the + * context for all existing entries in the sidtab. + */ + mls_context_destroy(c); + } else if (!args->oldp->mls_enabled && args->newp->mls_enabled) { + /* + * Switching between non-MLS and MLS policy: + * ensure that the MLS fields of the context for all + * existing entries in the sidtab are filled in with a + * suitable default value, likely taken from one of the + * initial SIDs. + */ + oc = args->newp->ocontexts[OCON_ISID]; + while (oc && oc->sid[0] != SECINITSID_UNLABELED) + oc = oc->next; + if (!oc) { + printk(KERN_ERR "SELinux: unable to look up" + " the initial SIDs list\n"); + goto bad; + } + range = &oc->context[0].range; + rc = mls_range_set(c, range); + if (rc) + goto bad; + } /* Check the validity of the new context. */ if (!policydb_context_isvalid(args->newp, c)) { @@ -1718,6 +1758,12 @@ int security_load_policy(void *data, size_t len) if (policydb_read(&newpolicydb, fp)) return -EINVAL; + /* If switching between different policy types, log MLS status */ + if (policydb.mls_enabled && !newpolicydb.mls_enabled) + printk(KERN_INFO "SELinux: Disabling MLS support...\n"); + else if (!policydb.mls_enabled && newpolicydb.mls_enabled) + printk(KERN_INFO "SELinux: Enabling MLS support...\n"); + rc = policydb_load_isids(&newpolicydb, &newsidtab); if (rc) { printk(KERN_ERR "SELinux: unable to load the initial SIDs\n"); @@ -1749,8 +1795,12 @@ int security_load_policy(void *data, size_t len) args.oldp = &policydb; args.newp = &newpolicydb; rc = sidtab_map(&newsidtab, convert_context, &args); - if (rc) + if (rc) { + printk(KERN_ERR "SELinux: unable to convert the internal" + " representation of contexts in the new SID" + " table\n"); goto err; + } /* Save the old policydb and SID table to free later. */ memcpy(&oldpolicydb, &policydb, sizeof policydb); @@ -2346,7 +2396,7 @@ int security_sid_mls_copy(u32 sid, u32 mls_sid, u32 *new_sid) u32 len; int rc = 0; - if (!ss_initialized || !selinux_mls_enabled) { + if (!ss_initialized || !policydb.mls_enabled) { *new_sid = sid; goto out; } @@ -2447,7 +2497,7 @@ int security_net_peersid_resolve(u32 nlbl_sid, u32 nlbl_type, /* we don't need to check ss_initialized here since the only way both * nlbl_sid and xfrm_sid are not equal to SECSID_NULL would be if the * security server was initialized and ss_initialized was true */ - if (!selinux_mls_enabled) { + if (!policydb.mls_enabled) { *peer_sid = SECSID_NULL; return 0; } From 002345925e6c45861f60db6f4fc6236713fd8847 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Wed, 3 Feb 2010 15:36:43 -0800 Subject: [PATCH 20/38] syslog: distinguish between /proc/kmsg and syscalls This allows the LSM to distinguish between syslog functions originating from /proc/kmsg access and direct syscalls. By default, the commoncaps will now no longer require CAP_SYS_ADMIN to read an opened /proc/kmsg file descriptor. For example the kernel syslog reader can now drop privileges after opening /proc/kmsg, instead of staying privileged with CAP_SYS_ADMIN. MAC systems that implement security_syslog have unchanged behavior. Signed-off-by: Kees Cook Acked-by: Serge Hallyn Acked-by: John Johansen Signed-off-by: James Morris --- fs/proc/kmsg.c | 14 +++++++------- include/linux/security.h | 11 ++++++----- include/linux/syslog.h | 29 +++++++++++++++++++++++++++++ kernel/printk.c | 7 ++++--- security/commoncap.c | 7 ++++++- security/security.c | 4 ++-- security/selinux/hooks.c | 5 +++-- security/smack/smack_lsm.c | 4 ++-- 8 files changed, 59 insertions(+), 22 deletions(-) create mode 100644 include/linux/syslog.h diff --git a/fs/proc/kmsg.c b/fs/proc/kmsg.c index 7ca78346d3f..6a3d843a108 100644 --- a/fs/proc/kmsg.c +++ b/fs/proc/kmsg.c @@ -12,37 +12,37 @@ #include #include #include +#include #include #include extern wait_queue_head_t log_wait; -extern int do_syslog(int type, char __user *bug, int count); - static int kmsg_open(struct inode * inode, struct file * file) { - return do_syslog(1,NULL,0); + return do_syslog(1, NULL, 0, SYSLOG_FROM_FILE); } static int kmsg_release(struct inode * inode, struct file * file) { - (void) do_syslog(0,NULL,0); + (void) do_syslog(0, NULL, 0, SYSLOG_FROM_FILE); return 0; } static ssize_t kmsg_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { - if ((file->f_flags & O_NONBLOCK) && !do_syslog(9, NULL, 0)) + if ((file->f_flags & O_NONBLOCK) && + !do_syslog(9, NULL, 0, SYSLOG_FROM_FILE)) return -EAGAIN; - return do_syslog(2, buf, count); + return do_syslog(2, buf, count, SYSLOG_FROM_FILE); } static unsigned int kmsg_poll(struct file *file, poll_table *wait) { poll_wait(file, &log_wait, wait); - if (do_syslog(9, NULL, 0)) + if (do_syslog(9, NULL, 0, SYSLOG_FROM_FILE)) return POLLIN | POLLRDNORM; return 0; } diff --git a/include/linux/security.h b/include/linux/security.h index 26eca85b241..a4dc74d86ac 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -76,7 +76,7 @@ extern int cap_task_prctl(int option, unsigned long arg2, unsigned long arg3, extern int cap_task_setscheduler(struct task_struct *p, int policy, struct sched_param *lp); extern int cap_task_setioprio(struct task_struct *p, int ioprio); extern int cap_task_setnice(struct task_struct *p, int nice); -extern int cap_syslog(int type); +extern int cap_syslog(int type, bool from_file); extern int cap_vm_enough_memory(struct mm_struct *mm, long pages); struct msghdr; @@ -1349,6 +1349,7 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts) * logging to the console. * See the syslog(2) manual page for an explanation of the @type values. * @type contains the type of action. + * @from_file indicates the context of action (if it came from /proc). * Return 0 if permission is granted. * @settime: * Check permission to change the system time. @@ -1463,7 +1464,7 @@ struct security_operations { int (*sysctl) (struct ctl_table *table, int op); int (*quotactl) (int cmds, int type, int id, struct super_block *sb); int (*quota_on) (struct dentry *dentry); - int (*syslog) (int type); + int (*syslog) (int type, bool from_file); int (*settime) (struct timespec *ts, struct timezone *tz); int (*vm_enough_memory) (struct mm_struct *mm, long pages); @@ -1762,7 +1763,7 @@ int security_acct(struct file *file); int security_sysctl(struct ctl_table *table, int op); int security_quotactl(int cmds, int type, int id, struct super_block *sb); int security_quota_on(struct dentry *dentry); -int security_syslog(int type); +int security_syslog(int type, bool from_file); int security_settime(struct timespec *ts, struct timezone *tz); int security_vm_enough_memory(long pages); int security_vm_enough_memory_mm(struct mm_struct *mm, long pages); @@ -2008,9 +2009,9 @@ static inline int security_quota_on(struct dentry *dentry) return 0; } -static inline int security_syslog(int type) +static inline int security_syslog(int type, bool from_file) { - return cap_syslog(type); + return cap_syslog(type, from_file); } static inline int security_settime(struct timespec *ts, struct timezone *tz) diff --git a/include/linux/syslog.h b/include/linux/syslog.h new file mode 100644 index 00000000000..5f02b1817be --- /dev/null +++ b/include/linux/syslog.h @@ -0,0 +1,29 @@ +/* Syslog internals + * + * Copyright 2010 Canonical, Ltd. + * Author: Kees Cook + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef _LINUX_SYSLOG_H +#define _LINUX_SYSLOG_H + +#define SYSLOG_FROM_CALL 0 +#define SYSLOG_FROM_FILE 1 + +int do_syslog(int type, char __user *buf, int count, bool from_file); + +#endif /* _LINUX_SYSLOG_H */ diff --git a/kernel/printk.c b/kernel/printk.c index 17463ca2e22..809cf9a258a 100644 --- a/kernel/printk.c +++ b/kernel/printk.c @@ -35,6 +35,7 @@ #include #include #include +#include #include @@ -273,14 +274,14 @@ static inline void boot_delay_msec(void) * 9 -- Return number of unread characters in the log buffer * 10 -- Return size of the log buffer */ -int do_syslog(int type, char __user *buf, int len) +int do_syslog(int type, char __user *buf, int len, bool from_file) { unsigned i, j, limit, count; int do_clear = 0; char c; int error = 0; - error = security_syslog(type); + error = security_syslog(type, from_file); if (error) return error; @@ -417,7 +418,7 @@ out: SYSCALL_DEFINE3(syslog, int, type, char __user *, buf, int, len) { - return do_syslog(type, buf, len); + return do_syslog(type, buf, len, SYSLOG_FROM_CALL); } /* diff --git a/security/commoncap.c b/security/commoncap.c index f800fdb3de9..677fad9d5cb 100644 --- a/security/commoncap.c +++ b/security/commoncap.c @@ -27,6 +27,7 @@ #include #include #include +#include /* * If a non-root user executes a setuid-root binary in @@ -888,12 +889,16 @@ error: /** * cap_syslog - Determine whether syslog function is permitted * @type: Function requested + * @from_file: Whether this request came from an open file (i.e. /proc) * * Determine whether the current process is permitted to use a particular * syslog function, returning 0 if permission is granted, -ve if not. */ -int cap_syslog(int type) +int cap_syslog(int type, bool from_file) { + /* /proc/kmsg can open be opened by CAP_SYS_ADMIN */ + if (type != 1 && from_file) + return 0; if ((type != 3 && type != 10) && !capable(CAP_SYS_ADMIN)) return -EPERM; return 0; diff --git a/security/security.c b/security/security.c index 440afe5eb54..971092c06f3 100644 --- a/security/security.c +++ b/security/security.c @@ -203,9 +203,9 @@ int security_quota_on(struct dentry *dentry) return security_ops->quota_on(dentry); } -int security_syslog(int type) +int security_syslog(int type, bool from_file) { - return security_ops->syslog(type); + return security_ops->syslog(type, from_file); } int security_settime(struct timespec *ts, struct timezone *tz) diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 9a2ee845e9d..a4862a0730f 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -76,6 +76,7 @@ #include #include #include +#include #include "avc.h" #include "objsec.h" @@ -2049,11 +2050,11 @@ static int selinux_quota_on(struct dentry *dentry) return dentry_has_perm(cred, NULL, dentry, FILE__QUOTAON); } -static int selinux_syslog(int type) +static int selinux_syslog(int type, bool from_file) { int rc; - rc = cap_syslog(type); + rc = cap_syslog(type, from_file); if (rc) return rc; diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index 529c9ca6587..a5721b373f5 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -157,12 +157,12 @@ static int smack_ptrace_traceme(struct task_struct *ptp) * * Returns 0 on success, error code otherwise. */ -static int smack_syslog(int type) +static int smack_syslog(int type, bool from_file) { int rc; char *sp = current_security(); - rc = cap_syslog(type); + rc = cap_syslog(type, from_file); if (rc != 0) return rc; From d78ca3cd733d8a2c3dcd88471beb1a15d973eed8 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Wed, 3 Feb 2010 15:37:13 -0800 Subject: [PATCH 21/38] syslog: use defined constants instead of raw numbers Right now the syslog "type" action are just raw numbers which makes the source difficult to follow. This patch replaces the raw numbers with defined constants for some level of sanity. Signed-off-by: Kees Cook Acked-by: John Johansen Acked-by: Serge Hallyn Signed-off-by: James Morris --- fs/proc/kmsg.c | 10 ++++----- include/linux/syslog.h | 23 ++++++++++++++++++++ kernel/printk.c | 45 +++++++++++++++++----------------------- security/commoncap.c | 5 +++-- security/selinux/hooks.c | 21 ++++++++++--------- 5 files changed, 61 insertions(+), 43 deletions(-) diff --git a/fs/proc/kmsg.c b/fs/proc/kmsg.c index 6a3d843a108..cfe90a48a6e 100644 --- a/fs/proc/kmsg.c +++ b/fs/proc/kmsg.c @@ -21,12 +21,12 @@ extern wait_queue_head_t log_wait; static int kmsg_open(struct inode * inode, struct file * file) { - return do_syslog(1, NULL, 0, SYSLOG_FROM_FILE); + return do_syslog(SYSLOG_ACTION_OPEN, NULL, 0, SYSLOG_FROM_FILE); } static int kmsg_release(struct inode * inode, struct file * file) { - (void) do_syslog(0, NULL, 0, SYSLOG_FROM_FILE); + (void) do_syslog(SYSLOG_ACTION_CLOSE, NULL, 0, SYSLOG_FROM_FILE); return 0; } @@ -34,15 +34,15 @@ static ssize_t kmsg_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { if ((file->f_flags & O_NONBLOCK) && - !do_syslog(9, NULL, 0, SYSLOG_FROM_FILE)) + !do_syslog(SYSLOG_ACTION_SIZE_UNREAD, NULL, 0, SYSLOG_FROM_FILE)) return -EAGAIN; - return do_syslog(2, buf, count, SYSLOG_FROM_FILE); + return do_syslog(SYSLOG_ACTION_READ, buf, count, SYSLOG_FROM_FILE); } static unsigned int kmsg_poll(struct file *file, poll_table *wait) { poll_wait(file, &log_wait, wait); - if (do_syslog(9, NULL, 0, SYSLOG_FROM_FILE)) + if (do_syslog(SYSLOG_ACTION_SIZE_UNREAD, NULL, 0, SYSLOG_FROM_FILE)) return POLLIN | POLLRDNORM; return 0; } diff --git a/include/linux/syslog.h b/include/linux/syslog.h index 5f02b1817be..38911391a13 100644 --- a/include/linux/syslog.h +++ b/include/linux/syslog.h @@ -21,6 +21,29 @@ #ifndef _LINUX_SYSLOG_H #define _LINUX_SYSLOG_H +/* Close the log. Currently a NOP. */ +#define SYSLOG_ACTION_CLOSE 0 +/* Open the log. Currently a NOP. */ +#define SYSLOG_ACTION_OPEN 1 +/* Read from the log. */ +#define SYSLOG_ACTION_READ 2 +/* Read all messages remaining in the ring buffer. */ +#define SYSLOG_ACTION_READ_ALL 3 +/* Read and clear all messages remaining in the ring buffer */ +#define SYSLOG_ACTION_READ_CLEAR 4 +/* Clear ring buffer. */ +#define SYSLOG_ACTION_CLEAR 5 +/* Disable printk's to console */ +#define SYSLOG_ACTION_CONSOLE_OFF 6 +/* Enable printk's to console */ +#define SYSLOG_ACTION_CONSOLE_ON 7 +/* Set level of messages printed to console */ +#define SYSLOG_ACTION_CONSOLE_LEVEL 8 +/* Return number of unread characters in the log buffer */ +#define SYSLOG_ACTION_SIZE_UNREAD 9 +/* Return size of the log buffer */ +#define SYSLOG_ACTION_SIZE_BUFFER 10 + #define SYSLOG_FROM_CALL 0 #define SYSLOG_FROM_FILE 1 diff --git a/kernel/printk.c b/kernel/printk.c index 809cf9a258a..3e162d86709 100644 --- a/kernel/printk.c +++ b/kernel/printk.c @@ -259,21 +259,6 @@ static inline void boot_delay_msec(void) } #endif -/* - * Commands to do_syslog: - * - * 0 -- Close the log. Currently a NOP. - * 1 -- Open the log. Currently a NOP. - * 2 -- Read from the log. - * 3 -- Read all messages remaining in the ring buffer. - * 4 -- Read and clear all messages remaining in the ring buffer - * 5 -- Clear ring buffer. - * 6 -- Disable printk's to console - * 7 -- Enable printk's to console - * 8 -- Set level of messages printed to console - * 9 -- Return number of unread characters in the log buffer - * 10 -- Return size of the log buffer - */ int do_syslog(int type, char __user *buf, int len, bool from_file) { unsigned i, j, limit, count; @@ -286,11 +271,11 @@ int do_syslog(int type, char __user *buf, int len, bool from_file) return error; switch (type) { - case 0: /* Close log */ + case SYSLOG_ACTION_CLOSE: /* Close log */ break; - case 1: /* Open log */ + case SYSLOG_ACTION_OPEN: /* Open log */ break; - case 2: /* Read from log */ + case SYSLOG_ACTION_READ: /* Read from log */ error = -EINVAL; if (!buf || len < 0) goto out; @@ -321,10 +306,12 @@ int do_syslog(int type, char __user *buf, int len, bool from_file) if (!error) error = i; break; - case 4: /* Read/clear last kernel messages */ + /* Read/clear last kernel messages */ + case SYSLOG_ACTION_READ_CLEAR: do_clear = 1; /* FALL THRU */ - case 3: /* Read last kernel messages */ + /* Read last kernel messages */ + case SYSLOG_ACTION_READ_ALL: error = -EINVAL; if (!buf || len < 0) goto out; @@ -377,21 +364,25 @@ int do_syslog(int type, char __user *buf, int len, bool from_file) } } break; - case 5: /* Clear ring buffer */ + /* Clear ring buffer */ + case SYSLOG_ACTION_CLEAR: logged_chars = 0; break; - case 6: /* Disable logging to console */ + /* Disable logging to console */ + case SYSLOG_ACTION_CONSOLE_OFF: if (saved_console_loglevel == -1) saved_console_loglevel = console_loglevel; console_loglevel = minimum_console_loglevel; break; - case 7: /* Enable logging to console */ + /* Enable logging to console */ + case SYSLOG_ACTION_CONSOLE_ON: if (saved_console_loglevel != -1) { console_loglevel = saved_console_loglevel; saved_console_loglevel = -1; } break; - case 8: /* Set level of messages printed to console */ + /* Set level of messages printed to console */ + case SYSLOG_ACTION_CONSOLE_LEVEL: error = -EINVAL; if (len < 1 || len > 8) goto out; @@ -402,10 +393,12 @@ int do_syslog(int type, char __user *buf, int len, bool from_file) saved_console_loglevel = -1; error = 0; break; - case 9: /* Number of chars in the log buffer */ + /* Number of chars in the log buffer */ + case SYSLOG_ACTION_SIZE_UNREAD: error = log_end - log_start; break; - case 10: /* Size of the log buffer */ + /* Size of the log buffer */ + case SYSLOG_ACTION_SIZE_BUFFER: error = log_buf_len; break; default: diff --git a/security/commoncap.c b/security/commoncap.c index 677fad9d5cb..cf01b2eebb6 100644 --- a/security/commoncap.c +++ b/security/commoncap.c @@ -897,9 +897,10 @@ error: int cap_syslog(int type, bool from_file) { /* /proc/kmsg can open be opened by CAP_SYS_ADMIN */ - if (type != 1 && from_file) + if (type != SYSLOG_ACTION_OPEN && from_file) return 0; - if ((type != 3 && type != 10) && !capable(CAP_SYS_ADMIN)) + if ((type != SYSLOG_ACTION_READ_ALL && + type != SYSLOG_ACTION_SIZE_BUFFER) && !capable(CAP_SYS_ADMIN)) return -EPERM; return 0; } diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index a4862a0730f..6b36ce2eef2 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -2059,20 +2059,21 @@ static int selinux_syslog(int type, bool from_file) return rc; switch (type) { - case 3: /* Read last kernel messages */ - case 10: /* Return size of the log buffer */ + case SYSLOG_ACTION_READ_ALL: /* Read last kernel messages */ + case SYSLOG_ACTION_SIZE_BUFFER: /* Return size of the log buffer */ rc = task_has_system(current, SYSTEM__SYSLOG_READ); break; - case 6: /* Disable logging to console */ - case 7: /* Enable logging to console */ - case 8: /* Set level of messages printed to console */ + case SYSLOG_ACTION_CONSOLE_OFF: /* Disable logging to console */ + case SYSLOG_ACTION_CONSOLE_ON: /* Enable logging to console */ + /* Set level of messages printed to console */ + case SYSLOG_ACTION_CONSOLE_LEVEL: rc = task_has_system(current, SYSTEM__SYSLOG_CONSOLE); break; - case 0: /* Close log */ - case 1: /* Open log */ - case 2: /* Read from log */ - case 4: /* Read/clear last kernel messages */ - case 5: /* Clear ring buffer */ + case SYSLOG_ACTION_CLOSE: /* Close log */ + case SYSLOG_ACTION_OPEN: /* Open log */ + case SYSLOG_ACTION_READ: /* Read from log */ + case SYSLOG_ACTION_READ_CLEAR: /* Read/clear last kernel messages */ + case SYSLOG_ACTION_CLEAR: /* Clear ring buffer */ default: rc = task_has_system(current, SYSTEM__SYSLOG_MOD); break; From f40a70861ace69001524644473cc389543b06c3c Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Thu, 4 Feb 2010 14:28:06 -0800 Subject: [PATCH 22/38] syslog: clean up needless comment Drop my typoed comment as it is both unhelpful and redundant. Signed-off-by: Kees Cook Acked-by: Serge Hallyn Signed-off-by: James Morris --- security/commoncap.c | 1 - 1 file changed, 1 deletion(-) diff --git a/security/commoncap.c b/security/commoncap.c index cf01b2eebb6..61669730da9 100644 --- a/security/commoncap.c +++ b/security/commoncap.c @@ -896,7 +896,6 @@ error: */ int cap_syslog(int type, bool from_file) { - /* /proc/kmsg can open be opened by CAP_SYS_ADMIN */ if (type != SYSLOG_ACTION_OPEN && from_file) return 0; if ((type != SYSLOG_ACTION_READ_ALL && From ea13ddbad0eb4be9cdc406cd7e0804fa4011f6e4 Mon Sep 17 00:00:00 2001 From: Tetsuo Handa Date: Wed, 3 Feb 2010 06:43:06 +0900 Subject: [PATCH 23/38] TOMOYO: Extract bitfield Since list elements are rounded up to kmalloc() size rather than sizeof(int), saving one byte by using bitfields is no longer helpful. Signed-off-by: Tetsuo Handa Acked-by: Serge Hallyn Signed-off-by: James Morris --- security/tomoyo/common.c | 16 ++++-------- security/tomoyo/common.h | 53 +++++++++------------------------------- security/tomoyo/domain.c | 25 +------------------ security/tomoyo/file.c | 27 ++++++-------------- 4 files changed, 25 insertions(+), 96 deletions(-) diff --git a/security/tomoyo/common.c b/security/tomoyo/common.c index ef6622300a8..ae3ed7313ee 100644 --- a/security/tomoyo/common.c +++ b/security/tomoyo/common.c @@ -842,9 +842,7 @@ bool tomoyo_domain_quota_is_ok(struct tomoyo_domain_info * const domain) if (!domain) return true; list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { - if (ptr->type & TOMOYO_ACL_DELETED) - continue; - switch (tomoyo_acl_type2(ptr)) { + switch (ptr->type) { struct tomoyo_single_path_acl_record *acl; u32 perm; u8 i; @@ -1384,8 +1382,7 @@ static int tomoyo_write_domain_policy(struct tomoyo_io_buffer *head) return 0; } if (!strcmp(data, TOMOYO_KEYWORD_IGNORE_GLOBAL_ALLOW_READ)) { - tomoyo_set_domain_flag(domain, is_delete, - TOMOYO_DOMAIN_FLAGS_IGNORE_GLOBAL_ALLOW_READ); + domain->ignore_global_allow_read = !is_delete; return 0; } return tomoyo_write_file_policy(data, domain, is_delete); @@ -1486,10 +1483,8 @@ static bool tomoyo_print_double_path_acl(struct tomoyo_io_buffer *head, static bool tomoyo_print_entry(struct tomoyo_io_buffer *head, struct tomoyo_acl_info *ptr) { - const u8 acl_type = tomoyo_acl_type2(ptr); + const u8 acl_type = ptr->type; - if (acl_type & TOMOYO_ACL_DELETED) - return true; if (acl_type == TOMOYO_TYPE_SINGLE_PATH_ACL) { struct tomoyo_single_path_acl_record *acl = container_of(ptr, @@ -1540,10 +1535,9 @@ static int tomoyo_read_domain_policy(struct tomoyo_io_buffer *head) /* Print domainname and flags. */ if (domain->quota_warned) quota_exceeded = "quota_exceeded\n"; - if (domain->flags & TOMOYO_DOMAIN_FLAGS_TRANSITION_FAILED) + if (domain->transition_failed) transition_failed = "transition_failed\n"; - if (domain->flags & - TOMOYO_DOMAIN_FLAGS_IGNORE_GLOBAL_ALLOW_READ) + if (domain->ignore_global_allow_read) ignore_global_allow_read = TOMOYO_KEYWORD_IGNORE_GLOBAL_ALLOW_READ "\n"; done = tomoyo_io_printf(head, "%s\n" TOMOYO_KEYWORD_USE_PROFILE diff --git a/security/tomoyo/common.h b/security/tomoyo/common.h index 8b59ec8fe11..509ced9ce69 100644 --- a/security/tomoyo/common.h +++ b/security/tomoyo/common.h @@ -101,11 +101,9 @@ struct tomoyo_path_info_with_data { * * (1) "list" which is linked to the ->acl_info_list of * "struct tomoyo_domain_info" - * (2) "type" which tells - * (a) type & 0x7F : type of the entry (either - * "struct tomoyo_single_path_acl_record" or - * "struct tomoyo_double_path_acl_record") - * (b) type & 0x80 : whether the entry is marked as "deleted". + * (2) "type" which tells type of the entry (either + * "struct tomoyo_single_path_acl_record" or + * "struct tomoyo_double_path_acl_record"). * * Packing "struct tomoyo_acl_info" allows * "struct tomoyo_single_path_acl_record" to embed "u8" + "u16" and @@ -114,17 +112,9 @@ struct tomoyo_path_info_with_data { */ struct tomoyo_acl_info { struct list_head list; - /* - * Type of this ACL entry. - * - * MSB is is_deleted flag. - */ u8 type; } __packed; -/* This ACL entry is deleted. */ -#define TOMOYO_ACL_DELETED 0x80 - /* * tomoyo_domain_info is a structure which is used for holding permissions * (e.g. "allow_read /lib/libc-2.5.so") given to each domain. @@ -138,7 +128,13 @@ struct tomoyo_acl_info { * "deleted", false otherwise. * (6) "quota_warned" is a bool which is used for suppressing warning message * when learning mode learned too much entries. - * (7) "flags" which remembers this domain's attributes. + * (7) "ignore_global_allow_read" is a bool which is true if this domain + * should ignore "allow_read" directive in exception policy. + * (8) "transition_failed" is a bool which is set to true when this domain was + * unable to create a new domain at tomoyo_find_next_domain() because the + * name of the domain to be created was too long or it could not allocate + * memory. If set to true, more than one process continued execve() + * without domain transition. * * A domain's lifecycle is an analogy of files on / directory. * Multiple domains with the same domainname cannot be created (as with @@ -155,23 +151,13 @@ struct tomoyo_domain_info { u8 profile; /* Profile number to use. */ bool is_deleted; /* Delete flag. */ bool quota_warned; /* Quota warnning flag. */ - /* DOMAIN_FLAGS_*. Use tomoyo_set_domain_flag() to modify. */ - u8 flags; + bool ignore_global_allow_read; /* Ignore "allow_read" flag. */ + bool transition_failed; /* Domain transition failed flag. */ }; /* Profile number is an integer between 0 and 255. */ #define TOMOYO_MAX_PROFILES 256 -/* Ignore "allow_read" directive in exception policy. */ -#define TOMOYO_DOMAIN_FLAGS_IGNORE_GLOBAL_ALLOW_READ 1 -/* - * This domain was unable to create a new domain at tomoyo_find_next_domain() - * because the name of the domain to be created was too long or - * it could not allocate memory. - * More than one process continued execve() without domain transition. - */ -#define TOMOYO_DOMAIN_FLAGS_TRANSITION_FAILED 2 - /* * tomoyo_single_path_acl_record is a structure which is used for holding an * entry with one pathname operation (e.g. open(), mkdir()). @@ -380,9 +366,6 @@ unsigned int tomoyo_check_flags(const struct tomoyo_domain_info *domain, void tomoyo_fill_path_info(struct tomoyo_path_info *ptr); /* Run policy loader when /sbin/init starts. */ void tomoyo_load_policy(const char *filename); -/* Change "struct tomoyo_domain_info"->flags. */ -void tomoyo_set_domain_flag(struct tomoyo_domain_info *domain, - const bool is_delete, const u8 flags); /* strcmp() for "struct tomoyo_path_info" structure. */ static inline bool tomoyo_pathcmp(const struct tomoyo_path_info *a, @@ -391,18 +374,6 @@ static inline bool tomoyo_pathcmp(const struct tomoyo_path_info *a, return a->hash != b->hash || strcmp(a->name, b->name); } -/* Get type of an ACL entry. */ -static inline u8 tomoyo_acl_type1(struct tomoyo_acl_info *ptr) -{ - return ptr->type & ~TOMOYO_ACL_DELETED; -} - -/* Get type of an ACL entry. */ -static inline u8 tomoyo_acl_type2(struct tomoyo_acl_info *ptr) -{ - return ptr->type; -} - /** * tomoyo_is_valid - Check whether the character is a valid char. * diff --git a/security/tomoyo/domain.c b/security/tomoyo/domain.c index 34843971cc6..ec612ae87b5 100644 --- a/security/tomoyo/domain.c +++ b/security/tomoyo/domain.c @@ -129,28 +129,6 @@ struct tomoyo_alias_entry { bool is_deleted; }; -/** - * tomoyo_set_domain_flag - Set or clear domain's attribute flags. - * - * @domain: Pointer to "struct tomoyo_domain_info". - * @is_delete: True if it is a delete request. - * @flags: Flags to set or clear. - * - * Returns nothing. - */ -void tomoyo_set_domain_flag(struct tomoyo_domain_info *domain, - const bool is_delete, const u8 flags) -{ - /* We need to serialize because this is bitfield operation. */ - static DEFINE_SPINLOCK(lock); - spin_lock(&lock); - if (!is_delete) - domain->flags |= flags; - else - domain->flags &= ~flags; - spin_unlock(&lock); -} - /** * tomoyo_get_last_name - Get last component of a domainname. * @@ -896,8 +874,7 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm) if (is_enforce) retval = -EPERM; else - tomoyo_set_domain_flag(old_domain, false, - TOMOYO_DOMAIN_FLAGS_TRANSITION_FAILED); + old_domain->transition_failed = true; out: if (!domain) domain = old_domain; diff --git a/security/tomoyo/file.c b/security/tomoyo/file.c index 24af081f1af..84c821a245c 100644 --- a/security/tomoyo/file.c +++ b/security/tomoyo/file.c @@ -688,7 +688,7 @@ static int tomoyo_check_single_path_acl2(const struct tomoyo_domain_info * list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { struct tomoyo_single_path_acl_record *acl; - if (tomoyo_acl_type2(ptr) != TOMOYO_TYPE_SINGLE_PATH_ACL) + if (ptr->type != TOMOYO_TYPE_SINGLE_PATH_ACL) continue; acl = container_of(ptr, struct tomoyo_single_path_acl_record, head); @@ -770,8 +770,7 @@ static int tomoyo_check_file_perm2(struct tomoyo_domain_info * const domain, if (!filename) return 0; error = tomoyo_check_file_acl(domain, filename, perm); - if (error && perm == 4 && - (domain->flags & TOMOYO_DOMAIN_FLAGS_IGNORE_GLOBAL_ALLOW_READ) == 0 + if (error && perm == 4 && !domain->ignore_global_allow_read && tomoyo_is_globally_readable_file(filename)) error = 0; if (perm == 6) @@ -885,15 +884,12 @@ static int tomoyo_update_single_path_acl(const u8 type, const char *filename, if (is_delete) goto delete; list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { - if (tomoyo_acl_type1(ptr) != TOMOYO_TYPE_SINGLE_PATH_ACL) + if (ptr->type != TOMOYO_TYPE_SINGLE_PATH_ACL) continue; acl = container_of(ptr, struct tomoyo_single_path_acl_record, head); if (acl->filename != saved_filename) continue; - /* Special case. Clear all bits if marked as deleted. */ - if (ptr->type & TOMOYO_ACL_DELETED) - acl->perm = 0; if (perm <= 0xFFFF) acl->perm |= perm; else @@ -902,7 +898,6 @@ static int tomoyo_update_single_path_acl(const u8 type, const char *filename, acl->perm |= 1 << TOMOYO_TYPE_READ_WRITE_ACL; else if (acl->perm & (1 << TOMOYO_TYPE_READ_WRITE_ACL)) acl->perm |= rw_mask; - ptr->type &= ~TOMOYO_ACL_DELETED; error = 0; goto out; } @@ -927,7 +922,7 @@ static int tomoyo_update_single_path_acl(const u8 type, const char *filename, delete: error = -ENOENT; list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { - if (tomoyo_acl_type2(ptr) != TOMOYO_TYPE_SINGLE_PATH_ACL) + if (ptr->type != TOMOYO_TYPE_SINGLE_PATH_ACL) continue; acl = container_of(ptr, struct tomoyo_single_path_acl_record, head); @@ -941,8 +936,6 @@ static int tomoyo_update_single_path_acl(const u8 type, const char *filename, acl->perm &= ~(1 << TOMOYO_TYPE_READ_WRITE_ACL); else if (!(acl->perm & (1 << TOMOYO_TYPE_READ_WRITE_ACL))) acl->perm &= ~rw_mask; - if (!acl->perm && !acl->perm_high) - ptr->type |= TOMOYO_ACL_DELETED; error = 0; break; } @@ -989,18 +982,14 @@ static int tomoyo_update_double_path_acl(const u8 type, const char *filename1, if (is_delete) goto delete; list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { - if (tomoyo_acl_type1(ptr) != TOMOYO_TYPE_DOUBLE_PATH_ACL) + if (ptr->type != TOMOYO_TYPE_DOUBLE_PATH_ACL) continue; acl = container_of(ptr, struct tomoyo_double_path_acl_record, head); if (acl->filename1 != saved_filename1 || acl->filename2 != saved_filename2) continue; - /* Special case. Clear all bits if marked as deleted. */ - if (ptr->type & TOMOYO_ACL_DELETED) - acl->perm = 0; acl->perm |= perm; - ptr->type &= ~TOMOYO_ACL_DELETED; error = 0; goto out; } @@ -1021,7 +1010,7 @@ static int tomoyo_update_double_path_acl(const u8 type, const char *filename1, delete: error = -ENOENT; list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { - if (tomoyo_acl_type2(ptr) != TOMOYO_TYPE_DOUBLE_PATH_ACL) + if (ptr->type != TOMOYO_TYPE_DOUBLE_PATH_ACL) continue; acl = container_of(ptr, struct tomoyo_double_path_acl_record, head); @@ -1029,8 +1018,6 @@ static int tomoyo_update_double_path_acl(const u8 type, const char *filename1, acl->filename2 != saved_filename2) continue; acl->perm &= ~perm; - if (!acl->perm) - ptr->type |= TOMOYO_ACL_DELETED; error = 0; break; } @@ -1086,7 +1073,7 @@ static int tomoyo_check_double_path_acl(const struct tomoyo_domain_info *domain, return 0; list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { struct tomoyo_double_path_acl_record *acl; - if (tomoyo_acl_type2(ptr) != TOMOYO_TYPE_DOUBLE_PATH_ACL) + if (ptr->type != TOMOYO_TYPE_DOUBLE_PATH_ACL) continue; acl = container_of(ptr, struct tomoyo_double_path_acl_record, head); From 8007f10259d04f37044c2c731bf9ccdd9161d825 Mon Sep 17 00:00:00 2001 From: Xiaotian Feng Date: Tue, 9 Feb 2010 08:22:24 +1100 Subject: [PATCH 24/38] selinux: fix memory leak in sel_make_bools In sel_make_bools, kernel allocates memory for bool_pending_names[i] with security_get_bools. So if we just free bool_pending_names, those memories for bool_pending_names[i] will be leaked. This patch resolves dozens of following kmemleak report after resuming from suspend: unreferenced object 0xffff88022e4c7380 (size 32): comm "init", pid 1, jiffies 4294677173 backtrace: [] create_object+0x1a2/0x2a9 [] kmemleak_alloc+0x26/0x4b [] __kmalloc+0x18f/0x1b8 [] security_get_bools+0xd7/0x16f [] sel_write_load+0x12e/0x62b [] vfs_write+0xae/0x10b [] sys_write+0x4a/0x6e [] system_call_fastpath+0x16/0x1b [] 0xffffffffffffffff Signed-off-by: Xiaotian Feng Signed-off-by: James Morris --- security/selinux/selinuxfs.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c index a1cfc464bbb..cd191bbec03 100644 --- a/security/selinux/selinuxfs.c +++ b/security/selinux/selinuxfs.c @@ -977,6 +977,8 @@ static int sel_make_bools(void) u32 sid; /* remove any existing files */ + for (i = 0; i < bool_num; i++) + kfree(bool_pending_names[i]); kfree(bool_pending_names); kfree(bool_pending_values); bool_pending_names = NULL; From ca0b7df3374c5566468c17f26fa2dfd3fe3c6a37 Mon Sep 17 00:00:00 2001 From: Tetsuo Handa Date: Sun, 7 Feb 2010 20:23:59 +0900 Subject: [PATCH 25/38] TOMOYO: Reduce lines by using common path for addition and deletion. Since the codes for adding an entry and removing an entry are similar, we can save some lines by using "if (is_delete) { ... } else { ... }" branches. Signed-off-by: Tetsuo Handa Acked-by: Serge Hallyn Signed-off-by: James Morris --- security/tomoyo/common.c | 28 ++--- security/tomoyo/domain.c | 147 ++++++++++++------------ security/tomoyo/file.c | 242 +++++++++++++++++---------------------- 3 files changed, 187 insertions(+), 230 deletions(-) diff --git a/security/tomoyo/common.c b/security/tomoyo/common.c index ae3ed7313ee..a53ee059da4 100644 --- a/security/tomoyo/common.c +++ b/security/tomoyo/common.c @@ -1103,10 +1103,10 @@ static LIST_HEAD(tomoyo_policy_manager_list); static int tomoyo_update_manager_entry(const char *manager, const bool is_delete) { - struct tomoyo_policy_manager_entry *new_entry; + struct tomoyo_policy_manager_entry *entry = NULL; struct tomoyo_policy_manager_entry *ptr; const struct tomoyo_path_info *saved_manager; - int error = -ENOMEM; + int error = is_delete ? -ENOENT : -ENOMEM; bool is_domain = false; if (tomoyo_is_domain_def(manager)) { @@ -1120,29 +1120,25 @@ static int tomoyo_update_manager_entry(const char *manager, saved_manager = tomoyo_save_name(manager); if (!saved_manager) return -ENOMEM; - new_entry = kmalloc(sizeof(*new_entry), GFP_KERNEL); + if (!is_delete) + entry = kmalloc(sizeof(*entry), GFP_KERNEL); mutex_lock(&tomoyo_policy_lock); list_for_each_entry_rcu(ptr, &tomoyo_policy_manager_list, list) { if (ptr->manager != saved_manager) continue; ptr->is_deleted = is_delete; error = 0; - goto out; + break; } - if (is_delete) { - error = -ENOENT; - goto out; + if (!is_delete && error && tomoyo_memory_ok(entry)) { + entry->manager = saved_manager; + entry->is_domain = is_domain; + list_add_tail_rcu(&entry->list, &tomoyo_policy_manager_list); + entry = NULL; + error = 0; } - if (!tomoyo_memory_ok(new_entry)) - goto out; - new_entry->manager = saved_manager; - new_entry->is_domain = is_domain; - list_add_tail_rcu(&new_entry->list, &tomoyo_policy_manager_list); - new_entry = NULL; - error = 0; - out: mutex_unlock(&tomoyo_policy_lock); - kfree(new_entry); + kfree(entry); return error; } diff --git a/security/tomoyo/domain.c b/security/tomoyo/domain.c index ec612ae87b5..229de1e71a3 100644 --- a/security/tomoyo/domain.c +++ b/security/tomoyo/domain.c @@ -201,11 +201,11 @@ static int tomoyo_update_domain_initializer_entry(const char *domainname, const bool is_not, const bool is_delete) { - struct tomoyo_domain_initializer_entry *new_entry; + struct tomoyo_domain_initializer_entry *entry = NULL; struct tomoyo_domain_initializer_entry *ptr; const struct tomoyo_path_info *saved_program; const struct tomoyo_path_info *saved_domainname = NULL; - int error = -ENOMEM; + int error = is_delete ? -ENOENT : -ENOMEM; bool is_last_name = false; if (!tomoyo_is_correct_path(program, 1, -1, -1, __func__)) @@ -218,12 +218,13 @@ static int tomoyo_update_domain_initializer_entry(const char *domainname, return -EINVAL; saved_domainname = tomoyo_save_name(domainname); if (!saved_domainname) - return -ENOMEM; + goto out; } saved_program = tomoyo_save_name(program); if (!saved_program) - return -ENOMEM; - new_entry = kmalloc(sizeof(*new_entry), GFP_KERNEL); + goto out; + if (!is_delete) + entry = kmalloc(sizeof(*entry), GFP_KERNEL); mutex_lock(&tomoyo_policy_lock); list_for_each_entry_rcu(ptr, &tomoyo_domain_initializer_list, list) { if (ptr->is_not != is_not || @@ -232,24 +233,21 @@ static int tomoyo_update_domain_initializer_entry(const char *domainname, continue; ptr->is_deleted = is_delete; error = 0; - goto out; + break; } - if (is_delete) { - error = -ENOENT; - goto out; + if (!is_delete && error && tomoyo_memory_ok(entry)) { + entry->domainname = saved_domainname; + entry->program = saved_program; + entry->is_not = is_not; + entry->is_last_name = is_last_name; + list_add_tail_rcu(&entry->list, + &tomoyo_domain_initializer_list); + entry = NULL; + error = 0; } - if (!tomoyo_memory_ok(new_entry)) - goto out; - new_entry->domainname = saved_domainname; - new_entry->program = saved_program; - new_entry->is_not = is_not; - new_entry->is_last_name = is_last_name; - list_add_tail_rcu(&new_entry->list, &tomoyo_domain_initializer_list); - new_entry = NULL; - error = 0; - out: mutex_unlock(&tomoyo_policy_lock); - kfree(new_entry); + out: + kfree(entry); return error; } @@ -419,11 +417,11 @@ static int tomoyo_update_domain_keeper_entry(const char *domainname, const bool is_not, const bool is_delete) { - struct tomoyo_domain_keeper_entry *new_entry; + struct tomoyo_domain_keeper_entry *entry = NULL; struct tomoyo_domain_keeper_entry *ptr; const struct tomoyo_path_info *saved_domainname; const struct tomoyo_path_info *saved_program = NULL; - int error = -ENOMEM; + int error = is_delete ? -ENOENT : -ENOMEM; bool is_last_name = false; if (!tomoyo_is_domain_def(domainname) && @@ -436,12 +434,13 @@ static int tomoyo_update_domain_keeper_entry(const char *domainname, return -EINVAL; saved_program = tomoyo_save_name(program); if (!saved_program) - return -ENOMEM; + goto out; } saved_domainname = tomoyo_save_name(domainname); if (!saved_domainname) - return -ENOMEM; - new_entry = kmalloc(sizeof(*new_entry), GFP_KERNEL); + goto out; + if (!is_delete) + entry = kmalloc(sizeof(*entry), GFP_KERNEL); mutex_lock(&tomoyo_policy_lock); list_for_each_entry_rcu(ptr, &tomoyo_domain_keeper_list, list) { if (ptr->is_not != is_not || @@ -450,24 +449,20 @@ static int tomoyo_update_domain_keeper_entry(const char *domainname, continue; ptr->is_deleted = is_delete; error = 0; - goto out; + break; } - if (is_delete) { - error = -ENOENT; - goto out; + if (!is_delete && error && tomoyo_memory_ok(entry)) { + entry->domainname = saved_domainname; + entry->program = saved_program; + entry->is_not = is_not; + entry->is_last_name = is_last_name; + list_add_tail_rcu(&entry->list, &tomoyo_domain_keeper_list); + entry = NULL; + error = 0; } - if (!tomoyo_memory_ok(new_entry)) - goto out; - new_entry->domainname = saved_domainname; - new_entry->program = saved_program; - new_entry->is_not = is_not; - new_entry->is_last_name = is_last_name; - list_add_tail_rcu(&new_entry->list, &tomoyo_domain_keeper_list); - new_entry = NULL; - error = 0; - out: mutex_unlock(&tomoyo_policy_lock); - kfree(new_entry); + out: + kfree(entry); return error; } @@ -619,11 +614,11 @@ static int tomoyo_update_alias_entry(const char *original_name, const char *aliased_name, const bool is_delete) { - struct tomoyo_alias_entry *new_entry; + struct tomoyo_alias_entry *entry = NULL; struct tomoyo_alias_entry *ptr; const struct tomoyo_path_info *saved_original_name; const struct tomoyo_path_info *saved_aliased_name; - int error = -ENOMEM; + int error = is_delete ? -ENOENT : -ENOMEM; if (!tomoyo_is_correct_path(original_name, 1, -1, -1, __func__) || !tomoyo_is_correct_path(aliased_name, 1, -1, -1, __func__)) @@ -631,8 +626,9 @@ static int tomoyo_update_alias_entry(const char *original_name, saved_original_name = tomoyo_save_name(original_name); saved_aliased_name = tomoyo_save_name(aliased_name); if (!saved_original_name || !saved_aliased_name) - return -ENOMEM; - new_entry = kmalloc(sizeof(*new_entry), GFP_KERNEL); + goto out; + if (!is_delete) + entry = kmalloc(sizeof(*entry), GFP_KERNEL); mutex_lock(&tomoyo_policy_lock); list_for_each_entry_rcu(ptr, &tomoyo_alias_list, list) { if (ptr->original_name != saved_original_name || @@ -640,22 +636,18 @@ static int tomoyo_update_alias_entry(const char *original_name, continue; ptr->is_deleted = is_delete; error = 0; - goto out; + break; } - if (is_delete) { - error = -ENOENT; - goto out; + if (!is_delete && error && tomoyo_memory_ok(entry)) { + entry->original_name = saved_original_name; + entry->aliased_name = saved_aliased_name; + list_add_tail_rcu(&entry->list, &tomoyo_alias_list); + entry = NULL; + error = 0; } - if (!tomoyo_memory_ok(new_entry)) - goto out; - new_entry->original_name = saved_original_name; - new_entry->aliased_name = saved_aliased_name; - list_add_tail_rcu(&new_entry->list, &tomoyo_alias_list); - new_entry = NULL; - error = 0; - out: mutex_unlock(&tomoyo_policy_lock); - kfree(new_entry); + out: + kfree(entry); return error; } @@ -722,32 +714,37 @@ struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char * domainname, const u8 profile) { + struct tomoyo_domain_info *entry; struct tomoyo_domain_info *domain; const struct tomoyo_path_info *saved_domainname; + bool found = false; - mutex_lock(&tomoyo_policy_lock); - domain = tomoyo_find_domain(domainname); - if (domain) - goto out; if (!tomoyo_is_correct_domain(domainname, __func__)) - goto out; + return NULL; saved_domainname = tomoyo_save_name(domainname); if (!saved_domainname) - goto out; - domain = kmalloc(sizeof(*domain), GFP_KERNEL); - if (tomoyo_memory_ok(domain)) { - INIT_LIST_HEAD(&domain->acl_info_list); - domain->domainname = saved_domainname; - domain->profile = profile; - list_add_tail_rcu(&domain->list, &tomoyo_domain_list); - } else { - kfree(domain); - domain = NULL; + return NULL; + entry = kzalloc(sizeof(*entry), GFP_KERNEL); + mutex_lock(&tomoyo_policy_lock); + list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) { + if (domain->is_deleted || + tomoyo_pathcmp(saved_domainname, domain->domainname)) + continue; + found = true; + break; + } + if (!found && tomoyo_memory_ok(entry)) { + INIT_LIST_HEAD(&entry->acl_info_list); + entry->domainname = saved_domainname; + entry->profile = profile; + list_add_tail_rcu(&entry->list, &tomoyo_domain_list); + domain = entry; + entry = NULL; + found = true; } - - out: mutex_unlock(&tomoyo_policy_lock); - return domain; + kfree(entry); + return found ? domain : NULL; } /** diff --git a/security/tomoyo/file.c b/security/tomoyo/file.c index 84c821a245c..f4a27714e07 100644 --- a/security/tomoyo/file.c +++ b/security/tomoyo/file.c @@ -215,38 +215,34 @@ static LIST_HEAD(tomoyo_globally_readable_list); static int tomoyo_update_globally_readable_entry(const char *filename, const bool is_delete) { - struct tomoyo_globally_readable_file_entry *new_entry; + struct tomoyo_globally_readable_file_entry *entry = NULL; struct tomoyo_globally_readable_file_entry *ptr; const struct tomoyo_path_info *saved_filename; - int error = -ENOMEM; + int error = is_delete ? -ENOENT : -ENOMEM; if (!tomoyo_is_correct_path(filename, 1, 0, -1, __func__)) return -EINVAL; saved_filename = tomoyo_save_name(filename); if (!saved_filename) return -ENOMEM; - new_entry = kmalloc(sizeof(*new_entry), GFP_KERNEL); + if (!is_delete) + entry = kmalloc(sizeof(*entry), GFP_KERNEL); mutex_lock(&tomoyo_policy_lock); list_for_each_entry_rcu(ptr, &tomoyo_globally_readable_list, list) { if (ptr->filename != saved_filename) continue; ptr->is_deleted = is_delete; error = 0; - goto out; + break; } - if (is_delete) { - error = -ENOENT; - goto out; + if (!is_delete && error && tomoyo_memory_ok(entry)) { + entry->filename = saved_filename; + list_add_tail_rcu(&entry->list, &tomoyo_globally_readable_list); + entry = NULL; + error = 0; } - if (!tomoyo_memory_ok(new_entry)) - goto out; - new_entry->filename = saved_filename; - list_add_tail_rcu(&new_entry->list, &tomoyo_globally_readable_list); - new_entry = NULL; - error = 0; - out: mutex_unlock(&tomoyo_policy_lock); - kfree(new_entry); + kfree(entry); return error; } @@ -364,38 +360,35 @@ static LIST_HEAD(tomoyo_pattern_list); static int tomoyo_update_file_pattern_entry(const char *pattern, const bool is_delete) { - struct tomoyo_pattern_entry *new_entry; + struct tomoyo_pattern_entry *entry = NULL; struct tomoyo_pattern_entry *ptr; const struct tomoyo_path_info *saved_pattern; - int error = -ENOMEM; + int error = is_delete ? -ENOENT : -ENOMEM; - if (!tomoyo_is_correct_path(pattern, 0, 1, 0, __func__)) - return -EINVAL; saved_pattern = tomoyo_save_name(pattern); if (!saved_pattern) - return -ENOMEM; - new_entry = kmalloc(sizeof(*new_entry), GFP_KERNEL); + return error; + if (!saved_pattern->is_patterned) + goto out; + if (!is_delete) + entry = kmalloc(sizeof(*entry), GFP_KERNEL); mutex_lock(&tomoyo_policy_lock); list_for_each_entry_rcu(ptr, &tomoyo_pattern_list, list) { if (saved_pattern != ptr->pattern) continue; ptr->is_deleted = is_delete; error = 0; - goto out; + break; } - if (is_delete) { - error = -ENOENT; - goto out; + if (!is_delete && error && tomoyo_memory_ok(entry)) { + entry->pattern = saved_pattern; + list_add_tail_rcu(&entry->list, &tomoyo_pattern_list); + entry = NULL; + error = 0; } - if (!tomoyo_memory_ok(new_entry)) - goto out; - new_entry->pattern = saved_pattern; - list_add_tail_rcu(&new_entry->list, &tomoyo_pattern_list); - new_entry = NULL; - error = 0; - out: mutex_unlock(&tomoyo_policy_lock); - kfree(new_entry); + out: + kfree(entry); return error; } @@ -518,37 +511,34 @@ static LIST_HEAD(tomoyo_no_rewrite_list); static int tomoyo_update_no_rewrite_entry(const char *pattern, const bool is_delete) { - struct tomoyo_no_rewrite_entry *new_entry, *ptr; + struct tomoyo_no_rewrite_entry *entry = NULL; + struct tomoyo_no_rewrite_entry *ptr; const struct tomoyo_path_info *saved_pattern; - int error = -ENOMEM; + int error = is_delete ? -ENOENT : -ENOMEM; if (!tomoyo_is_correct_path(pattern, 0, 0, 0, __func__)) return -EINVAL; saved_pattern = tomoyo_save_name(pattern); if (!saved_pattern) - return -ENOMEM; - new_entry = kmalloc(sizeof(*new_entry), GFP_KERNEL); + return error; + if (!is_delete) + entry = kmalloc(sizeof(*entry), GFP_KERNEL); mutex_lock(&tomoyo_policy_lock); list_for_each_entry_rcu(ptr, &tomoyo_no_rewrite_list, list) { if (ptr->pattern != saved_pattern) continue; ptr->is_deleted = is_delete; error = 0; - goto out; + break; } - if (is_delete) { - error = -ENOENT; - goto out; + if (!is_delete && error && tomoyo_memory_ok(entry)) { + entry->pattern = saved_pattern; + list_add_tail_rcu(&entry->list, &tomoyo_no_rewrite_list); + entry = NULL; + error = 0; } - if (!tomoyo_memory_ok(new_entry)) - goto out; - new_entry->pattern = saved_pattern; - list_add_tail_rcu(&new_entry->list, &tomoyo_no_rewrite_list); - new_entry = NULL; - error = 0; - out: mutex_unlock(&tomoyo_policy_lock); - kfree(new_entry); + kfree(entry); return error; } @@ -869,8 +859,8 @@ static int tomoyo_update_single_path_acl(const u8 type, const char *filename, (1 << TOMOYO_TYPE_READ_ACL) | (1 << TOMOYO_TYPE_WRITE_ACL); const struct tomoyo_path_info *saved_filename; struct tomoyo_acl_info *ptr; - struct tomoyo_single_path_acl_record *acl; - int error = -ENOMEM; + struct tomoyo_single_path_acl_record *entry = NULL; + int error = is_delete ? -ENOENT : -ENOMEM; const u32 perm = 1 << type; if (!domain) @@ -880,67 +870,55 @@ static int tomoyo_update_single_path_acl(const u8 type, const char *filename, saved_filename = tomoyo_save_name(filename); if (!saved_filename) return -ENOMEM; + if (!is_delete) + entry = kmalloc(sizeof(*entry), GFP_KERNEL); mutex_lock(&tomoyo_policy_lock); - if (is_delete) - goto delete; list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { + struct tomoyo_single_path_acl_record *acl = + container_of(ptr, struct tomoyo_single_path_acl_record, + head); if (ptr->type != TOMOYO_TYPE_SINGLE_PATH_ACL) continue; - acl = container_of(ptr, struct tomoyo_single_path_acl_record, - head); if (acl->filename != saved_filename) continue; - if (perm <= 0xFFFF) - acl->perm |= perm; - else - acl->perm_high |= (perm >> 16); - if ((acl->perm & rw_mask) == rw_mask) - acl->perm |= 1 << TOMOYO_TYPE_READ_WRITE_ACL; - else if (acl->perm & (1 << TOMOYO_TYPE_READ_WRITE_ACL)) - acl->perm |= rw_mask; - error = 0; - goto out; - } - /* Not found. Append it to the tail. */ - acl = kmalloc(sizeof(*acl), GFP_KERNEL); - if (!tomoyo_memory_ok(acl)) { - kfree(acl); - acl = NULL; - goto out; - } - acl->head.type = TOMOYO_TYPE_SINGLE_PATH_ACL; - if (perm <= 0xFFFF) - acl->perm = perm; - else - acl->perm_high = (perm >> 16); - if (perm == (1 << TOMOYO_TYPE_READ_WRITE_ACL)) - acl->perm |= rw_mask; - acl->filename = saved_filename; - list_add_tail_rcu(&acl->head.list, &domain->acl_info_list); - error = 0; - goto out; - delete: - error = -ENOENT; - list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { - if (ptr->type != TOMOYO_TYPE_SINGLE_PATH_ACL) - continue; - acl = container_of(ptr, struct tomoyo_single_path_acl_record, - head); - if (acl->filename != saved_filename) - continue; - if (perm <= 0xFFFF) - acl->perm &= ~perm; - else - acl->perm_high &= ~(perm >> 16); - if ((acl->perm & rw_mask) != rw_mask) - acl->perm &= ~(1 << TOMOYO_TYPE_READ_WRITE_ACL); - else if (!(acl->perm & (1 << TOMOYO_TYPE_READ_WRITE_ACL))) - acl->perm &= ~rw_mask; + if (is_delete) { + if (perm <= 0xFFFF) + acl->perm &= ~perm; + else + acl->perm_high &= ~(perm >> 16); + if ((acl->perm & rw_mask) != rw_mask) + acl->perm &= ~(1 << TOMOYO_TYPE_READ_WRITE_ACL); + else if (!(acl->perm & + (1 << TOMOYO_TYPE_READ_WRITE_ACL))) + acl->perm &= ~rw_mask; + } else { + if (perm <= 0xFFFF) + acl->perm |= perm; + else + acl->perm_high |= (perm >> 16); + if ((acl->perm & rw_mask) == rw_mask) + acl->perm |= 1 << TOMOYO_TYPE_READ_WRITE_ACL; + else if (acl->perm & (1 << TOMOYO_TYPE_READ_WRITE_ACL)) + acl->perm |= rw_mask; + } error = 0; break; } - out: + if (!is_delete && error && tomoyo_memory_ok(entry)) { + entry->head.type = TOMOYO_TYPE_SINGLE_PATH_ACL; + if (perm <= 0xFFFF) + entry->perm = perm; + else + entry->perm_high = (perm >> 16); + if (perm == (1 << TOMOYO_TYPE_READ_WRITE_ACL)) + entry->perm |= rw_mask; + entry->filename = saved_filename; + list_add_tail_rcu(&entry->head.list, &domain->acl_info_list); + entry = NULL; + error = 0; + } mutex_unlock(&tomoyo_policy_lock); + kfree(entry); return error; } @@ -965,8 +943,8 @@ static int tomoyo_update_double_path_acl(const u8 type, const char *filename1, const struct tomoyo_path_info *saved_filename1; const struct tomoyo_path_info *saved_filename2; struct tomoyo_acl_info *ptr; - struct tomoyo_double_path_acl_record *acl; - int error = -ENOMEM; + struct tomoyo_double_path_acl_record *entry = NULL; + int error = is_delete ? -ENOENT : -ENOMEM; const u8 perm = 1 << type; if (!domain) @@ -977,52 +955,38 @@ static int tomoyo_update_double_path_acl(const u8 type, const char *filename1, saved_filename1 = tomoyo_save_name(filename1); saved_filename2 = tomoyo_save_name(filename2); if (!saved_filename1 || !saved_filename2) - return -ENOMEM; + goto out; + if (!is_delete) + entry = kmalloc(sizeof(*entry), GFP_KERNEL); mutex_lock(&tomoyo_policy_lock); - if (is_delete) - goto delete; list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { + struct tomoyo_double_path_acl_record *acl = + container_of(ptr, struct tomoyo_double_path_acl_record, + head); if (ptr->type != TOMOYO_TYPE_DOUBLE_PATH_ACL) continue; - acl = container_of(ptr, struct tomoyo_double_path_acl_record, - head); if (acl->filename1 != saved_filename1 || acl->filename2 != saved_filename2) continue; - acl->perm |= perm; - error = 0; - goto out; - } - /* Not found. Append it to the tail. */ - acl = kmalloc(sizeof(*acl), GFP_KERNEL); - if (!tomoyo_memory_ok(acl)) { - kfree(acl); - acl = NULL; - goto out; - } - acl->head.type = TOMOYO_TYPE_DOUBLE_PATH_ACL; - acl->perm = perm; - acl->filename1 = saved_filename1; - acl->filename2 = saved_filename2; - list_add_tail_rcu(&acl->head.list, &domain->acl_info_list); - error = 0; - goto out; - delete: - error = -ENOENT; - list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { - if (ptr->type != TOMOYO_TYPE_DOUBLE_PATH_ACL) - continue; - acl = container_of(ptr, struct tomoyo_double_path_acl_record, - head); - if (acl->filename1 != saved_filename1 || - acl->filename2 != saved_filename2) - continue; - acl->perm &= ~perm; + if (is_delete) + acl->perm &= ~perm; + else + acl->perm |= perm; error = 0; break; } - out: + if (!is_delete && error && tomoyo_memory_ok(entry)) { + entry->head.type = TOMOYO_TYPE_DOUBLE_PATH_ACL; + entry->perm = perm; + entry->filename1 = saved_filename1; + entry->filename2 = saved_filename2; + list_add_tail_rcu(&entry->head.list, &domain->acl_info_list); + entry = NULL; + error = 0; + } mutex_unlock(&tomoyo_policy_lock); + out: + kfree(entry); return error; } From bf24fb016c861b7f52be0c36c4cedd3e89afa2e2 Mon Sep 17 00:00:00 2001 From: Tetsuo Handa Date: Thu, 11 Feb 2010 09:41:58 +0900 Subject: [PATCH 26/38] TOMOYO: Add refcounter on string data. Add refcounter to "struct tomoyo_name_entry" and replace tomoyo_save_name() with tomoyo_get_name()/tomoyo_put_name() pair so that we can kfree() when garbage collector is added. Signed-off-by: Tetsuo Handa Acked-by: Serge Hallyn Signed-off-by: James Morris --- security/tomoyo/common.c | 10 +++++++--- security/tomoyo/domain.c | 32 +++++++++++++++++++++++--------- security/tomoyo/file.c | 24 ++++++++++++++++++------ security/tomoyo/realpath.c | 30 +++++++++--------------------- security/tomoyo/realpath.h | 21 ++++++++++++++++++++- 5 files changed, 77 insertions(+), 40 deletions(-) diff --git a/security/tomoyo/common.c b/security/tomoyo/common.c index a53ee059da4..0c7ea51e7a4 100644 --- a/security/tomoyo/common.c +++ b/security/tomoyo/common.c @@ -12,8 +12,8 @@ #include #include #include -#include "realpath.h" #include "common.h" +#include "realpath.h" #include "tomoyo.h" /* Lock for protecting policy. */ @@ -943,7 +943,9 @@ static int tomoyo_write_profile(struct tomoyo_io_buffer *head) return -EINVAL; *cp = '\0'; if (!strcmp(data, "COMMENT")) { - profile->comment = tomoyo_save_name(cp + 1); + const struct tomoyo_path_info *old_comment = profile->comment; + profile->comment = tomoyo_get_name(cp + 1); + tomoyo_put_name(old_comment); return 0; } for (i = 0; i < TOMOYO_MAX_CONTROL_INDEX; i++) { @@ -1117,7 +1119,7 @@ static int tomoyo_update_manager_entry(const char *manager, if (!tomoyo_is_correct_path(manager, 1, -1, -1, __func__)) return -EINVAL; } - saved_manager = tomoyo_save_name(manager); + saved_manager = tomoyo_get_name(manager); if (!saved_manager) return -ENOMEM; if (!is_delete) @@ -1132,12 +1134,14 @@ static int tomoyo_update_manager_entry(const char *manager, } if (!is_delete && error && tomoyo_memory_ok(entry)) { entry->manager = saved_manager; + saved_manager = NULL; entry->is_domain = is_domain; list_add_tail_rcu(&entry->list, &tomoyo_policy_manager_list); entry = NULL; error = 0; } mutex_unlock(&tomoyo_policy_lock); + tomoyo_put_name(saved_manager); kfree(entry); return error; } diff --git a/security/tomoyo/domain.c b/security/tomoyo/domain.c index 229de1e71a3..0b826256780 100644 --- a/security/tomoyo/domain.c +++ b/security/tomoyo/domain.c @@ -203,7 +203,7 @@ static int tomoyo_update_domain_initializer_entry(const char *domainname, { struct tomoyo_domain_initializer_entry *entry = NULL; struct tomoyo_domain_initializer_entry *ptr; - const struct tomoyo_path_info *saved_program; + const struct tomoyo_path_info *saved_program = NULL; const struct tomoyo_path_info *saved_domainname = NULL; int error = is_delete ? -ENOENT : -ENOMEM; bool is_last_name = false; @@ -216,11 +216,11 @@ static int tomoyo_update_domain_initializer_entry(const char *domainname, is_last_name = true; else if (!tomoyo_is_correct_domain(domainname, __func__)) return -EINVAL; - saved_domainname = tomoyo_save_name(domainname); + saved_domainname = tomoyo_get_name(domainname); if (!saved_domainname) goto out; } - saved_program = tomoyo_save_name(program); + saved_program = tomoyo_get_name(program); if (!saved_program) goto out; if (!is_delete) @@ -237,7 +237,9 @@ static int tomoyo_update_domain_initializer_entry(const char *domainname, } if (!is_delete && error && tomoyo_memory_ok(entry)) { entry->domainname = saved_domainname; + saved_domainname = NULL; entry->program = saved_program; + saved_program = NULL; entry->is_not = is_not; entry->is_last_name = is_last_name; list_add_tail_rcu(&entry->list, @@ -247,6 +249,8 @@ static int tomoyo_update_domain_initializer_entry(const char *domainname, } mutex_unlock(&tomoyo_policy_lock); out: + tomoyo_put_name(saved_domainname); + tomoyo_put_name(saved_program); kfree(entry); return error; } @@ -419,7 +423,7 @@ static int tomoyo_update_domain_keeper_entry(const char *domainname, { struct tomoyo_domain_keeper_entry *entry = NULL; struct tomoyo_domain_keeper_entry *ptr; - const struct tomoyo_path_info *saved_domainname; + const struct tomoyo_path_info *saved_domainname = NULL; const struct tomoyo_path_info *saved_program = NULL; int error = is_delete ? -ENOENT : -ENOMEM; bool is_last_name = false; @@ -432,11 +436,11 @@ static int tomoyo_update_domain_keeper_entry(const char *domainname, if (program) { if (!tomoyo_is_correct_path(program, 1, -1, -1, __func__)) return -EINVAL; - saved_program = tomoyo_save_name(program); + saved_program = tomoyo_get_name(program); if (!saved_program) goto out; } - saved_domainname = tomoyo_save_name(domainname); + saved_domainname = tomoyo_get_name(domainname); if (!saved_domainname) goto out; if (!is_delete) @@ -453,7 +457,9 @@ static int tomoyo_update_domain_keeper_entry(const char *domainname, } if (!is_delete && error && tomoyo_memory_ok(entry)) { entry->domainname = saved_domainname; + saved_domainname = NULL; entry->program = saved_program; + saved_program = NULL; entry->is_not = is_not; entry->is_last_name = is_last_name; list_add_tail_rcu(&entry->list, &tomoyo_domain_keeper_list); @@ -462,6 +468,8 @@ static int tomoyo_update_domain_keeper_entry(const char *domainname, } mutex_unlock(&tomoyo_policy_lock); out: + tomoyo_put_name(saved_domainname); + tomoyo_put_name(saved_program); kfree(entry); return error; } @@ -623,8 +631,8 @@ static int tomoyo_update_alias_entry(const char *original_name, if (!tomoyo_is_correct_path(original_name, 1, -1, -1, __func__) || !tomoyo_is_correct_path(aliased_name, 1, -1, -1, __func__)) return -EINVAL; /* No patterns allowed. */ - saved_original_name = tomoyo_save_name(original_name); - saved_aliased_name = tomoyo_save_name(aliased_name); + saved_original_name = tomoyo_get_name(original_name); + saved_aliased_name = tomoyo_get_name(aliased_name); if (!saved_original_name || !saved_aliased_name) goto out; if (!is_delete) @@ -640,13 +648,17 @@ static int tomoyo_update_alias_entry(const char *original_name, } if (!is_delete && error && tomoyo_memory_ok(entry)) { entry->original_name = saved_original_name; + saved_original_name = NULL; entry->aliased_name = saved_aliased_name; + saved_aliased_name = NULL; list_add_tail_rcu(&entry->list, &tomoyo_alias_list); entry = NULL; error = 0; } mutex_unlock(&tomoyo_policy_lock); out: + tomoyo_put_name(saved_original_name); + tomoyo_put_name(saved_aliased_name); kfree(entry); return error; } @@ -721,7 +733,7 @@ struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char * if (!tomoyo_is_correct_domain(domainname, __func__)) return NULL; - saved_domainname = tomoyo_save_name(domainname); + saved_domainname = tomoyo_get_name(domainname); if (!saved_domainname) return NULL; entry = kzalloc(sizeof(*entry), GFP_KERNEL); @@ -736,6 +748,7 @@ struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char * if (!found && tomoyo_memory_ok(entry)) { INIT_LIST_HEAD(&entry->acl_info_list); entry->domainname = saved_domainname; + saved_domainname = NULL; entry->profile = profile; list_add_tail_rcu(&entry->list, &tomoyo_domain_list); domain = entry; @@ -743,6 +756,7 @@ struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char * found = true; } mutex_unlock(&tomoyo_policy_lock); + tomoyo_put_name(saved_domainname); kfree(entry); return found ? domain : NULL; } diff --git a/security/tomoyo/file.c b/security/tomoyo/file.c index f4a27714e07..a49e18cc7bc 100644 --- a/security/tomoyo/file.c +++ b/security/tomoyo/file.c @@ -222,7 +222,7 @@ static int tomoyo_update_globally_readable_entry(const char *filename, if (!tomoyo_is_correct_path(filename, 1, 0, -1, __func__)) return -EINVAL; - saved_filename = tomoyo_save_name(filename); + saved_filename = tomoyo_get_name(filename); if (!saved_filename) return -ENOMEM; if (!is_delete) @@ -237,11 +237,13 @@ static int tomoyo_update_globally_readable_entry(const char *filename, } if (!is_delete && error && tomoyo_memory_ok(entry)) { entry->filename = saved_filename; + saved_filename = NULL; list_add_tail_rcu(&entry->list, &tomoyo_globally_readable_list); entry = NULL; error = 0; } mutex_unlock(&tomoyo_policy_lock); + tomoyo_put_name(saved_filename); kfree(entry); return error; } @@ -365,7 +367,7 @@ static int tomoyo_update_file_pattern_entry(const char *pattern, const struct tomoyo_path_info *saved_pattern; int error = is_delete ? -ENOENT : -ENOMEM; - saved_pattern = tomoyo_save_name(pattern); + saved_pattern = tomoyo_get_name(pattern); if (!saved_pattern) return error; if (!saved_pattern->is_patterned) @@ -382,6 +384,7 @@ static int tomoyo_update_file_pattern_entry(const char *pattern, } if (!is_delete && error && tomoyo_memory_ok(entry)) { entry->pattern = saved_pattern; + saved_pattern = NULL; list_add_tail_rcu(&entry->list, &tomoyo_pattern_list); entry = NULL; error = 0; @@ -389,6 +392,7 @@ static int tomoyo_update_file_pattern_entry(const char *pattern, mutex_unlock(&tomoyo_policy_lock); out: kfree(entry); + tomoyo_put_name(saved_pattern); return error; } @@ -518,7 +522,7 @@ static int tomoyo_update_no_rewrite_entry(const char *pattern, if (!tomoyo_is_correct_path(pattern, 0, 0, 0, __func__)) return -EINVAL; - saved_pattern = tomoyo_save_name(pattern); + saved_pattern = tomoyo_get_name(pattern); if (!saved_pattern) return error; if (!is_delete) @@ -533,11 +537,13 @@ static int tomoyo_update_no_rewrite_entry(const char *pattern, } if (!is_delete && error && tomoyo_memory_ok(entry)) { entry->pattern = saved_pattern; + saved_pattern = NULL; list_add_tail_rcu(&entry->list, &tomoyo_no_rewrite_list); entry = NULL; error = 0; } mutex_unlock(&tomoyo_policy_lock); + tomoyo_put_name(saved_pattern); kfree(entry); return error; } @@ -867,7 +873,7 @@ static int tomoyo_update_single_path_acl(const u8 type, const char *filename, return -EINVAL; if (!tomoyo_is_correct_path(filename, 0, 0, 0, __func__)) return -EINVAL; - saved_filename = tomoyo_save_name(filename); + saved_filename = tomoyo_get_name(filename); if (!saved_filename) return -ENOMEM; if (!is_delete) @@ -913,12 +919,14 @@ static int tomoyo_update_single_path_acl(const u8 type, const char *filename, if (perm == (1 << TOMOYO_TYPE_READ_WRITE_ACL)) entry->perm |= rw_mask; entry->filename = saved_filename; + saved_filename = NULL; list_add_tail_rcu(&entry->head.list, &domain->acl_info_list); entry = NULL; error = 0; } mutex_unlock(&tomoyo_policy_lock); kfree(entry); + tomoyo_put_name(saved_filename); return error; } @@ -952,8 +960,8 @@ static int tomoyo_update_double_path_acl(const u8 type, const char *filename1, if (!tomoyo_is_correct_path(filename1, 0, 0, 0, __func__) || !tomoyo_is_correct_path(filename2, 0, 0, 0, __func__)) return -EINVAL; - saved_filename1 = tomoyo_save_name(filename1); - saved_filename2 = tomoyo_save_name(filename2); + saved_filename1 = tomoyo_get_name(filename1); + saved_filename2 = tomoyo_get_name(filename2); if (!saved_filename1 || !saved_filename2) goto out; if (!is_delete) @@ -979,13 +987,17 @@ static int tomoyo_update_double_path_acl(const u8 type, const char *filename1, entry->head.type = TOMOYO_TYPE_DOUBLE_PATH_ACL; entry->perm = perm; entry->filename1 = saved_filename1; + saved_filename1 = NULL; entry->filename2 = saved_filename2; + saved_filename2 = NULL; list_add_tail_rcu(&entry->head.list, &domain->acl_info_list); entry = NULL; error = 0; } mutex_unlock(&tomoyo_policy_lock); out: + tomoyo_put_name(saved_filename1); + tomoyo_put_name(saved_filename2); kfree(entry); return error; } diff --git a/security/tomoyo/realpath.c b/security/tomoyo/realpath.c index 92460c7ded6..2f7f54fc681 100644 --- a/security/tomoyo/realpath.c +++ b/security/tomoyo/realpath.c @@ -253,21 +253,6 @@ static unsigned int tomoyo_quota_for_savename; #define TOMOYO_HASH_BITS 8 #define TOMOYO_MAX_HASH (1u<entry.hash && !strcmp(name, ptr->entry.name)) - goto out; + if (hash != ptr->entry.hash || strcmp(name, ptr->entry.name)) + continue; + atomic_inc(&ptr->users); + goto out; } ptr = kzalloc(sizeof(*ptr) + len, GFP_KERNEL); allocated_len = ptr ? ksize(ptr) : 0; @@ -309,7 +296,7 @@ const struct tomoyo_path_info *tomoyo_save_name(const char *name) > tomoyo_quota_for_savename)) { kfree(ptr); printk(KERN_WARNING "ERROR: Out of memory " - "for tomoyo_save_name().\n"); + "for tomoyo_get_name().\n"); if (!tomoyo_policy_loaded) panic("MAC Initialization failed.\n"); ptr = NULL; @@ -318,6 +305,7 @@ const struct tomoyo_path_info *tomoyo_save_name(const char *name) tomoyo_allocated_memory_for_savename += allocated_len; ptr->entry.name = ((char *) ptr) + sizeof(*ptr); memmove((char *) ptr->entry.name, name, len); + atomic_set(&ptr->users, 1); tomoyo_fill_path_info(&ptr->entry); list_add_tail(&ptr->list, head); out: @@ -336,7 +324,7 @@ void __init tomoyo_realpath_init(void) for (i = 0; i < TOMOYO_MAX_HASH; i++) INIT_LIST_HEAD(&tomoyo_name_list[i]); INIT_LIST_HEAD(&tomoyo_kernel_domain.acl_info_list); - tomoyo_kernel_domain.domainname = tomoyo_save_name(TOMOYO_ROOT_NAME); + tomoyo_kernel_domain.domainname = tomoyo_get_name(TOMOYO_ROOT_NAME); /* * tomoyo_read_lock() is not needed because this function is * called before the first "delete" request. diff --git a/security/tomoyo/realpath.h b/security/tomoyo/realpath.h index da4f06ff6f8..b94cb512adb 100644 --- a/security/tomoyo/realpath.h +++ b/security/tomoyo/realpath.h @@ -43,7 +43,7 @@ bool tomoyo_memory_ok(void *ptr); * Keep the given name on the RAM. * The RAM is shared, so NEVER try to modify or kfree() the returned name. */ -const struct tomoyo_path_info *tomoyo_save_name(const char *name); +const struct tomoyo_path_info *tomoyo_get_name(const char *name); /* Check for memory usage. */ int tomoyo_read_memory_counter(struct tomoyo_io_buffer *head); @@ -54,4 +54,23 @@ int tomoyo_write_memory_quota(struct tomoyo_io_buffer *head); /* Initialize realpath related code. */ void __init tomoyo_realpath_init(void); +/* + * tomoyo_name_entry is a structure which is used for linking + * "struct tomoyo_path_info" into tomoyo_name_list . + */ +struct tomoyo_name_entry { + struct list_head list; + atomic_t users; + struct tomoyo_path_info entry; +}; + +static inline void tomoyo_put_name(const struct tomoyo_path_info *name) +{ + if (name) { + struct tomoyo_name_entry *ptr = + container_of(name, struct tomoyo_name_entry, entry); + atomic_dec(&ptr->users); + } +} + #endif /* !defined(_SECURITY_TOMOYO_REALPATH_H) */ From 76bb0895d038be7bcdb6ccfcd2dd7deb30371d6b Mon Sep 17 00:00:00 2001 From: Tetsuo Handa Date: Thu, 11 Feb 2010 09:42:40 +0900 Subject: [PATCH 27/38] TOMOYO: Merge headers. Gather structures and constants scattered around security/tomoyo/ directory. This is for preparation for adding garbage collector since garbage collector needs to know structures and constants which TOMOYO uses. Signed-off-by: Tetsuo Handa Acked-by: Serge Hallyn Signed-off-by: James Morris --- security/tomoyo/common.c | 23 --- security/tomoyo/common.h | 411 +++++++++++++++++++++++++++++++------ security/tomoyo/domain.c | 72 ------- security/tomoyo/file.c | 52 ----- security/tomoyo/realpath.c | 10 - security/tomoyo/realpath.h | 76 ------- security/tomoyo/tomoyo.c | 2 - security/tomoyo/tomoyo.h | 102 --------- 8 files changed, 351 insertions(+), 397 deletions(-) delete mode 100644 security/tomoyo/realpath.h delete mode 100644 security/tomoyo/tomoyo.h diff --git a/security/tomoyo/common.c b/security/tomoyo/common.c index 0c7ea51e7a4..634f7449e8b 100644 --- a/security/tomoyo/common.c +++ b/security/tomoyo/common.c @@ -13,8 +13,6 @@ #include #include #include "common.h" -#include "realpath.h" -#include "tomoyo.h" /* Lock for protecting policy. */ DEFINE_MUTEX(tomoyo_policy_lock); @@ -1039,27 +1037,6 @@ static int tomoyo_read_profile(struct tomoyo_io_buffer *head) return 0; } -/* - * tomoyo_policy_manager_entry is a structure which is used for holding list of - * domainnames or programs which are permitted to modify configuration via - * /sys/kernel/security/tomoyo/ interface. - * It has following fields. - * - * (1) "list" which is linked to tomoyo_policy_manager_list . - * (2) "manager" is a domainname or a program's pathname. - * (3) "is_domain" is a bool which is true if "manager" is a domainname, false - * otherwise. - * (4) "is_deleted" is a bool which is true if marked as deleted, false - * otherwise. - */ -struct tomoyo_policy_manager_entry { - struct list_head list; - /* A path to program or a domainname. */ - const struct tomoyo_path_info *manager; - bool is_domain; /* True if manager is a domainname. */ - bool is_deleted; /* True if this entry is deleted. */ -}; - /* * tomoyo_policy_manager_list is used for holding list of domainnames or * programs which are permitted to modify configuration via diff --git a/security/tomoyo/common.h b/security/tomoyo/common.h index 509ced9ce69..f6aff59b088 100644 --- a/security/tomoyo/common.h +++ b/security/tomoyo/common.h @@ -1,12 +1,9 @@ /* * security/tomoyo/common.h * - * Common functions for TOMOYO. - * - * Copyright (C) 2005-2009 NTT DATA CORPORATION - * - * Version: 2.2.0 2009/04/01 + * Header file for TOMOYO. * + * Copyright (C) 2005-2010 NTT DATA CORPORATION */ #ifndef _SECURITY_TOMOYO_COMMON_H @@ -22,9 +19,110 @@ #include #include #include +#include +struct linux_binprm; -struct dentry; -struct vfsmount; +/********** Constants definitions. **********/ + +/* + * TOMOYO uses this hash only when appending a string into the string + * table. Frequency of appending strings is very low. So we don't need + * large (e.g. 64k) hash size. 256 will be sufficient. + */ +#define TOMOYO_HASH_BITS 8 +#define TOMOYO_MAX_HASH (1u<. */ +#define TOMOYO_ROOT_NAME "" +#define TOMOYO_ROOT_NAME_LEN (sizeof(TOMOYO_ROOT_NAME) - 1) + +/* Index numbers for Access Controls. */ +#define TOMOYO_MAC_FOR_FILE 0 /* domain_policy.conf */ +#define TOMOYO_MAX_ACCEPT_ENTRY 1 +#define TOMOYO_VERBOSE 2 +#define TOMOYO_MAX_CONTROL_INDEX 3 + +/* Index numbers for Access Controls. */ + +#define TOMOYO_TYPE_SINGLE_PATH_ACL 0 +#define TOMOYO_TYPE_DOUBLE_PATH_ACL 1 + +/* Index numbers for File Controls. */ + +/* + * TYPE_READ_WRITE_ACL is special. TYPE_READ_WRITE_ACL is automatically set + * if both TYPE_READ_ACL and TYPE_WRITE_ACL are set. Both TYPE_READ_ACL and + * TYPE_WRITE_ACL are automatically set if TYPE_READ_WRITE_ACL is set. + * TYPE_READ_WRITE_ACL is automatically cleared if either TYPE_READ_ACL or + * TYPE_WRITE_ACL is cleared. Both TYPE_READ_ACL and TYPE_WRITE_ACL are + * automatically cleared if TYPE_READ_WRITE_ACL is cleared. + */ + +#define TOMOYO_TYPE_READ_WRITE_ACL 0 +#define TOMOYO_TYPE_EXECUTE_ACL 1 +#define TOMOYO_TYPE_READ_ACL 2 +#define TOMOYO_TYPE_WRITE_ACL 3 +#define TOMOYO_TYPE_CREATE_ACL 4 +#define TOMOYO_TYPE_UNLINK_ACL 5 +#define TOMOYO_TYPE_MKDIR_ACL 6 +#define TOMOYO_TYPE_RMDIR_ACL 7 +#define TOMOYO_TYPE_MKFIFO_ACL 8 +#define TOMOYO_TYPE_MKSOCK_ACL 9 +#define TOMOYO_TYPE_MKBLOCK_ACL 10 +#define TOMOYO_TYPE_MKCHAR_ACL 11 +#define TOMOYO_TYPE_TRUNCATE_ACL 12 +#define TOMOYO_TYPE_SYMLINK_ACL 13 +#define TOMOYO_TYPE_REWRITE_ACL 14 +#define TOMOYO_TYPE_IOCTL_ACL 15 +#define TOMOYO_TYPE_CHMOD_ACL 16 +#define TOMOYO_TYPE_CHOWN_ACL 17 +#define TOMOYO_TYPE_CHGRP_ACL 18 +#define TOMOYO_TYPE_CHROOT_ACL 19 +#define TOMOYO_TYPE_MOUNT_ACL 20 +#define TOMOYO_TYPE_UMOUNT_ACL 21 +#define TOMOYO_MAX_SINGLE_PATH_OPERATION 22 + +#define TOMOYO_TYPE_LINK_ACL 0 +#define TOMOYO_TYPE_RENAME_ACL 1 +#define TOMOYO_TYPE_PIVOT_ROOT_ACL 2 +#define TOMOYO_MAX_DOUBLE_PATH_OPERATION 3 + +#define TOMOYO_DOMAINPOLICY 0 +#define TOMOYO_EXCEPTIONPOLICY 1 +#define TOMOYO_DOMAIN_STATUS 2 +#define TOMOYO_PROCESS_STATUS 3 +#define TOMOYO_MEMINFO 4 +#define TOMOYO_SELFDOMAIN 5 +#define TOMOYO_VERSION 6 +#define TOMOYO_PROFILE 7 +#define TOMOYO_MANAGER 8 + +/********** Structure definitions. **********/ /* * tomoyo_page_buffer is a structure which is used for holding a pathname @@ -66,13 +164,14 @@ struct tomoyo_path_info { }; /* - * 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 \\. + * tomoyo_name_entry is a structure which is used for linking + * "struct tomoyo_path_info" into tomoyo_name_list . */ -#define TOMOYO_MAX_PATHNAME_LEN 4000 +struct tomoyo_name_entry { + struct list_head list; + atomic_t users; + struct tomoyo_path_info entry; +}; /* * tomoyo_path_info_with_data is a structure which is used for holding a @@ -155,9 +254,6 @@ struct tomoyo_domain_info { bool transition_failed; /* Domain transition failed flag. */ }; -/* Profile number is an integer between 0 and 255. */ -#define TOMOYO_MAX_PROFILES 256 - /* * tomoyo_single_path_acl_record is a structure which is used for holding an * entry with one pathname operation (e.g. open(), mkdir()). @@ -204,29 +300,6 @@ struct tomoyo_double_path_acl_record { const struct tomoyo_path_info *filename2; }; -/* Keywords for ACLs. */ -#define TOMOYO_KEYWORD_ALIAS "alias " -#define TOMOYO_KEYWORD_ALLOW_READ "allow_read " -#define TOMOYO_KEYWORD_DELETE "delete " -#define TOMOYO_KEYWORD_DENY_REWRITE "deny_rewrite " -#define TOMOYO_KEYWORD_FILE_PATTERN "file_pattern " -#define TOMOYO_KEYWORD_INITIALIZE_DOMAIN "initialize_domain " -#define TOMOYO_KEYWORD_KEEP_DOMAIN "keep_domain " -#define TOMOYO_KEYWORD_NO_INITIALIZE_DOMAIN "no_initialize_domain " -#define TOMOYO_KEYWORD_NO_KEEP_DOMAIN "no_keep_domain " -#define TOMOYO_KEYWORD_SELECT "select " -#define TOMOYO_KEYWORD_USE_PROFILE "use_profile " -#define TOMOYO_KEYWORD_IGNORE_GLOBAL_ALLOW_READ "ignore_global_allow_read" -/* A domain definition starts with . */ -#define TOMOYO_ROOT_NAME "" -#define TOMOYO_ROOT_NAME_LEN (sizeof(TOMOYO_ROOT_NAME) - 1) - -/* Index numbers for Access Controls. */ -#define TOMOYO_MAC_FOR_FILE 0 /* domain_policy.conf */ -#define TOMOYO_MAX_ACCEPT_ENTRY 1 -#define TOMOYO_VERBOSE 2 -#define TOMOYO_MAX_CONTROL_INDEX 3 - /* * tomoyo_io_buffer is a structure which is used for reading and modifying * configuration via /sys/kernel/security/tomoyo/ interface. @@ -285,6 +358,149 @@ struct tomoyo_io_buffer { int writebuf_size; }; +/* + * tomoyo_globally_readable_file_entry is a structure which is used for holding + * "allow_read" entries. + * It has following fields. + * + * (1) "list" which is linked to tomoyo_globally_readable_list . + * (2) "filename" is a pathname which is allowed to open(O_RDONLY). + * (3) "is_deleted" is a bool which is true if marked as deleted, false + * otherwise. + */ +struct tomoyo_globally_readable_file_entry { + struct list_head list; + const struct tomoyo_path_info *filename; + bool is_deleted; +}; + +/* + * tomoyo_pattern_entry is a structure which is used for holding + * "tomoyo_pattern_list" entries. + * It has following fields. + * + * (1) "list" which is linked to tomoyo_pattern_list . + * (2) "pattern" is a pathname pattern which is used for converting pathnames + * to pathname patterns during learning mode. + * (3) "is_deleted" is a bool which is true if marked as deleted, false + * otherwise. + */ +struct tomoyo_pattern_entry { + struct list_head list; + const struct tomoyo_path_info *pattern; + bool is_deleted; +}; + +/* + * tomoyo_no_rewrite_entry is a structure which is used for holding + * "deny_rewrite" entries. + * It has following fields. + * + * (1) "list" which is linked to tomoyo_no_rewrite_list . + * (2) "pattern" is a pathname which is by default not permitted to modify + * already existing content. + * (3) "is_deleted" is a bool which is true if marked as deleted, false + * otherwise. + */ +struct tomoyo_no_rewrite_entry { + struct list_head list; + const struct tomoyo_path_info *pattern; + bool is_deleted; +}; + +/* + * tomoyo_domain_initializer_entry is a structure which is used for holding + * "initialize_domain" and "no_initialize_domain" entries. + * It has following fields. + * + * (1) "list" which is linked to tomoyo_domain_initializer_list . + * (2) "domainname" which is "a domainname" or "the last component of a + * domainname". This field is NULL if "from" clause is not specified. + * (3) "program" which is a program's pathname. + * (4) "is_deleted" is a bool which is true if marked as deleted, false + * otherwise. + * (5) "is_not" is a bool which is true if "no_initialize_domain", false + * otherwise. + * (6) "is_last_name" is a bool which is true if "domainname" is "the last + * component of a domainname", false otherwise. + */ +struct tomoyo_domain_initializer_entry { + struct list_head list; + const struct tomoyo_path_info *domainname; /* This may be NULL */ + const struct tomoyo_path_info *program; + bool is_deleted; + bool is_not; /* True if this entry is "no_initialize_domain". */ + /* True if the domainname is tomoyo_get_last_name(). */ + bool is_last_name; +}; + +/* + * tomoyo_domain_keeper_entry is a structure which is used for holding + * "keep_domain" and "no_keep_domain" entries. + * It has following fields. + * + * (1) "list" which is linked to tomoyo_domain_keeper_list . + * (2) "domainname" which is "a domainname" or "the last component of a + * domainname". + * (3) "program" which is a program's pathname. + * This field is NULL if "from" clause is not specified. + * (4) "is_deleted" is a bool which is true if marked as deleted, false + * otherwise. + * (5) "is_not" is a bool which is true if "no_initialize_domain", false + * otherwise. + * (6) "is_last_name" is a bool which is true if "domainname" is "the last + * component of a domainname", false otherwise. + */ +struct tomoyo_domain_keeper_entry { + struct list_head list; + const struct tomoyo_path_info *domainname; + const struct tomoyo_path_info *program; /* This may be NULL */ + bool is_deleted; + bool is_not; /* True if this entry is "no_keep_domain". */ + /* True if the domainname is tomoyo_get_last_name(). */ + bool is_last_name; +}; + +/* + * tomoyo_alias_entry is a structure which is used for holding "alias" entries. + * It has following fields. + * + * (1) "list" which is linked to tomoyo_alias_list . + * (2) "original_name" which is a dereferenced pathname. + * (3) "aliased_name" which is a symlink's pathname. + * (4) "is_deleted" is a bool which is true if marked as deleted, false + * otherwise. + */ +struct tomoyo_alias_entry { + struct list_head list; + const struct tomoyo_path_info *original_name; + const struct tomoyo_path_info *aliased_name; + bool is_deleted; +}; + +/* + * tomoyo_policy_manager_entry is a structure which is used for holding list of + * domainnames or programs which are permitted to modify configuration via + * /sys/kernel/security/tomoyo/ interface. + * It has following fields. + * + * (1) "list" which is linked to tomoyo_policy_manager_list . + * (2) "manager" is a domainname or a program's pathname. + * (3) "is_domain" is a bool which is true if "manager" is a domainname, false + * otherwise. + * (4) "is_deleted" is a bool which is true if marked as deleted, false + * otherwise. + */ +struct tomoyo_policy_manager_entry { + struct list_head list; + /* A path to program or a domainname. */ + const struct tomoyo_path_info *manager; + bool is_domain; /* True if manager is a domainname. */ + bool is_deleted; /* True if this entry is deleted. */ +}; + +/********** Function prototypes. **********/ + /* Check whether the domain has too many ACL entries to hold. */ bool tomoyo_domain_quota_is_ok(struct tomoyo_domain_info * const domain); /* Transactional sprintf() for policy dump. */ @@ -367,6 +583,85 @@ void tomoyo_fill_path_info(struct tomoyo_path_info *ptr); /* Run policy loader when /sbin/init starts. */ void tomoyo_load_policy(const char *filename); +/* 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); + +/* + * Returns realpath(3) of the given pathname but ignores chroot'ed root. + * These functions use kzalloc(), so the caller must call kfree() + * if these functions didn't return NULL. + */ +char *tomoyo_realpath(const char *pathname); +/* + * Same with tomoyo_realpath() except that it doesn't follow the final symlink. + */ +char *tomoyo_realpath_nofollow(const char *pathname); +/* Same with tomoyo_realpath() except that the pathname is already solved. */ +char *tomoyo_realpath_from_path(struct path *path); + +/* Check memory quota. */ +bool tomoyo_memory_ok(void *ptr); + +/* + * Keep the given name on the RAM. + * The RAM is shared, so NEVER try to modify or kfree() the returned name. + */ +const struct tomoyo_path_info *tomoyo_get_name(const char *name); + +/* Check for memory usage. */ +int tomoyo_read_memory_counter(struct tomoyo_io_buffer *head); + +/* Set memory quota. */ +int tomoyo_write_memory_quota(struct tomoyo_io_buffer *head); + +/* Initialize realpath related code. */ +void __init tomoyo_realpath_init(void); +int tomoyo_check_exec_perm(struct tomoyo_domain_info *domain, + const struct tomoyo_path_info *filename); +int tomoyo_check_open_permission(struct tomoyo_domain_info *domain, + struct path *path, const int flag); +int tomoyo_check_1path_perm(struct tomoyo_domain_info *domain, + const u8 operation, struct path *path); +int tomoyo_check_2path_perm(struct tomoyo_domain_info *domain, + const u8 operation, struct path *path1, + struct path *path2); +int tomoyo_check_rewrite_permission(struct tomoyo_domain_info *domain, + struct file *filp); +int tomoyo_find_next_domain(struct linux_binprm *bprm); + +/********** External variable definitions. **********/ + +/* Lock for GC. */ +extern struct srcu_struct tomoyo_ss; + +/* The list for "struct tomoyo_domain_info". */ +extern struct list_head tomoyo_domain_list; + +/* Lock for protecting policy. */ +extern struct mutex tomoyo_policy_lock; + +/* Has /sbin/init started? */ +extern bool tomoyo_policy_loaded; + +/* The kernel's domain. */ +extern struct tomoyo_domain_info tomoyo_kernel_domain; + +/********** Inlined functions. **********/ + +static inline int tomoyo_read_lock(void) +{ + return srcu_read_lock(&tomoyo_ss); +} + +static inline void tomoyo_read_unlock(int idx) +{ + srcu_read_unlock(&tomoyo_ss, idx); +} + /* strcmp() for "struct tomoyo_path_info" structure. */ static inline bool tomoyo_pathcmp(const struct tomoyo_path_info *a, const struct tomoyo_path_info *b) @@ -398,17 +693,25 @@ static inline bool tomoyo_is_invalid(const unsigned char c) return c && (c <= ' ' || c >= 127); } -/* The list for "struct tomoyo_domain_info". */ -extern struct list_head tomoyo_domain_list; +static inline void tomoyo_put_name(const struct tomoyo_path_info *name) +{ + if (name) { + struct tomoyo_name_entry *ptr = + container_of(name, struct tomoyo_name_entry, entry); + atomic_dec(&ptr->users); + } +} -/* Lock for protecting policy. */ -extern struct mutex tomoyo_policy_lock; +static inline struct tomoyo_domain_info *tomoyo_domain(void) +{ + return current_cred()->security; +} -/* Has /sbin/init started? */ -extern bool tomoyo_policy_loaded; - -/* The kernel's domain. */ -extern struct tomoyo_domain_info tomoyo_kernel_domain; +static inline struct tomoyo_domain_info *tomoyo_real_domain(struct task_struct + *task) +{ + return task_cred_xxx(task, security); +} /** * list_for_each_cookie - iterate over a list with cookie. @@ -428,16 +731,4 @@ extern struct tomoyo_domain_info tomoyo_kernel_domain; prefetch(pos->next), pos != (head) || ((cookie) = NULL); \ (cookie) = pos, pos = rcu_dereference(pos->next)) -extern struct srcu_struct tomoyo_ss; - -static inline int tomoyo_read_lock(void) -{ - return srcu_read_lock(&tomoyo_ss); -} - -static inline void tomoyo_read_unlock(int idx) -{ - srcu_read_unlock(&tomoyo_ss, idx); -} - #endif /* !defined(_SECURITY_TOMOYO_COMMON_H) */ diff --git a/security/tomoyo/domain.c b/security/tomoyo/domain.c index 0b826256780..d60b8a61b0c 100644 --- a/security/tomoyo/domain.c +++ b/security/tomoyo/domain.c @@ -10,8 +10,6 @@ */ #include "common.h" -#include "tomoyo.h" -#include "realpath.h" #include /* Variables definitions.*/ @@ -59,76 +57,6 @@ struct tomoyo_domain_info tomoyo_kernel_domain; */ LIST_HEAD(tomoyo_domain_list); -/* - * tomoyo_domain_initializer_entry is a structure which is used for holding - * "initialize_domain" and "no_initialize_domain" entries. - * It has following fields. - * - * (1) "list" which is linked to tomoyo_domain_initializer_list . - * (2) "domainname" which is "a domainname" or "the last component of a - * domainname". This field is NULL if "from" clause is not specified. - * (3) "program" which is a program's pathname. - * (4) "is_deleted" is a bool which is true if marked as deleted, false - * otherwise. - * (5) "is_not" is a bool which is true if "no_initialize_domain", false - * otherwise. - * (6) "is_last_name" is a bool which is true if "domainname" is "the last - * component of a domainname", false otherwise. - */ -struct tomoyo_domain_initializer_entry { - struct list_head list; - const struct tomoyo_path_info *domainname; /* This may be NULL */ - const struct tomoyo_path_info *program; - bool is_deleted; - bool is_not; /* True if this entry is "no_initialize_domain". */ - /* True if the domainname is tomoyo_get_last_name(). */ - bool is_last_name; -}; - -/* - * tomoyo_domain_keeper_entry is a structure which is used for holding - * "keep_domain" and "no_keep_domain" entries. - * It has following fields. - * - * (1) "list" which is linked to tomoyo_domain_keeper_list . - * (2) "domainname" which is "a domainname" or "the last component of a - * domainname". - * (3) "program" which is a program's pathname. - * This field is NULL if "from" clause is not specified. - * (4) "is_deleted" is a bool which is true if marked as deleted, false - * otherwise. - * (5) "is_not" is a bool which is true if "no_initialize_domain", false - * otherwise. - * (6) "is_last_name" is a bool which is true if "domainname" is "the last - * component of a domainname", false otherwise. - */ -struct tomoyo_domain_keeper_entry { - struct list_head list; - const struct tomoyo_path_info *domainname; - const struct tomoyo_path_info *program; /* This may be NULL */ - bool is_deleted; - bool is_not; /* True if this entry is "no_keep_domain". */ - /* True if the domainname is tomoyo_get_last_name(). */ - bool is_last_name; -}; - -/* - * tomoyo_alias_entry is a structure which is used for holding "alias" entries. - * It has following fields. - * - * (1) "list" which is linked to tomoyo_alias_list . - * (2) "original_name" which is a dereferenced pathname. - * (3) "aliased_name" which is a symlink's pathname. - * (4) "is_deleted" is a bool which is true if marked as deleted, false - * otherwise. - */ -struct tomoyo_alias_entry { - struct list_head list; - const struct tomoyo_path_info *original_name; - const struct tomoyo_path_info *aliased_name; - bool is_deleted; -}; - /** * tomoyo_get_last_name - Get last component of a domainname. * diff --git a/security/tomoyo/file.c b/security/tomoyo/file.c index a49e18cc7bc..c69dd39e604 100644 --- a/security/tomoyo/file.c +++ b/security/tomoyo/file.c @@ -10,58 +10,6 @@ */ #include "common.h" -#include "tomoyo.h" -#include "realpath.h" - -/* - * tomoyo_globally_readable_file_entry is a structure which is used for holding - * "allow_read" entries. - * It has following fields. - * - * (1) "list" which is linked to tomoyo_globally_readable_list . - * (2) "filename" is a pathname which is allowed to open(O_RDONLY). - * (3) "is_deleted" is a bool which is true if marked as deleted, false - * otherwise. - */ -struct tomoyo_globally_readable_file_entry { - struct list_head list; - const struct tomoyo_path_info *filename; - bool is_deleted; -}; - -/* - * tomoyo_pattern_entry is a structure which is used for holding - * "tomoyo_pattern_list" entries. - * It has following fields. - * - * (1) "list" which is linked to tomoyo_pattern_list . - * (2) "pattern" is a pathname pattern which is used for converting pathnames - * to pathname patterns during learning mode. - * (3) "is_deleted" is a bool which is true if marked as deleted, false - * otherwise. - */ -struct tomoyo_pattern_entry { - struct list_head list; - const struct tomoyo_path_info *pattern; - bool is_deleted; -}; - -/* - * tomoyo_no_rewrite_entry is a structure which is used for holding - * "deny_rewrite" entries. - * It has following fields. - * - * (1) "list" which is linked to tomoyo_no_rewrite_list . - * (2) "pattern" is a pathname which is by default not permitted to modify - * already existing content. - * (3) "is_deleted" is a bool which is true if marked as deleted, false - * otherwise. - */ -struct tomoyo_no_rewrite_entry { - struct list_head list; - const struct tomoyo_path_info *pattern; - bool is_deleted; -}; /* Keyword array for single path operations. */ static const char *tomoyo_sp_keyword[TOMOYO_MAX_SINGLE_PATH_OPERATION] = { diff --git a/security/tomoyo/realpath.c b/security/tomoyo/realpath.c index 2f7f54fc681..9557168b376 100644 --- a/security/tomoyo/realpath.c +++ b/security/tomoyo/realpath.c @@ -15,9 +15,7 @@ #include #include #include - #include "common.h" -#include "realpath.h" /** * tomoyo_encode: Convert binary string to ascii string. @@ -245,14 +243,6 @@ static unsigned int tomoyo_allocated_memory_for_savename; /* Quota for holding string data in bytes. */ static unsigned int tomoyo_quota_for_savename; -/* - * TOMOYO uses this hash only when appending a string into the string - * table. Frequency of appending strings is very low. So we don't need - * large (e.g. 64k) hash size. 256 will be sufficient. - */ -#define TOMOYO_HASH_BITS 8 -#define TOMOYO_MAX_HASH (1u<users); - } -} - -#endif /* !defined(_SECURITY_TOMOYO_REALPATH_H) */ diff --git a/security/tomoyo/tomoyo.c b/security/tomoyo/tomoyo.c index 714daa34d49..8a0988dade7 100644 --- a/security/tomoyo/tomoyo.c +++ b/security/tomoyo/tomoyo.c @@ -11,8 +11,6 @@ #include #include "common.h" -#include "tomoyo.h" -#include "realpath.h" static int tomoyo_cred_alloc_blank(struct cred *new, gfp_t gfp) { diff --git a/security/tomoyo/tomoyo.h b/security/tomoyo/tomoyo.h deleted file mode 100644 index bf3986addc1..00000000000 --- a/security/tomoyo/tomoyo.h +++ /dev/null @@ -1,102 +0,0 @@ -/* - * security/tomoyo/tomoyo.h - * - * Implementation of the Domain-Based Mandatory Access Control. - * - * Copyright (C) 2005-2009 NTT DATA CORPORATION - * - * Version: 2.2.0 2009/04/01 - * - */ - -#ifndef _SECURITY_TOMOYO_TOMOYO_H -#define _SECURITY_TOMOYO_TOMOYO_H - -struct tomoyo_path_info; -struct path; -struct inode; -struct linux_binprm; -struct pt_regs; - -int tomoyo_check_exec_perm(struct tomoyo_domain_info *domain, - const struct tomoyo_path_info *filename); -int tomoyo_check_open_permission(struct tomoyo_domain_info *domain, - struct path *path, const int flag); -int tomoyo_check_1path_perm(struct tomoyo_domain_info *domain, - const u8 operation, struct path *path); -int tomoyo_check_2path_perm(struct tomoyo_domain_info *domain, - const u8 operation, struct path *path1, - struct path *path2); -int tomoyo_check_rewrite_permission(struct tomoyo_domain_info *domain, - struct file *filp); -int tomoyo_find_next_domain(struct linux_binprm *bprm); - -/* Index numbers for Access Controls. */ - -#define TOMOYO_TYPE_SINGLE_PATH_ACL 0 -#define TOMOYO_TYPE_DOUBLE_PATH_ACL 1 - -/* Index numbers for File Controls. */ - -/* - * TYPE_READ_WRITE_ACL is special. TYPE_READ_WRITE_ACL is automatically set - * if both TYPE_READ_ACL and TYPE_WRITE_ACL are set. Both TYPE_READ_ACL and - * TYPE_WRITE_ACL are automatically set if TYPE_READ_WRITE_ACL is set. - * TYPE_READ_WRITE_ACL is automatically cleared if either TYPE_READ_ACL or - * TYPE_WRITE_ACL is cleared. Both TYPE_READ_ACL and TYPE_WRITE_ACL are - * automatically cleared if TYPE_READ_WRITE_ACL is cleared. - */ - -#define TOMOYO_TYPE_READ_WRITE_ACL 0 -#define TOMOYO_TYPE_EXECUTE_ACL 1 -#define TOMOYO_TYPE_READ_ACL 2 -#define TOMOYO_TYPE_WRITE_ACL 3 -#define TOMOYO_TYPE_CREATE_ACL 4 -#define TOMOYO_TYPE_UNLINK_ACL 5 -#define TOMOYO_TYPE_MKDIR_ACL 6 -#define TOMOYO_TYPE_RMDIR_ACL 7 -#define TOMOYO_TYPE_MKFIFO_ACL 8 -#define TOMOYO_TYPE_MKSOCK_ACL 9 -#define TOMOYO_TYPE_MKBLOCK_ACL 10 -#define TOMOYO_TYPE_MKCHAR_ACL 11 -#define TOMOYO_TYPE_TRUNCATE_ACL 12 -#define TOMOYO_TYPE_SYMLINK_ACL 13 -#define TOMOYO_TYPE_REWRITE_ACL 14 -#define TOMOYO_TYPE_IOCTL_ACL 15 -#define TOMOYO_TYPE_CHMOD_ACL 16 -#define TOMOYO_TYPE_CHOWN_ACL 17 -#define TOMOYO_TYPE_CHGRP_ACL 18 -#define TOMOYO_TYPE_CHROOT_ACL 19 -#define TOMOYO_TYPE_MOUNT_ACL 20 -#define TOMOYO_TYPE_UMOUNT_ACL 21 -#define TOMOYO_MAX_SINGLE_PATH_OPERATION 22 - -#define TOMOYO_TYPE_LINK_ACL 0 -#define TOMOYO_TYPE_RENAME_ACL 1 -#define TOMOYO_TYPE_PIVOT_ROOT_ACL 2 -#define TOMOYO_MAX_DOUBLE_PATH_OPERATION 3 - -#define TOMOYO_DOMAINPOLICY 0 -#define TOMOYO_EXCEPTIONPOLICY 1 -#define TOMOYO_DOMAIN_STATUS 2 -#define TOMOYO_PROCESS_STATUS 3 -#define TOMOYO_MEMINFO 4 -#define TOMOYO_SELFDOMAIN 5 -#define TOMOYO_VERSION 6 -#define TOMOYO_PROFILE 7 -#define TOMOYO_MANAGER 8 - -extern struct tomoyo_domain_info tomoyo_kernel_domain; - -static inline struct tomoyo_domain_info *tomoyo_domain(void) -{ - return current_cred()->security; -} - -static inline struct tomoyo_domain_info *tomoyo_real_domain(struct task_struct - *task) -{ - return task_cred_xxx(task, security); -} - -#endif /* !defined(_SECURITY_TOMOYO_TOMOYO_H) */ From ec8e6a4e062e2edebef91e930c20572c9f4c0dda Mon Sep 17 00:00:00 2001 From: Tetsuo Handa Date: Thu, 11 Feb 2010 09:43:20 +0900 Subject: [PATCH 28/38] TOMOYO: Add refcounter on domain structure. Add refcounter to "struct tomoyo_domain_info" since garbage collector needs to determine whether this struct is referred by "struct cred"->security or not. Signed-off-by: Tetsuo Handa Acked-by: Serge Hallyn Signed-off-by: James Morris --- security/tomoyo/common.h | 5 +++++ security/tomoyo/domain.c | 2 ++ security/tomoyo/tomoyo.c | 37 +++++++++++++++++++++---------------- 3 files changed, 28 insertions(+), 16 deletions(-) diff --git a/security/tomoyo/common.h b/security/tomoyo/common.h index f6aff59b088..521b4b5adda 100644 --- a/security/tomoyo/common.h +++ b/security/tomoyo/common.h @@ -234,6 +234,10 @@ struct tomoyo_acl_info { * name of the domain to be created was too long or it could not allocate * memory. If set to true, more than one process continued execve() * without domain transition. + * (9) "users" is an atomic_t that holds how many "struct cred"->security + * are referring this "struct tomoyo_domain_info". If is_deleted == true + * and users == 0, this struct will be kfree()d upon next garbage + * collection. * * A domain's lifecycle is an analogy of files on / directory. * Multiple domains with the same domainname cannot be created (as with @@ -252,6 +256,7 @@ struct tomoyo_domain_info { bool quota_warned; /* Quota warnning flag. */ bool ignore_global_allow_read; /* Ignore "allow_read" flag. */ bool transition_failed; /* Domain transition failed flag. */ + atomic_t users; /* Number of referring credentials. */ }; /* diff --git a/security/tomoyo/domain.c b/security/tomoyo/domain.c index d60b8a61b0c..6f74b30d6bb 100644 --- a/security/tomoyo/domain.c +++ b/security/tomoyo/domain.c @@ -817,6 +817,8 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm) out: if (!domain) domain = old_domain; + /* Update reference count on "struct tomoyo_domain_info". */ + atomic_inc(&domain->users); bprm->cred->security = domain; kfree(real_program_name); kfree(symlink_program_name); diff --git a/security/tomoyo/tomoyo.c b/security/tomoyo/tomoyo.c index 8a0988dade7..87e82bfeac2 100644 --- a/security/tomoyo/tomoyo.c +++ b/security/tomoyo/tomoyo.c @@ -21,21 +21,23 @@ static int tomoyo_cred_alloc_blank(struct cred *new, gfp_t gfp) static int tomoyo_cred_prepare(struct cred *new, const struct cred *old, gfp_t gfp) { - /* - * Since "struct tomoyo_domain_info *" is a sharable pointer, - * we don't need to duplicate. - */ - new->security = old->security; + struct tomoyo_domain_info *domain = old->security; + new->security = domain; + if (domain) + atomic_inc(&domain->users); return 0; } static void tomoyo_cred_transfer(struct cred *new, const struct cred *old) { - /* - * Since "struct tomoyo_domain_info *" is a sharable pointer, - * we don't need to duplicate. - */ - new->security = old->security; + tomoyo_cred_prepare(new, old, 0); +} + +static void tomoyo_cred_free(struct cred *cred) +{ + struct tomoyo_domain_info *domain = cred->security; + if (domain) + atomic_dec(&domain->users); } static int tomoyo_bprm_set_creds(struct linux_binprm *bprm) @@ -58,6 +60,14 @@ static int tomoyo_bprm_set_creds(struct linux_binprm *bprm) */ if (!tomoyo_policy_loaded) tomoyo_load_policy(bprm->filename); + /* + * Release reference to "struct tomoyo_domain_info" stored inside + * "bprm->cred->security". New reference to "struct tomoyo_domain_info" + * stored inside "bprm->cred->security" will be acquired later inside + * tomoyo_find_next_domain(). + */ + atomic_dec(&((struct tomoyo_domain_info *) + bprm->cred->security)->users); /* * Tell tomoyo_bprm_check_security() is called for the first time of an * execve operation. @@ -75,12 +85,6 @@ static int tomoyo_bprm_check_security(struct linux_binprm *bprm) * using current domain. */ if (!domain) { - /* - * We will need to protect whole execve() operation when GC - * starts kfree()ing "struct tomoyo_domain_info" because - * bprm->cred->security points to "struct tomoyo_domain_info" - * but "struct tomoyo_domain_info" does not have a refcounter. - */ const int idx = tomoyo_read_lock(); const int err = tomoyo_find_next_domain(bprm); tomoyo_read_unlock(idx); @@ -265,6 +269,7 @@ static struct security_operations tomoyo_security_ops = { .cred_alloc_blank = tomoyo_cred_alloc_blank, .cred_prepare = tomoyo_cred_prepare, .cred_transfer = tomoyo_cred_transfer, + .cred_free = tomoyo_cred_free, .bprm_set_creds = tomoyo_bprm_set_creds, .bprm_check_security = tomoyo_bprm_check_security, .file_fcntl = tomoyo_file_fcntl, From 847b173ea3d6f50936823d07f2245059bf44713b Mon Sep 17 00:00:00 2001 From: Tetsuo Handa Date: Thu, 11 Feb 2010 09:43:54 +0900 Subject: [PATCH 29/38] TOMOYO: Add garbage collector. This patch adds garbage collector support to TOMOYO. Elements are protected by "struct srcu_struct tomoyo_ss". Signed-off-by: Tetsuo Handa Acked-by: Serge Hallyn Signed-off-by: James Morris --- security/tomoyo/Makefile | 2 +- security/tomoyo/common.c | 5 +- security/tomoyo/common.h | 15 ++ security/tomoyo/domain.c | 6 +- security/tomoyo/file.c | 6 +- security/tomoyo/gc.c | 370 +++++++++++++++++++++++++++++++++++++ security/tomoyo/realpath.c | 86 ++++----- 7 files changed, 436 insertions(+), 54 deletions(-) create mode 100644 security/tomoyo/gc.c diff --git a/security/tomoyo/Makefile b/security/tomoyo/Makefile index 10ccd686b29..60a9e2002da 100644 --- a/security/tomoyo/Makefile +++ b/security/tomoyo/Makefile @@ -1 +1 @@ -obj-y = common.o realpath.o tomoyo.o domain.o file.o +obj-y = common.o realpath.o tomoyo.o domain.o file.o gc.o diff --git a/security/tomoyo/common.c b/security/tomoyo/common.c index 634f7449e8b..3a36b56a2f5 100644 --- a/security/tomoyo/common.c +++ b/security/tomoyo/common.c @@ -1067,7 +1067,7 @@ static int tomoyo_read_profile(struct tomoyo_io_buffer *head) * * # cat /sys/kernel/security/tomoyo/manager */ -static LIST_HEAD(tomoyo_policy_manager_list); +LIST_HEAD(tomoyo_policy_manager_list); /** * tomoyo_update_manager_entry - Add a manager entry. @@ -2109,6 +2109,7 @@ static int tomoyo_write_control(struct file *file, const char __user *buffer, static int tomoyo_close_control(struct file *file) { struct tomoyo_io_buffer *head = file->private_data; + const bool is_write = !!head->write_buf; tomoyo_read_unlock(head->reader_idx); /* Release memory used for policy I/O. */ @@ -2119,6 +2120,8 @@ static int tomoyo_close_control(struct file *file) kfree(head); head = NULL; file->private_data = NULL; + if (is_write) + tomoyo_run_gc(); return 0; } diff --git a/security/tomoyo/common.h b/security/tomoyo/common.h index 521b4b5adda..1c8c97a4c06 100644 --- a/security/tomoyo/common.h +++ b/security/tomoyo/common.h @@ -638,6 +638,11 @@ int tomoyo_check_rewrite_permission(struct tomoyo_domain_info *domain, struct file *filp); int tomoyo_find_next_domain(struct linux_binprm *bprm); +/* Run garbage collector. */ +void tomoyo_run_gc(void); + +void tomoyo_memory_free(void *ptr); + /********** External variable definitions. **********/ /* Lock for GC. */ @@ -646,6 +651,16 @@ extern struct srcu_struct tomoyo_ss; /* The list for "struct tomoyo_domain_info". */ extern struct list_head tomoyo_domain_list; +extern struct list_head tomoyo_domain_initializer_list; +extern struct list_head tomoyo_domain_keeper_list; +extern struct list_head tomoyo_alias_list; +extern struct list_head tomoyo_globally_readable_list; +extern struct list_head tomoyo_pattern_list; +extern struct list_head tomoyo_no_rewrite_list; +extern struct list_head tomoyo_policy_manager_list; +extern struct list_head tomoyo_name_list[TOMOYO_MAX_HASH]; +extern struct mutex tomoyo_name_list_lock; + /* Lock for protecting policy. */ extern struct mutex tomoyo_policy_lock; diff --git a/security/tomoyo/domain.c b/security/tomoyo/domain.c index 6f74b30d6bb..74cd0f52e3a 100644 --- a/security/tomoyo/domain.c +++ b/security/tomoyo/domain.c @@ -110,7 +110,7 @@ const char *tomoyo_get_last_name(const struct tomoyo_domain_info *domain) * will cause "/usr/sbin/httpd" to belong to " /usr/sbin/httpd" domain * unless executed from " /etc/rc.d/init.d/httpd" domain. */ -static LIST_HEAD(tomoyo_domain_initializer_list); +LIST_HEAD(tomoyo_domain_initializer_list); /** * tomoyo_update_domain_initializer_entry - Update "struct tomoyo_domain_initializer_entry" list. @@ -330,7 +330,7 @@ static bool tomoyo_is_domain_initializer(const struct tomoyo_path_info * * " /usr/sbin/sshd /bin/bash /usr/bin/passwd" domain, unless * explicitly specified by "initialize_domain". */ -static LIST_HEAD(tomoyo_domain_keeper_list); +LIST_HEAD(tomoyo_domain_keeper_list); /** * tomoyo_update_domain_keeper_entry - Update "struct tomoyo_domain_keeper_entry" list. @@ -533,7 +533,7 @@ static bool tomoyo_is_domain_keeper(const struct tomoyo_path_info *domainname, * /bin/busybox and domainname which the current process will belong to after * execve() succeeds is calculated using /bin/cat rather than /bin/busybox . */ -static LIST_HEAD(tomoyo_alias_list); +LIST_HEAD(tomoyo_alias_list); /** * tomoyo_update_alias_entry - Update "struct tomoyo_alias_entry" list. diff --git a/security/tomoyo/file.c b/security/tomoyo/file.c index c69dd39e604..10ee7cece08 100644 --- a/security/tomoyo/file.c +++ b/security/tomoyo/file.c @@ -148,7 +148,7 @@ static int tomoyo_update_single_path_acl(const u8 type, const char *filename, * given "allow_read /lib/libc-2.5.so" to the domain which current process * belongs to. */ -static LIST_HEAD(tomoyo_globally_readable_list); +LIST_HEAD(tomoyo_globally_readable_list); /** * tomoyo_update_globally_readable_entry - Update "struct tomoyo_globally_readable_file_entry" list. @@ -295,7 +295,7 @@ bool tomoyo_read_globally_readable_policy(struct tomoyo_io_buffer *head) * which pretends as if /proc/self/ is not a symlink; so that we can forbid * current process from accessing other process's information. */ -static LIST_HEAD(tomoyo_pattern_list); +LIST_HEAD(tomoyo_pattern_list); /** * tomoyo_update_file_pattern_entry - Update "struct tomoyo_pattern_entry" list. @@ -448,7 +448,7 @@ bool tomoyo_read_file_pattern(struct tomoyo_io_buffer *head) * " (deleted)" suffix if the file is already unlink()ed; so that we don't * need to worry whether the file is already unlink()ed or not. */ -static LIST_HEAD(tomoyo_no_rewrite_list); +LIST_HEAD(tomoyo_no_rewrite_list); /** * tomoyo_update_no_rewrite_entry - Update "struct tomoyo_no_rewrite_entry" list. diff --git a/security/tomoyo/gc.c b/security/tomoyo/gc.c new file mode 100644 index 00000000000..ee15da39387 --- /dev/null +++ b/security/tomoyo/gc.c @@ -0,0 +1,370 @@ +/* + * security/tomoyo/gc.c + * + * Implementation of the Domain-Based Mandatory Access Control. + * + * Copyright (C) 2005-2010 NTT DATA CORPORATION + * + */ + +#include "common.h" +#include + +enum tomoyo_gc_id { + TOMOYO_ID_DOMAIN_INITIALIZER, + TOMOYO_ID_DOMAIN_KEEPER, + TOMOYO_ID_ALIAS, + TOMOYO_ID_GLOBALLY_READABLE, + TOMOYO_ID_PATTERN, + TOMOYO_ID_NO_REWRITE, + TOMOYO_ID_MANAGER, + TOMOYO_ID_NAME, + TOMOYO_ID_ACL, + TOMOYO_ID_DOMAIN +}; + +struct tomoyo_gc_entry { + struct list_head list; + int type; + void *element; +}; +static LIST_HEAD(tomoyo_gc_queue); +static DEFINE_MUTEX(tomoyo_gc_mutex); + +/* Caller holds tomoyo_policy_lock mutex. */ +static bool tomoyo_add_to_gc(const int type, void *element) +{ + struct tomoyo_gc_entry *entry = kzalloc(sizeof(*entry), GFP_ATOMIC); + if (!entry) + return false; + entry->type = type; + entry->element = element; + list_add(&entry->list, &tomoyo_gc_queue); + return true; +} + +static void tomoyo_del_allow_read +(struct tomoyo_globally_readable_file_entry *ptr) +{ + tomoyo_put_name(ptr->filename); +} + +static void tomoyo_del_file_pattern(struct tomoyo_pattern_entry *ptr) +{ + tomoyo_put_name(ptr->pattern); +} + +static void tomoyo_del_no_rewrite(struct tomoyo_no_rewrite_entry *ptr) +{ + tomoyo_put_name(ptr->pattern); +} + +static void tomoyo_del_domain_initializer +(struct tomoyo_domain_initializer_entry *ptr) +{ + tomoyo_put_name(ptr->domainname); + tomoyo_put_name(ptr->program); +} + +static void tomoyo_del_domain_keeper(struct tomoyo_domain_keeper_entry *ptr) +{ + tomoyo_put_name(ptr->domainname); + tomoyo_put_name(ptr->program); +} + +static void tomoyo_del_alias(struct tomoyo_alias_entry *ptr) +{ + tomoyo_put_name(ptr->original_name); + tomoyo_put_name(ptr->aliased_name); +} + +static void tomoyo_del_manager(struct tomoyo_policy_manager_entry *ptr) +{ + tomoyo_put_name(ptr->manager); +} + +static void tomoyo_del_acl(struct tomoyo_acl_info *acl) +{ + switch (acl->type) { + case TOMOYO_TYPE_SINGLE_PATH_ACL: + { + struct tomoyo_single_path_acl_record *entry + = container_of(acl, typeof(*entry), head); + tomoyo_put_name(entry->filename); + } + break; + case TOMOYO_TYPE_DOUBLE_PATH_ACL: + { + struct tomoyo_double_path_acl_record *entry + = container_of(acl, typeof(*entry), head); + tomoyo_put_name(entry->filename1); + tomoyo_put_name(entry->filename2); + } + break; + default: + printk(KERN_WARNING "Unknown type\n"); + break; + } +} + +static bool tomoyo_del_domain(struct tomoyo_domain_info *domain) +{ + struct tomoyo_acl_info *acl; + struct tomoyo_acl_info *tmp; + /* + * Since we don't protect whole execve() operation using SRCU, + * we need to recheck domain->users at this point. + * + * (1) Reader starts SRCU section upon execve(). + * (2) Reader traverses tomoyo_domain_list and finds this domain. + * (3) Writer marks this domain as deleted. + * (4) Garbage collector removes this domain from tomoyo_domain_list + * because this domain is marked as deleted and used by nobody. + * (5) Reader saves reference to this domain into + * "struct linux_binprm"->cred->security . + * (6) Reader finishes SRCU section, although execve() operation has + * not finished yet. + * (7) Garbage collector waits for SRCU synchronization. + * (8) Garbage collector kfree() this domain because this domain is + * used by nobody. + * (9) Reader finishes execve() operation and restores this domain from + * "struct linux_binprm"->cred->security. + * + * By updating domain->users at (5), we can solve this race problem + * by rechecking domain->users at (8). + */ + if (atomic_read(&domain->users)) + return false; + list_for_each_entry_safe(acl, tmp, &domain->acl_info_list, list) { + tomoyo_del_acl(acl); + tomoyo_memory_free(acl); + } + tomoyo_put_name(domain->domainname); + return true; +} + + +static void tomoyo_del_name(const struct tomoyo_name_entry *ptr) +{ +} + +static void tomoyo_collect_entry(void) +{ + mutex_lock(&tomoyo_policy_lock); + { + struct tomoyo_globally_readable_file_entry *ptr; + list_for_each_entry_rcu(ptr, &tomoyo_globally_readable_list, + list) { + if (!ptr->is_deleted) + continue; + if (tomoyo_add_to_gc(TOMOYO_ID_GLOBALLY_READABLE, ptr)) + list_del_rcu(&ptr->list); + else + break; + } + } + { + struct tomoyo_pattern_entry *ptr; + list_for_each_entry_rcu(ptr, &tomoyo_pattern_list, list) { + if (!ptr->is_deleted) + continue; + if (tomoyo_add_to_gc(TOMOYO_ID_PATTERN, ptr)) + list_del_rcu(&ptr->list); + else + break; + } + } + { + struct tomoyo_no_rewrite_entry *ptr; + list_for_each_entry_rcu(ptr, &tomoyo_no_rewrite_list, list) { + if (!ptr->is_deleted) + continue; + if (tomoyo_add_to_gc(TOMOYO_ID_NO_REWRITE, ptr)) + list_del_rcu(&ptr->list); + else + break; + } + } + { + struct tomoyo_domain_initializer_entry *ptr; + list_for_each_entry_rcu(ptr, &tomoyo_domain_initializer_list, + list) { + if (!ptr->is_deleted) + continue; + if (tomoyo_add_to_gc(TOMOYO_ID_DOMAIN_INITIALIZER, ptr)) + list_del_rcu(&ptr->list); + else + break; + } + } + { + struct tomoyo_domain_keeper_entry *ptr; + list_for_each_entry_rcu(ptr, &tomoyo_domain_keeper_list, list) { + if (!ptr->is_deleted) + continue; + if (tomoyo_add_to_gc(TOMOYO_ID_DOMAIN_KEEPER, ptr)) + list_del_rcu(&ptr->list); + else + break; + } + } + { + struct tomoyo_alias_entry *ptr; + list_for_each_entry_rcu(ptr, &tomoyo_alias_list, list) { + if (!ptr->is_deleted) + continue; + if (tomoyo_add_to_gc(TOMOYO_ID_ALIAS, ptr)) + list_del_rcu(&ptr->list); + else + break; + } + } + { + struct tomoyo_policy_manager_entry *ptr; + list_for_each_entry_rcu(ptr, &tomoyo_policy_manager_list, + list) { + if (!ptr->is_deleted) + continue; + if (tomoyo_add_to_gc(TOMOYO_ID_MANAGER, ptr)) + list_del_rcu(&ptr->list); + else + break; + } + } + { + struct tomoyo_domain_info *domain; + list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) { + struct tomoyo_acl_info *acl; + list_for_each_entry_rcu(acl, &domain->acl_info_list, + list) { + switch (acl->type) { + case TOMOYO_TYPE_SINGLE_PATH_ACL: + if (container_of(acl, + struct tomoyo_single_path_acl_record, + head)->perm || + container_of(acl, + struct tomoyo_single_path_acl_record, + head)->perm_high) + continue; + break; + case TOMOYO_TYPE_DOUBLE_PATH_ACL: + if (container_of(acl, + struct tomoyo_double_path_acl_record, + head)->perm) + continue; + break; + default: + continue; + } + if (tomoyo_add_to_gc(TOMOYO_ID_ACL, acl)) + list_del_rcu(&acl->list); + else + break; + } + if (!domain->is_deleted || atomic_read(&domain->users)) + continue; + /* + * Nobody is referring this domain. But somebody may + * refer this domain after successful execve(). + * We recheck domain->users after SRCU synchronization. + */ + if (tomoyo_add_to_gc(TOMOYO_ID_DOMAIN, domain)) + list_del_rcu(&domain->list); + else + break; + } + } + mutex_unlock(&tomoyo_policy_lock); + mutex_lock(&tomoyo_name_list_lock); + { + int i; + for (i = 0; i < TOMOYO_MAX_HASH; i++) { + struct tomoyo_name_entry *ptr; + list_for_each_entry_rcu(ptr, &tomoyo_name_list[i], + list) { + if (atomic_read(&ptr->users)) + continue; + if (tomoyo_add_to_gc(TOMOYO_ID_NAME, ptr)) + list_del_rcu(&ptr->list); + else { + i = TOMOYO_MAX_HASH; + break; + } + } + } + } + mutex_unlock(&tomoyo_name_list_lock); +} + +static void tomoyo_kfree_entry(void) +{ + struct tomoyo_gc_entry *p; + struct tomoyo_gc_entry *tmp; + + list_for_each_entry_safe(p, tmp, &tomoyo_gc_queue, list) { + switch (p->type) { + case TOMOYO_ID_DOMAIN_INITIALIZER: + tomoyo_del_domain_initializer(p->element); + break; + case TOMOYO_ID_DOMAIN_KEEPER: + tomoyo_del_domain_keeper(p->element); + break; + case TOMOYO_ID_ALIAS: + tomoyo_del_alias(p->element); + break; + case TOMOYO_ID_GLOBALLY_READABLE: + tomoyo_del_allow_read(p->element); + break; + case TOMOYO_ID_PATTERN: + tomoyo_del_file_pattern(p->element); + break; + case TOMOYO_ID_NO_REWRITE: + tomoyo_del_no_rewrite(p->element); + break; + case TOMOYO_ID_MANAGER: + tomoyo_del_manager(p->element); + break; + case TOMOYO_ID_NAME: + tomoyo_del_name(p->element); + break; + case TOMOYO_ID_ACL: + tomoyo_del_acl(p->element); + break; + case TOMOYO_ID_DOMAIN: + if (!tomoyo_del_domain(p->element)) + continue; + break; + default: + printk(KERN_WARNING "Unknown type\n"); + break; + } + tomoyo_memory_free(p->element); + list_del(&p->list); + kfree(p); + } +} + +static int tomoyo_gc_thread(void *unused) +{ + daemonize("GC for TOMOYO"); + if (mutex_trylock(&tomoyo_gc_mutex)) { + int i; + for (i = 0; i < 10; i++) { + tomoyo_collect_entry(); + if (list_empty(&tomoyo_gc_queue)) + break; + synchronize_srcu(&tomoyo_ss); + tomoyo_kfree_entry(); + } + mutex_unlock(&tomoyo_gc_mutex); + } + do_exit(0); +} + +void tomoyo_run_gc(void) +{ + struct task_struct *task = kthread_create(tomoyo_gc_thread, NULL, + "GC for TOMOYO"); + if (!IS_ERR(task)) + wake_up_process(task); +} diff --git a/security/tomoyo/realpath.c b/security/tomoyo/realpath.c index 9557168b376..c00df45c7ed 100644 --- a/security/tomoyo/realpath.c +++ b/security/tomoyo/realpath.c @@ -205,9 +205,9 @@ char *tomoyo_realpath_nofollow(const char *pathname) } /* Memory allocated for non-string data. */ -static unsigned int tomoyo_allocated_memory_for_elements; -/* Quota for holding non-string data. */ -static unsigned int tomoyo_quota_for_elements; +static atomic_t tomoyo_policy_memory_size; +/* Quota for holding policy. */ +static unsigned int tomoyo_quota_for_policy; /** * tomoyo_memory_ok - Check memory quota. @@ -222,26 +222,30 @@ static unsigned int tomoyo_quota_for_elements; bool tomoyo_memory_ok(void *ptr) { int allocated_len = ptr ? ksize(ptr) : 0; - bool result = false; - if (!ptr || (tomoyo_quota_for_elements && - tomoyo_allocated_memory_for_elements - + allocated_len > tomoyo_quota_for_elements)) { - printk(KERN_WARNING "ERROR: Out of memory " - "for tomoyo_alloc_element().\n"); - if (!tomoyo_policy_loaded) - panic("MAC Initialization failed.\n"); - } else { - result = true; - tomoyo_allocated_memory_for_elements += allocated_len; + atomic_add(allocated_len, &tomoyo_policy_memory_size); + if (ptr && (!tomoyo_quota_for_policy || + atomic_read(&tomoyo_policy_memory_size) + <= tomoyo_quota_for_policy)) { memset(ptr, 0, allocated_len); + return true; } - return result; + printk(KERN_WARNING "ERROR: Out of memory " + "for tomoyo_alloc_element().\n"); + if (!tomoyo_policy_loaded) + panic("MAC Initialization failed.\n"); + return false; } -/* Memory allocated for string data in bytes. */ -static unsigned int tomoyo_allocated_memory_for_savename; -/* Quota for holding string data in bytes. */ -static unsigned int tomoyo_quota_for_savename; +/** + * tomoyo_memory_free - Free memory for elements. + * + * @ptr: Pointer to allocated memory. + */ +void tomoyo_memory_free(void *ptr) +{ + atomic_sub(ksize(ptr), &tomoyo_policy_memory_size); + kfree(ptr); +} /* * tomoyo_name_list is used for holding string data used by TOMOYO. @@ -249,7 +253,9 @@ static unsigned int tomoyo_quota_for_savename; * "/lib/libc-2.5.so"), TOMOYO shares string data in the form of * "const struct tomoyo_path_info *". */ -static struct list_head tomoyo_name_list[TOMOYO_MAX_HASH]; +struct list_head tomoyo_name_list[TOMOYO_MAX_HASH]; +/* Lock for protecting tomoyo_name_list . */ +DEFINE_MUTEX(tomoyo_name_list_lock); /** * tomoyo_get_name - Allocate permanent memory for string data. @@ -260,7 +266,6 @@ static struct list_head tomoyo_name_list[TOMOYO_MAX_HASH]; */ const struct tomoyo_path_info *tomoyo_get_name(const char *name) { - static DEFINE_MUTEX(lock); struct tomoyo_name_entry *ptr; unsigned int hash; int len; @@ -272,7 +277,7 @@ const struct tomoyo_path_info *tomoyo_get_name(const char *name) len = strlen(name) + 1; hash = full_name_hash((const unsigned char *) name, len - 1); head = &tomoyo_name_list[hash_long(hash, TOMOYO_HASH_BITS)]; - mutex_lock(&lock); + mutex_lock(&tomoyo_name_list_lock); list_for_each_entry(ptr, head, list) { if (hash != ptr->entry.hash || strcmp(name, ptr->entry.name)) continue; @@ -281,9 +286,9 @@ const struct tomoyo_path_info *tomoyo_get_name(const char *name) } ptr = kzalloc(sizeof(*ptr) + len, GFP_KERNEL); allocated_len = ptr ? ksize(ptr) : 0; - if (!ptr || (tomoyo_quota_for_savename && - tomoyo_allocated_memory_for_savename + allocated_len - > tomoyo_quota_for_savename)) { + if (!ptr || (tomoyo_quota_for_policy && + atomic_read(&tomoyo_policy_memory_size) + allocated_len + > tomoyo_quota_for_policy)) { kfree(ptr); printk(KERN_WARNING "ERROR: Out of memory " "for tomoyo_get_name().\n"); @@ -292,14 +297,14 @@ const struct tomoyo_path_info *tomoyo_get_name(const char *name) ptr = NULL; goto out; } - tomoyo_allocated_memory_for_savename += allocated_len; + atomic_add(allocated_len, &tomoyo_policy_memory_size); ptr->entry.name = ((char *) ptr) + sizeof(*ptr); memmove((char *) ptr->entry.name, name, len); atomic_set(&ptr->users, 1); tomoyo_fill_path_info(&ptr->entry); list_add_tail(&ptr->list, head); out: - mutex_unlock(&lock); + mutex_unlock(&tomoyo_name_list_lock); return ptr ? &ptr->entry : NULL; } @@ -334,28 +339,19 @@ void __init tomoyo_realpath_init(void) int tomoyo_read_memory_counter(struct tomoyo_io_buffer *head) { if (!head->read_eof) { - const unsigned int shared - = tomoyo_allocated_memory_for_savename; - const unsigned int private - = tomoyo_allocated_memory_for_elements; + const unsigned int policy + = atomic_read(&tomoyo_policy_memory_size); char buffer[64]; memset(buffer, 0, sizeof(buffer)); - if (tomoyo_quota_for_savename) + if (tomoyo_quota_for_policy) snprintf(buffer, sizeof(buffer) - 1, " (Quota: %10u)", - tomoyo_quota_for_savename); + tomoyo_quota_for_policy); else buffer[0] = '\0'; - tomoyo_io_printf(head, "Shared: %10u%s\n", shared, buffer); - if (tomoyo_quota_for_elements) - snprintf(buffer, sizeof(buffer) - 1, - " (Quota: %10u)", - tomoyo_quota_for_elements); - else - buffer[0] = '\0'; - tomoyo_io_printf(head, "Private: %10u%s\n", private, buffer); - tomoyo_io_printf(head, "Total: %10u\n", shared + private); + tomoyo_io_printf(head, "Policy: %10u%s\n", policy, buffer); + tomoyo_io_printf(head, "Total: %10u\n", policy); head->read_eof = true; } return 0; @@ -373,9 +369,7 @@ int tomoyo_write_memory_quota(struct tomoyo_io_buffer *head) char *data = head->write_buf; unsigned int size; - if (sscanf(data, "Shared: %u", &size) == 1) - tomoyo_quota_for_savename = size; - else if (sscanf(data, "Private: %u", &size) == 1) - tomoyo_quota_for_elements = size; + if (sscanf(data, "Policy: %u", &size) == 1) + tomoyo_quota_for_policy = size; return 0; } From 084da356f6e55ce42f1d2739178502023908c107 Mon Sep 17 00:00:00 2001 From: Tetsuo Handa Date: Mon, 15 Feb 2010 15:10:39 +0900 Subject: [PATCH 30/38] TOMOYO: Use enum for index numbers. Use enum to declare index numbers. Signed-off-by: Tetsuo Handa Signed-off-by: James Morris --- security/tomoyo/common.h | 95 ++++++++++++++++++++++------------------ 1 file changed, 52 insertions(+), 43 deletions(-) diff --git a/security/tomoyo/common.h b/security/tomoyo/common.h index 1c8c97a4c06..3727296f01f 100644 --- a/security/tomoyo/common.h +++ b/security/tomoyo/common.h @@ -62,15 +62,18 @@ struct linux_binprm; #define TOMOYO_ROOT_NAME_LEN (sizeof(TOMOYO_ROOT_NAME) - 1) /* Index numbers for Access Controls. */ -#define TOMOYO_MAC_FOR_FILE 0 /* domain_policy.conf */ -#define TOMOYO_MAX_ACCEPT_ENTRY 1 -#define TOMOYO_VERBOSE 2 -#define TOMOYO_MAX_CONTROL_INDEX 3 +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. */ - -#define TOMOYO_TYPE_SINGLE_PATH_ACL 0 -#define TOMOYO_TYPE_DOUBLE_PATH_ACL 1 +enum tomoyo_acl_entry_type_index { + TOMOYO_TYPE_SINGLE_PATH_ACL, + TOMOYO_TYPE_DOUBLE_PATH_ACL, +}; /* Index numbers for File Controls. */ @@ -83,44 +86,50 @@ struct linux_binprm; * automatically cleared if TYPE_READ_WRITE_ACL is cleared. */ -#define TOMOYO_TYPE_READ_WRITE_ACL 0 -#define TOMOYO_TYPE_EXECUTE_ACL 1 -#define TOMOYO_TYPE_READ_ACL 2 -#define TOMOYO_TYPE_WRITE_ACL 3 -#define TOMOYO_TYPE_CREATE_ACL 4 -#define TOMOYO_TYPE_UNLINK_ACL 5 -#define TOMOYO_TYPE_MKDIR_ACL 6 -#define TOMOYO_TYPE_RMDIR_ACL 7 -#define TOMOYO_TYPE_MKFIFO_ACL 8 -#define TOMOYO_TYPE_MKSOCK_ACL 9 -#define TOMOYO_TYPE_MKBLOCK_ACL 10 -#define TOMOYO_TYPE_MKCHAR_ACL 11 -#define TOMOYO_TYPE_TRUNCATE_ACL 12 -#define TOMOYO_TYPE_SYMLINK_ACL 13 -#define TOMOYO_TYPE_REWRITE_ACL 14 -#define TOMOYO_TYPE_IOCTL_ACL 15 -#define TOMOYO_TYPE_CHMOD_ACL 16 -#define TOMOYO_TYPE_CHOWN_ACL 17 -#define TOMOYO_TYPE_CHGRP_ACL 18 -#define TOMOYO_TYPE_CHROOT_ACL 19 -#define TOMOYO_TYPE_MOUNT_ACL 20 -#define TOMOYO_TYPE_UMOUNT_ACL 21 -#define TOMOYO_MAX_SINGLE_PATH_OPERATION 22 +enum tomoyo_path_acl_index { + TOMOYO_TYPE_READ_WRITE_ACL, + TOMOYO_TYPE_EXECUTE_ACL, + TOMOYO_TYPE_READ_ACL, + TOMOYO_TYPE_WRITE_ACL, + TOMOYO_TYPE_CREATE_ACL, + TOMOYO_TYPE_UNLINK_ACL, + TOMOYO_TYPE_MKDIR_ACL, + TOMOYO_TYPE_RMDIR_ACL, + TOMOYO_TYPE_MKFIFO_ACL, + TOMOYO_TYPE_MKSOCK_ACL, + TOMOYO_TYPE_MKBLOCK_ACL, + TOMOYO_TYPE_MKCHAR_ACL, + TOMOYO_TYPE_TRUNCATE_ACL, + TOMOYO_TYPE_SYMLINK_ACL, + TOMOYO_TYPE_REWRITE_ACL, + TOMOYO_TYPE_IOCTL_ACL, + TOMOYO_TYPE_CHMOD_ACL, + TOMOYO_TYPE_CHOWN_ACL, + TOMOYO_TYPE_CHGRP_ACL, + TOMOYO_TYPE_CHROOT_ACL, + TOMOYO_TYPE_MOUNT_ACL, + TOMOYO_TYPE_UMOUNT_ACL, + TOMOYO_MAX_SINGLE_PATH_OPERATION +}; -#define TOMOYO_TYPE_LINK_ACL 0 -#define TOMOYO_TYPE_RENAME_ACL 1 -#define TOMOYO_TYPE_PIVOT_ROOT_ACL 2 -#define TOMOYO_MAX_DOUBLE_PATH_OPERATION 3 +enum tomoyo_path2_acl_index { + TOMOYO_TYPE_LINK_ACL, + TOMOYO_TYPE_RENAME_ACL, + TOMOYO_TYPE_PIVOT_ROOT_ACL, + TOMOYO_MAX_DOUBLE_PATH_OPERATION +}; -#define TOMOYO_DOMAINPOLICY 0 -#define TOMOYO_EXCEPTIONPOLICY 1 -#define TOMOYO_DOMAIN_STATUS 2 -#define TOMOYO_PROCESS_STATUS 3 -#define TOMOYO_MEMINFO 4 -#define TOMOYO_SELFDOMAIN 5 -#define TOMOYO_VERSION 6 -#define TOMOYO_PROFILE 7 -#define TOMOYO_MANAGER 8 +enum tomoyo_securityfs_interface_index { + TOMOYO_DOMAINPOLICY, + TOMOYO_EXCEPTIONPOLICY, + TOMOYO_DOMAIN_STATUS, + TOMOYO_PROCESS_STATUS, + TOMOYO_MEMINFO, + TOMOYO_SELFDOMAIN, + TOMOYO_VERSION, + TOMOYO_PROFILE, + TOMOYO_MANAGER +}; /********** Structure definitions. **********/ From 7ef612331fb219620cc1abfc2446bb027d388aa0 Mon Sep 17 00:00:00 2001 From: Tetsuo Handa Date: Tue, 16 Feb 2010 08:03:30 +0900 Subject: [PATCH 31/38] TOMOYO: Use shorter names. Use shorter name to reduce newlines needed for 80 columns limit. Signed-off-by: Tetsuo Handa Signed-off-by: James Morris --- security/tomoyo/common.c | 74 ++++------ security/tomoyo/common.h | 90 ++++++------ security/tomoyo/file.c | 295 ++++++++++++++++++--------------------- security/tomoyo/gc.c | 18 +-- security/tomoyo/tomoyo.c | 72 ++++------ 5 files changed, 250 insertions(+), 299 deletions(-) diff --git a/security/tomoyo/common.c b/security/tomoyo/common.c index 3a36b56a2f5..ffcf0245056 100644 --- a/security/tomoyo/common.c +++ b/security/tomoyo/common.c @@ -841,25 +841,22 @@ bool tomoyo_domain_quota_is_ok(struct tomoyo_domain_info * const domain) return true; list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { switch (ptr->type) { - struct tomoyo_single_path_acl_record *acl; + struct tomoyo_path_acl *acl; u32 perm; u8 i; - case TOMOYO_TYPE_SINGLE_PATH_ACL: - acl = container_of(ptr, - struct tomoyo_single_path_acl_record, - head); + case TOMOYO_TYPE_PATH_ACL: + acl = container_of(ptr, struct tomoyo_path_acl, head); perm = acl->perm | (((u32) acl->perm_high) << 16); - for (i = 0; i < TOMOYO_MAX_SINGLE_PATH_OPERATION; i++) + for (i = 0; i < TOMOYO_MAX_PATH_OPERATION; i++) if (perm & (1 << i)) count++; - if (perm & (1 << TOMOYO_TYPE_READ_WRITE_ACL)) + if (perm & (1 << TOMOYO_TYPE_READ_WRITE)) count -= 2; break; - case TOMOYO_TYPE_DOUBLE_PATH_ACL: - perm = container_of(ptr, - struct tomoyo_double_path_acl_record, - head)->perm; - for (i = 0; i < TOMOYO_MAX_DOUBLE_PATH_OPERATION; i++) + case TOMOYO_TYPE_PATH2_ACL: + perm = container_of(ptr, struct tomoyo_path2_acl, head) + ->perm; + for (i = 0; i < TOMOYO_MAX_PATH2_OPERATION; i++) if (perm & (1 << i)) count++; break; @@ -1366,16 +1363,15 @@ static int tomoyo_write_domain_policy(struct tomoyo_io_buffer *head) } /** - * tomoyo_print_single_path_acl - Print a single path ACL entry. + * tomoyo_print_path_acl - Print a single path ACL entry. * * @head: Pointer to "struct tomoyo_io_buffer". - * @ptr: Pointer to "struct tomoyo_single_path_acl_record". + * @ptr: Pointer to "struct tomoyo_path_acl". * * Returns true on success, false otherwise. */ -static bool tomoyo_print_single_path_acl(struct tomoyo_io_buffer *head, - struct tomoyo_single_path_acl_record * - ptr) +static bool tomoyo_print_path_acl(struct tomoyo_io_buffer *head, + struct tomoyo_path_acl *ptr) { int pos; u8 bit; @@ -1384,17 +1380,15 @@ static bool tomoyo_print_single_path_acl(struct tomoyo_io_buffer *head, const u32 perm = ptr->perm | (((u32) ptr->perm_high) << 16); filename = ptr->filename->name; - for (bit = head->read_bit; bit < TOMOYO_MAX_SINGLE_PATH_OPERATION; - bit++) { + for (bit = head->read_bit; bit < TOMOYO_MAX_PATH_OPERATION; bit++) { const char *msg; if (!(perm & (1 << bit))) continue; /* Print "read/write" instead of "read" and "write". */ - if ((bit == TOMOYO_TYPE_READ_ACL || - bit == TOMOYO_TYPE_WRITE_ACL) - && (perm & (1 << TOMOYO_TYPE_READ_WRITE_ACL))) + if ((bit == TOMOYO_TYPE_READ || bit == TOMOYO_TYPE_WRITE) + && (perm & (1 << TOMOYO_TYPE_READ_WRITE))) continue; - msg = tomoyo_sp2keyword(bit); + msg = tomoyo_path2keyword(bit); pos = head->read_avail; if (!tomoyo_io_printf(head, "allow_%s %s%s\n", msg, atmark, filename)) @@ -1409,16 +1403,15 @@ static bool tomoyo_print_single_path_acl(struct tomoyo_io_buffer *head, } /** - * tomoyo_print_double_path_acl - Print a double path ACL entry. + * tomoyo_print_path2_acl - Print a double path ACL entry. * * @head: Pointer to "struct tomoyo_io_buffer". - * @ptr: Pointer to "struct tomoyo_double_path_acl_record". + * @ptr: Pointer to "struct tomoyo_path2_acl". * * Returns true on success, false otherwise. */ -static bool tomoyo_print_double_path_acl(struct tomoyo_io_buffer *head, - struct tomoyo_double_path_acl_record * - ptr) +static bool tomoyo_print_path2_acl(struct tomoyo_io_buffer *head, + struct tomoyo_path2_acl *ptr) { int pos; const char *atmark1 = ""; @@ -1430,12 +1423,11 @@ static bool tomoyo_print_double_path_acl(struct tomoyo_io_buffer *head, filename1 = ptr->filename1->name; filename2 = ptr->filename2->name; - for (bit = head->read_bit; bit < TOMOYO_MAX_DOUBLE_PATH_OPERATION; - bit++) { + for (bit = head->read_bit; bit < TOMOYO_MAX_PATH2_OPERATION; bit++) { const char *msg; if (!(perm & (1 << bit))) continue; - msg = tomoyo_dp2keyword(bit); + msg = tomoyo_path22keyword(bit); pos = head->read_avail; if (!tomoyo_io_printf(head, "allow_%s %s%s %s%s\n", msg, atmark1, filename1, atmark2, filename2)) @@ -1462,19 +1454,15 @@ static bool tomoyo_print_entry(struct tomoyo_io_buffer *head, { const u8 acl_type = ptr->type; - if (acl_type == TOMOYO_TYPE_SINGLE_PATH_ACL) { - struct tomoyo_single_path_acl_record *acl - = container_of(ptr, - struct tomoyo_single_path_acl_record, - head); - return tomoyo_print_single_path_acl(head, acl); + if (acl_type == TOMOYO_TYPE_PATH_ACL) { + struct tomoyo_path_acl *acl + = container_of(ptr, struct tomoyo_path_acl, head); + return tomoyo_print_path_acl(head, acl); } - if (acl_type == TOMOYO_TYPE_DOUBLE_PATH_ACL) { - struct tomoyo_double_path_acl_record *acl - = container_of(ptr, - struct tomoyo_double_path_acl_record, - head); - return tomoyo_print_double_path_acl(head, acl); + if (acl_type == TOMOYO_TYPE_PATH2_ACL) { + struct tomoyo_path2_acl *acl + = container_of(ptr, struct tomoyo_path2_acl, head); + return tomoyo_print_path2_acl(head, acl); } BUG(); /* This must not happen. */ return false; diff --git a/security/tomoyo/common.h b/security/tomoyo/common.h index 3727296f01f..f4d3050b9c0 100644 --- a/security/tomoyo/common.h +++ b/security/tomoyo/common.h @@ -71,8 +71,8 @@ enum tomoyo_mac_index { /* Index numbers for Access Controls. */ enum tomoyo_acl_entry_type_index { - TOMOYO_TYPE_SINGLE_PATH_ACL, - TOMOYO_TYPE_DOUBLE_PATH_ACL, + TOMOYO_TYPE_PATH_ACL, + TOMOYO_TYPE_PATH2_ACL, }; /* Index numbers for File Controls. */ @@ -87,36 +87,36 @@ enum tomoyo_acl_entry_type_index { */ enum tomoyo_path_acl_index { - TOMOYO_TYPE_READ_WRITE_ACL, - TOMOYO_TYPE_EXECUTE_ACL, - TOMOYO_TYPE_READ_ACL, - TOMOYO_TYPE_WRITE_ACL, - TOMOYO_TYPE_CREATE_ACL, - TOMOYO_TYPE_UNLINK_ACL, - TOMOYO_TYPE_MKDIR_ACL, - TOMOYO_TYPE_RMDIR_ACL, - TOMOYO_TYPE_MKFIFO_ACL, - TOMOYO_TYPE_MKSOCK_ACL, - TOMOYO_TYPE_MKBLOCK_ACL, - TOMOYO_TYPE_MKCHAR_ACL, - TOMOYO_TYPE_TRUNCATE_ACL, - TOMOYO_TYPE_SYMLINK_ACL, - TOMOYO_TYPE_REWRITE_ACL, - TOMOYO_TYPE_IOCTL_ACL, - TOMOYO_TYPE_CHMOD_ACL, - TOMOYO_TYPE_CHOWN_ACL, - TOMOYO_TYPE_CHGRP_ACL, - TOMOYO_TYPE_CHROOT_ACL, - TOMOYO_TYPE_MOUNT_ACL, - TOMOYO_TYPE_UMOUNT_ACL, - TOMOYO_MAX_SINGLE_PATH_OPERATION + TOMOYO_TYPE_READ_WRITE, + TOMOYO_TYPE_EXECUTE, + TOMOYO_TYPE_READ, + TOMOYO_TYPE_WRITE, + TOMOYO_TYPE_CREATE, + TOMOYO_TYPE_UNLINK, + TOMOYO_TYPE_MKDIR, + TOMOYO_TYPE_RMDIR, + TOMOYO_TYPE_MKFIFO, + TOMOYO_TYPE_MKSOCK, + TOMOYO_TYPE_MKBLOCK, + TOMOYO_TYPE_MKCHAR, + TOMOYO_TYPE_TRUNCATE, + TOMOYO_TYPE_SYMLINK, + TOMOYO_TYPE_REWRITE, + TOMOYO_TYPE_IOCTL, + TOMOYO_TYPE_CHMOD, + TOMOYO_TYPE_CHOWN, + TOMOYO_TYPE_CHGRP, + TOMOYO_TYPE_CHROOT, + TOMOYO_TYPE_MOUNT, + TOMOYO_TYPE_UMOUNT, + TOMOYO_MAX_PATH_OPERATION }; enum tomoyo_path2_acl_index { - TOMOYO_TYPE_LINK_ACL, - TOMOYO_TYPE_RENAME_ACL, - TOMOYO_TYPE_PIVOT_ROOT_ACL, - TOMOYO_MAX_DOUBLE_PATH_OPERATION + TOMOYO_TYPE_LINK, + TOMOYO_TYPE_RENAME, + TOMOYO_TYPE_PIVOT_ROOT, + TOMOYO_MAX_PATH2_OPERATION }; enum tomoyo_securityfs_interface_index { @@ -210,12 +210,11 @@ struct tomoyo_path_info_with_data { * (1) "list" which is linked to the ->acl_info_list of * "struct tomoyo_domain_info" * (2) "type" which tells type of the entry (either - * "struct tomoyo_single_path_acl_record" or - * "struct tomoyo_double_path_acl_record"). + * "struct tomoyo_path_acl" or "struct tomoyo_path2_acl"). * * Packing "struct tomoyo_acl_info" allows - * "struct tomoyo_single_path_acl_record" to embed "u8" + "u16" and - * "struct tomoyo_double_path_acl_record" to embed "u8" + * "struct tomoyo_path_acl" to embed "u8" + "u16" and + * "struct tomoyo_path2_acl" to embed "u8" * without enlarging their structure size. */ struct tomoyo_acl_info { @@ -269,7 +268,7 @@ struct tomoyo_domain_info { }; /* - * tomoyo_single_path_acl_record is a structure which is used for holding an + * tomoyo_path_acl is a structure which is used for holding an * entry with one pathname operation (e.g. open(), mkdir()). * It has following fields. * @@ -284,8 +283,8 @@ struct tomoyo_domain_info { * "allow_chmod", "allow_chown", "allow_chgrp", "allow_chroot", "allow_mount" * and "allow_unmount". */ -struct tomoyo_single_path_acl_record { - struct tomoyo_acl_info head; /* type = TOMOYO_TYPE_SINGLE_PATH_ACL */ +struct tomoyo_path_acl { + struct tomoyo_acl_info head; /* type = TOMOYO_TYPE_PATH_ACL */ u8 perm_high; u16 perm; /* Pointer to single pathname. */ @@ -293,7 +292,7 @@ struct tomoyo_single_path_acl_record { }; /* - * tomoyo_double_path_acl_record is a structure which is used for holding an + * tomoyo_path2_acl is a structure which is used for holding an * entry with two pathnames operation (i.e. link(), rename() and pivot_root()). * It has following fields. * @@ -305,8 +304,8 @@ struct tomoyo_single_path_acl_record { * Directives held by this structure are "allow_rename", "allow_link" and * "allow_pivot_root". */ -struct tomoyo_double_path_acl_record { - struct tomoyo_acl_info head; /* type = TOMOYO_TYPE_DOUBLE_PATH_ACL */ +struct tomoyo_path2_acl { + struct tomoyo_acl_info head; /* type = TOMOYO_TYPE_PATH2_ACL */ u8 perm; /* Pointer to single pathname. */ const struct tomoyo_path_info *filename1; @@ -550,13 +549,13 @@ bool tomoyo_read_no_rewrite_policy(struct tomoyo_io_buffer *head); /* Write domain policy violation warning message to console? */ bool tomoyo_verbose_mode(const struct tomoyo_domain_info *domain); /* Convert double path operation to operation name. */ -const char *tomoyo_dp2keyword(const u8 operation); +const char *tomoyo_path22keyword(const u8 operation); /* Get the last component of the given domainname. */ const char *tomoyo_get_last_name(const struct tomoyo_domain_info *domain); /* Get warning message. */ const char *tomoyo_get_msg(const bool is_enforce); /* Convert single path operation to operation name. */ -const char *tomoyo_sp2keyword(const u8 operation); +const char *tomoyo_path2keyword(const u8 operation); /* Create "alias" entry in exception policy. */ int tomoyo_write_alias_policy(char *data, const bool is_delete); /* @@ -638,11 +637,10 @@ int tomoyo_check_exec_perm(struct tomoyo_domain_info *domain, const struct tomoyo_path_info *filename); int tomoyo_check_open_permission(struct tomoyo_domain_info *domain, struct path *path, const int flag); -int tomoyo_check_1path_perm(struct tomoyo_domain_info *domain, - const u8 operation, struct path *path); -int tomoyo_check_2path_perm(struct tomoyo_domain_info *domain, - const u8 operation, struct path *path1, - struct path *path2); +int tomoyo_path_perm(struct tomoyo_domain_info *domain, const u8 operation, + struct path *path); +int tomoyo_path2_perm(struct tomoyo_domain_info *domain, const u8 operation, + struct path *path1, struct path *path2); int tomoyo_check_rewrite_permission(struct tomoyo_domain_info *domain, struct file *filp); int tomoyo_find_next_domain(struct linux_binprm *bprm); diff --git a/security/tomoyo/file.c b/security/tomoyo/file.c index 10ee7cece08..09feaf24864 100644 --- a/security/tomoyo/file.c +++ b/security/tomoyo/file.c @@ -12,62 +12,62 @@ #include "common.h" /* Keyword array for single path operations. */ -static const char *tomoyo_sp_keyword[TOMOYO_MAX_SINGLE_PATH_OPERATION] = { - [TOMOYO_TYPE_READ_WRITE_ACL] = "read/write", - [TOMOYO_TYPE_EXECUTE_ACL] = "execute", - [TOMOYO_TYPE_READ_ACL] = "read", - [TOMOYO_TYPE_WRITE_ACL] = "write", - [TOMOYO_TYPE_CREATE_ACL] = "create", - [TOMOYO_TYPE_UNLINK_ACL] = "unlink", - [TOMOYO_TYPE_MKDIR_ACL] = "mkdir", - [TOMOYO_TYPE_RMDIR_ACL] = "rmdir", - [TOMOYO_TYPE_MKFIFO_ACL] = "mkfifo", - [TOMOYO_TYPE_MKSOCK_ACL] = "mksock", - [TOMOYO_TYPE_MKBLOCK_ACL] = "mkblock", - [TOMOYO_TYPE_MKCHAR_ACL] = "mkchar", - [TOMOYO_TYPE_TRUNCATE_ACL] = "truncate", - [TOMOYO_TYPE_SYMLINK_ACL] = "symlink", - [TOMOYO_TYPE_REWRITE_ACL] = "rewrite", - [TOMOYO_TYPE_IOCTL_ACL] = "ioctl", - [TOMOYO_TYPE_CHMOD_ACL] = "chmod", - [TOMOYO_TYPE_CHOWN_ACL] = "chown", - [TOMOYO_TYPE_CHGRP_ACL] = "chgrp", - [TOMOYO_TYPE_CHROOT_ACL] = "chroot", - [TOMOYO_TYPE_MOUNT_ACL] = "mount", - [TOMOYO_TYPE_UMOUNT_ACL] = "unmount", +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. */ -static const char *tomoyo_dp_keyword[TOMOYO_MAX_DOUBLE_PATH_OPERATION] = { - [TOMOYO_TYPE_LINK_ACL] = "link", - [TOMOYO_TYPE_RENAME_ACL] = "rename", - [TOMOYO_TYPE_PIVOT_ROOT_ACL] = "pivot_root", +static const char *tomoyo_path2_keyword[TOMOYO_MAX_PATH2_OPERATION] = { + [TOMOYO_TYPE_LINK] = "link", + [TOMOYO_TYPE_RENAME] = "rename", + [TOMOYO_TYPE_PIVOT_ROOT] = "pivot_root", }; /** - * tomoyo_sp2keyword - Get the name of single path operation. + * tomoyo_path2keyword - Get the name of single path operation. * * @operation: Type of operation. * * Returns the name of single path operation. */ -const char *tomoyo_sp2keyword(const u8 operation) +const char *tomoyo_path2keyword(const u8 operation) { - return (operation < TOMOYO_MAX_SINGLE_PATH_OPERATION) - ? tomoyo_sp_keyword[operation] : NULL; + return (operation < TOMOYO_MAX_PATH_OPERATION) + ? tomoyo_path_keyword[operation] : NULL; } /** - * tomoyo_dp2keyword - Get the name of double path operation. + * tomoyo_path22keyword - Get the name of double path operation. * * @operation: Type of operation. * * Returns the name of double path operation. */ -const char *tomoyo_dp2keyword(const u8 operation) +const char *tomoyo_path22keyword(const u8 operation) { - return (operation < TOMOYO_MAX_DOUBLE_PATH_OPERATION) - ? tomoyo_dp_keyword[operation] : NULL; + return (operation < TOMOYO_MAX_PATH2_OPERATION) + ? tomoyo_path2_keyword[operation] : NULL; } /** @@ -115,13 +115,13 @@ static struct tomoyo_path_info *tomoyo_get_path(struct path *path) return NULL; } -static int tomoyo_update_double_path_acl(const u8 type, const char *filename1, - const char *filename2, - struct tomoyo_domain_info * - const domain, const bool is_delete); -static int tomoyo_update_single_path_acl(const u8 type, const char *filename, - struct tomoyo_domain_info * - const domain, const bool is_delete); +static int tomoyo_update_path2_acl(const u8 type, const char *filename1, + const char *filename2, + struct tomoyo_domain_info *const domain, + const bool is_delete); +static int tomoyo_update_path_acl(const u8 type, const char *filename, + struct tomoyo_domain_info *const domain, + const bool is_delete); /* * tomoyo_globally_readable_list is used for holding list of pathnames which @@ -597,19 +597,19 @@ static int tomoyo_update_file_acl(const char *filename, u8 perm, */ return 0; if (perm & 4) - tomoyo_update_single_path_acl(TOMOYO_TYPE_READ_ACL, filename, - domain, is_delete); + tomoyo_update_path_acl(TOMOYO_TYPE_READ, filename, domain, + is_delete); if (perm & 2) - tomoyo_update_single_path_acl(TOMOYO_TYPE_WRITE_ACL, filename, - domain, is_delete); + tomoyo_update_path_acl(TOMOYO_TYPE_WRITE, filename, domain, + is_delete); if (perm & 1) - tomoyo_update_single_path_acl(TOMOYO_TYPE_EXECUTE_ACL, - filename, domain, is_delete); + tomoyo_update_path_acl(TOMOYO_TYPE_EXECUTE, filename, domain, + is_delete); return 0; } /** - * tomoyo_check_single_path_acl2 - Check permission for single path operation. + * tomoyo_path_acl2 - Check permission for single path operation. * * @domain: Pointer to "struct tomoyo_domain_info". * @filename: Filename to check. @@ -620,22 +620,18 @@ static int tomoyo_update_file_acl(const char *filename, u8 perm, * * Caller holds tomoyo_read_lock(). */ -static int tomoyo_check_single_path_acl2(const struct tomoyo_domain_info * - domain, - const struct tomoyo_path_info * - filename, - const u32 perm, - const bool may_use_pattern) +static int tomoyo_path_acl2(const struct tomoyo_domain_info *domain, + const struct tomoyo_path_info *filename, + const u32 perm, const bool may_use_pattern) { struct tomoyo_acl_info *ptr; int error = -EPERM; list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { - struct tomoyo_single_path_acl_record *acl; - if (ptr->type != TOMOYO_TYPE_SINGLE_PATH_ACL) + struct tomoyo_path_acl *acl; + if (ptr->type != TOMOYO_TYPE_PATH_ACL) continue; - acl = container_of(ptr, struct tomoyo_single_path_acl_record, - head); + acl = container_of(ptr, struct tomoyo_path_acl, head); if (perm <= 0xFFFF) { if (!(acl->perm & perm)) continue; @@ -676,17 +672,16 @@ static int tomoyo_check_file_acl(const struct tomoyo_domain_info *domain, if (!tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE)) return 0; if (operation == 6) - perm = 1 << TOMOYO_TYPE_READ_WRITE_ACL; + perm = 1 << TOMOYO_TYPE_READ_WRITE; else if (operation == 4) - perm = 1 << TOMOYO_TYPE_READ_ACL; + perm = 1 << TOMOYO_TYPE_READ; else if (operation == 2) - perm = 1 << TOMOYO_TYPE_WRITE_ACL; + perm = 1 << TOMOYO_TYPE_WRITE; else if (operation == 1) - perm = 1 << TOMOYO_TYPE_EXECUTE_ACL; + perm = 1 << TOMOYO_TYPE_EXECUTE; else BUG(); - return tomoyo_check_single_path_acl2(domain, filename, perm, - operation != 1); + return tomoyo_path_acl2(domain, filename, perm, operation != 1); } /** @@ -718,13 +713,13 @@ static int tomoyo_check_file_perm2(struct tomoyo_domain_info * const domain, && tomoyo_is_globally_readable_file(filename)) error = 0; if (perm == 6) - msg = tomoyo_sp2keyword(TOMOYO_TYPE_READ_WRITE_ACL); + msg = tomoyo_path2keyword(TOMOYO_TYPE_READ_WRITE); else if (perm == 4) - msg = tomoyo_sp2keyword(TOMOYO_TYPE_READ_ACL); + msg = tomoyo_path2keyword(TOMOYO_TYPE_READ); else if (perm == 2) - msg = tomoyo_sp2keyword(TOMOYO_TYPE_WRITE_ACL); + msg = tomoyo_path2keyword(TOMOYO_TYPE_WRITE); else if (perm == 1) - msg = tomoyo_sp2keyword(TOMOYO_TYPE_EXECUTE_ACL); + msg = tomoyo_path2keyword(TOMOYO_TYPE_EXECUTE); else BUG(); if (!error) @@ -773,28 +768,28 @@ int tomoyo_write_file_policy(char *data, struct tomoyo_domain_info *domain, if (strncmp(data, "allow_", 6)) goto out; data += 6; - for (type = 0; type < TOMOYO_MAX_SINGLE_PATH_OPERATION; type++) { - if (strcmp(data, tomoyo_sp_keyword[type])) + for (type = 0; type < TOMOYO_MAX_PATH_OPERATION; type++) { + if (strcmp(data, tomoyo_path_keyword[type])) continue; - return tomoyo_update_single_path_acl(type, filename, - domain, is_delete); + 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_DOUBLE_PATH_OPERATION; type++) { - if (strcmp(data, tomoyo_dp_keyword[type])) + for (type = 0; type < TOMOYO_MAX_PATH2_OPERATION; type++) { + if (strcmp(data, tomoyo_path2_keyword[type])) continue; - return tomoyo_update_double_path_acl(type, filename, filename2, - domain, is_delete); + return tomoyo_update_path2_acl(type, filename, filename2, + domain, is_delete); } out: return -EINVAL; } /** - * tomoyo_update_single_path_acl - Update "struct tomoyo_single_path_acl_record" list. + * tomoyo_update_path_acl - Update "struct tomoyo_path_acl" list. * * @type: Type of operation. * @filename: Filename. @@ -805,15 +800,15 @@ int tomoyo_write_file_policy(char *data, struct tomoyo_domain_info *domain, * * Caller holds tomoyo_read_lock(). */ -static int tomoyo_update_single_path_acl(const u8 type, const char *filename, - struct tomoyo_domain_info * - const domain, const bool is_delete) +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 rw_mask = - (1 << TOMOYO_TYPE_READ_ACL) | (1 << TOMOYO_TYPE_WRITE_ACL); + (1 << TOMOYO_TYPE_READ) | (1 << TOMOYO_TYPE_WRITE); const struct tomoyo_path_info *saved_filename; struct tomoyo_acl_info *ptr; - struct tomoyo_single_path_acl_record *entry = NULL; + struct tomoyo_path_acl *entry = NULL; int error = is_delete ? -ENOENT : -ENOMEM; const u32 perm = 1 << type; @@ -828,10 +823,9 @@ static int tomoyo_update_single_path_acl(const u8 type, const char *filename, entry = kmalloc(sizeof(*entry), GFP_KERNEL); mutex_lock(&tomoyo_policy_lock); list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { - struct tomoyo_single_path_acl_record *acl = - container_of(ptr, struct tomoyo_single_path_acl_record, - head); - if (ptr->type != TOMOYO_TYPE_SINGLE_PATH_ACL) + struct tomoyo_path_acl *acl = + container_of(ptr, struct tomoyo_path_acl, head); + if (ptr->type != TOMOYO_TYPE_PATH_ACL) continue; if (acl->filename != saved_filename) continue; @@ -841,9 +835,8 @@ static int tomoyo_update_single_path_acl(const u8 type, const char *filename, else acl->perm_high &= ~(perm >> 16); if ((acl->perm & rw_mask) != rw_mask) - acl->perm &= ~(1 << TOMOYO_TYPE_READ_WRITE_ACL); - else if (!(acl->perm & - (1 << TOMOYO_TYPE_READ_WRITE_ACL))) + acl->perm &= ~(1 << TOMOYO_TYPE_READ_WRITE); + else if (!(acl->perm & (1 << TOMOYO_TYPE_READ_WRITE))) acl->perm &= ~rw_mask; } else { if (perm <= 0xFFFF) @@ -851,20 +844,20 @@ static int tomoyo_update_single_path_acl(const u8 type, const char *filename, else acl->perm_high |= (perm >> 16); if ((acl->perm & rw_mask) == rw_mask) - acl->perm |= 1 << TOMOYO_TYPE_READ_WRITE_ACL; - else if (acl->perm & (1 << TOMOYO_TYPE_READ_WRITE_ACL)) + acl->perm |= 1 << TOMOYO_TYPE_READ_WRITE; + else if (acl->perm & (1 << TOMOYO_TYPE_READ_WRITE)) acl->perm |= rw_mask; } error = 0; break; } if (!is_delete && error && tomoyo_memory_ok(entry)) { - entry->head.type = TOMOYO_TYPE_SINGLE_PATH_ACL; + entry->head.type = TOMOYO_TYPE_PATH_ACL; if (perm <= 0xFFFF) entry->perm = perm; else entry->perm_high = (perm >> 16); - if (perm == (1 << TOMOYO_TYPE_READ_WRITE_ACL)) + if (perm == (1 << TOMOYO_TYPE_READ_WRITE)) entry->perm |= rw_mask; entry->filename = saved_filename; saved_filename = NULL; @@ -879,7 +872,7 @@ static int tomoyo_update_single_path_acl(const u8 type, const char *filename, } /** - * tomoyo_update_double_path_acl - Update "struct tomoyo_double_path_acl_record" list. + * tomoyo_update_path2_acl - Update "struct tomoyo_path2_acl" list. * * @type: Type of operation. * @filename1: First filename. @@ -891,15 +884,15 @@ static int tomoyo_update_single_path_acl(const u8 type, const char *filename, * * Caller holds tomoyo_read_lock(). */ -static int tomoyo_update_double_path_acl(const u8 type, const char *filename1, - const char *filename2, - struct tomoyo_domain_info * - const domain, const bool is_delete) +static int tomoyo_update_path2_acl(const u8 type, const char *filename1, + const char *filename2, + struct tomoyo_domain_info *const domain, + const bool is_delete) { const struct tomoyo_path_info *saved_filename1; const struct tomoyo_path_info *saved_filename2; struct tomoyo_acl_info *ptr; - struct tomoyo_double_path_acl_record *entry = NULL; + struct tomoyo_path2_acl *entry = NULL; int error = is_delete ? -ENOENT : -ENOMEM; const u8 perm = 1 << type; @@ -916,10 +909,9 @@ static int tomoyo_update_double_path_acl(const u8 type, const char *filename1, entry = kmalloc(sizeof(*entry), GFP_KERNEL); mutex_lock(&tomoyo_policy_lock); list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { - struct tomoyo_double_path_acl_record *acl = - container_of(ptr, struct tomoyo_double_path_acl_record, - head); - if (ptr->type != TOMOYO_TYPE_DOUBLE_PATH_ACL) + struct tomoyo_path2_acl *acl = + container_of(ptr, struct tomoyo_path2_acl, head); + if (ptr->type != TOMOYO_TYPE_PATH2_ACL) continue; if (acl->filename1 != saved_filename1 || acl->filename2 != saved_filename2) @@ -932,7 +924,7 @@ static int tomoyo_update_double_path_acl(const u8 type, const char *filename1, break; } if (!is_delete && error && tomoyo_memory_ok(entry)) { - entry->head.type = TOMOYO_TYPE_DOUBLE_PATH_ACL; + entry->head.type = TOMOYO_TYPE_PATH2_ACL; entry->perm = perm; entry->filename1 = saved_filename1; saved_filename1 = NULL; @@ -951,7 +943,7 @@ static int tomoyo_update_double_path_acl(const u8 type, const char *filename1, } /** - * tomoyo_check_single_path_acl - Check permission for single path operation. + * tomoyo_path_acl - Check permission for single path operation. * * @domain: Pointer to "struct tomoyo_domain_info". * @type: Type of operation. @@ -961,17 +953,16 @@ static int tomoyo_update_double_path_acl(const u8 type, const char *filename1, * * Caller holds tomoyo_read_lock(). */ -static int tomoyo_check_single_path_acl(struct tomoyo_domain_info *domain, - const u8 type, - const struct tomoyo_path_info *filename) +static int tomoyo_path_acl(struct tomoyo_domain_info *domain, const u8 type, + const struct tomoyo_path_info *filename) { if (!tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE)) return 0; - return tomoyo_check_single_path_acl2(domain, filename, 1 << type, 1); + return tomoyo_path_acl2(domain, filename, 1 << type, 1); } /** - * tomoyo_check_double_path_acl - Check permission for double path operation. + * tomoyo_path2_acl - Check permission for double path operation. * * @domain: Pointer to "struct tomoyo_domain_info". * @type: Type of operation. @@ -982,12 +973,10 @@ static int tomoyo_check_single_path_acl(struct tomoyo_domain_info *domain, * * Caller holds tomoyo_read_lock(). */ -static int tomoyo_check_double_path_acl(const struct tomoyo_domain_info *domain, - const u8 type, - const struct tomoyo_path_info * - filename1, - const struct tomoyo_path_info * - filename2) +static int tomoyo_path2_acl(const struct tomoyo_domain_info *domain, + const u8 type, + const struct tomoyo_path_info *filename1, + const struct tomoyo_path_info *filename2) { struct tomoyo_acl_info *ptr; const u8 perm = 1 << type; @@ -996,11 +985,10 @@ static int tomoyo_check_double_path_acl(const struct tomoyo_domain_info *domain, if (!tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE)) return 0; list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) { - struct tomoyo_double_path_acl_record *acl; - if (ptr->type != TOMOYO_TYPE_DOUBLE_PATH_ACL) + struct tomoyo_path2_acl *acl; + if (ptr->type != TOMOYO_TYPE_PATH2_ACL) continue; - acl = container_of(ptr, struct tomoyo_double_path_acl_record, - head); + acl = container_of(ptr, struct tomoyo_path2_acl, head); if (!(acl->perm & perm)) continue; if (!tomoyo_path_matches_pattern(filename1, acl->filename1)) @@ -1014,7 +1002,7 @@ static int tomoyo_check_double_path_acl(const struct tomoyo_domain_info *domain, } /** - * tomoyo_check_single_path_permission2 - Check permission for single path operation. + * tomoyo_path_permission2 - Check permission for single path operation. * * @domain: Pointer to "struct tomoyo_domain_info". * @operation: Type of operation. @@ -1025,10 +1013,10 @@ static int tomoyo_check_double_path_acl(const struct tomoyo_domain_info *domain, * * Caller holds tomoyo_read_lock(). */ -static int tomoyo_check_single_path_permission2(struct tomoyo_domain_info * - const domain, u8 operation, - const struct tomoyo_path_info * - filename, const u8 mode) +static int tomoyo_path_permission2(struct tomoyo_domain_info *const domain, + u8 operation, + const struct tomoyo_path_info *filename, + const u8 mode) { const char *msg; int error; @@ -1037,8 +1025,8 @@ static int tomoyo_check_single_path_permission2(struct tomoyo_domain_info * if (!mode) return 0; next: - error = tomoyo_check_single_path_acl(domain, operation, filename); - msg = tomoyo_sp2keyword(operation); + error = tomoyo_path_acl(domain, operation, filename); + msg = tomoyo_path2keyword(operation); if (!error) goto ok; if (tomoyo_verbose_mode(domain)) @@ -1047,7 +1035,7 @@ static int tomoyo_check_single_path_permission2(struct tomoyo_domain_info * tomoyo_get_last_name(domain)); if (mode == 1 && tomoyo_domain_quota_is_ok(domain)) { const char *name = tomoyo_get_file_pattern(filename)->name; - tomoyo_update_single_path_acl(operation, name, domain, false); + tomoyo_update_path_acl(operation, name, domain, false); } if (!is_enforce) error = 0; @@ -1057,9 +1045,9 @@ static int tomoyo_check_single_path_permission2(struct tomoyo_domain_info * * we need to check "allow_rewrite" permission if the filename is * specified by "deny_rewrite" keyword. */ - if (!error && operation == TOMOYO_TYPE_TRUNCATE_ACL && + if (!error && operation == TOMOYO_TYPE_TRUNCATE && tomoyo_is_no_rewrite_file(filename)) { - operation = TOMOYO_TYPE_REWRITE_ACL; + operation = TOMOYO_TYPE_REWRITE; goto next; } return error; @@ -1127,17 +1115,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_check_single_path_permission2(domain, - TOMOYO_TYPE_REWRITE_ACL, - buf, mode); + error = tomoyo_path_permission2(domain, TOMOYO_TYPE_REWRITE, + buf, mode); } if (!error) error = tomoyo_check_file_perm2(domain, buf, acc_mode, "open", mode); if (!error && (flag & O_TRUNC)) - error = tomoyo_check_single_path_permission2(domain, - TOMOYO_TYPE_TRUNCATE_ACL, - buf, mode); + error = tomoyo_path_permission2(domain, TOMOYO_TYPE_TRUNCATE, + buf, mode); out: kfree(buf); tomoyo_read_unlock(idx); @@ -1147,7 +1133,7 @@ int tomoyo_check_open_permission(struct tomoyo_domain_info *domain, } /** - * tomoyo_check_1path_perm - Check permission for "create", "unlink", "mkdir", "rmdir", "mkfifo", "mksock", "mkblock", "mkchar", "truncate", "symlink", "ioctl", "chmod", "chown", "chgrp", "chroot", "mount" and "unmount". + * tomoyo_path_perm - Check permission for "create", "unlink", "mkdir", "rmdir", "mkfifo", "mksock", "mkblock", "mkchar", "truncate", "symlink", "ioctl", "chmod", "chown", "chgrp", "chroot", "mount" and "unmount". * * @domain: Pointer to "struct tomoyo_domain_info". * @operation: Type of operation. @@ -1155,8 +1141,8 @@ int tomoyo_check_open_permission(struct tomoyo_domain_info *domain, * * Returns 0 on success, negative value otherwise. */ -int tomoyo_check_1path_perm(struct tomoyo_domain_info *domain, - const u8 operation, struct path *path) +int tomoyo_path_perm(struct tomoyo_domain_info *domain, + const u8 operation, struct path *path) { int error = -ENOMEM; struct tomoyo_path_info *buf; @@ -1171,9 +1157,9 @@ int tomoyo_check_1path_perm(struct tomoyo_domain_info *domain, if (!buf) goto out; switch (operation) { - case TOMOYO_TYPE_MKDIR_ACL: - case TOMOYO_TYPE_RMDIR_ACL: - case TOMOYO_TYPE_CHROOT_ACL: + case TOMOYO_TYPE_MKDIR: + case TOMOYO_TYPE_RMDIR: + case TOMOYO_TYPE_CHROOT: if (!buf->is_dir) { /* * tomoyo_get_path() reserves space for appending "/." @@ -1182,8 +1168,7 @@ int tomoyo_check_1path_perm(struct tomoyo_domain_info *domain, tomoyo_fill_path_info(buf); } } - error = tomoyo_check_single_path_permission2(domain, operation, buf, - mode); + error = tomoyo_path_permission2(domain, operation, buf, mode); out: kfree(buf); tomoyo_read_unlock(idx); @@ -1220,9 +1205,7 @@ int tomoyo_check_rewrite_permission(struct tomoyo_domain_info *domain, error = 0; goto out; } - error = tomoyo_check_single_path_permission2(domain, - TOMOYO_TYPE_REWRITE_ACL, - buf, mode); + error = tomoyo_path_permission2(domain, TOMOYO_TYPE_REWRITE, buf, mode); out: kfree(buf); tomoyo_read_unlock(idx); @@ -1232,7 +1215,7 @@ int tomoyo_check_rewrite_permission(struct tomoyo_domain_info *domain, } /** - * tomoyo_check_2path_perm - Check permission for "rename", "link" and "pivot_root". + * tomoyo_path2_perm - Check permission for "rename", "link" and "pivot_root". * * @domain: Pointer to "struct tomoyo_domain_info". * @operation: Type of operation. @@ -1241,9 +1224,9 @@ int tomoyo_check_rewrite_permission(struct tomoyo_domain_info *domain, * * Returns 0 on success, negative value otherwise. */ -int tomoyo_check_2path_perm(struct tomoyo_domain_info * const domain, - const u8 operation, struct path *path1, - struct path *path2) +int tomoyo_path2_perm(struct tomoyo_domain_info * const domain, + const u8 operation, struct path *path1, + struct path *path2) { int error = -ENOMEM; struct tomoyo_path_info *buf1, *buf2; @@ -1275,8 +1258,8 @@ int tomoyo_check_2path_perm(struct tomoyo_domain_info * const domain, } } } - error = tomoyo_check_double_path_acl(domain, operation, buf1, buf2); - msg = tomoyo_dp2keyword(operation); + error = tomoyo_path2_acl(domain, operation, buf1, buf2); + msg = tomoyo_path22keyword(operation); if (!error) goto out; if (tomoyo_verbose_mode(domain)) @@ -1287,8 +1270,8 @@ int tomoyo_check_2path_perm(struct tomoyo_domain_info * const domain, if (mode == 1 && tomoyo_domain_quota_is_ok(domain)) { const char *name1 = tomoyo_get_file_pattern(buf1)->name; const char *name2 = tomoyo_get_file_pattern(buf2)->name; - tomoyo_update_double_path_acl(operation, name1, name2, domain, - false); + tomoyo_update_path2_acl(operation, name1, name2, domain, + false); } out: kfree(buf1); diff --git a/security/tomoyo/gc.c b/security/tomoyo/gc.c index ee15da39387..9645525ccdd 100644 --- a/security/tomoyo/gc.c +++ b/security/tomoyo/gc.c @@ -86,16 +86,16 @@ static void tomoyo_del_manager(struct tomoyo_policy_manager_entry *ptr) static void tomoyo_del_acl(struct tomoyo_acl_info *acl) { switch (acl->type) { - case TOMOYO_TYPE_SINGLE_PATH_ACL: + case TOMOYO_TYPE_PATH_ACL: { - struct tomoyo_single_path_acl_record *entry + struct tomoyo_path_acl *entry = container_of(acl, typeof(*entry), head); tomoyo_put_name(entry->filename); } break; - case TOMOYO_TYPE_DOUBLE_PATH_ACL: + case TOMOYO_TYPE_PATH2_ACL: { - struct tomoyo_double_path_acl_record *entry + struct tomoyo_path2_acl *entry = container_of(acl, typeof(*entry), head); tomoyo_put_name(entry->filename1); tomoyo_put_name(entry->filename2); @@ -238,18 +238,18 @@ static void tomoyo_collect_entry(void) list_for_each_entry_rcu(acl, &domain->acl_info_list, list) { switch (acl->type) { - case TOMOYO_TYPE_SINGLE_PATH_ACL: + case TOMOYO_TYPE_PATH_ACL: if (container_of(acl, - struct tomoyo_single_path_acl_record, + struct tomoyo_path_acl, head)->perm || container_of(acl, - struct tomoyo_single_path_acl_record, + struct tomoyo_path_acl, head)->perm_high) continue; break; - case TOMOYO_TYPE_DOUBLE_PATH_ACL: + case TOMOYO_TYPE_PATH2_ACL: if (container_of(acl, - struct tomoyo_double_path_acl_record, + struct tomoyo_path2_acl, head)->perm) continue; break; diff --git a/security/tomoyo/tomoyo.c b/security/tomoyo/tomoyo.c index 87e82bfeac2..e3945d0511b 100644 --- a/security/tomoyo/tomoyo.c +++ b/security/tomoyo/tomoyo.c @@ -100,67 +100,56 @@ static int tomoyo_bprm_check_security(struct linux_binprm *bprm) static int tomoyo_path_truncate(struct path *path, loff_t length, unsigned int time_attrs) { - return tomoyo_check_1path_perm(tomoyo_domain(), - TOMOYO_TYPE_TRUNCATE_ACL, - path); + return tomoyo_path_perm(tomoyo_domain(), TOMOYO_TYPE_TRUNCATE, path); } static int tomoyo_path_unlink(struct path *parent, struct dentry *dentry) { struct path path = { parent->mnt, dentry }; - return tomoyo_check_1path_perm(tomoyo_domain(), - TOMOYO_TYPE_UNLINK_ACL, - &path); + return tomoyo_path_perm(tomoyo_domain(), TOMOYO_TYPE_UNLINK, &path); } static int tomoyo_path_mkdir(struct path *parent, struct dentry *dentry, int mode) { struct path path = { parent->mnt, dentry }; - return tomoyo_check_1path_perm(tomoyo_domain(), - TOMOYO_TYPE_MKDIR_ACL, - &path); + return tomoyo_path_perm(tomoyo_domain(), TOMOYO_TYPE_MKDIR, &path); } static int tomoyo_path_rmdir(struct path *parent, struct dentry *dentry) { struct path path = { parent->mnt, dentry }; - return tomoyo_check_1path_perm(tomoyo_domain(), - TOMOYO_TYPE_RMDIR_ACL, - &path); + return tomoyo_path_perm(tomoyo_domain(), TOMOYO_TYPE_RMDIR, &path); } static int tomoyo_path_symlink(struct path *parent, struct dentry *dentry, const char *old_name) { struct path path = { parent->mnt, dentry }; - return tomoyo_check_1path_perm(tomoyo_domain(), - TOMOYO_TYPE_SYMLINK_ACL, - &path); + return tomoyo_path_perm(tomoyo_domain(), TOMOYO_TYPE_SYMLINK, &path); } static int tomoyo_path_mknod(struct path *parent, struct dentry *dentry, int mode, unsigned int dev) { struct path path = { parent->mnt, dentry }; - int type = TOMOYO_TYPE_CREATE_ACL; + int type = TOMOYO_TYPE_CREATE; switch (mode & S_IFMT) { case S_IFCHR: - type = TOMOYO_TYPE_MKCHAR_ACL; + type = TOMOYO_TYPE_MKCHAR; break; case S_IFBLK: - type = TOMOYO_TYPE_MKBLOCK_ACL; + type = TOMOYO_TYPE_MKBLOCK; break; case S_IFIFO: - type = TOMOYO_TYPE_MKFIFO_ACL; + type = TOMOYO_TYPE_MKFIFO; break; case S_IFSOCK: - type = TOMOYO_TYPE_MKSOCK_ACL; + type = TOMOYO_TYPE_MKSOCK; break; } - return tomoyo_check_1path_perm(tomoyo_domain(), - type, &path); + return tomoyo_path_perm(tomoyo_domain(), type, &path); } static int tomoyo_path_link(struct dentry *old_dentry, struct path *new_dir, @@ -168,9 +157,8 @@ static int tomoyo_path_link(struct dentry *old_dentry, struct path *new_dir, { struct path path1 = { new_dir->mnt, old_dentry }; struct path path2 = { new_dir->mnt, new_dentry }; - return tomoyo_check_2path_perm(tomoyo_domain(), - TOMOYO_TYPE_LINK_ACL, - &path1, &path2); + return tomoyo_path2_perm(tomoyo_domain(), TOMOYO_TYPE_LINK, &path1, + &path2); } static int tomoyo_path_rename(struct path *old_parent, @@ -180,9 +168,8 @@ static int tomoyo_path_rename(struct path *old_parent, { struct path path1 = { old_parent->mnt, old_dentry }; struct path path2 = { new_parent->mnt, new_dentry }; - return tomoyo_check_2path_perm(tomoyo_domain(), - TOMOYO_TYPE_RENAME_ACL, - &path1, &path2); + return tomoyo_path2_perm(tomoyo_domain(), TOMOYO_TYPE_RENAME, &path1, + &path2); } static int tomoyo_file_fcntl(struct file *file, unsigned int cmd, @@ -209,55 +196,50 @@ static int tomoyo_dentry_open(struct file *f, const struct cred *cred) static int tomoyo_file_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { - return tomoyo_check_1path_perm(tomoyo_domain(), TOMOYO_TYPE_IOCTL_ACL, - &file->f_path); + return tomoyo_path_perm(tomoyo_domain(), TOMOYO_TYPE_IOCTL, + &file->f_path); } static int tomoyo_path_chmod(struct dentry *dentry, struct vfsmount *mnt, mode_t mode) { struct path path = { mnt, dentry }; - return tomoyo_check_1path_perm(tomoyo_domain(), TOMOYO_TYPE_CHMOD_ACL, - &path); + return tomoyo_path_perm(tomoyo_domain(), TOMOYO_TYPE_CHMOD, &path); } static int tomoyo_path_chown(struct path *path, uid_t uid, gid_t gid) { int error = 0; if (uid != (uid_t) -1) - error = tomoyo_check_1path_perm(tomoyo_domain(), - TOMOYO_TYPE_CHOWN_ACL, path); + error = tomoyo_path_perm(tomoyo_domain(), TOMOYO_TYPE_CHOWN, + path); if (!error && gid != (gid_t) -1) - error = tomoyo_check_1path_perm(tomoyo_domain(), - TOMOYO_TYPE_CHGRP_ACL, path); + error = tomoyo_path_perm(tomoyo_domain(), TOMOYO_TYPE_CHGRP, + path); return error; } static int tomoyo_path_chroot(struct path *path) { - return tomoyo_check_1path_perm(tomoyo_domain(), TOMOYO_TYPE_CHROOT_ACL, - path); + return tomoyo_path_perm(tomoyo_domain(), TOMOYO_TYPE_CHROOT, path); } static int tomoyo_sb_mount(char *dev_name, struct path *path, char *type, unsigned long flags, void *data) { - return tomoyo_check_1path_perm(tomoyo_domain(), TOMOYO_TYPE_MOUNT_ACL, - path); + return tomoyo_path_perm(tomoyo_domain(), TOMOYO_TYPE_MOUNT, path); } static int tomoyo_sb_umount(struct vfsmount *mnt, int flags) { struct path path = { mnt, mnt->mnt_root }; - return tomoyo_check_1path_perm(tomoyo_domain(), TOMOYO_TYPE_UMOUNT_ACL, - &path); + return tomoyo_path_perm(tomoyo_domain(), TOMOYO_TYPE_UMOUNT, &path); } static int tomoyo_sb_pivotroot(struct path *old_path, struct path *new_path) { - return tomoyo_check_2path_perm(tomoyo_domain(), - TOMOYO_TYPE_PIVOT_ROOT_ACL, - new_path, old_path); + return tomoyo_path2_perm(tomoyo_domain(), TOMOYO_TYPE_PIVOT_ROOT, + new_path, old_path); } /* From 97d6931ead3e89a764cdaa3ad0924037367f0d34 Mon Sep 17 00:00:00 2001 From: Tetsuo Handa Date: Tue, 16 Feb 2010 09:46:15 +0900 Subject: [PATCH 32/38] TOMOYO: Remove unneeded parameter. tomoyo_path_perm() tomoyo_path2_perm() and tomoyo_check_rewrite_permission() always receive tomoyo_domain(). We can move it from caller to callee. Signed-off-by: Tetsuo Handa Signed-off-by: James Morris --- security/tomoyo/common.h | 10 ++++------ security/tomoyo/file.c | 15 ++++++--------- security/tomoyo/tomoyo.c | 40 +++++++++++++++++----------------------- 3 files changed, 27 insertions(+), 38 deletions(-) diff --git a/security/tomoyo/common.h b/security/tomoyo/common.h index f4d3050b9c0..17ed365521b 100644 --- a/security/tomoyo/common.h +++ b/security/tomoyo/common.h @@ -637,12 +637,10 @@ int tomoyo_check_exec_perm(struct tomoyo_domain_info *domain, const struct tomoyo_path_info *filename); int tomoyo_check_open_permission(struct tomoyo_domain_info *domain, struct path *path, const int flag); -int tomoyo_path_perm(struct tomoyo_domain_info *domain, const u8 operation, - struct path *path); -int tomoyo_path2_perm(struct tomoyo_domain_info *domain, const u8 operation, - struct path *path1, struct path *path2); -int tomoyo_check_rewrite_permission(struct tomoyo_domain_info *domain, - struct file *filp); +int tomoyo_path_perm(const u8 operation, struct path *path); +int tomoyo_path2_perm(const u8 operation, struct path *path1, + struct path *path2); +int tomoyo_check_rewrite_permission(struct file *filp); int tomoyo_find_next_domain(struct linux_binprm *bprm); /* Run garbage collector. */ diff --git a/security/tomoyo/file.c b/security/tomoyo/file.c index 09feaf24864..db342ef87af 100644 --- a/security/tomoyo/file.c +++ b/security/tomoyo/file.c @@ -1135,17 +1135,16 @@ 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", "ioctl", "chmod", "chown", "chgrp", "chroot", "mount" and "unmount". * - * @domain: Pointer to "struct tomoyo_domain_info". * @operation: Type of operation. * @path: Pointer to "struct path". * * Returns 0 on success, negative value otherwise. */ -int tomoyo_path_perm(struct tomoyo_domain_info *domain, - const u8 operation, struct path *path) +int tomoyo_path_perm(const u8 operation, struct path *path) { int error = -ENOMEM; struct tomoyo_path_info *buf; + struct tomoyo_domain_info *domain = tomoyo_domain(); const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE); const bool is_enforce = (mode == 3); int idx; @@ -1180,15 +1179,14 @@ int tomoyo_path_perm(struct tomoyo_domain_info *domain, /** * tomoyo_check_rewrite_permission - Check permission for "rewrite". * - * @domain: Pointer to "struct tomoyo_domain_info". * @filp: Pointer to "struct file". * * Returns 0 on success, negative value otherwise. */ -int tomoyo_check_rewrite_permission(struct tomoyo_domain_info *domain, - struct file *filp) +int tomoyo_check_rewrite_permission(struct file *filp) { int error = -ENOMEM; + struct tomoyo_domain_info *domain = tomoyo_domain(); const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE); const bool is_enforce = (mode == 3); struct tomoyo_path_info *buf; @@ -1217,19 +1215,18 @@ int tomoyo_check_rewrite_permission(struct tomoyo_domain_info *domain, /** * tomoyo_path2_perm - Check permission for "rename", "link" and "pivot_root". * - * @domain: Pointer to "struct tomoyo_domain_info". * @operation: Type of operation. * @path1: Pointer to "struct path". * @path2: Pointer to "struct path". * * Returns 0 on success, negative value otherwise. */ -int tomoyo_path2_perm(struct tomoyo_domain_info * const domain, - const u8 operation, struct path *path1, +int tomoyo_path2_perm(const u8 operation, struct path *path1, struct path *path2) { int error = -ENOMEM; struct tomoyo_path_info *buf1, *buf2; + struct tomoyo_domain_info *domain = tomoyo_domain(); const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE); const bool is_enforce = (mode == 3); const char *msg; diff --git a/security/tomoyo/tomoyo.c b/security/tomoyo/tomoyo.c index e3945d0511b..c94e35c3c75 100644 --- a/security/tomoyo/tomoyo.c +++ b/security/tomoyo/tomoyo.c @@ -100,33 +100,33 @@ static int tomoyo_bprm_check_security(struct linux_binprm *bprm) static int tomoyo_path_truncate(struct path *path, loff_t length, unsigned int time_attrs) { - return tomoyo_path_perm(tomoyo_domain(), TOMOYO_TYPE_TRUNCATE, path); + return tomoyo_path_perm(TOMOYO_TYPE_TRUNCATE, path); } static int tomoyo_path_unlink(struct path *parent, struct dentry *dentry) { struct path path = { parent->mnt, dentry }; - return tomoyo_path_perm(tomoyo_domain(), TOMOYO_TYPE_UNLINK, &path); + return tomoyo_path_perm(TOMOYO_TYPE_UNLINK, &path); } static int tomoyo_path_mkdir(struct path *parent, struct dentry *dentry, int mode) { struct path path = { parent->mnt, dentry }; - return tomoyo_path_perm(tomoyo_domain(), TOMOYO_TYPE_MKDIR, &path); + return tomoyo_path_perm(TOMOYO_TYPE_MKDIR, &path); } static int tomoyo_path_rmdir(struct path *parent, struct dentry *dentry) { struct path path = { parent->mnt, dentry }; - return tomoyo_path_perm(tomoyo_domain(), TOMOYO_TYPE_RMDIR, &path); + return tomoyo_path_perm(TOMOYO_TYPE_RMDIR, &path); } static int tomoyo_path_symlink(struct path *parent, struct dentry *dentry, const char *old_name) { struct path path = { parent->mnt, dentry }; - return tomoyo_path_perm(tomoyo_domain(), TOMOYO_TYPE_SYMLINK, &path); + return tomoyo_path_perm(TOMOYO_TYPE_SYMLINK, &path); } static int tomoyo_path_mknod(struct path *parent, struct dentry *dentry, @@ -149,7 +149,7 @@ static int tomoyo_path_mknod(struct path *parent, struct dentry *dentry, type = TOMOYO_TYPE_MKSOCK; break; } - return tomoyo_path_perm(tomoyo_domain(), type, &path); + return tomoyo_path_perm(type, &path); } static int tomoyo_path_link(struct dentry *old_dentry, struct path *new_dir, @@ -157,8 +157,7 @@ static int tomoyo_path_link(struct dentry *old_dentry, struct path *new_dir, { struct path path1 = { new_dir->mnt, old_dentry }; struct path path2 = { new_dir->mnt, new_dentry }; - return tomoyo_path2_perm(tomoyo_domain(), TOMOYO_TYPE_LINK, &path1, - &path2); + return tomoyo_path2_perm(TOMOYO_TYPE_LINK, &path1, &path2); } static int tomoyo_path_rename(struct path *old_parent, @@ -168,15 +167,14 @@ static int tomoyo_path_rename(struct path *old_parent, { struct path path1 = { old_parent->mnt, old_dentry }; struct path path2 = { new_parent->mnt, new_dentry }; - return tomoyo_path2_perm(tomoyo_domain(), TOMOYO_TYPE_RENAME, &path1, - &path2); + return tomoyo_path2_perm(TOMOYO_TYPE_RENAME, &path1, &path2); } static int tomoyo_file_fcntl(struct file *file, unsigned int cmd, unsigned long arg) { if (cmd == F_SETFL && ((arg ^ file->f_flags) & O_APPEND)) - return tomoyo_check_rewrite_permission(tomoyo_domain(), file); + return tomoyo_check_rewrite_permission(file); return 0; } @@ -196,50 +194,46 @@ static int tomoyo_dentry_open(struct file *f, const struct cred *cred) static int tomoyo_file_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { - return tomoyo_path_perm(tomoyo_domain(), TOMOYO_TYPE_IOCTL, - &file->f_path); + return tomoyo_path_perm(TOMOYO_TYPE_IOCTL, &file->f_path); } static int tomoyo_path_chmod(struct dentry *dentry, struct vfsmount *mnt, mode_t mode) { struct path path = { mnt, dentry }; - return tomoyo_path_perm(tomoyo_domain(), TOMOYO_TYPE_CHMOD, &path); + return tomoyo_path_perm(TOMOYO_TYPE_CHMOD, &path); } static int tomoyo_path_chown(struct path *path, uid_t uid, gid_t gid) { int error = 0; if (uid != (uid_t) -1) - error = tomoyo_path_perm(tomoyo_domain(), TOMOYO_TYPE_CHOWN, - path); + error = tomoyo_path_perm(TOMOYO_TYPE_CHOWN, path); if (!error && gid != (gid_t) -1) - error = tomoyo_path_perm(tomoyo_domain(), TOMOYO_TYPE_CHGRP, - path); + error = tomoyo_path_perm(TOMOYO_TYPE_CHGRP, path); return error; } static int tomoyo_path_chroot(struct path *path) { - return tomoyo_path_perm(tomoyo_domain(), TOMOYO_TYPE_CHROOT, path); + return tomoyo_path_perm(TOMOYO_TYPE_CHROOT, path); } static int tomoyo_sb_mount(char *dev_name, struct path *path, char *type, unsigned long flags, void *data) { - return tomoyo_path_perm(tomoyo_domain(), TOMOYO_TYPE_MOUNT, path); + return tomoyo_path_perm(TOMOYO_TYPE_MOUNT, path); } static int tomoyo_sb_umount(struct vfsmount *mnt, int flags) { struct path path = { mnt, mnt->mnt_root }; - return tomoyo_path_perm(tomoyo_domain(), TOMOYO_TYPE_UMOUNT, &path); + return tomoyo_path_perm(TOMOYO_TYPE_UMOUNT, &path); } static int tomoyo_sb_pivotroot(struct path *old_path, struct path *new_path) { - return tomoyo_path2_perm(tomoyo_domain(), TOMOYO_TYPE_PIVOT_ROOT, - new_path, old_path); + return tomoyo_path2_perm(TOMOYO_TYPE_PIVOT_ROOT, new_path, old_path); } /* From 2da5d31bc72d0a36dc16af7f5d5baa4f86df9c76 Mon Sep 17 00:00:00 2001 From: James Morris Date: Tue, 16 Feb 2010 17:29:06 +1100 Subject: [PATCH 33/38] security: fix a couple of sparse warnings Fix a couple of sparse warnings for callers of context_struct_to_string, which takes a *u32, not an *int. These cases are harmless as the values are not used. Signed-off-by: James Morris Acked-by: KaiGai Kohei --- security/selinux/ss/services.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index 4e976f58b98..0e5c3a422a8 100644 --- a/security/selinux/ss/services.c +++ b/security/selinux/ss/services.c @@ -455,7 +455,8 @@ static void security_dump_masked_av(struct context *scontext, char *scontext_name = NULL; char *tcontext_name = NULL; char *permission_names[32]; - int index, length; + int index; + u32 length; bool need_comma = false; if (!permissions) @@ -807,7 +808,7 @@ int security_bounded_transition(u32 old_sid, u32 new_sid) if (rc) { char *old_name = NULL; char *new_name = NULL; - int length; + u32 length; if (!context_struct_to_string(old_context, &old_name, &length) && From 170800088666963de1111d62fb503889c8c82eda Mon Sep 17 00:00:00 2001 From: Tetsuo Handa Date: Tue, 16 Feb 2010 21:14:48 +0900 Subject: [PATCH 34/38] TOMOYO: Remove __func__ from tomoyo_is_correct_path/domain __func__ is used for only debug printk(). We can remove it. Signed-off-by: Tetsuo Handa Signed-off-by: James Morris --- security/tomoyo/common.c | 18 ++++-------------- security/tomoyo/common.h | 6 ++---- security/tomoyo/domain.c | 18 +++++++++--------- security/tomoyo/file.c | 10 +++++----- 4 files changed, 20 insertions(+), 32 deletions(-) diff --git a/security/tomoyo/common.c b/security/tomoyo/common.c index ffcf0245056..30dd1c68a64 100644 --- a/security/tomoyo/common.c +++ b/security/tomoyo/common.c @@ -179,14 +179,12 @@ static void tomoyo_normalize_line(unsigned char *buffer) * 1 = must / -1 = must not / 0 = don't care * @end_type: Should the pathname end with '/'? * 1 = must / -1 = must not / 0 = don't care - * @function: The name of function calling me. * * Check whether the given filename follows the naming rules. * Returns true if @filename follows the naming rules, false otherwise. */ bool tomoyo_is_correct_path(const char *filename, const s8 start_type, - const s8 pattern_type, const s8 end_type, - const char *function) + const s8 pattern_type, const s8 end_type) { const char *const start = filename; bool in_repetition = false; @@ -194,7 +192,6 @@ bool tomoyo_is_correct_path(const char *filename, const s8 start_type, unsigned char c; unsigned char d; unsigned char e; - const char *original_filename = filename; if (!filename) goto out; @@ -283,25 +280,20 @@ bool tomoyo_is_correct_path(const char *filename, const s8 start_type, goto out; return true; out: - printk(KERN_DEBUG "%s: Invalid pathname '%s'\n", function, - original_filename); return false; } /** * tomoyo_is_correct_domain - Check whether the given domainname follows the naming rules. * @domainname: The domainname to check. - * @function: The name of function calling me. * * Returns true if @domainname follows the naming rules, false otherwise. */ -bool tomoyo_is_correct_domain(const unsigned char *domainname, - const char *function) +bool tomoyo_is_correct_domain(const unsigned char *domainname) { unsigned char c; unsigned char d; unsigned char e; - const char *org_domainname = domainname; if (!domainname || strncmp(domainname, TOMOYO_ROOT_NAME, TOMOYO_ROOT_NAME_LEN)) @@ -344,8 +336,6 @@ bool tomoyo_is_correct_domain(const unsigned char *domainname, } while (*domainname); return true; out: - printk(KERN_DEBUG "%s: Invalid domainname '%s'\n", function, - org_domainname); return false; } @@ -1086,11 +1076,11 @@ static int tomoyo_update_manager_entry(const char *manager, bool is_domain = false; if (tomoyo_is_domain_def(manager)) { - if (!tomoyo_is_correct_domain(manager, __func__)) + if (!tomoyo_is_correct_domain(manager)) return -EINVAL; is_domain = true; } else { - if (!tomoyo_is_correct_path(manager, 1, -1, -1, __func__)) + if (!tomoyo_is_correct_path(manager, 1, -1, -1)) return -EINVAL; } saved_manager = tomoyo_get_name(manager); diff --git a/security/tomoyo/common.h b/security/tomoyo/common.h index 17ed365521b..67bd22dd3e6 100644 --- a/security/tomoyo/common.h +++ b/security/tomoyo/common.h @@ -520,12 +520,10 @@ bool tomoyo_domain_quota_is_ok(struct tomoyo_domain_info * const domain); bool tomoyo_io_printf(struct tomoyo_io_buffer *head, const char *fmt, ...) __attribute__ ((format(printf, 2, 3))); /* Check whether the domainname is correct. */ -bool tomoyo_is_correct_domain(const unsigned char *domainname, - const char *function); +bool tomoyo_is_correct_domain(const unsigned char *domainname); /* Check whether the token is correct. */ bool tomoyo_is_correct_path(const char *filename, const s8 start_type, - const s8 pattern_type, const s8 end_type, - const char *function); + const s8 pattern_type, const s8 end_type); /* Check whether the token can be a domainname. */ bool tomoyo_is_domain_def(const unsigned char *buffer); /* Check whether the given filename matches the given pattern. */ diff --git a/security/tomoyo/domain.c b/security/tomoyo/domain.c index 74cd0f52e3a..66caaa1b842 100644 --- a/security/tomoyo/domain.c +++ b/security/tomoyo/domain.c @@ -136,13 +136,13 @@ static int tomoyo_update_domain_initializer_entry(const char *domainname, int error = is_delete ? -ENOENT : -ENOMEM; bool is_last_name = false; - if (!tomoyo_is_correct_path(program, 1, -1, -1, __func__)) + if (!tomoyo_is_correct_path(program, 1, -1, -1)) return -EINVAL; /* No patterns allowed. */ if (domainname) { if (!tomoyo_is_domain_def(domainname) && - tomoyo_is_correct_path(domainname, 1, -1, -1, __func__)) + tomoyo_is_correct_path(domainname, 1, -1, -1)) is_last_name = true; - else if (!tomoyo_is_correct_domain(domainname, __func__)) + else if (!tomoyo_is_correct_domain(domainname)) return -EINVAL; saved_domainname = tomoyo_get_name(domainname); if (!saved_domainname) @@ -357,12 +357,12 @@ static int tomoyo_update_domain_keeper_entry(const char *domainname, bool is_last_name = false; if (!tomoyo_is_domain_def(domainname) && - tomoyo_is_correct_path(domainname, 1, -1, -1, __func__)) + tomoyo_is_correct_path(domainname, 1, -1, -1)) is_last_name = true; - else if (!tomoyo_is_correct_domain(domainname, __func__)) + else if (!tomoyo_is_correct_domain(domainname)) return -EINVAL; if (program) { - if (!tomoyo_is_correct_path(program, 1, -1, -1, __func__)) + if (!tomoyo_is_correct_path(program, 1, -1, -1)) return -EINVAL; saved_program = tomoyo_get_name(program); if (!saved_program) @@ -556,8 +556,8 @@ static int tomoyo_update_alias_entry(const char *original_name, const struct tomoyo_path_info *saved_aliased_name; int error = is_delete ? -ENOENT : -ENOMEM; - if (!tomoyo_is_correct_path(original_name, 1, -1, -1, __func__) || - !tomoyo_is_correct_path(aliased_name, 1, -1, -1, __func__)) + if (!tomoyo_is_correct_path(original_name, 1, -1, -1) || + !tomoyo_is_correct_path(aliased_name, 1, -1, -1)) return -EINVAL; /* No patterns allowed. */ saved_original_name = tomoyo_get_name(original_name); saved_aliased_name = tomoyo_get_name(aliased_name); @@ -659,7 +659,7 @@ struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char * const struct tomoyo_path_info *saved_domainname; bool found = false; - if (!tomoyo_is_correct_domain(domainname, __func__)) + if (!tomoyo_is_correct_domain(domainname)) return NULL; saved_domainname = tomoyo_get_name(domainname); if (!saved_domainname) diff --git a/security/tomoyo/file.c b/security/tomoyo/file.c index db342ef87af..1b24304edb7 100644 --- a/security/tomoyo/file.c +++ b/security/tomoyo/file.c @@ -168,7 +168,7 @@ static int tomoyo_update_globally_readable_entry(const char *filename, const struct tomoyo_path_info *saved_filename; int error = is_delete ? -ENOENT : -ENOMEM; - if (!tomoyo_is_correct_path(filename, 1, 0, -1, __func__)) + if (!tomoyo_is_correct_path(filename, 1, 0, -1)) return -EINVAL; saved_filename = tomoyo_get_name(filename); if (!saved_filename) @@ -468,7 +468,7 @@ static int tomoyo_update_no_rewrite_entry(const char *pattern, const struct tomoyo_path_info *saved_pattern; int error = is_delete ? -ENOENT : -ENOMEM; - if (!tomoyo_is_correct_path(pattern, 0, 0, 0, __func__)) + if (!tomoyo_is_correct_path(pattern, 0, 0, 0)) return -EINVAL; saved_pattern = tomoyo_get_name(pattern); if (!saved_pattern) @@ -814,7 +814,7 @@ static int tomoyo_update_path_acl(const u8 type, const char *filename, if (!domain) return -EINVAL; - if (!tomoyo_is_correct_path(filename, 0, 0, 0, __func__)) + if (!tomoyo_is_correct_path(filename, 0, 0, 0)) return -EINVAL; saved_filename = tomoyo_get_name(filename); if (!saved_filename) @@ -898,8 +898,8 @@ static int tomoyo_update_path2_acl(const u8 type, const char *filename1, if (!domain) return -EINVAL; - if (!tomoyo_is_correct_path(filename1, 0, 0, 0, __func__) || - !tomoyo_is_correct_path(filename2, 0, 0, 0, __func__)) + if (!tomoyo_is_correct_path(filename1, 0, 0, 0) || + !tomoyo_is_correct_path(filename2, 0, 0, 0)) return -EINVAL; saved_filename1 = tomoyo_get_name(filename1); saved_filename2 = tomoyo_get_name(filename2); From 2ae3ba39389b51d8502123de0a59374bec899c4d Mon Sep 17 00:00:00 2001 From: KaiGai Kohei Date: Wed, 17 Feb 2010 08:49:41 +0900 Subject: [PATCH 35/38] selinux: libsepol: remove dead code in check_avtab_hierarchy_callback() This patch revert the commit of 7d52a155e38d5a165759dbbee656455861bf7801 which removed a part of type_attribute_bounds_av as a dead code. However, at that time, we didn't find out the target side boundary allows to handle some of pseudo /proc//* entries with its process's security context well. Signed-off-by: KaiGai Kohei Acked-by: Stephen Smalley -- security/selinux/ss/services.c | 43 ++++++++++++++++++++++++++++++++++++--- 1 files changed, 39 insertions(+), 4 deletions(-) Signed-off-by: James Morris --- security/selinux/ss/services.c | 43 ++++++++++++++++++++++++++++++---- 1 file changed, 39 insertions(+), 4 deletions(-) diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index 0e5c3a422a8..cf27b3ee1a9 100644 --- a/security/selinux/ss/services.c +++ b/security/selinux/ss/services.c @@ -525,14 +525,16 @@ static void type_attribute_bounds_av(struct context *scontext, u16 tclass, struct av_decision *avd) { + struct context lo_scontext; + struct context lo_tcontext; + struct av_decision lo_avd; struct type_datum *source = policydb.type_val_to_struct[scontext->type - 1]; + struct type_datum *target + = policydb.type_val_to_struct[tcontext->type - 1]; + u32 masked = 0; if (source->bounds) { - struct context lo_scontext; - struct av_decision lo_avd; - u32 masked; - memset(&lo_avd, 0, sizeof(lo_avd)); memcpy(&lo_scontext, scontext, sizeof(lo_scontext)); @@ -545,7 +547,40 @@ static void type_attribute_bounds_av(struct context *scontext, if ((lo_avd.allowed & avd->allowed) == avd->allowed) return; /* no masked permission */ masked = ~lo_avd.allowed & avd->allowed; + } + if (target->bounds) { + memset(&lo_avd, 0, sizeof(lo_avd)); + + memcpy(&lo_tcontext, tcontext, sizeof(lo_tcontext)); + lo_tcontext.type = target->bounds; + + context_struct_compute_av(scontext, + &lo_tcontext, + tclass, + &lo_avd); + if ((lo_avd.allowed & avd->allowed) == avd->allowed) + return; /* no masked permission */ + masked = ~lo_avd.allowed & avd->allowed; + } + + if (source->bounds && target->bounds) { + memset(&lo_avd, 0, sizeof(lo_avd)); + /* + * lo_scontext and lo_tcontext are already + * set up. + */ + + context_struct_compute_av(&lo_scontext, + &lo_tcontext, + tclass, + &lo_avd); + if ((lo_avd.allowed & avd->allowed) == avd->allowed) + return; /* no masked permission */ + masked = ~lo_avd.allowed & avd->allowed; + } + + if (masked) { /* mask violated permissions */ avd->allowed &= ~masked; From 189b3b1c89761054fee3438f063d7f257306e2d8 Mon Sep 17 00:00:00 2001 From: "wzt.wzt@gmail.com" Date: Tue, 23 Feb 2010 23:15:28 +0800 Subject: [PATCH 36/38] Security: add static to security_ops and default_security_ops variable Enhance the security framework to support resetting the active security module. This eliminates the need for direct use of the security_ops and default_security_ops variables outside of security.c, so make security_ops and default_security_ops static. Also remove the secondary_ops variable as a cleanup since there is no use for that. secondary_ops was originally used by SELinux to call the "secondary" security module (capability or dummy), but that was replaced by direct calls to capability and the only remaining use is to save and restore the original security ops pointer value if SELinux is disabled by early userspace based on /etc/selinux/config. Further, if we support this directly in the security framework, then we can just use &default_security_ops for this purpose since that is now available. Signed-off-by: Zhitong Wang Acked-by: Stephen Smalley Signed-off-by: James Morris --- include/linux/security.h | 2 ++ security/capability.c | 4 ---- security/security.c | 11 +++++++++-- security/selinux/hooks.c | 13 +------------ 4 files changed, 12 insertions(+), 18 deletions(-) diff --git a/include/linux/security.h b/include/linux/security.h index a4dc74d86ac..233d20b52c1 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -95,6 +95,8 @@ struct seq_file; extern int cap_netlink_send(struct sock *sk, struct sk_buff *skb); extern int cap_netlink_recv(struct sk_buff *skb, int cap); +void reset_security_ops(void); + #ifdef CONFIG_MMU extern unsigned long mmap_min_addr; extern unsigned long dac_mmap_min_addr; diff --git a/security/capability.c b/security/capability.c index 5c700e1a4fd..4875142b858 100644 --- a/security/capability.c +++ b/security/capability.c @@ -906,10 +906,6 @@ static void cap_audit_rule_free(void *lsmrule) } #endif /* CONFIG_AUDIT */ -struct security_operations default_security_ops = { - .name = "default", -}; - #define set_to_cap_if_null(ops, function) \ do { \ if (!ops->function) { \ diff --git a/security/security.c b/security/security.c index 971092c06f3..edae56b7877 100644 --- a/security/security.c +++ b/security/security.c @@ -23,10 +23,12 @@ static __initdata char chosen_lsm[SECURITY_NAME_MAX + 1] = CONFIG_DEFAULT_SECURITY; /* things that live in capability.c */ -extern struct security_operations default_security_ops; extern void security_fixup_ops(struct security_operations *ops); -struct security_operations *security_ops; /* Initialized to NULL */ +static struct security_operations *security_ops; +static struct security_operations default_security_ops = { + .name = "default", +}; static inline int verify(struct security_operations *ops) { @@ -63,6 +65,11 @@ int __init security_init(void) return 0; } +void reset_security_ops(void) +{ + security_ops = &default_security_ops; +} + /* Save user chosen LSM */ static int __init choose_lsm(char *str) { diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 6b36ce2eef2..dc7660074b9 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -126,13 +126,6 @@ __setup("selinux=", selinux_enabled_setup); int selinux_enabled = 1; #endif - -/* - * Minimal support for a secondary security module, - * just to allow the use of the capability module. - */ -static struct security_operations *secondary_ops; - /* Lists of inode and superblock security structures initialized before the policy was loaded. */ static LIST_HEAD(superblock_security_head); @@ -5674,9 +5667,6 @@ static __init int selinux_init(void) 0, SLAB_PANIC, NULL); avc_init(); - secondary_ops = security_ops; - if (!secondary_ops) - panic("SELinux: No initial security operations\n"); if (register_security(&selinux_ops)) panic("SELinux: Unable to register with kernel.\n"); @@ -5837,8 +5827,7 @@ int selinux_disable(void) selinux_disabled = 1; selinux_enabled = 0; - /* Reset security_ops to the secondary module, dummy or capability. */ - security_ops = secondary_ops; + reset_security_ops(); /* Try to destroy the avc node cache */ avc_disable(); From 1fcdc7c527010b144d3951f9ce25faedf264933c Mon Sep 17 00:00:00 2001 From: Tetsuo Handa Date: Thu, 25 Feb 2010 17:19:25 +0900 Subject: [PATCH 37/38] TOMOYO: Protect find_task_by_vpid() with RCU. Holding tasklist_lock is no longer sufficient for find_task_by_vpid(). Explicit rcu_read_lock() is required. Signed-off-by: Tetsuo Handa -- security/tomoyo/common.c | 4 ++++ 1 file changed, 4 insertions(+) Signed-off-by: James Morris --- security/tomoyo/common.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/security/tomoyo/common.c b/security/tomoyo/common.c index 30dd1c68a64..ff51f1026b5 100644 --- a/security/tomoyo/common.c +++ b/security/tomoyo/common.c @@ -1232,11 +1232,13 @@ static bool tomoyo_is_select_one(struct tomoyo_io_buffer *head, if (sscanf(data, "pid=%u", &pid) == 1) { struct task_struct *p; + rcu_read_lock(); read_lock(&tasklist_lock); p = find_task_by_vpid(pid); if (p) domain = tomoyo_real_domain(p); read_unlock(&tasklist_lock); + rcu_read_unlock(); } else if (!strncmp(data, "domain=", 7)) { if (tomoyo_is_domain_def(data + 7)) domain = tomoyo_find_domain(data + 7); @@ -1635,11 +1637,13 @@ static int tomoyo_read_pid(struct tomoyo_io_buffer *head) const int pid = head->read_step; struct task_struct *p; struct tomoyo_domain_info *domain = NULL; + rcu_read_lock(); read_lock(&tasklist_lock); p = find_task_by_vpid(pid); if (p) domain = tomoyo_real_domain(p); read_unlock(&tasklist_lock); + rcu_read_unlock(); if (domain) tomoyo_io_printf(head, "%d %u %s", pid, domain->profile, domain->domainname->name); From ef57471a73b67a7b65fd8708fd55c77cb7c619af Mon Sep 17 00:00:00 2001 From: David Howells Date: Fri, 26 Feb 2010 01:56:16 +0000 Subject: [PATCH 38/38] SELinux: Make selinux_kernel_create_files_as() shouldn't just always return 0 Make selinux_kernel_create_files_as() return an error when it gets one, rather than unconditionally returning 0. Without this, cachefiles doesn't return an error if the SELinux policy doesn't let it create files with the label of the directory at the base of the cache. Signed-off-by: David Howells Signed-off-by: James Morris --- security/selinux/hooks.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index dc7660074b9..5feecb41009 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -3329,7 +3329,7 @@ static int selinux_kernel_create_files_as(struct cred *new, struct inode *inode) if (ret == 0) tsec->create_sid = isec->sid; - return 0; + return ret; } static int selinux_kernel_module_request(char *kmod_name)