SourceForge.JP: Open Source Software

Login Create Account Help [auto][en][zh][de][fr][ko][es][pt]
Search

Browse Subversion Repository

View of /trunk/2.1.x/tomoyo-lsm/patches/tomoyo-hooks.diff

Parent Directory Parent Directory | Revision Log Revision Log


Revision 653 - (download) (as text) (annotate)
Mon Nov 5 08:44:30 2007 UTC (2 years ago) by kumaneko
File size: 24087 byte(s)

LSM wrapper functions for TOMOYO Linux access control.
If bind mounts are used, TOMOYO requires all permissions for
all possible pathnames (whereas AppArmor requires one of possible pathnames).
If "struct vfsmount" is passed to LSM hooks as AppArmor proposes,
this file will become more simpler.

Signed-off-by: Kentaro Takeda <takedakn@nttdata.co.jp>
Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
 security/tomoyo/tomoyo.c |  952 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 952 insertions(+)

--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.23/security/tomoyo/tomoyo.c	2007-11-05 16:55:38.307124208 +0900
@@ -0,0 +1,952 @@
+/*
+ * security/tomoyo/tomoyo.c
+ *
+ * LSM hooks for TOMOYO Linux.
+ */
+
+#include "tomoyo.h"
+#include "realpath.h"
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22)
+static inline struct iphdr *ip_hdr(const struct sk_buff *skb)
+{
+	return skb->nh.iph;
+}
+static inline struct udphdr *udp_hdr(const struct sk_buff *skb)
+{
+	return skb->h.uh;
+}
+static inline struct ipv6hdr *ipv6_hdr(const struct sk_buff *skb)
+{
+	return skb->nh.ipv6h;
+}
+#endif
+
+#define MAX_SOCK_ADDR 128 /* net/socket.c */
+
+LIST_HEAD(domain_list);
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 20)
+static struct kmem_cache *tmy_cachep;
+#else
+static kmem_cache_t *tmy_cachep;
+#endif
+
+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) {
+			TMY_SECURITY->domain = next_domain;
+			TMY_SECURITY->flags |=
+				TMY_CHECK_READ_FOR_OPEN_EXEC;
+		}
+	}
+
+	return retval;
+}
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 11)
+static void tomoyo_bprm_apply_creds(struct linux_binprm *bprm, int unsafe)
+{
+	TMY_SECURITY->prev_domain = TMY_SECURITY->domain;
+}
+#else
+static void tmy_bprm_post_apply_creds(struct linux_binprm *bprm)
+{
+	TMY_SECURITY->prev_domain = TMY_SECURITY->domain;
+}
+#endif
+
+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;
+}
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 21)
+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;
+}
+#endif
+
+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 || !nd->dentry || !nd->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->dentry, nd->mnt, flag);
+}
+
+static int tmy_do_single_write_perm(int operation, struct dentry *dentry)
+{
+	int err = 0;
+	struct task_struct *task = current;
+	struct seq_file m;
+	loff_t pos = 0;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
+	struct namespace *namespace = NULL;
+#else
+	struct mnt_namespace *namespace = NULL;
+#endif
+	if (!dentry)
+		return 0;
+	if (!sbin_init_started)
+		return 0;
+	memset(&m, 0, sizeof(m));
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)
+	namespace = task->namespace;
+#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
+	if (task->nsproxy)
+		namespace = task->nsproxy->namespace;
+#else
+	if (task->nsproxy)
+		namespace = task->nsproxy->mnt_ns;
+#endif
+	if (!namespace)
+		return 0;
+	m.private = namespace;
+	while (!err) {
+		struct vfsmount *mnt;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 23)
+		mnt = mounts_op.start(&m, &pos);
+		if (!mnt) {
+			mounts_op.stop(&m, NULL);
+			break;
+		}
+#else
+		struct list_head *p;
+		p = mounts_op.start(&m, &pos);
+		if (!p) {
+			mounts_op.stop(&m, NULL);
+			break;
+		}
+		mnt = list_entry(p, struct vfsmount, mnt_list);
+#endif
+		mntget(mnt);
+		mounts_op.stop(&m, NULL);
+		pos++;
+		if (mnt->mnt_root->d_sb == dentry->d_sb)
+			err = tmy_single_write_perm(operation, dentry, mnt);
+		mntput(mnt);
+	}
+	return err;
+}
+
+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)
+{
+	int err = 0;
+	struct task_struct *task = current;
+	struct seq_file m;
+	loff_t pos = 0;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
+	struct namespace *namespace = NULL;
+#else
+	struct mnt_namespace *namespace = NULL;
+#endif
+	if (!old_dentry || !new_dentry)
+		return 0;
+	if (!sbin_init_started)
+		return 0;
+	memset(&m, 0, sizeof(m));
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)
+	namespace = task->namespace;
+#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
+	if (task->nsproxy)
+		namespace = task->nsproxy->namespace;
+#else
+	if (task->nsproxy)
+		namespace = task->nsproxy->mnt_ns;
+#endif
+	if (!namespace)
+		return 0;
+	m.private = namespace;
+	while (!err) {
+		struct vfsmount *mnt;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 23)
+		mnt = mounts_op.start(&m, &pos);
+		if (!mnt) {
+			mounts_op.stop(&m, NULL);
+			break;
+		}
+#else
+		struct list_head *p;
+		p = mounts_op.start(&m, &pos);
+		if (!p) {
+			mounts_op.stop(&m, NULL);
+			break;
+		}
+		mnt = list_entry(p, struct vfsmount, mnt_list);
+#endif
+		mntget(mnt);
+		mounts_op.stop(&m, NULL);
+		pos++;
+		if (mnt->mnt_root->d_sb == old_dentry->d_sb)
+			err = tmy_double_write_perm(operation, old_dentry, mnt,
+						    new_dentry, mnt);
+		mntput(mnt);
+	}
+	return err;
+}
+
+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 LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
+		if (S_ISREG(file->f_dentry->d_inode->i_mode))
+			return 0;
+#else
+		if (S_ISREG(file->f_path.dentry->d_inode->i_mode))
+			return 0;
+#endif
+	}
+	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;
+}
+
+#ifdef TMY_LSM_EXPANSION
+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_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;
+}
+#endif
+
+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->dentry, nd->mnt, 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);
+}
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10)
+static int tmy_settime(struct timespec *ts, struct timezone *tz)
+{
+	return tmy_capable(TMY_SYS_SETTIME);
+}
+#endif
+
+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 TMY_LSM_EXPANSION
+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,
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 11)
+	.bprm_apply_creds      = tomoyo_bprm_apply_creds,
+#else
+	.bprm_post_apply_creds = tmy_bprm_post_apply_creds,
+#endif
+	.bprm_free_security    = tmy_bprm_free_security,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 21)
+	.sysctl                = tmy_sysctl,
+#endif
+	.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,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10)
+	.settime               = tmy_settime,
+#endif
+	.capable               = tmy_task_capable,
+#ifdef TMY_LSM_EXPANSION
+	.socket_post_accept    = tmy_socket_post_accept,
+	.post_recv_datagram    = tmy_post_recv_datagram,
+	.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);
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23)
+	tmy_cachep = kmem_cache_create("tomoyo_security",
+				       sizeof(struct tmy_security),
+				       0, SLAB_PANIC, NULL);
+#else
+	tmy_cachep = kmem_cache_create("tomoyo_security",
+				       sizeof(struct tmy_security),
+				       0, SLAB_PANIC, NULL, NULL);
+#endif
+
+	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);

Back to Project
Back to SourceForge.jp
  SourceForge.jp (Powered by ViewVC)
Powered by ViewVC 1.0.5
ViewVC Help
©OSDN Corporation