lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20080109005426.817321431@nttdata.co.jp>
Date:	Wed, 09 Jan 2008 09:53:38 +0900
From:	Kentaro Takeda <takedakn@...data.co.jp>
To:	akpm@...ux-foundation.org
Cc:	linux-kernel@...r.kernel.org,
	linux-security-module@...r.kernel.org,
	Kentaro Takeda <takedakn@...data.co.jp>,
	Tetsuo Handa <penguin-kernel@...ove.SAKURA.ne.jp>
Subject: [TOMOYO #6 retry 18/21] LSM adapter functions.

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

Signed-off-by: Kentaro Takeda <takedakn@...data.co.jp>
Signed-off-by: Tetsuo Handa <penguin-kernel@...ove.SAKURA.ne.jp>
---
 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-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ