To avoid namespace_sem deadlock, this patch uses
"current->last_vfsmount" associated by wrapper functions.

Signed-off-by: Kentaro Takeda <[EMAIL PROTECTED]>
Signed-off-by: Tetsuo Handa <[EMAIL PROTECTED]>
---
 security/tomoyo/tomoyo.c |  825 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 825 insertions(+)

--- /dev/null
+++ linux-2.6-mm/security/tomoyo/tomoyo.c
@@ -0,0 +1,825 @@
+/*
+ * security/tomoyo/tomoyo.c
+ *
+ * LSM hooks for TOMOYO Linux.
+ */
+
+#include "tomoyo.h"
+#include "realpath.h"
+
+#define MAX_SOCK_ADDR 128 /* net/socket.c */
+
+LIST_HEAD(domain_list);
+
+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)) {
+               retval = tmy_find_next_domain(bprm, &next_domain);
+               if (retval == 0) {
+                       struct domain_info *domain = TMY_SECURITY->domain;
+                       TMY_SECURITY->domain = next_domain;
+                       retval = tmy_check_environ(bprm);
+                       if (!retval)
+                               TMY_SECURITY->flags |=
+                                       TMY_CHECK_READ_FOR_OPEN_EXEC;
+                       else
+                               TMY_SECURITY->domain = domain;
+               }
+       }
+
+       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_file_perm(name, op & 6, "sysctl");
+       tmy_free(name);
+
+       return error;
+}
+
+static int tmy_inode_permission(struct inode *inode,
+                               int mask,
+                               struct nameidata *nd)
+{
+       int flag = 0;
+
+       if (S_ISDIR(inode->i_mode)) /* ignore because inode is directory */
+               return 0;
+       /*
+       if (!nd) {
+               printk("tmy_inode_permission: NULL nameidata\n");
+               dump_stack();
+               return 0;
+       } else if (!nd->mnt) {
+               printk("tmy_inode_permission: NULL vfsmount\n");
+               dump_stack();
+               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))
+               mask = MAY_READ;
+       if ((mask == MAY_EXEC) || (mask == 0))
+               return 0;
+
+       if (mask == (MAY_READ | MAY_EXEC))
+               flag |= O_RDONLY + 1;
+       else {
+               if (mask & MAY_READ)
+                       flag |= O_RDONLY + 1;
+               if (mask & MAY_WRITE)
+                       flag |= O_WRONLY + 1;
+               if ((mask & MAY_APPEND))
+                       flag |= O_APPEND;
+       }
+
+       return tmy_open_perm(nd->path.dentry, nd->path.mnt, flag);
+}
+
+static int tmy_do_single_write_perm(int operation, struct dentry *dentry)
+{
+       struct vfsmount *mnt = current->last_vfsmount;
+       if (!dentry || !mnt)
+               return 0;
+       if (!sbin_init_started)
+               return 0;
+       return tmy_single_write_perm(operation, dentry, mnt);
+}
+
+static int tmy_inode_setattr(struct dentry *dentry, struct iattr *iattr)
+{
+       int err = 0;
+       unsigned int ia_valid = iattr->ia_valid;
+       if (ia_valid & ATTR_MODE)
+               err = tmy_capable(TMY_SYS_CHMOD);
+       if (!err && (ia_valid & (ATTR_UID | ATTR_GID)))
+               err = tmy_capable(TMY_SYS_CHOWN);
+       if (err)
+               return err;
+       if (ia_valid & ATTR_SIZE)
+               return tmy_do_single_write_perm(TMY_TYPE_TRUNCATE_ACL, dentry);
+       return 0;
+}
+
+static int tmy_inode_create(struct inode *dir, struct dentry *dentry, int mode)
+{
+       return tmy_do_single_write_perm(TMY_TYPE_CREATE_ACL, dentry);
+}
+
+static int tmy_inode_unlink(struct inode *dir, struct dentry *dentry)
+{
+       const int err = tmy_capable(TMY_SYS_UNLINK);
+       if (err)
+               return err;
+       return tmy_do_single_write_perm(TMY_TYPE_UNLINK_ACL, dentry);
+}
+
+static int tmy_inode_mkdir(struct inode *dir, struct dentry *dentry, int mode)
+{
+       return tmy_do_single_write_perm(TMY_TYPE_MKDIR_ACL, dentry);
+}
+
+static int tmy_inode_rmdir(struct inode *dir, struct dentry *dentry)
+{
+       return tmy_do_single_write_perm(TMY_TYPE_RMDIR_ACL, dentry);
+}
+
+static int tmy_inode_symlink(struct inode *dir,
+                            struct dentry *dentry,
+                            const char *old_name)
+{
+       const int err = tmy_capable(TMY_SYS_SYMLINK);
+       if (err)
+               return err;
+       return tmy_do_single_write_perm(TMY_TYPE_SYMLINK_ACL, dentry);
+}
+
+static int tmy_inode_mknod(struct inode *inode,
+                          struct dentry *dentry,
+                          int mode,
+                          dev_t dev)
+{
+       int err;
+       if (S_ISCHR(mode)) {
+               err = tmy_capable(TMY_CREATE_CHAR_DEV);
+               if (err)
+                       return err;
+               return tmy_do_single_write_perm(TMY_TYPE_MKCHAR_ACL, dentry);
+       }
+       if (S_ISBLK(mode)) {
+               err = tmy_capable(TMY_CREATE_BLOCK_DEV);
+               if (err)
+                       return err;
+               return tmy_do_single_write_perm(TMY_TYPE_MKBLOCK_ACL, dentry);
+       }
+       if (S_ISFIFO(mode)) {
+               err = tmy_capable(TMY_CREATE_FIFO);
+               if (err)
+                       return err;
+               return tmy_do_single_write_perm(TMY_TYPE_MKFIFO_ACL, dentry);
+       }
+       if (S_ISSOCK(mode)) {
+               err = tmy_capable(TMY_CREATE_UNIX_SOCKET);
+               if (err)
+                       return err;
+               return tmy_do_single_write_perm(TMY_TYPE_MKSOCK_ACL, dentry);
+       }
+
+       return 0;
+}
+
+static int tmy_do_double_write_perm(int operation,
+                                   struct dentry *old_dentry,
+                                   struct dentry *new_dentry)
+{
+       struct vfsmount *mnt = current->last_vfsmount;
+       if (!old_dentry || !new_dentry || !mnt)
+               return 0;
+       if (!sbin_init_started)
+               return 0;
+       return tmy_double_write_perm(operation, old_dentry, mnt,
+                                    new_dentry, mnt);
+}
+
+static int tmy_inode_link(struct dentry *old_dentry,
+                         struct inode *inode,
+                         struct dentry *new_dentry)
+{
+       const int err = tmy_capable(TMY_SYS_LINK);
+       if (err)
+               return err;
+       return tmy_do_double_write_perm(TMY_TYPE_LINK_ACL,
+                                       old_dentry, new_dentry);
+}
+
+static int tmy_inode_rename(struct inode *old_inode,
+                           struct dentry *old_dentry,
+                           struct inode *new_inode,
+                           struct dentry *new_dentry)
+{
+       const int err = tmy_capable(TMY_SYS_RENAME);
+       if (err)
+               return err;
+       return tmy_do_double_write_perm(TMY_TYPE_RENAME_ACL,
+                                       old_dentry,
+                                       new_dentry);
+}
+
+static int tmy_file_fcntl(struct file *file,
+                         unsigned int cmd,
+                         unsigned long arg)
+{
+       if (!(arg & O_APPEND))
+               return tmy_rewrite_perm(file);
+       return 0;
+}
+
+static int tmy_file_ioctl(struct file *file, unsigned int cmd,
+                         unsigned long arg)
+{
+       switch (cmd) {
+       case FIOCLEX:
+       case FIONCLEX:
+       case FIONBIO:
+       case FIOASYNC:
+       case FIOQSIZE:
+               return 0;
+       case FIBMAP:
+       case FIGETBSZ:
+       case FIONREAD:
+               if (S_ISREG(file->f_path.dentry->d_inode->i_mode))
+                       return 0;
+       }
+       return tmy_capable(TMY_SYS_IOCTL);
+}
+
+static int tmy_socket_listen(struct socket *sock, int backlog)
+{
+       char addr[MAX_SOCK_ADDR];
+       int addr_len;
+       int error;
+
+       /* I don't check if called by kernel process. */
+       if (segment_eq(get_fs(), KERNEL_DS))
+               return 0;
+
+       if (sock->type != SOCK_STREAM)
+               return 0;
+       if (sock->sk->sk_family != PF_INET && sock->sk->sk_family != PF_INET6)
+               return 0;
+
+       error = tmy_capable(TMY_INET_STREAM_SOCKET_LISTEN);
+       if (error)
+               return error;
+
+       if (sock->ops->getname(sock, (struct sockaddr *) addr, &addr_len, 0))
+               return -EPERM;
+
+       switch (((struct sockaddr *) addr)->sa_family) {
+               struct sockaddr_in6 *in6;
+               struct sockaddr_in *in;
+
+       case AF_INET6:
+               in6 = (struct sockaddr_in6 *) addr;
+               error = tmy_network_listen_acl(1, in6->sin6_addr.s6_addr,
+                                              in6->sin6_port);
+               break;
+       case AF_INET:
+               in = (struct sockaddr_in *) addr;
+               error = tmy_network_listen_acl(0, (u8 *) &in->sin_addr,
+                                              in->sin_port);
+               break;
+       }
+
+       return error;
+}
+
+static int tmy_socket_create(int family, int type, int protocol, int kern)
+{
+       int error = 0;
+       if (kern)
+               return 0;
+       if (family == PF_INET || family == PF_INET6) {
+               switch (type) {
+               case SOCK_STREAM:
+                       return tmy_capable(TMY_INET_STREAM_SOCKET_CREATE);
+                       break;
+               case SOCK_DGRAM:
+                       return tmy_capable(TMY_USE_INET_DGRAM_SOCKET);
+                       break;
+               case SOCK_RAW:
+                       return tmy_capable(TMY_USE_INET_RAW_SOCKET);
+                       break;
+               }
+       } else if (family == PF_PACKET) {
+               return tmy_capable(TMY_USE_PACKET_SOCKET);
+       } else if (family == PF_ROUTE) {
+               return tmy_capable(TMY_USE_ROUTE_SOCKET);
+       }
+       return error;
+}
+
+static int tmy_socket_connect(struct socket *sock,
+                             struct sockaddr *addr,
+                             int addr_len0)
+{
+       unsigned int addr_len = (unsigned int) addr_len0;
+       int error = 0;
+       const unsigned int type = sock->type;
+
+       /* I don't check if called by kernel process. */
+       if (segment_eq(get_fs(), KERNEL_DS))
+               return 0;
+
+       if (type == SOCK_STREAM) {
+               error = tmy_capable(TMY_INET_STREAM_SOCKET_CONNECT);
+               if (error)
+                       return error;
+       }
+
+       if (type != SOCK_STREAM && type != SOCK_DGRAM && type != SOCK_RAW)
+               return 0;
+
+       switch (addr->sa_family) {
+               struct sockaddr_in6 *in6;
+               struct sockaddr_in *in;
+
+       case AF_INET6:
+               if (addr_len < SIN6_LEN_RFC2133)
+                       break;
+
+               in6 = (struct sockaddr_in6 *) addr;
+               if (type != SOCK_RAW)
+                       error = tmy_network_connect_acl(1, type,
+                                                       in6->sin6_addr.s6_addr,
+                                                       in6->sin6_port);
+               else {
+                       const u16 port = htons(sock->sk->sk_protocol);
+
+                       error = tmy_network_connect_acl(1, SOCK_RAW,
+                                                       in6->sin6_addr.s6_addr,
+                                                       port);
+               }
+               break;
+
+       case AF_INET:
+               if (addr_len < sizeof(struct sockaddr_in))
+                       break;
+
+               in = (struct sockaddr_in *) addr;
+               if (type != SOCK_RAW)
+                       error = tmy_network_connect_acl(0, type,
+                                                       (u8 *) &in->sin_addr,
+                                                       in->sin_port);
+               else {
+                       const u16 port = htons(sock->sk->sk_protocol);
+
+                       error = tmy_network_connect_acl(0, SOCK_RAW,
+                                                       (u8 *) &in->sin_addr,
+                                                       port);
+               }
+               break;
+       }
+
+       return error;
+}
+
+static int tmy_socket_bind(struct socket *sock,
+                          struct sockaddr *addr,
+                          int addr_len0)
+{
+       unsigned int addr_len = (unsigned int) addr_len0;
+       int error = 0;
+       const unsigned int type = sock->type;
+
+       /* I don't check if called by kernel process. */
+       if (segment_eq(get_fs(), KERNEL_DS))
+               return 0;
+
+       if (type != SOCK_STREAM && type != SOCK_DGRAM && type != SOCK_RAW)
+               return error;
+
+       switch (addr->sa_family) {
+               struct sockaddr_in6 *in6;
+               struct sockaddr_in *in;
+
+       case AF_INET6:
+               if (addr_len < SIN6_LEN_RFC2133)
+                       break;
+
+               in6 = ((struct sockaddr_in6 *) addr);
+               if (type != SOCK_RAW)
+                       error = tmy_network_bind_acl(1, type,
+                                                    in6->sin6_addr.s6_addr,
+                                                    in6->sin6_port);
+               else {
+                       const u16 port = htons(sock->sk->sk_protocol);
+
+                       error = tmy_network_bind_acl(1, SOCK_RAW,
+                                                    in6->sin6_addr.s6_addr,
+                                                    port);
+               }
+               break;
+
+       case AF_INET:
+               if (addr_len < sizeof(struct sockaddr_in))
+                       break;
+
+               in = (struct sockaddr_in *) addr;
+               if (type != SOCK_RAW)
+                       error = tmy_network_bind_acl(0, type,
+                                                    (u8 *) &in->sin_addr,
+                                                    in->sin_port);
+               else {
+                       const u16 port = htons(sock->sk->sk_protocol);
+
+                       error = tmy_network_bind_acl(0, SOCK_RAW,
+                                                    (u8 *) &in->sin_addr,
+                                                    port);
+               }
+               break;
+       }
+
+       return error;
+}
+
+static int tmy_socket_sendmsg(struct socket *sock, struct msghdr *msg, int 
size)
+{
+       int error = 0;
+       const int type = sock->type;
+       struct sockaddr *addr = (struct sockaddr *) msg->msg_name;
+       const unsigned int addr_len = msg->msg_namelen;
+
+       /* I don't check if called by kernel process. */
+       if (segment_eq(get_fs(), KERNEL_DS))
+               return 0;
+
+       if (!addr || (type != SOCK_DGRAM && type != SOCK_RAW))
+               return error;
+
+       switch (addr->sa_family) {
+               struct sockaddr_in6 *in6;
+               struct sockaddr_in *in;
+               u16 port;
+
+       case AF_INET6:
+               if (addr_len < SIN6_LEN_RFC2133)
+                       break;
+
+               in6 = (struct sockaddr_in6 *) addr;
+               port = htons(sock->sk->sk_protocol);
+               error = tmy_network_sendmsg_acl(1, type, in6->sin6_addr.s6_addr,
+                                               type == SOCK_DGRAM ?
+                                               in6->sin6_port : port);
+               break;
+
+       case AF_INET:
+               if (addr_len < sizeof(struct sockaddr_in))
+                       break;
+
+               in = (struct sockaddr_in *) addr;
+               port = htons(sock->sk->sk_protocol);
+               error = tmy_network_sendmsg_acl(0, type, (u8 *) &in->sin_addr,
+                                               type == SOCK_DGRAM ?
+                                               in->sin_port : port);
+               break;
+       }
+
+       return error;
+}
+
+static int tmy_socket_post_accept(struct socket *sock, struct socket *newsock)
+{
+       int error = 0;
+       int addr_len;
+       char addr[MAX_SOCK_ADDR];
+       struct sockaddr *sockaddr = (struct sockaddr *) addr;
+
+       /* I don't check if called by kernel process. */
+       if (segment_eq(get_fs(), KERNEL_DS))
+               return 0;
+
+       if ((newsock->sk->sk_family != PF_INET) &&
+           (newsock->sk->sk_family != PF_INET6))
+               return error;
+
+       if (newsock->ops->getname(newsock, sockaddr, &addr_len, 2) == 0) {
+               switch (sockaddr->sa_family) {
+                       struct sockaddr_in6 *in6;
+                       struct sockaddr_in *in;
+
+               case AF_INET6:
+                       in6 = (struct sockaddr_in6 *) addr;
+                       error = tmy_network_accept_acl(1,
+                                                      in6->sin6_addr.s6_addr,
+                                                      in6->sin6_port);
+                       break;
+
+               case AF_INET:
+                       in = (struct sockaddr_in *) addr;
+                       error = tmy_network_accept_acl(0, (u8 *) &in->sin_addr,
+                                                      in->sin_port);
+                       break;
+               }
+       } else
+               error = -EPERM;
+
+       if (error)
+               return -ECONNABORTED;
+       return error;
+}
+
+static int tmy_socket_post_recv_datagram(struct sock *sk,
+                                        struct sk_buff *skb,
+                                        unsigned int flags)
+{
+       int error = 0;
+       const unsigned int type = sk->sk_type;
+
+       /* skb_recv_datagram() didn't dequeue. */
+       if (!skb)
+               return 0;
+
+       /* skb_recv_datagram() can be called from interrupt context. */
+       if (in_interrupt())
+               return 0;
+       /* I don't check if called by kernel process. */
+       if (segment_eq(get_fs(), KERNEL_DS))
+               return 0;
+
+       if (type != SOCK_DGRAM && type != SOCK_RAW)
+               return 0;
+
+       switch (sk->sk_family) {
+               struct sockaddr_in6 sin6;
+               struct sockaddr_in sin;
+               u16 port;
+
+       case AF_INET6:
+
+               if (type == SOCK_DGRAM) {
+                       /* UDP IPv6 */
+                       sin6.sin6_family = AF_INET6;
+                       sin6.sin6_port = udp_hdr(skb)->source;
+
+                       if (skb->protocol == htons(ETH_P_IP))
+                               ipv6_addr_set(&sin6.sin6_addr, 0, 0,
+                                             htonl(0xffff),
+                                             ip_hdr(skb)->saddr);
+                       else
+                               ipv6_addr_copy(&sin6.sin6_addr,
+                                              &ipv6_hdr(skb)->saddr);
+
+                       port = sin6.sin6_port;
+               } else {
+                       /* RAW IPv6 */
+                       sin6.sin6_family = AF_INET6;
+                       sin6.sin6_port = 0;
+                       ipv6_addr_copy(&sin6.sin6_addr, &ipv6_hdr(skb)->saddr);
+
+                       port = htons(sk->sk_protocol);
+               }
+
+               error = tmy_network_recvmsg_acl(1, type,
+                                               sin6.sin6_addr.s6_addr, port);
+
+               break;
+
+       case AF_INET:
+
+               if (type == SOCK_DGRAM) {
+                       /* UDP IPv4 */
+                       sin.sin_family = AF_INET;
+                       sin.sin_port = udp_hdr(skb)->source;
+                       sin.sin_addr.s_addr = ip_hdr(skb)->saddr;
+
+                       port = sin.sin_port;
+               } else {
+                       /* RAW IPv4 */
+                       sin.sin_family = AF_INET;
+                       sin.sin_addr.s_addr = ip_hdr(skb)->saddr;
+                       sin.sin_port = 0;
+
+                       port = htons(sk->sk_protocol);
+               }
+
+               error = tmy_network_recvmsg_acl(0, type,
+                                               (u8 *) &sin.sin_addr, port);
+
+               break;
+
+       }
+
+       if (error)
+               error = -EAGAIN;
+       return error;
+}
+
+static int tmy_sb_mount(char *dev_name,
+                       struct nameidata *nd,
+                       char *type,
+                       unsigned long flags,
+                       void *data)
+{
+       char *buf;
+       char *dir_name;
+       int error;
+
+       error = tmy_capable(TMY_SYS_MOUNT);
+       if (error)
+               return error;
+
+       buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+
+       dir_name = d_path(&nd->path, buf, PAGE_SIZE);
+
+       if (IS_ERR(dir_name))
+               error = PTR_ERR(dir_name);
+       else
+               error = tmy_mount_perm(dev_name, dir_name, type, flags);
+
+       if (!error && (flags & MS_REMOUNT) == 0)
+               error = tmy_conceal_mount(nd);
+
+       kfree(buf);
+       return error;
+}
+
+static int tmy_sb_umount(struct vfsmount *mnt, int flags)
+{
+       const int err = tmy_capable(TMY_SYS_UMOUNT);
+       if (err)
+               return err;
+       return tmy_umount_perm(mnt);
+}
+
+static int tmy_settime(struct timespec *ts, struct timezone *tz)
+{
+       return tmy_capable(TMY_SYS_SETTIME);
+}
+
+static int tmy_sb_pivotroot(struct nameidata *old_nd, struct nameidata *new_nd)
+{
+       const int err = tmy_capable(TMY_SYS_PIVOT_ROOT);
+       if (err)
+               return err;
+       return tmy_pivot_root_perm(old_nd, new_nd);
+}
+
+static int tmy_task_capable(struct task_struct *tsk, int cap)
+{
+       int err = 0;
+       if (cap == CAP_SYS_CHROOT)
+               err = tmy_capable(TMY_SYS_CHROOT);
+       else if (cap == CAP_SYS_TTY_CONFIG)
+               err = tmy_capable(TMY_SYS_VHANGUP);
+       else if (cap == CAP_SYS_BOOT)
+               err = tmy_capable(TMY_SYS_REBOOT);
+       else if (cap == CAP_SYS_TIME)
+               err = tmy_capable(TMY_SYS_SETTIME);
+       if (err)
+               return err;
+       if (cap_raised(tsk->cap_effective, cap))
+               return 0;
+       return -EPERM;
+}
+
+#ifdef __HAVE_LSM_TASK_KILL_UNLOCKED
+static int tmy_task_kill_unlocked(int pid, int sig)
+{
+       const int err = tmy_capable(TMY_SYS_KILL);
+       if (err)
+               return err;
+       return tmy_signal_acl(sig, pid);
+}
+
+static int tmy_task_tkill_unlocked(int pid, int sig)
+{
+       const int err = tmy_capable(TMY_SYS_KILL);
+       if (err)
+               return err;
+       return tmy_signal_acl(sig, pid);
+}
+
+static int tmy_task_tgkill_unlocked(int tgid, int pid, int sig)
+{
+       const int err = tmy_capable(TMY_SYS_KILL);
+       if (err)
+               return err;
+       return tmy_signal_acl(sig, pid);
+}
+#endif
+
+static struct security_operations tomoyo_security_ops = {
+       .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,
+       .inode_setattr             = tmy_inode_setattr,
+       .inode_create              = tmy_inode_create,
+       .inode_unlink              = tmy_inode_unlink,
+       .inode_mkdir               = tmy_inode_mkdir,
+       .inode_rmdir               = tmy_inode_rmdir,
+       .inode_symlink             = tmy_inode_symlink,
+       .inode_mknod               = tmy_inode_mknod,
+       .inode_link                = tmy_inode_link,
+       .inode_rename              = tmy_inode_rename,
+       .file_fcntl                = tmy_file_fcntl,
+       .file_ioctl                = tmy_file_ioctl,
+       .socket_listen             = tmy_socket_listen,
+       .socket_create             = tmy_socket_create,
+       .socket_connect            = tmy_socket_connect,
+       .socket_bind               = tmy_socket_bind,
+       .socket_sendmsg            = tmy_socket_sendmsg,
+       .sb_mount                  = tmy_sb_mount,
+       .sb_umount                 = tmy_sb_umount,
+       .sb_pivotroot              = tmy_sb_pivotroot,
+       .settime                   = tmy_settime,
+       .capable                   = tmy_task_capable,
+       .socket_post_accept        = tmy_socket_post_accept,
+       .socket_post_recv_datagram = tmy_socket_post_recv_datagram,
+#ifdef __HAVE_LSM_TASK_KILL_UNLOCKED
+       .task_kill_unlocked        = tmy_task_kill_unlocked,
+       .task_tkill_unlocked       = tmy_task_tkill_unlocked,
+       .task_tgkill_unlocked      = tmy_task_tgkill_unlocked,
+#endif
+};
+
+static int __init tmy_init(void)
+{
+
+       /* register ourselves with the security framework */
+       if (register_security(&tomoyo_security_ops))
+               panic("Failure registering TOMOYO Linux");
+
+       printk(KERN_INFO "TOMOYO Linux initialized\n");
+
+       INIT_LIST_HEAD(&KERNEL_DOMAIN.list);
+       INIT_LIST_HEAD(&KERNEL_DOMAIN.acl_info_list);
+       KERNEL_DOMAIN.domainname = tmy_save_name(TMY_ROOT_NAME);
+       list_add_tail_mb(&KERNEL_DOMAIN.list, &domain_list);
+       tmy_cachep = kmem_cache_create("tomoyo_security",
+                                      sizeof(struct tmy_security),
+                                      0, SLAB_PANIC, NULL);
+       init_task.security = kmem_cache_alloc(tmy_cachep, GFP_KERNEL);
+       ((struct tmy_security *) init_task.security)->domain = &KERNEL_DOMAIN;
+       ((struct tmy_security *) init_task.security)->prev_domain = NULL;
+       ((struct tmy_security *) init_task.security)->flags = 0;
+
+       return 0;
+}
+
+security_initcall(tmy_init);

-- 
-
To unsubscribe from this list: send the line "unsubscribe 
linux-security-module" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to