lkml.org 
[lkml]   [2007]   [Aug]   [24]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
Date
From
Subject[TOMOYO 13/15] LSM adapter for TOMOYO.
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 and "namespace_sem" can remain "static".

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 | 745 +++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 745 insertions(+)
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6/security/tomoyo/tomoyo.c 2007-08-24 15:51:38.000000000 +0900
@@ -0,0 +1,745 @@
+/*
+ * security/tomoyo/tomoyo.c
+ *
+ * LSM hooks for TOMOYO Linux.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/security.h>
+#include <linux/highmem.h>
+#include <linux/namei.h>
+#include <linux/mnt_namespace.h>
+#include <linux/sysctl.h>
+#include <linux/proc_fs.h>
+#include <linux/sched.h>
+#include <linux/uaccess.h>
+#include <net/ip.h>
+#include <net/ipv6.h>
+
+#include "tomoyo.h"
+#include "realpath.h"
+#define MAX_SOCK_ADDR 128 /* net/socket.c */
+
+/* The initial domain. */
+struct domain_info KERNEL_DOMAIN = { NULL, NULL, NULL, 0, 0, 0 };
+
+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) {
+ TMY_SECURITY->domain = next_domain;
+ TMY_SECURITY->flags |=
+ TMY_CHECK_READ_FOR_OPEN_EXEC;
+ }
+ }
+
+ 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 || !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)
+{
+ struct mnt_namespace *namespace = current->nsproxy->mnt_ns;
+ struct list_head *p;
+ int ret = 0;
+ int error = 0;
+ int index = 0;
+ int index2 = 0;
+
+ if (!dentry || !namespace)
+ return 0;
+
+start: ;
+ index2 = 0;
+
+ /* lock namespace */
+ down_read(&namespace_sem);
+
+ list_for_each(p, &namespace->list) {
+ struct vfsmount *mnt = list_entry(p, struct vfsmount, mnt_list);
+
+ if (mnt->mnt_root->d_sb != dentry->d_sb)
+ continue;
+ if (index2++ < index)
+ continue;
+
+ /* unlock namespace */
+ up_read(&namespace_sem);
+ error = tmy_single_write_perm(operation, dentry, mnt);
+
+ if (error != 0)
+ ret = error;
+
+ index++;
+
+ goto start;
+ }
+
+ /* unlock namespace */
+ up_read(&namespace_sem);
+
+ return ret;
+}
+
+static int tmy_inode_setattr(struct dentry *dentry, struct iattr *iattr)
+{
+ if (iattr->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)
+{
+ 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)
+{
+ 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)
+{
+ if (S_ISCHR(mode))
+ return tmy_do_single_write_perm(TMY_TYPE_MKCHAR_ACL, dentry);
+ if (S_ISBLK(mode))
+ return tmy_do_single_write_perm(TMY_TYPE_MKBLOCK_ACL, dentry);
+ if (S_ISFIFO(mode))
+ return tmy_do_single_write_perm(TMY_TYPE_MKFIFO_ACL, dentry);
+ if (S_ISSOCK(mode))
+ 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 mnt_namespace *namespace = current->nsproxy->mnt_ns;
+ struct list_head *p;
+ int ret = 0;
+ int error = 0;
+ int index = 0;
+ int index2 = 0;
+
+ if (!old_dentry || !new_dentry)
+ return 0;
+start: ;
+ index2 = 0;
+
+ /* lock namespace */
+ down_read(&namespace_sem);
+
+ list_for_each(p, &namespace->list) {
+ struct vfsmount *mnt = list_entry(p, struct vfsmount, mnt_list);
+
+ if (mnt->mnt_root->d_sb != old_dentry->d_sb)
+ continue;
+ if (index2++ < index)
+ continue;
+ /* unlock namespace */
+ up_read(&namespace_sem);
+ error = tmy_double_write_perm(operation, old_dentry, mnt,
+ new_dentry, mnt);
+ if (error != 0)
+ ret = error;
+ index++;
+ goto start;
+ }
+
+ /* unlock namespace */
+ up_read(&namespace_sem);
+
+ return ret;
+}
+
+static int tmy_inode_link(struct dentry *old_dentry,
+ struct inode *inode,
+ struct dentry *new_dentry)
+{
+ 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)
+{
+ 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_socket_listen(struct socket *sock, int backlog)
+{
+ char addr[MAX_SOCK_ADDR];
+ int addr_len;
+ int error = 0;
+
+ /* I don't check if called by kernel process. */
+ if (segment_eq(get_fs(), KERNEL_DS))
+ return 0;
+
+ if (sock->type != SOCK_STREAM)
+ return error;
+ if (sock->sk->sk_family != PF_INET && sock->sk->sk_family != PF_INET6)
+ 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_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 && 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_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_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 = kmalloc(PAGE_SIZE, GFP_KERNEL);
+ char *dir_name;
+ int error;
+
+ 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)
+{
+ return tmy_umount_perm(mnt);
+}
+
+static int tmy_sb_pivotroot(struct nameidata *old_nd, struct nameidata *new_nd)
+{
+ return tmy_pivot_root_perm(old_nd, new_nd);
+}
+
+static int tmy_task_kill_unlocked(int pid, int sig)
+{
+ return tmy_signal_acl(sig, pid);
+}
+
+static int tmy_task_tkill_unlocked(int pid, int sig)
+{
+ return tmy_signal_acl(sig, pid);
+}
+
+static int tmy_task_tgkill_unlocked(int tgid, int pid, int sig)
+{
+ return tmy_signal_acl(sig, pid);
+}
+
+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,
+ .socket_listen = tmy_socket_listen,
+ .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,
+#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");
+
+ tmy_proc_init();
+
+ 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@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
\
 
 \ /
  Last update: 2007-08-24 15:01    [from the cache]
©2003-2011 Jasper Spaans