From: Nick Bellinger <nickb@attheoffice.org> To: linux-security-module@wirex.com Subject: OpenWall SECURE_LINK as a LSM Date: 09 Nov 2001 16:32:53 -0700 Greetings, After a few months of lurking on the LSM mailing list, here is an attempt at something constructive. Attached is Solar Designer's Openwall SECURE_LINK feature as an LSM. Thanks to everybody who is working on LSM, everybody in #kernelnewbies, and Emily Ratliff's NPROC_RLIMIT which is an _excellent_ starting point for anyone who wants to get involved with LSM. Nick Bellinger diff -urN linux-2.4.14-lsm-cvs/Documentation/Configure.help linux-2.4.14-lsm/Documentation/Configure.help --- linux-2.4.14-lsm-cvs/Documentation/Configure.help Fri Nov 9 19:14:44 2001 +++ linux-2.4.14-lsm/Documentation/Configure.help Fri Nov 9 19:06:03 2001 @@ -19209,6 +19209,22 @@ If you are unsure how to answer this question, answer N. +Restricted links in /tmp +CONFIG_SECURITY_LINK + There's a very common attack that involves a malicious user creating + a symbolic link in /tmp, with a carefully chosen name, pointing at + another user's file. When the victim then writes to that file name, + without the required precautions, they inadvertently write to the + wrong file. Enabling this option reduces the impact of this class of + holes (some get fixed, many others allow for DoS attacks only, most + of the rest become harder to exploit) by preventing a process from + following a link which is in a +t directory, unless the link owner + is trusted (that is, it's the user we're running as or the directory + owner). To prevent from using a hard link in an attack instead, this + option does not allow users to create hard links to files they don't + own, unless they could read and write the file. This might break + things. Say Y if security is more important. + Domain and Type Enforcement CONFIG_SECURITY_DTE This enables Domain and Type Enforcement. It assigns labels to diff -urN linux-2.4.14-lsm-cvs/security/Config.in linux-2.4.14-lsm/security/Config.in --- linux-2.4.14-lsm-cvs/security/Config.in Fri Nov 9 19:14:19 2001 +++ linux-2.4.14-lsm/security/Config.in Fri Nov 9 19:05:27 2001 @@ -6,5 +6,6 @@ tristate 'Capabilities Support' CONFIG_SECURITY_CAPABILITIES dep_tristate 'IP Networking Support' CONFIG_SECURITY_IP $CONFIG_NETFILTER dep_tristate 'Add RLIMITS_NPROC check to execve (EXPERIMENTAL)' CONFIG_SECURITY_NPROC $CONFIG_EXPERIMENTAL +dep_tristate 'Restricted links in /tmp (EXPERIMENTAL)' CONFIG_SECURITY_LINK $CONFIG_EXPERIMENTAL dep_tristate 'Domain and Type Enforcement (EXPERIMENTAL)' CONFIG_SECURITY_DTE $CONFIG_EXPERIMENTAL endmenu diff -urN linux-2.4.14-lsm-cvs/security/Makefile linux-2.4.14-lsm/security/Makefile --- linux-2.4.14-lsm-cvs/security/Makefile Fri Nov 9 19:14:13 2001 +++ linux-2.4.14-lsm/security/Makefile Fri Nov 9 19:07:41 2001 @@ -17,5 +17,6 @@ obj-$(CONFIG_SECURITY_CAPABILITIES) += capability.o obj-$(CONFIG_SECURITY_IP) += lsm_ip_glue.o obj-$(CONFIG_SECURITY_NPROC) += nproc.o +obj-$(CONFIG_SECURITY_LINK) += slink.o include $(TOPDIR)/Rules.make diff -urN linux-2.4.14-lsm-cvs/security/slink.c linux-2.4.14-lsm/security/slink.c --- linux-2.4.14-lsm-cvs/security/slink.c Wed Dec 31 16:00:00 1969 +++ linux-2.4.14-lsm/security/slink.c Fri Nov 9 19:00:51 2001 @@ -0,0 +1,1192 @@ +/* + * SECURE_LINK Linux Security Module + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This module is basically a LSM port of the SECURE_LINK + * part of Solar Designer's OpenWall 2.2 code and is based off + * of capability.c, dummy.c and Emily Ratliff's NPROC_RLIMIT module. + * + * LSM port by Nick Bellinger, Esquire <nickb@attheoffice.org> + * + */ + +#include <linux/config.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/security.h> +#include <linux/stat.h> +#include <linux/netfilter.h> +#include <linux/netlink.h> + + +/* flag to keep track of how we were registered */ +static int secondary; + +static int slink_sethostname (char *hostname) +{ + return 0; +} + +static int slink_setdomainname (char *domainname) +{ + return 0; +} + +static int slink_reboot (unsigned int cmd) +{ + return 0; +} + +static int slink_ioperm (unsigned long from, unsigned long num, int turn_on) +{ + return 0; +} + +static int slink_iopl (unsigned int old, unsigned int level) +{ + return 0; +} + +static int slink_ptrace (struct task_struct *parent, struct task_struct *child) +{ + return 0; +} + +static int slink_capget (struct task_struct *target, kernel_cap_t * effective, + kernel_cap_t * inheritable, kernel_cap_t * permitted) +{ + return 0; +} + +static int slink_capset_check (struct task_struct *target, + kernel_cap_t * effective, + kernel_cap_t * inheritable, + kernel_cap_t * permitted) +{ + return 0; +} + +static void slink_capset_set (struct task_struct *target, + kernel_cap_t * effective, + kernel_cap_t * inheritable, + kernel_cap_t * permitted) +{ + return; +} + +static int slink_acct (struct file *file) +{ + return 0; +} + +static int slink_capable (struct task_struct *tsk, int cap) +{ + /* from dummy.c */ + if (cap_is_fs_cap (cap) ? tsk->fsuid == 0 : tsk->euid == 0) + /* capability granted */ + return 0; + + /* capability denied */ + return -EPERM; +} + +static int slink_sysctl (ctl_table * table, int op) +{ + return 0; +} + +static int slink_sys_security (unsigned int id, unsigned int call, + unsigned long *args) +{ + return -ENOSYS; +} + +static int slink_swapon (struct dentry *dentry) +{ + return 0; +} + +static int slink_swapoff (struct dentry *dentry) +{ + return 0; +} + +static int slink_nfsservctl (int cmd, struct nfsctl_arg *arg) +{ + return 0; +} + +static int slink_quotactl (int cmds, int type, int id, struct super_block *sb) +{ + return 0; +} + +static int slink_quota_on (struct file *f) +{ + return 0; +} + +static int slink_bdflush (int func, long data) +{ + return 0; +} + +static int slink_syslog (int type) +{ + return 0; +} + +static int slink_netlink_send (struct sk_buff *skb) +{ + /* from dummy.c */ + if (current->euid == 0) + cap_raise (NETLINK_CB (skb).eff_cap, CAP_NET_ADMIN); + else + NETLINK_CB (skb).eff_cap = 0; + return 0; +} + +static int slink_netlink_recv (struct sk_buff *skb) +{ + /* from dummy.c */ + if (!cap_raised (NETLINK_CB (skb).eff_cap, CAP_NET_ADMIN)) + return -EPERM; + return 0; +} + +static int slink_binprm_alloc_security(struct linux_binprm *bprm) +{ + return 0; +} + +static void slink_binprm_free_security (struct linux_binprm *bprm) +{ + return; +} + +static void slink_binprm_compute_creds (struct linux_binprm *bprm) +{ + return; +} + +static int slink_binprm_set_security (struct linux_binprm *bprm) +{ + return 0; +} + +static int slink_sb_alloc_security (struct super_block *sb) +{ + return 0; +} + +static void slink_sb_free_security (struct super_block *sb) +{ + return; +} + +static int slink_sb_statfs (struct super_block *sb) +{ + return 0; +} + +static int slink_sb_mount (char *devname, struct nameidata *nd, char *type, + unsigned long flags, void *data) +{ + return 0; +} + +static int slink_sb_check_sb (struct vfsmount *mnt, struct nameidata *nd) +{ + return 0; +} + +static int slink_sb_umount (struct vfsmount *mnt, int flags) +{ + return 0; +} + +static void slink_sb_umount_close (struct vfsmount *mnt) +{ + return; +} + +static void slink_sb_umount_busy (struct vfsmount *mnt) +{ + return; +} +static void slink_sb_post_remount (struct vfsmount *mnt, unsigned long flags, + void *data) +{ + return; +} + +static void slink_sb_post_mountroot (struct super_block *sb) +{ + return; +} + +static void slink_sb_post_addmount (struct vfsmount *mnt, struct nameidata *nd) +{ + return; +} + +static int slink_inode_alloc_security (struct inode *inode) +{ + return 0; +} + +static void slink_inode_free_security (struct inode *inode) +{ + return; +} + +static int slink_inode_create (struct inode *inode, struct dentry *dentry, + int mask) +{ + return 0; +} + +static void slink_inode_post_create (struct inode *inode, struct dentry *dentry, + int mask) +{ + return; +} + +static int slink_inode_link (struct dentry *old_dentry, struct inode *inode, + struct dentry *new_dentry) +{ + int error; + + if(current->fsuid != old_dentry->d_inode->i_uid && + (!S_ISREG(old_dentry->d_inode->i_mode) || (old_dentry->d_inode->i_mode & S_ISUID) || + ((old_dentry->d_inode->i_mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) || + (error = permission(old_dentry->d_inode, MAY_READ | MAY_WRITE))) && + !capable(CAP_FOWNER) && current->uid) { + printk(KERN_INFO "LSM/OpenWall: denied hardlink to %d.%d for %d.%d, pid %d\n", + old_dentry->d_inode->i_uid, old_dentry->d_inode->i_gid, + current->uid, current->euid, current->pid); + return -EPERM; + } + + return 0; +} + +static void slink_inode_post_link (struct dentry *old_dentry, + struct inode *inode, + struct dentry *new_dentry) +{ + return; +} + +static int slink_inode_unlink (struct inode *inode, struct dentry *dentry) +{ + return 0; +} + +static int slink_inode_symlink (struct inode *inode, struct dentry *dentry, + const char *name) +{ + return 0; +} + +static void slink_inode_post_symlink (struct inode *inode, + struct dentry *dentry, const char *name) +{ + return; +} + +static int slink_inode_mkdir (struct inode *inode, struct dentry *dentry, + int mask) +{ + return 0; +} + +static void slink_inode_post_mkdir (struct inode *inode, struct dentry *dentry, + int mask) +{ + return; +} + +static int slink_inode_rmdir (struct inode *inode, struct dentry *dentry) +{ + return 0; +} + +static int slink_inode_mknod (struct inode *inode, struct dentry *dentry, + int major, dev_t minor) +{ + return 0; +} + +static void slink_inode_post_mknod (struct inode *inode, struct dentry *dentry, + int major, dev_t minor) +{ + return; +} + +static int slink_inode_rename (struct inode *old_inode, + struct dentry *old_dentry, + struct inode *new_inode, + struct dentry *new_dentry) +{ + return 0; +} + +static void slink_inode_post_rename (struct inode *old_inode, + struct dentry *old_dentry, + struct inode *new_inode, + struct dentry *new_dentry) +{ + return; +} + +static int slink_inode_readlink (struct dentry *dentry) +{ + return 0; +} + +static int slink_inode_follow_link (struct dentry *dentry, + struct nameidata *nameidata) +{ + + if (S_ISLNK(dentry->d_inode->i_mode) && (dentry->d_parent->d_inode->i_mode & S_ISVTX) && + dentry->d_parent->d_inode->i_uid != dentry->d_inode->i_uid && + (dentry->d_parent->d_inode->i_mode & S_IWOTH) && + current->fsuid != dentry->d_inode->i_uid) { + printk(KERN_INFO "LSM/OpenWall: not following symlink of %d.%d by %d.%d pid %d\n", + dentry->d_inode->i_uid, dentry->d_inode->i_gid, + current->uid, current->euid, current->pid); + return -EACCES; + } + + return 0; +} + +static int slink_inode_permission (struct inode *inode, int mask) +{ + return 0; +} + +static int slink_inode_revalidate (struct dentry *inode) +{ + return 0; +} + +static int slink_inode_setattr (struct dentry *dentry, struct iattr *iattr) +{ + return 0; +} + +static int slink_inode_stat (struct inode *inode) +{ + return 0; +} + +static void slink_post_lookup (struct inode *ino, struct dentry *d) +{ + return; +} + +static void slink_delete (struct inode *ino) +{ + return; +} + +static int slink_file_permission (struct file *file, int mask) +{ + return 0; +} + +static int slink_file_alloc_security (struct file *file) +{ + return 0; +} + +static void slink_file_free_security (struct file *file) +{ + return; +} + +static int slink_file_llseek (struct file *file) +{ + return 0; +} + +static int slink_file_ioctl (struct file *file, unsigned int command , + unsigned long arg) +{ + return 0; +} + +static int slink_file_mmap (struct file *file, unsigned long prot, + unsigned long flags) +{ + return 0; +} + +static int slink_file_mprotect (struct vm_area_struct *vma, unsigned long prot) +{ + return 0; +} + +static int slink_file_lock (struct file *file, unsigned int cmd) +{ + return 0; +} + +static int slink_file_fcntl (struct file *file, unsigned int cmd, + unsigned long arg) +{ + return 0; +} + +static int slink_file_set_fowner (struct file *file) +{ + return 0; +} + +static int slink_file_send_sigiotask (struct task_struct *tsk, + struct fown_struct *fown, + int fd, int reason) +{ + return 0; +} + +static int slink_file_receive (struct file *file) +{ + return 0; +} + +static int slink_task_create (unsigned long clone_flags) +{ + return 0; +} + +static int slink_task_alloc_security (struct task_struct *p) +{ + return 0; +} + +static void slink_task_free_security (struct task_struct *p) +{ + return; +} + +static int slink_task_setuid (uid_t id0, uid_t id1, uid_t id2, int flags) +{ + return 0; +} + +static int slink_task_post_setuid(uid_t old_ruid, uid_t old_euid, + uid_t old_suid, int flags) +{ + return 0; +} + +static int slink_task_setgid (gid_t id0, gid_t id1, gid_t id2, int flags) +{ + return 0; +} + +static int slink_task_setpgid (struct task_struct *p, pid_t pgid) +{ + return 0; +} + +static int slink_task_getpgid (struct task_struct *p) +{ + return 0; +} + +static int slink_task_getsid (struct task_struct *p) +{ + return 0; +} + +static int slink_task_setgroups (int gidsetsize, gid_t *grouplist) +{ + return 0; +} + +static int slink_task_setnice (struct task_struct *p, int nice) +{ + return 0; +} + +static int slink_task_setrlimit (unsigned int resource, struct rlimit *new_rlim) +{ + return 0; +} + +static int slink_task_setscheduler (struct task_struct *p, int policy, + struct sched_param *lp) +{ + return 0; +} + +static int slink_task_getscheduler (struct task_struct *p) +{ + return 0; +} + +static int slink_task_wait (struct task_struct *p) +{ + return 0; +} + +static int slink_task_kill (struct task_struct *p, struct siginfo *info, int sig) +{ + return 0; +} + +static int slink_task_prctl (int option, unsigned long arg2, unsigned long arg3, + unsigned long arg4, unsigned long arg5) +{ + return 0; +} + +static void slink_task_kmod_set_label (void) +{ + return; +} + +static unsigned int slink_ip_preroute_first (unsigned int hooknum, + struct sk_buff **pskb, + const struct net_device *in, + const struct net_device *out, + int (*okfn)(struct sk_buff *)) +{ + return NF_ACCEPT; +} + +static unsigned int slink_ip_preroute_last (unsigned int hooknum, + struct sk_buff **pskb, + const struct net_device *in, + const struct net_device *out, + int (*okfn)(struct sk_buff *)) +{ + return NF_ACCEPT; +} + +static unsigned int slink_ip_input_first (unsigned int hooknum, + struct sk_buff **pskb, + const struct net_device *in, + const struct net_device *out, + int (*okfn)(struct sk_buff *)) +{ + return NF_ACCEPT; +} + +static unsigned int slink_ip_input_last (unsigned int hooknum, + struct sk_buff **pskb, + const struct net_device *in, + const struct net_device *out, + int (*okfn)(struct sk_buff *)) +{ + return NF_ACCEPT; +} + +static unsigned int slink_ip_forward_first (unsigned int hooknum, + struct sk_buff **pskb, + const struct net_device *in, + const struct net_device *out, + int (*okfn)(struct sk_buff *)) +{ + return NF_ACCEPT; +} + +static unsigned int slink_ip_forward_last (unsigned int hooknum, + struct sk_buff **pskb, + const struct net_device *in, + const struct net_device *out, + int (*okfn)(struct sk_buff *)) +{ + return NF_ACCEPT; +} + +static unsigned int slink_ip_output_first (unsigned int hooknum, + struct sk_buff **pskb, + const struct net_device *in, + const struct net_device *out, + int (*okfn)(struct sk_buff *)) +{ + return NF_ACCEPT; +} + +static unsigned int slink_ip_output_last (unsigned int hooknum, + struct sk_buff **pskb, + const struct net_device *in, + const struct net_device *out, + int (*okfn)(struct sk_buff *)) +{ + return NF_ACCEPT; +} + +static unsigned int slink_ip_postroute_first (unsigned int hooknum, + struct sk_buff **pskb, + const struct net_device *in, + const struct net_device *out, + int (*okfn)(struct sk_buff *)) +{ + return NF_ACCEPT; +} + +static unsigned int slink_ip_postroute_last (unsigned int hooknum, + struct sk_buff **pskb, + const struct net_device *in, + const struct net_device *out, + int (*okfn)(struct sk_buff *)) +{ + return NF_ACCEPT; +} + +static void slink_ip_fragment (struct sk_buff *newskb, + const struct sk_buff *oldskb) +{ + return; +} + +static int slink_ip_defragment (struct sk_buff *skb) +{ + return 0; +} + +static void slink_ip_encapsulate (struct sk_buff *skb) +{ + return; +} + +static void slink_ip_decapsulate (struct sk_buff *skb) +{ + return; +} + +static int slink_decode_options (struct sk_buff *skb, const char *optptr, + unsigned char **pp_ptr) +{ + /* from dummy.c */ + if (!skb && !capable (CAP_NET_RAW)) { + (const unsigned char *) *pp_ptr = optptr; + return -EPERM; + } + return 0; +} + +static void slink_netdev_unregister (struct net_device *dev) +{ + return; +} + +static int slink_socket_create (int family, int type, int protocol) +{ + return 0; +} +static void slink_socket_post_create (struct socket *sock, int family, + int type, int protocol) +{ + return; +} + +static int slink_socket_bind (struct socket *sock, struct sockaddr *address, + int addrlen) +{ + return 0; +} + +static int slink_socket_connect (struct socket *sock, struct sockaddr *address, + int addrlen) +{ + return 0; +} + +static int slink_socket_listen (struct socket *sock, int backlog) +{ + return 0; +} + +static int slink_socket_accept (struct socket *sock, struct socket *newsock) +{ + return 0; +} + +static int slink_socket_sendmsg (struct socket *sock, struct msghdr *msg, + int size) +{ + return 0; +} + +static int slink_socket_recvmsg (struct socket *sock, struct msghdr *msg, + int size, int flags) +{ + return 0; +} + +static int slink_socket_getsockname (struct socket *sock) +{ + return 0; +} + +static int slink_socket_getpeername (struct socket *sock) +{ + return 0; +} + +static int slink_socket_setsockopt (struct socket *sock, int level, int optname) +{ + return 0; +} + +static int slink_socket_getsockopt (struct socket *sock, int level, int optname) +{ + return 0; +} + +static int slink_socket_shutdown (struct socket *sock, int how) +{ + return 0; +} + +static int slink_socket_sock_rcv_skb (struct sock *sk, struct sk_buff *skb) +{ + return 0; +} + +static int slink_socket_unix_stream_connect (struct socket *sock, + struct socket *other) +{ + return 0; +} + +static int slink_socket_unix_may_send (struct socket *sock, + struct socket *other) +{ + return 0; +} + +static int slink_module_create_module (const char *name_user, size_t size) +{ + return 0; +} + +static int slink_module_init_module (struct module *mod) +{ + return 0; +} + +static int slink_module_delete_module (const struct module *mod) +{ + return 0; +} + +static int slink_ipc_permission (struct kern_ipc_perm *ipcp, short flag) +{ + return 0; +} + +static int slink_ipc_getinfo (int id, int cmd) +{ + return 0; +} + +static int slink_msg_msg_alloc_security (struct msg_msg *msg) +{ + return 0; +} + +static void slink_msg_msg_free_security (struct msg_msg *msg) +{ + return; +} + +static int slink_msg_queue_alloc_security (struct msg_queue *msq) +{ + return 0; +} + +static void slink_msg_queue_free_security (struct msg_queue *msq) +{ + return; +} + +static int slink_msg_queue_associate (struct msg_queue *msq, int msgid, + int msgflg) +{ + return 0; +} + +static int slink_msg_queue_msgctl (struct msg_queue *msq, int msgid, int cmd) +{ + return 0; +} + +static int slink_msg_queue_msgsnd (struct msg_queue *msq, struct msg_msg *msg, + int msgid, int msgflg) +{ + return 0; +} + +static int slink_msg_queue_msgrcv (struct msg_queue *msq, struct msg_msg *msg, + struct task_struct *target, + long type, int mode) +{ + return 0; +} + +static int slink_shm_alloc_security (struct shmid_kernel *shp) +{ + return 0; +} + +static void slink_shm_free_security (struct shmid_kernel *shp) +{ + return; +} + +static int slink_shm_associate (struct shmid_kernel *shp, int shmid, int shmflg) +{ + return 0; +} + +static int slink_shm_shmctl (struct shmid_kernel *shp, int shmid, int cmd) +{ + return 0; +} + +static int slink_shm_shmat (struct shmid_kernel *shp, int shmid, char *shmaddr, + int shmflg) +{ + return 0; +} + +static int slink_sem_alloc_security (struct sem_array *sma) +{ + return 0; +} + +static void slink_sem_free_security (struct sem_array *sma) +{ + return; +} + +static int slink_sem_associate (struct sem_array *sma, int semid, int semflg) +{ + return 0; +} + +static int slink_sem_semctl (struct sem_array *sma, int semid, int cmd) +{ + return 0; +} + +static int slink_sem_semop (struct sem_array *sma, int semid, + struct sembuf *sops, unsigned nsops, int alter) +{ + return 0; +} + +static int slink_skb_alloc_security (struct sk_buff *skb) +{ + return 0; +} + +static int slink_skb_clone (struct sk_buff *newskb, + const struct sk_buff *oldskb) +{ + return 0; +} + +static void slink_skb_copy (struct sk_buff *newskb, + const struct sk_buff *oldskb) +{ + return; +} + +static void slink_skb_set_owner_w (struct sk_buff *skb, struct sock *sk) +{ + return; +} + +static void slink_skb_free_security (struct sk_buff *skb) +{ + return; +} + +static int slink_register (const char *name, struct security_operations *ops) +{ + return -EINVAL; +} + +static int slink_unregister (const char *name, struct security_operations *ops) +{ + return -EINVAL; +} + +static struct binprm_security_ops slink_binprm_ops = { + alloc_security: slink_binprm_alloc_security, + free_security: slink_binprm_free_security, + compute_creds: slink_binprm_compute_creds, + set_security: slink_binprm_set_security, +}; + +static struct super_block_security_ops slink_sb_ops = { + alloc_security: slink_sb_alloc_security, + free_security: slink_sb_free_security, + statfs: slink_sb_statfs, + mount: slink_sb_mount, + check_sb: slink_sb_check_sb, + umount: slink_sb_umount, + umount_close: slink_sb_umount_close, + umount_busy: slink_sb_umount_busy, + post_remount: slink_sb_post_remount, + post_mountroot: slink_sb_post_mountroot, + post_addmount: slink_sb_post_addmount, +}; + +static struct inode_security_ops slink_inode_ops = { + alloc_security: slink_inode_alloc_security, + free_security: slink_inode_free_security, + create: slink_inode_create, + post_create: slink_inode_post_create, + link: slink_inode_link, + post_link: slink_inode_post_link, + unlink: slink_inode_unlink, + symlink: slink_inode_symlink, + post_symlink: slink_inode_post_symlink, + mkdir: slink_inode_mkdir, + post_mkdir: slink_inode_post_mkdir, + rmdir: slink_inode_rmdir, + mknod: slink_inode_mknod, + post_mknod: slink_inode_post_mknod, + rename: slink_inode_rename, + post_rename: slink_inode_post_rename, + readlink: slink_inode_readlink, + follow_link: slink_inode_follow_link, + permission: slink_inode_permission, + revalidate: slink_inode_revalidate, + setattr: slink_inode_setattr, + stat: slink_inode_stat, + post_lookup: slink_post_lookup, + delete: slink_delete, +}; + +static struct file_security_ops slink_file_ops = { + permission: slink_file_permission, + alloc_security: slink_file_alloc_security, + free_security: slink_file_free_security, + llseek: slink_file_llseek, + ioctl: slink_file_ioctl, + mmap: slink_file_mmap, + mprotect: slink_file_mprotect, + lock: slink_file_lock, + fcntl: slink_file_fcntl, + set_fowner: slink_file_set_fowner, + send_sigiotask: slink_file_send_sigiotask, + receive: slink_file_receive, +}; + +static struct task_security_ops slink_task_ops = { + create: slink_task_create, + alloc_security: slink_task_alloc_security, + free_security: slink_task_free_security, + setuid: slink_task_setuid, + post_setuid: slink_task_post_setuid, + setgid: slink_task_setgid, + setpgid: slink_task_setpgid, + getpgid: slink_task_getpgid, + getsid: slink_task_getsid, + setgroups: slink_task_setgroups, + setnice: slink_task_setnice, + setrlimit: slink_task_setrlimit, + setscheduler: slink_task_setscheduler, + getscheduler: slink_task_getscheduler, + wait: slink_task_wait, + kill: slink_task_kill, + prctl: slink_task_prctl, + kmod_set_label: slink_task_kmod_set_label, +}; + +static struct socket_security_ops slink_socket_ops = { + create: slink_socket_create, + post_create: slink_socket_post_create, + bind: slink_socket_bind, + connect: slink_socket_connect, + listen: slink_socket_listen, + accept: slink_socket_accept, + sendmsg: slink_socket_sendmsg, + recvmsg: slink_socket_recvmsg, + getsockname: slink_socket_getsockname, + getpeername: slink_socket_getpeername, + getsockopt: slink_socket_getsockopt, + setsockopt: slink_socket_setsockopt, + shutdown: slink_socket_shutdown, + sock_rcv_skb: slink_socket_sock_rcv_skb, + unix_stream_connect: slink_socket_unix_stream_connect, + unix_may_send: slink_socket_unix_may_send, +}; + +static struct skb_security_ops slink_skb_ops = { + alloc_security: slink_skb_alloc_security, + clone: slink_skb_clone, + copy: slink_skb_copy, + set_owner_w: slink_skb_set_owner_w, + free_security: slink_skb_free_security, +}; + +static struct ip_security_ops slink_ip_ops = { + preroute_first: slink_ip_preroute_first, + preroute_last: slink_ip_preroute_last, + input_first: slink_ip_input_first, + input_last: slink_ip_input_last, + forward_first: slink_ip_forward_first, + forward_last: slink_ip_forward_last, + output_first: slink_ip_output_first, + output_last: slink_ip_output_last, + postroute_first: slink_ip_postroute_first, + postroute_last: slink_ip_postroute_last, + fragment: slink_ip_fragment, + defragment: slink_ip_defragment, + encapsulate: slink_ip_encapsulate, + decapsulate: slink_ip_decapsulate, + decode_options: slink_decode_options, +}; + +static struct netdev_security_ops slink_netdev_ops = { + unregister: slink_netdev_unregister, +}; + +static struct module_security_ops slink_module_ops = { + create_module: slink_module_create_module, + init_module: slink_module_init_module, + delete_module: slink_module_delete_module, + +}; + +static struct ipc_security_ops slink_ipc_ops = { + permission: slink_ipc_permission, + getinfo: slink_ipc_getinfo, +}; + +static struct msg_msg_security_ops slink_msg_ops = { + alloc_security: slink_msg_msg_alloc_security, + free_security: slink_msg_msg_free_security, +}; + +static struct msg_queue_security_ops slink_msg_queue_ops = { + alloc_security: slink_msg_queue_alloc_security, + free_security: slink_msg_queue_free_security, + associate: slink_msg_queue_associate, + msgctl: slink_msg_queue_msgctl, + msgsnd: slink_msg_queue_msgsnd, + msgrcv: slink_msg_queue_msgrcv, +}; + +static struct shm_security_ops slink_shm_ops = { + alloc_security: slink_shm_alloc_security, + free_security: slink_shm_free_security, + associate: slink_shm_associate, + shmctl: slink_shm_shmctl, + shmat: slink_shm_shmat, +}; + +static struct sem_security_ops slink_sem_ops = { + alloc_security: slink_sem_alloc_security, + free_security: slink_sem_free_security, + associate: slink_sem_associate, + semctl: slink_sem_semctl, + semop: slink_sem_semop, +}; + +static struct security_operations slink_ops = { + sethostname: slink_sethostname, + setdomainname: slink_setdomainname, + reboot: slink_reboot, + ioperm: slink_ioperm, + iopl: slink_iopl, + ptrace: slink_ptrace, + capget: slink_capget, + capset_check: slink_capset_check, + capset_set: slink_capset_set, + acct: slink_acct, + sysctl: slink_sysctl, + capable: slink_capable, + sys_security: slink_sys_security, + swapon: slink_swapon, + swapoff: slink_swapoff, + nfsservctl: slink_nfsservctl, + quotactl: slink_quotactl, + quota_on: slink_quota_on, + bdflush: slink_bdflush, + syslog: slink_syslog, + netlink_send: slink_netlink_send, + netlink_recv: slink_netlink_recv, + + bprm_ops: &slink_binprm_ops, + sb_ops: &slink_sb_ops, + inode_ops: &slink_inode_ops, + file_ops: &slink_file_ops, + task_ops: &slink_task_ops, + socket_ops: &slink_socket_ops, + skb_ops: &slink_skb_ops, + ip_ops: &slink_ip_ops, + netdev_ops: &slink_netdev_ops, + module_ops: &slink_module_ops, + ipc_ops: &slink_ipc_ops, + msg_msg_ops: &slink_msg_ops, + msg_queue_ops: &slink_msg_queue_ops, + shm_ops: &slink_shm_ops, + sem_ops: &slink_sem_ops, + + register_security: slink_register, + unregister_security: slink_unregister, +}; + +#if defined(CONFIG_SECURITY_SLINK_MODULE) +#define MODULE_NAME THIS_MODULE->name +#else +#define MODULE_NAME "slink" +#endif + +static int __init slink_init (void) +{ + /* register ourselves with the security framework */ + if (register_security (&slink_ops)) { + printk (KERN_INFO + "Failure registering slink module with the kernel\n"); + /* try registering with primary module */ + if (mod_reg_security (MODULE_NAME, &slink_ops)) { + printk (KERN_INFO "Failure registering slink module " + "with primary security module.\n"); + return -EINVAL; + } + secondary = 1; + } + printk(KERN_INFO "LSM/OpenWall: slink initialized\n"); + return 0; +} + +static void __exit slink_exit (void) +{ + /* remove ourselves from the security framework */ + if (secondary) { + if (mod_unreg_security (MODULE_NAME, &slink_ops)) + printk (KERN_INFO "Failure unregistering slink module " + "with primary module.\n"); + return; + } + + if (unregister_security (&slink_ops)) { + printk (KERN_INFO + "Failure unregistering slink module with the kernel\n"); + } +} + +module_init (slink_init); +module_exit (slink_exit); + +MODULE_DESCRIPTION("LSM implementation of the Openwall kernel patch adding SECURE_LINK to link and follow_link"); +MODULE_LICENSE("GPL"); +