#include <linux/nfs_mount.h>
#include <net/ipv6.h>
#include <linux/hugetlb.h>
+#include <linux/major.h>
#include "avc.h"
#include "objsec.h"
#define XATTR_SELINUX_SUFFIX "selinux"
#define XATTR_NAME_SELINUX XATTR_SECURITY_PREFIX XATTR_SELINUX_SUFFIX
+extern int policydb_loaded_version;
+extern int selinux_nlmsg_lookup(u16 sclass, u16 nlmsg_type, u32 *perm);
+
#ifdef CONFIG_SECURITY_SELINUX_DEVELOP
int selinux_enforcing = 0;
return SECCLASS_FILE;
}
-static inline u16 socket_type_to_security_class(int family, int type)
+static inline u16 socket_type_to_security_class(int family, int type, int protocol)
{
switch (family) {
case PF_UNIX:
return SECCLASS_RAWIP_SOCKET;
}
case PF_NETLINK:
- return SECCLASS_NETLINK_SOCKET;
+ switch (protocol) {
+ case NETLINK_ROUTE:
+ return SECCLASS_NETLINK_ROUTE_SOCKET;
+ case NETLINK_FIREWALL:
+ return SECCLASS_NETLINK_FIREWALL_SOCKET;
+ case NETLINK_TCPDIAG:
+ return SECCLASS_NETLINK_TCPDIAG_SOCKET;
+ case NETLINK_NFLOG:
+ return SECCLASS_NETLINK_NFLOG_SOCKET;
+ case NETLINK_XFRM:
+ return SECCLASS_NETLINK_XFRM_SOCKET;
+ case NETLINK_SELINUX:
+ return SECCLASS_NETLINK_SELINUX_SOCKET;
+ case NETLINK_AUDIT:
+ return SECCLASS_NETLINK_AUDIT_SOCKET;
+ case NETLINK_IP6_FW:
+ return SECCLASS_NETLINK_IP6FW_SOCKET;
+ case NETLINK_DNRTMSG:
+ return SECCLASS_NETLINK_DNRT_SOCKET;
+ default:
+ return SECCLASS_NETLINK_SOCKET;
+ }
case PF_PACKET:
return SECCLASS_PACKET_SOCKET;
case PF_KEY:
struct socket *sock = SOCKET_I(inode);
if (sock->sk) {
isec->sclass = socket_type_to_security_class(sock->sk->sk_family,
- sock->sk->sk_type);
+ sock->sk->sk_type,
+ sock->sk->sk_protocol);
} else {
isec->sclass = SECCLASS_SOCKET;
}
{
int error;
- error = task_has_perm(current, target, PROCESS__SETCAP);
+ error = secondary_ops->capset_check(target, effective, inheritable, permitted);
if (error)
return error;
- return secondary_ops->capset_check(target, effective, inheritable, permitted);
+ return task_has_perm(current, target, PROCESS__SETCAP);
}
static void selinux_capset_set(struct task_struct *target, kernel_cap_t *effective,
if (error)
return;
- return secondary_ops->capset_set(target, effective, inheritable, permitted);
+ secondary_ops->capset_set(target, effective, inheritable, permitted);
}
static int selinux_capable(struct task_struct *tsk, int cap)
u32 tsid;
int rc;
+ rc = secondary_ops->sysctl(table, op);
+ if (rc)
+ return rc;
+
tsec = current->security;
rc = selinux_proc_get_sid(table->de, (op == 001) ?
switch (type) {
case 3: /* Read last kernel messages */
+ case 10: /* Return size of the log buffer */
rc = task_has_system(current, SYSTEM__SYSLOG_READ);
break;
case 6: /* Disable logging to console */
return -ENOMEM;
}
-static int selinux_netlink_send(struct sk_buff *skb)
-{
- if (capable(CAP_NET_ADMIN))
- cap_raise (NETLINK_CB (skb).eff_cap, CAP_NET_ADMIN);
- else
- NETLINK_CB(skb).eff_cap = 0;
- return 0;
-}
-
-static int selinux_netlink_recv(struct sk_buff *skb)
-{
- if (!cap_raised(NETLINK_CB(skb).eff_cap, CAP_NET_ADMIN))
- return -EPERM;
- return 0;
-}
-
/* binprm security operations */
static int selinux_bprm_alloc_security(struct linux_binprm *bprm)
static int selinux_bprm_check_security (struct linux_binprm *bprm)
{
- return 0;
+ return secondary_ops->bprm_check_security(bprm);
}
PROCESS__NOATSECURE, NULL, NULL);
}
- /* Note that we must include the legacy uid/gid test below
- to retain it, as the new userland will simply use the
- value passed by AT_SECURE to decide whether to enable
- secure mode. */
- return ( atsecure || current->euid != current->uid ||
- current->egid != current->gid);
+ return (atsecure || secondary_ops->bprm_secureexec(bprm));
}
static void selinux_bprm_free_security(struct linux_binprm *bprm)
kfree(bsec);
}
+/* Create an open file that refers to the null device.
+ Derived from the OpenWall LSM. */
+struct file *open_devnull(void)
+{
+ struct inode *inode;
+ struct dentry *dentry;
+ struct file *file = NULL;
+ struct inode_security_struct *isec;
+ dev_t dev;
+
+ inode = new_inode(current->fs->rootmnt->mnt_sb);
+ if (!inode)
+ goto out;
+
+ dentry = dget(d_alloc_root(inode));
+ if (!dentry)
+ goto out_iput;
+
+ file = get_empty_filp();
+ if (!file)
+ goto out_dput;
+
+ dev = MKDEV(MEM_MAJOR, 3); /* null device */
+
+ inode->i_uid = current->fsuid;
+ inode->i_gid = current->fsgid;
+ inode->i_blksize = PAGE_SIZE;
+ inode->i_blocks = 0;
+ inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+ inode->i_state = I_DIRTY; /* so that mark_inode_dirty won't touch us */
+
+ isec = inode->i_security;
+ isec->sid = SECINITSID_DEVNULL;
+ isec->sclass = SECCLASS_CHR_FILE;
+ isec->initialized = 1;
+
+ file->f_flags = O_RDWR;
+ file->f_mode = FMODE_READ | FMODE_WRITE;
+ file->f_dentry = dentry;
+ file->f_vfsmnt = mntget(current->fs->rootmnt);
+ file->f_pos = 0;
+
+ init_special_inode(inode, S_IFCHR | S_IRUGO | S_IWUGO, dev);
+ if (inode->i_fop->open(inode, file))
+ goto out_fput;
+
+out:
+ return file;
+out_fput:
+ mntput(file->f_vfsmnt);
+ put_filp(file);
+out_dput:
+ dput(dentry);
+out_iput:
+ iput(inode);
+ file = NULL;
+ goto out;
+}
+
/* Derived from fs/exec.c:flush_old_files. */
static inline void flush_unauthorized_files(struct files_struct * files)
{
struct avc_audit_data ad;
- struct file *file;
+ struct file *file, *devnull = NULL;
long j = -1;
AVC_AUDIT_DATA_INIT(&ad,FS);
spin_lock(&files->file_lock);
for (;;) {
unsigned long set, i;
+ int fd;
j++;
i = j * __NFDBITS;
continue;
if (file_has_perm(current,
file,
- file_to_av(file)))
+ file_to_av(file))) {
sys_close(i);
+ fd = get_unused_fd();
+ if (fd != i) {
+ if (fd >= 0)
+ put_unused_fd(fd);
+ fput(file);
+ continue;
+ }
+ if (devnull) {
+ atomic_inc(&devnull->f_count);
+ } else {
+ devnull = open_devnull();
+ if (!devnull) {
+ put_unused_fd(fd);
+ fput(file);
+ continue;
+ }
+ }
+ fd_install(fd, devnull);
+ }
fput(file);
}
}
unsigned long flags,
void * data)
{
+ int rc;
+
+ rc = secondary_ops->sb_mount(dev_name, nd, type, flags, data);
+ if (rc)
+ return rc;
+
if (flags & MS_REMOUNT)
return superblock_has_perm(current, nd->mnt->mnt_sb,
FILESYSTEM__REMOUNT, NULL);
static int selinux_umount(struct vfsmount *mnt, int flags)
{
+ int rc;
+
+ rc = secondary_ops->sb_umount(mnt, flags);
+ if (rc)
+ return rc;
+
return superblock_has_perm(current,mnt->mnt_sb,
FILESYSTEM__UNMOUNT,NULL);
}
static int selinux_inode_unlink(struct inode *dir, struct dentry *dentry)
{
+ int rc;
+
+ rc = secondary_ops->inode_unlink(dir, dentry);
+ if (rc)
+ return rc;
return may_link(dir, dentry, MAY_UNLINK);
}
static int selinux_inode_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
{
+ int rc;
+
+ rc = secondary_ops->inode_mknod(dir, dentry, mode, dev);
+ if (rc)
+ return rc;
+
return may_create(dir, dentry, inode_mode_to_security_class(mode));
}
static int selinux_inode_permission(struct inode *inode, int mask,
struct nameidata *nd)
{
+ int rc;
+
+ rc = secondary_ops->inode_permission(inode, mask, nd);
+ if (rc)
+ return rc;
+
if (!mask) {
/* No permission to check. Existence test. */
return 0;
static int selinux_inode_setattr(struct dentry *dentry, struct iattr *iattr)
{
+ int rc;
+
+ rc = secondary_ops->inode_setattr(dentry, iattr);
+ if (rc)
+ return rc;
+
if (iattr->ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID |
ATTR_ATIME_SET | ATTR_MTIME_SET))
return dentry_has_perm(current, NULL, dentry, FILE__SETATTR);
static int selinux_file_mmap(struct file *file, unsigned long prot, unsigned long flags)
{
u32 av;
+ int rc;
+
+ rc = secondary_ops->file_mmap(file, prot, flags);
+ if (rc)
+ return rc;
if (file) {
/* read access is always possible with a mapping */
static int selinux_file_mprotect(struct vm_area_struct *vma,
unsigned long prot)
{
+ int rc;
+
+ rc = secondary_ops->file_mprotect(vma, prot);
+ if (rc)
+ return rc;
+
return selinux_file_mmap(vma->vm_file, prot, vma->vm_flags);
}
static int selinux_task_create(unsigned long clone_flags)
{
+ int rc;
+
+ rc = secondary_ops->task_create(clone_flags);
+ if (rc)
+ return rc;
+
return task_has_perm(current, current, PROCESS__FORK);
}
static int selinux_task_setnice(struct task_struct *p, int nice)
{
+ int rc;
+
+ rc = secondary_ops->task_setnice(p, nice);
+ if (rc)
+ return rc;
+
return task_has_perm(current,p, PROCESS__SETSCHED);
}
static int selinux_task_setrlimit(unsigned int resource, struct rlimit *new_rlim)
{
struct rlimit *old_rlim = current->rlim + resource;
+ int rc;
+
+ rc = secondary_ops->task_setrlimit(resource, new_rlim);
+ if (rc)
+ return rc;
/* Control the ability to change the hard limit (whether
lowering or raising it), so that the hard limit can
static int selinux_task_kill(struct task_struct *p, struct siginfo *info, int sig)
{
u32 perm;
+ int rc;
+
+ rc = secondary_ops->task_kill(p, info, sig);
+ if (rc)
+ return rc;
if (info && ((unsigned long)info == 1 ||
(unsigned long)info == 2 || SI_FROMKERNEL(info)))
tsec = current->security;
err = avc_has_perm(tsec->sid, tsec->sid,
- socket_type_to_security_class(family, type),
- SOCKET__CREATE, NULL, NULL);
+ socket_type_to_security_class(family, type,
+ protocol), SOCKET__CREATE, NULL, NULL);
out:
return err;
isec = SOCK_INODE(sock)->i_security;
tsec = current->security;
- isec->sclass = socket_type_to_security_class(family, type);
+ isec->sclass = socket_type_to_security_class(family, type, protocol);
isec->sid = kern ? SECINITSID_KERNEL : tsec->sid;
return;
struct avc_audit_data ad;
int err;
+ err = secondary_ops->unix_stream_connect(sock, other, newsk);
+ if (err)
+ return err;
+
isec = SOCK_INODE(sock)->i_security;
other_isec = SOCK_INODE(other)->i_security;
char *addrp;
int len, err = 0;
u32 netif_perm, node_perm, node_sid, recv_perm = 0;
+ u32 sock_sid = 0;
+ u16 sock_class = 0;
struct socket *sock;
- struct inode *inode;
struct net_device *dev;
struct sel_netif *netif;
struct netif_security_struct *nsec;
- struct inode_security_struct *isec;
struct avc_audit_data ad;
family = sk->sk_family;
if (family == PF_INET6 && skb->protocol == ntohs(ETH_P_IP))
family = PF_INET;
- sock = sk->sk_socket;
-
- /* TCP control messages don't always have a socket. */
- if (!sock)
- goto out;
-
- inode = SOCK_INODE(sock);
- if (!inode)
- goto out;
+ read_lock_bh(&sk->sk_callback_lock);
+ sock = sk->sk_socket;
+ if (sock) {
+ struct inode *inode;
+ inode = SOCK_INODE(sock);
+ if (inode) {
+ struct inode_security_struct *isec;
+ isec = inode->i_security;
+ sock_sid = isec->sid;
+ sock_class = isec->sclass;
+ }
+ }
+ read_unlock_bh(&sk->sk_callback_lock);
+ if (!sock_sid)
+ goto out;
dev = skb->dev;
if (!dev)
}
nsec = &netif->nsec;
- isec = inode->i_security;
- switch (isec->sclass) {
+ switch (sock_class) {
case SECCLASS_UDP_SOCKET:
netif_perm = NETIF__UDP_RECV;
node_perm = NODE__UDP_RECV;
goto out;
}
- err = avc_has_perm(isec->sid, nsec->if_sid, SECCLASS_NETIF,
+ err = avc_has_perm(sock_sid, nsec->if_sid, SECCLASS_NETIF,
netif_perm, &nsec->avcr, &ad);
sel_netif_put(netif);
if (err)
if (err)
goto out;
- err = avc_has_perm(isec->sid, node_sid, SECCLASS_NODE, node_perm, NULL, &ad);
+ err = avc_has_perm(sock_sid, node_sid, SECCLASS_NODE, node_perm, NULL, &ad);
if (err)
goto out;
if (err)
goto out;
- err = avc_has_perm(isec->sid, port_sid, isec->sclass,
+ err = avc_has_perm(sock_sid, port_sid, sock_class,
recv_perm, NULL, &ad);
}
out:
sk_free_security(sk);
}
+static int selinux_nlmsg_perm(struct sock *sk, struct sk_buff *skb)
+{
+ int err = 0;
+ u32 perm;
+ struct nlmsghdr *nlh;
+ struct socket *sock = sk->sk_socket;
+ struct inode_security_struct *isec = SOCK_INODE(sock)->i_security;
+
+ if (skb->len < NLMSG_SPACE(0)) {
+ err = -EINVAL;
+ goto out;
+ }
+ nlh = (struct nlmsghdr *)skb->data;
+
+ err = selinux_nlmsg_lookup(isec->sclass, nlh->nlmsg_type, &perm);
+ if (err) {
+ /* Ignore */
+ if (err == -ENOENT)
+ err = 0;
+ goto out;
+ }
+
+ err = socket_has_perm(current, sock, perm);
+out:
+ return err;
+}
+
#ifdef CONFIG_NETFILTER
static unsigned int selinux_ip_postroute_last(unsigned int hooknum,
#endif /* CONFIG_NETFILTER */
+#else
+
+static inline int selinux_nlmsg_perm(struct sock *sk, struct sk_buff *skb)
+{
+ return 0;
+}
+
#endif /* CONFIG_SECURITY_NETWORK */
+static int selinux_netlink_send(struct sock *sk, struct sk_buff *skb)
+{
+ int err = 0;
+
+ if (capable(CAP_NET_ADMIN))
+ cap_raise (NETLINK_CB (skb).eff_cap, CAP_NET_ADMIN);
+ else
+ NETLINK_CB(skb).eff_cap = 0;
+
+ if (policydb_loaded_version >= POLICYDB_VERSION_NLCLASS)
+ err = selinux_nlmsg_perm(sk, skb);
+
+ return err;
+}
+
+static int selinux_netlink_recv(struct sk_buff *skb)
+{
+ if (!cap_raised(NETLINK_CB(skb).eff_cap, CAP_NET_ADMIN))
+ return -EPERM;
+ return 0;
+}
+
static int ipc_alloc_security(struct task_struct *task,
struct kern_ipc_perm *perm,
u16 sclass)
static void selinux_msg_msg_free_security(struct msg_msg *msg)
{
- return msg_msg_free_security(msg);
+ msg_msg_free_security(msg);
}
/* message queue security operations */
}
static int selinux_shm_shmat(struct shmid_kernel *shp,
- char *shmaddr, int shmflg)
+ char __user *shmaddr, int shmflg)
{
u32 perms;
+ int rc;
+
+ rc = secondary_ops->shm_shmat(shp, shmaddr, shmflg);
+ if (rc)
+ return rc;
if (shmflg & SHM_RDONLY)
perms = SHM__READ;