#include <linux/nfs_mount.h>
#include <net/ipv6.h>
#include <linux/hugetlb.h>
+#include <linux/major.h>
#include "avc.h"
#include "objsec.h"
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 */
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;
+ unsigned long set, i, 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);
}
}
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: