[TOMOYO #8 (2.6.25-mm1) 2/7] LSM adapter functions.

From: Toshiharu Harada
Date: Thu May 01 2008 - 01:57:13 EST


Signed-off-by: Kentaro Takeda <takedakn@xxxxxxxxxxxxx>
Signed-off-by: Tetsuo Handa <penguin-kernel@xxxxxxxxxxxxxxxxxxx>
Signed-off-by: Toshiharu Harada <haradats@xxxxxxxxxxxxx>
---
security/tomoyo/tomoyo.c | 279 +++++++++++++++++++++++++++++++++++++++++++++++
security/tomoyo/tomoyo.h | 102 +++++++++++++++++
2 files changed, 381 insertions(+)

--- /dev/null
+++ mm/security/tomoyo/tomoyo.h
@@ -0,0 +1,102 @@
+/*
+ * security/tomoyo/tomoyo.h
+ *
+ * Implementation of the Domain-Based Mandatory Access Control.
+ *
+ * Copyright (C) 2005-2008 NTT DATA CORPORATION
+ *
+ * Version: 2.2.0-pre 2008/04/30
+ *
+ */
+
+#ifndef _LINUX_TOMOYO_H
+#define _LINUX_TOMOYO_H
+
+struct path_info;
+struct dentry;
+struct vfsmount;
+struct inode;
+struct linux_binprm;
+struct pt_regs;
+struct tmy_page_buffer;
+
+char *sysctlpath_from_table(struct ctl_table *table);
+int tmy_check_file_perm(const char *filename, const u8 perm,
+ const char *operation);
+int tmy_check_exec_perm(const struct path_info *filename,
+ struct tmy_page_buffer *buf);
+int tmy_check_open_permission(struct dentry *dentry, struct vfsmount *mnt,
+ const int flag);
+int tmy_check_1path_perm(const u8 operation,
+ struct dentry *dentry,
+ struct vfsmount *mnt);
+int tmy_check_2path_perm(const u8 operation,
+ struct dentry *dentry1,
+ struct vfsmount *mnt1,
+ struct dentry *dentry2,
+ struct vfsmount *mnt2);
+int tmy_check_rewrite_permission(struct file *filp);
+int tmy_find_next_domain(struct linux_binprm *bprm,
+ struct domain_info **next_domain);
+
+#define TMY_CHECK_READ_FOR_OPEN_EXEC 1
+
+/* Index numbers for Access Controls. */
+
+#define TYPE_SINGLE_PATH_ACL 0
+#define 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 TMY_TYPE_READ_WRITE_ACL 0
+#define TMY_TYPE_EXECUTE_ACL 1
+#define TMY_TYPE_READ_ACL 2
+#define TMY_TYPE_WRITE_ACL 3
+#define TMY_TYPE_CREATE_ACL 4
+#define TMY_TYPE_UNLINK_ACL 5
+#define TMY_TYPE_MKDIR_ACL 6
+#define TMY_TYPE_RMDIR_ACL 7
+#define TMY_TYPE_MKFIFO_ACL 8
+#define TMY_TYPE_MKSOCK_ACL 9
+#define TMY_TYPE_MKBLOCK_ACL 10
+#define TMY_TYPE_MKCHAR_ACL 11
+#define TMY_TYPE_TRUNCATE_ACL 12
+#define TMY_TYPE_SYMLINK_ACL 13
+#define TMY_TYPE_REWRITE_ACL 14
+#define MAX_SINGLE_PATH_OPERATION 15
+
+#define TMY_TYPE_LINK_ACL 0
+#define TMY_TYPE_RENAME_ACL 1
+#define MAX_DOUBLE_PATH_OPERATION 2
+
+struct tmy_security {
+ struct domain_info *domain;
+ struct domain_info *prev_domain;
+ u32 flags;
+};
+
+#define TMY_SECURITY ((struct tmy_security *) current->security)
+
+#define TMY_DOMAINPOLICY 0
+#define TMY_EXCEPTIONPOLICY 1
+#define TMY_DOMAIN_STATUS 2
+#define TMY_PROCESS_STATUS 3
+#define TMY_MEMINFO 4
+#define TMY_SELFDOMAIN 5
+#define TMY_VERSION 6
+#define TMY_PROFILE 7
+#define TMY_MANAGER 8
+#define TMY_UPDATESCOUNTER 9
+
+extern struct domain_info KERNEL_DOMAIN;
+
+#endif
--- /dev/null
+++ mm/security/tomoyo/tomoyo.c
@@ -0,0 +1,279 @@
+/*
+ * security/tomoyo/tomoyo.c
+ *
+ * LSM hooks for TOMOYO Linux.
+ */
+
+#include <linux/security.h>
+#include "common.h"
+#include "tomoyo.h"
+#include "realpath.h"
+
+static struct kmem_cache *tmy_cachep;
+
+static int tmy_task_alloc_security(struct task_struct *p)
+{
+ struct tmy_security *ptr = kmem_cache_alloc(tmy_cachep, GFP_KERNEL);
+
+ if (!ptr)
+ return -ENOMEM;
+ memcpy(ptr, TMY_SECURITY, sizeof(*ptr));
+ p->security = ptr;
+ return 0;
+}
+
+static void tmy_task_free_security(struct task_struct *p)
+{
+ kmem_cache_free(tmy_cachep, p->security);
+}
+
+static int tmy_bprm_alloc_security(struct linux_binprm *bprm)
+{
+ TMY_SECURITY->prev_domain = TMY_SECURITY->domain;
+ return 0;
+}
+
+static int tmy_bprm_check_security(struct linux_binprm *bprm)
+{
+ struct domain_info *next_domain = NULL;
+ int retval = 0;
+
+ tmy_load_policy(bprm->filename);
+
+ /*
+ * TMY_CHECK_READ_FOR_OPEN_EXEC bit indicates whether this function is
+ * called by do_execve() or not.
+ * If called by do_execve(), I do domain transition.
+ */
+ if ((TMY_SECURITY->flags & TMY_CHECK_READ_FOR_OPEN_EXEC))
+ goto out;
+ retval = tmy_find_next_domain(bprm, &next_domain);
+ if (retval)
+ goto out;
+ TMY_SECURITY->domain = next_domain;
+ TMY_SECURITY->flags |= TMY_CHECK_READ_FOR_OPEN_EXEC;
+out:
+ return retval;
+}
+
+static void tmy_bprm_post_apply_creds(struct linux_binprm *bprm)
+{
+ TMY_SECURITY->prev_domain = TMY_SECURITY->domain;
+}
+
+static void tmy_bprm_free_security(struct linux_binprm *bprm)
+{
+ TMY_SECURITY->domain = TMY_SECURITY->prev_domain;
+ TMY_SECURITY->flags &= ~TMY_CHECK_READ_FOR_OPEN_EXEC;
+}
+
+static int tmy_sysctl(struct ctl_table *table, int op)
+{
+ int error;
+ char *name;
+
+ if ((op & 6) == 0)
+ return 0;
+
+ name = sysctlpath_from_table(table);
+ if (!name)
+ return -ENOMEM;
+
+ error = tmy_check_file_perm(name, op & 6, "sysctl");
+ tmy_free(name);
+
+ return error;
+}
+
+static int tmy_inode_permission(struct inode *inode, int mask,
+ struct nameidata *nd)
+{
+ if (S_ISDIR(inode->i_mode)) /* ignore because inode is directory */
+ return 0;
+ if (!nd || !nd->path.dentry || !nd->path.mnt)
+ return 0;
+
+ /*
+ * If called by other than do_execve(), I check for read permission of
+ * interpreter.
+ * Unlike DAC, I don't check for read permission of pathname passed to
+ * do_execve().
+ * TOMOYO Linux checks for program's execute permission and
+ * interpreter's read permission.
+ */
+ if ((mask != MAY_EXEC) ||
+ !(TMY_SECURITY->flags & TMY_CHECK_READ_FOR_OPEN_EXEC))
+ return 0;
+
+ /* called from open_exec() other than do_execve() */;
+ return tmy_check_open_permission(nd->path.dentry, nd->path.mnt,
+ O_RDONLY + 1);
+}
+
+static int tmy_path_open(struct dentry *dentry, struct vfsmount *mnt, int flags)
+{
+ return tmy_check_open_permission(dentry, mnt, flags);
+}
+
+static int tmy_path_truncate(struct path *path, loff_t length,
+ unsigned int time_attrs, struct file *filp)
+{
+ return tmy_check_1path_perm(TMY_TYPE_TRUNCATE_ACL, path->dentry,
+ path->mnt);
+}
+
+static int tmy_path_create(struct inode *dir, struct dentry *dentry, int mode,
+ struct nameidata *nd)
+{
+ if (!nd || !nd->path.mnt)
+ return 0;
+ return tmy_check_1path_perm(TMY_TYPE_CREATE_ACL, dentry, nd->path.mnt);
+}
+
+static int tmy_path_unlink(struct path *dir, struct dentry *dentry)
+{
+ const int err = pre_vfs_unlink(dir->dentry->d_inode, dentry);
+ if (err)
+ return err;
+ return tmy_check_1path_perm(TMY_TYPE_UNLINK_ACL, dentry, dir->mnt);
+}
+
+static int tmy_path_mkdir(struct path *dir, struct dentry *dentry, int mode)
+{
+ const int err = pre_vfs_mkdir(dir->dentry->d_inode, dentry);
+ if (err)
+ return err;
+ return tmy_check_1path_perm(TMY_TYPE_MKDIR_ACL, dentry, dir->mnt);
+}
+
+static int tmy_path_rmdir(struct path *dir, struct dentry *dentry)
+{
+ const int err = pre_vfs_rmdir(dir->dentry->d_inode, dentry);
+ if (err)
+ return err;
+ return tmy_check_1path_perm(TMY_TYPE_RMDIR_ACL, dentry, dir->mnt);
+}
+
+static int tmy_path_symlink(struct path *dir, struct dentry *dentry,
+ const char *old_name)
+{
+ const int err = pre_vfs_symlink(dir->dentry->d_inode, dentry);
+ if (err)
+ return err;
+ return tmy_check_1path_perm(TMY_TYPE_SYMLINK_ACL, dentry, dir->mnt);
+}
+
+static int tmy_path_mknod(struct path *dir, struct dentry *dentry, int mode,
+ unsigned int dev)
+{
+ struct vfsmount *mnt = dir->mnt;
+ int err = 0;
+ switch (mode & S_IFMT) {
+ case S_IFCHR:
+ case S_IFBLK:
+ case S_IFIFO:
+ case S_IFSOCK:
+ break;
+ default:
+ return 0;
+ }
+ err = pre_vfs_mknod(dir->dentry->d_inode, dentry, mode);
+ if (err)
+ return err;
+ if (S_ISCHR(mode))
+ return tmy_check_1path_perm(TMY_TYPE_MKCHAR_ACL, dentry, mnt);
+ if (S_ISBLK(mode))
+ return tmy_check_1path_perm(TMY_TYPE_MKBLOCK_ACL, dentry, mnt);
+ if (S_ISFIFO(mode))
+ return tmy_check_1path_perm(TMY_TYPE_MKFIFO_ACL, dentry, mnt);
+ if (S_ISSOCK(mode))
+ return tmy_check_1path_perm(TMY_TYPE_MKSOCK_ACL, dentry, mnt);
+ return 0;
+}
+
+static int tmy_path_link(struct path *old_path, struct path *new_dir,
+ struct dentry *new_dentry)
+{
+ const int err = pre_vfs_link(old_path->dentry, new_dir->dentry->d_inode,
+ new_dentry);
+ if (err)
+ return err;
+ return tmy_check_2path_perm(TMY_TYPE_LINK_ACL,
+ old_path->dentry, old_path->mnt,
+ new_dentry, new_dir->mnt);
+}
+
+static int tmy_path_rename(struct path *old_dir, struct dentry *old_dentry,
+ struct path *new_dir, struct dentry *new_dentry)
+{
+ const int err = pre_vfs_rename(old_dir->dentry->d_inode, old_dentry,
+ new_dir->dentry->d_inode, new_dentry);
+ if (err)
+ return err;
+ return tmy_check_2path_perm(TMY_TYPE_RENAME_ACL,
+ old_dentry, old_dir->mnt,
+ new_dentry, new_dir->mnt);
+}
+
+static int tmy_path_uselib(struct nameidata *nd)
+{
+ return tmy_check_open_permission(nd->path.dentry, nd->path.mnt,
+ O_RDONLY + 1);
+}
+
+static int tmy_file_fcntl(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ if (cmd == F_SETFL && ((arg ^ file->f_flags) & O_APPEND))
+ return tmy_check_rewrite_permission(file);
+ return 0;
+}
+
+static struct security_operations tomoyo_security_ops = {
+ .name = "tomoyo",
+
+ .task_alloc_security = tmy_task_alloc_security,
+ .task_free_security = tmy_task_free_security,
+ .bprm_alloc_security = tmy_bprm_alloc_security,
+ .bprm_check_security = tmy_bprm_check_security,
+ .bprm_post_apply_creds = tmy_bprm_post_apply_creds,
+ .bprm_free_security = tmy_bprm_free_security,
+ .sysctl = tmy_sysctl,
+ .inode_permission = tmy_inode_permission,
+ .path_truncate = tmy_path_truncate,
+ .path_create = tmy_path_create,
+ .path_unlink = tmy_path_unlink,
+ .path_mkdir = tmy_path_mkdir,
+ .path_rmdir = tmy_path_rmdir,
+ .path_symlink = tmy_path_symlink,
+ .path_mknod = tmy_path_mknod,
+ .path_link = tmy_path_link,
+ .path_rename = tmy_path_rename,
+ .path_open = tmy_path_open,
+ .path_uselib = tmy_path_uselib,
+ .file_fcntl = tmy_file_fcntl,
+};
+
+static int __init tmy_init(void)
+{
+ struct tmy_security *tmy_security;
+ if (!security_module_enable(&tomoyo_security_ops))
+ return 0;
+
+ /* register ourselves with the security framework */
+ if (register_security(&tomoyo_security_ops))
+ panic("Failure registering TOMOYO Linux");
+
+ printk(KERN_INFO "TOMOYO Linux initialized\n");
+ tmy_cachep = kmem_cache_create("tomoyo_security",
+ sizeof(struct tmy_security),
+ 0, SLAB_PANIC, NULL);
+ tmy_security = kmem_cache_alloc(tmy_cachep, GFP_KERNEL);
+ BUG_ON(!tmy_security);
+ memset(tmy_security, 0, sizeof(*tmy_security));
+ tmy_security->domain = &KERNEL_DOMAIN;
+ init_task.security = tmy_security;
+ return 0;
+}
+
+security_initcall(tmy_init);

--

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/