]> bbs.cooldavid.org Git - net-next-2.6.git/blobdiff - security/selinux/hooks.c
SELinux: special dontaudit for access checks
[net-next-2.6.git] / security / selinux / hooks.c
index 01f52424cfe5befcd10d6b330c640bd5845f3f0c..650947a72a2bc328c884a662274eed805a348717 100644 (file)
@@ -87,9 +87,6 @@
 #include "netlabel.h"
 #include "audit.h"
 
-#define XATTR_SELINUX_SUFFIX "selinux"
-#define XATTR_NAME_SELINUX XATTR_SECURITY_PREFIX XATTR_SELINUX_SUFFIX
-
 #define NUM_SEL_MNT_OPTS 5
 
 extern int selinux_nlmsg_lookup(u16 sclass, u16 nlmsg_type, u32 *perm);
@@ -188,7 +185,7 @@ static inline u32 task_sid(const struct task_struct *task)
  */
 static inline u32 current_sid(void)
 {
-       const struct task_security_struct *tsec = current_cred()->security;
+       const struct task_security_struct *tsec = current_security();
 
        return tsec->sid;
 }
@@ -1558,8 +1555,7 @@ static int may_create(struct inode *dir,
                      struct dentry *dentry,
                      u16 tclass)
 {
-       const struct cred *cred = current_cred();
-       const struct task_security_struct *tsec = cred->security;
+       const struct task_security_struct *tsec = current_security();
        struct inode_security_struct *dsec;
        struct superblock_security_struct *sbsec;
        u32 sid, newsid;
@@ -2157,8 +2153,7 @@ static int selinux_bprm_set_creds(struct linux_binprm *bprm)
 
 static int selinux_bprm_secureexec(struct linux_binprm *bprm)
 {
-       const struct cred *cred = current_cred();
-       const struct task_security_struct *tsec = cred->security;
+       const struct task_security_struct *tsec = current_security();
        u32 sid, osid;
        int atsecure = 0;
 
@@ -2533,8 +2528,7 @@ static int selinux_inode_init_security(struct inode *inode, struct inode *dir,
                                       char **name, void **value,
                                       size_t *len)
 {
-       const struct cred *cred = current_cred();
-       const struct task_security_struct *tsec = cred->security;
+       const struct task_security_struct *tsec = current_security();
        struct inode_security_struct *dsec;
        struct superblock_security_struct *sbsec;
        u32 sid, newsid, clen;
@@ -2650,14 +2644,26 @@ static int selinux_inode_follow_link(struct dentry *dentry, struct nameidata *na
 static int selinux_inode_permission(struct inode *inode, int mask)
 {
        const struct cred *cred = current_cred();
+       struct common_audit_data ad;
+       u32 perms;
+       bool from_access;
 
-       if (!mask) {
-               /* No permission to check.  Existence test. */
+       from_access = mask & MAY_ACCESS;
+       mask &= (MAY_READ|MAY_WRITE|MAY_EXEC|MAY_APPEND);
+
+       /* No permission to check.  Existence test. */
+       if (!mask)
                return 0;
-       }
 
-       return inode_has_perm(cred, inode,
-                             file_mask_to_av(inode->i_mode, mask), NULL);
+       COMMON_AUDIT_DATA_INIT(&ad, FS);
+       ad.u.fs.inode = inode;
+
+       if (from_access)
+               ad.selinux_audit_data.auditdeny |= FILE__AUDIT_ACCESS;
+
+       perms = file_mask_to_av(inode->i_mode, mask);
+
+       return inode_has_perm(cred, inode, perms, &ad);
 }
 
 static int selinux_inode_setattr(struct dentry *dentry, struct iattr *iattr)
@@ -3651,33 +3657,25 @@ static u32 socket_sockcreate_sid(const struct task_security_struct *tsec)
        return tsec->sockcreate_sid ? : tsec->sid;
 }
 
-static int socket_has_perm(struct task_struct *task, struct socket *sock,
-                          u32 perms)
+static int sock_has_perm(struct task_struct *task, struct sock *sk, u32 perms)
 {
-       struct inode_security_struct *isec;
+       struct sk_security_struct *sksec = sk->sk_security;
        struct common_audit_data ad;
-       u32 sid;
-       int err = 0;
+       u32 tsid = task_sid(task);
 
-       isec = SOCK_INODE(sock)->i_security;
-
-       if (isec->sid == SECINITSID_KERNEL)
-               goto out;
-       sid = task_sid(task);
+       if (sksec->sid == SECINITSID_KERNEL)
+               return 0;
 
        COMMON_AUDIT_DATA_INIT(&ad, NET);
-       ad.u.net.sk = sock->sk;
-       err = avc_has_perm(sid, isec->sid, isec->sclass, perms, &ad);
+       ad.u.net.sk = sk;
 
-out:
-       return err;
+       return avc_has_perm(tsid, sksec->sid, sksec->sclass, perms, &ad);
 }
 
 static int selinux_socket_create(int family, int type,
                                 int protocol, int kern)
 {
-       const struct cred *cred = current_cred();
-       const struct task_security_struct *tsec = cred->security;
+       const struct task_security_struct *tsec = current_security();
        u32 newsid;
        u16 secclass;
 
@@ -3692,8 +3690,7 @@ static int selinux_socket_create(int family, int type,
 static int selinux_socket_post_create(struct socket *sock, int family,
                                      int type, int protocol, int kern)
 {
-       const struct cred *cred = current_cred();
-       const struct task_security_struct *tsec = cred->security;
+       const struct task_security_struct *tsec = current_security();
        struct inode_security_struct *isec = SOCK_INODE(sock)->i_security;
        struct sk_security_struct *sksec;
        int err = 0;
@@ -3722,10 +3719,11 @@ static int selinux_socket_post_create(struct socket *sock, int family,
 
 static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, int addrlen)
 {
+       struct sock *sk = sock->sk;
        u16 family;
        int err;
 
-       err = socket_has_perm(current, sock, SOCKET__BIND);
+       err = sock_has_perm(current, sk, SOCKET__BIND);
        if (err)
                goto out;
 
@@ -3734,19 +3732,16 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in
         * Multiple address binding for SCTP is not supported yet: we just
         * check the first address now.
         */
-       family = sock->sk->sk_family;
+       family = sk->sk_family;
        if (family == PF_INET || family == PF_INET6) {
                char *addrp;
-               struct inode_security_struct *isec;
+               struct sk_security_struct *sksec = sk->sk_security;
                struct common_audit_data ad;
                struct sockaddr_in *addr4 = NULL;
                struct sockaddr_in6 *addr6 = NULL;
                unsigned short snum;
-               struct sock *sk = sock->sk;
                u32 sid, node_perm;
 
-               isec = SOCK_INODE(sock)->i_security;
-
                if (family == PF_INET) {
                        addr4 = (struct sockaddr_in *)address;
                        snum = ntohs(addr4->sin_port);
@@ -3770,15 +3765,15 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in
                                COMMON_AUDIT_DATA_INIT(&ad, NET);
                                ad.u.net.sport = htons(snum);
                                ad.u.net.family = family;
-                               err = avc_has_perm(isec->sid, sid,
-                                                  isec->sclass,
+                               err = avc_has_perm(sksec->sid, sid,
+                                                  sksec->sclass,
                                                   SOCKET__NAME_BIND, &ad);
                                if (err)
                                        goto out;
                        }
                }
 
-               switch (isec->sclass) {
+               switch (sksec->sclass) {
                case SECCLASS_TCP_SOCKET:
                        node_perm = TCP_SOCKET__NODE_BIND;
                        break;
@@ -3809,8 +3804,8 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in
                else
                        ipv6_addr_copy(&ad.u.net.v6info.saddr, &addr6->sin6_addr);
 
-               err = avc_has_perm(isec->sid, sid,
-                                  isec->sclass, node_perm, &ad);
+               err = avc_has_perm(sksec->sid, sid,
+                                  sksec->sclass, node_perm, &ad);
                if (err)
                        goto out;
        }
@@ -3821,19 +3816,18 @@ out:
 static int selinux_socket_connect(struct socket *sock, struct sockaddr *address, int addrlen)
 {
        struct sock *sk = sock->sk;
-       struct inode_security_struct *isec;
+       struct sk_security_struct *sksec = sk->sk_security;
        int err;
 
-       err = socket_has_perm(current, sock, SOCKET__CONNECT);
+       err = sock_has_perm(current, sk, SOCKET__CONNECT);
        if (err)
                return err;
 
        /*
         * If a TCP or DCCP socket, check name_connect permission for the port.
         */
-       isec = SOCK_INODE(sock)->i_security;
-       if (isec->sclass == SECCLASS_TCP_SOCKET ||
-           isec->sclass == SECCLASS_DCCP_SOCKET) {
+       if (sksec->sclass == SECCLASS_TCP_SOCKET ||
+           sksec->sclass == SECCLASS_DCCP_SOCKET) {
                struct common_audit_data ad;
                struct sockaddr_in *addr4 = NULL;
                struct sockaddr_in6 *addr6 = NULL;
@@ -3856,13 +3850,13 @@ static int selinux_socket_connect(struct socket *sock, struct sockaddr *address,
                if (err)
                        goto out;
 
-               perm = (isec->sclass == SECCLASS_TCP_SOCKET) ?
+               perm = (sksec->sclass == SECCLASS_TCP_SOCKET) ?
                       TCP_SOCKET__NAME_CONNECT : DCCP_SOCKET__NAME_CONNECT;
 
                COMMON_AUDIT_DATA_INIT(&ad, NET);
                ad.u.net.dport = htons(snum);
                ad.u.net.family = sk->sk_family;
-               err = avc_has_perm(isec->sid, sid, isec->sclass, perm, &ad);
+               err = avc_has_perm(sksec->sid, sid, sksec->sclass, perm, &ad);
                if (err)
                        goto out;
        }
@@ -3875,7 +3869,7 @@ out:
 
 static int selinux_socket_listen(struct socket *sock, int backlog)
 {
-       return socket_has_perm(current, sock, SOCKET__LISTEN);
+       return sock_has_perm(current, sock->sk, SOCKET__LISTEN);
 }
 
 static int selinux_socket_accept(struct socket *sock, struct socket *newsock)
@@ -3884,7 +3878,7 @@ static int selinux_socket_accept(struct socket *sock, struct socket *newsock)
        struct inode_security_struct *isec;
        struct inode_security_struct *newisec;
 
-       err = socket_has_perm(current, sock, SOCKET__ACCEPT);
+       err = sock_has_perm(current, sock->sk, SOCKET__ACCEPT);
        if (err)
                return err;
 
@@ -3901,30 +3895,30 @@ static int selinux_socket_accept(struct socket *sock, struct socket *newsock)
 static int selinux_socket_sendmsg(struct socket *sock, struct msghdr *msg,
                                  int size)
 {
-       return socket_has_perm(current, sock, SOCKET__WRITE);
+       return sock_has_perm(current, sock->sk, SOCKET__WRITE);
 }
 
 static int selinux_socket_recvmsg(struct socket *sock, struct msghdr *msg,
                                  int size, int flags)
 {
-       return socket_has_perm(current, sock, SOCKET__READ);
+       return sock_has_perm(current, sock->sk, SOCKET__READ);
 }
 
 static int selinux_socket_getsockname(struct socket *sock)
 {
-       return socket_has_perm(current, sock, SOCKET__GETATTR);
+       return sock_has_perm(current, sock->sk, SOCKET__GETATTR);
 }
 
 static int selinux_socket_getpeername(struct socket *sock)
 {
-       return socket_has_perm(current, sock, SOCKET__GETATTR);
+       return sock_has_perm(current, sock->sk, SOCKET__GETATTR);
 }
 
 static int selinux_socket_setsockopt(struct socket *sock, int level, int optname)
 {
        int err;
 
-       err = socket_has_perm(current, sock, SOCKET__SETOPT);
+       err = sock_has_perm(current, sock->sk, SOCKET__SETOPT);
        if (err)
                return err;
 
@@ -3934,12 +3928,12 @@ static int selinux_socket_setsockopt(struct socket *sock, int level, int optname
 static int selinux_socket_getsockopt(struct socket *sock, int level,
                                     int optname)
 {
-       return socket_has_perm(current, sock, SOCKET__GETOPT);
+       return sock_has_perm(current, sock->sk, SOCKET__GETOPT);
 }
 
 static int selinux_socket_shutdown(struct socket *sock, int how)
 {
-       return socket_has_perm(current, sock, SOCKET__SHUTDOWN);
+       return sock_has_perm(current, sock->sk, SOCKET__SHUTDOWN);
 }
 
 static int selinux_socket_unix_stream_connect(struct socket *sock,
@@ -3977,23 +3971,15 @@ static int selinux_socket_unix_stream_connect(struct socket *sock,
 static int selinux_socket_unix_may_send(struct socket *sock,
                                        struct socket *other)
 {
-       struct inode_security_struct *isec;
-       struct inode_security_struct *other_isec;
+       struct sk_security_struct *ssec = sock->sk->sk_security;
+       struct sk_security_struct *osec = other->sk->sk_security;
        struct common_audit_data ad;
-       int err;
-
-       isec = SOCK_INODE(sock)->i_security;
-       other_isec = SOCK_INODE(other)->i_security;
 
        COMMON_AUDIT_DATA_INIT(&ad, NET);
        ad.u.net.sk = other->sk;
 
-       err = avc_has_perm(isec->sid, other_isec->sid,
-                          isec->sclass, SOCKET__SENDTO, &ad);
-       if (err)
-               return err;
-
-       return 0;
+       return avc_has_perm(ssec->sid, osec->sid, osec->sclass, SOCKET__SENDTO,
+                           &ad);
 }
 
 static int selinux_inet_sys_rcv_skb(int ifindex, char *addrp, u16 family,
@@ -4132,26 +4118,18 @@ static int selinux_socket_getpeersec_stream(struct socket *sock, char __user *op
        int err = 0;
        char *scontext;
        u32 scontext_len;
-       struct sk_security_struct *sksec;
-       struct inode_security_struct *isec;
+       struct sk_security_struct *sksec = sock->sk->sk_security;
        u32 peer_sid = SECSID_NULL;
 
-       isec = SOCK_INODE(sock)->i_security;
-
-       if (isec->sclass == SECCLASS_UNIX_STREAM_SOCKET ||
-           isec->sclass == SECCLASS_TCP_SOCKET) {
-               sksec = sock->sk->sk_security;
+       if (sksec->sclass == SECCLASS_UNIX_STREAM_SOCKET ||
+           sksec->sclass == SECCLASS_TCP_SOCKET)
                peer_sid = sksec->peer_sid;
-       }
-       if (peer_sid == SECSID_NULL) {
-               err = -ENOPROTOOPT;
-               goto out;
-       }
+       if (peer_sid == SECSID_NULL)
+               return -ENOPROTOOPT;
 
        err = security_sid_to_context(peer_sid, &scontext, &scontext_len);
-
        if (err)
-               goto out;
+               return err;
 
        if (scontext_len > len) {
                err = -ERANGE;
@@ -4164,9 +4142,7 @@ static int selinux_socket_getpeersec_stream(struct socket *sock, char __user *op
 out_len:
        if (put_user(scontext_len, optlen))
                err = -EFAULT;
-
        kfree(scontext);
-out:
        return err;
 }
 
@@ -4378,8 +4354,7 @@ 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;
+       struct sk_security_struct *sksec = sk->sk_security;
 
        if (skb->len < NLMSG_SPACE(0)) {
                err = -EINVAL;
@@ -4387,13 +4362,13 @@ static int selinux_nlmsg_perm(struct sock *sk, struct sk_buff *skb)
        }
        nlh = nlmsg_hdr(skb);
 
-       err = selinux_nlmsg_lookup(isec->sclass, nlh->nlmsg_type, &perm);
+       err = selinux_nlmsg_lookup(sksec->sclass, nlh->nlmsg_type, &perm);
        if (err) {
                if (err == -EINVAL) {
                        audit_log(current->audit_context, GFP_KERNEL, AUDIT_SELINUX_ERR,
                                  "SELinux:  unrecognized netlink message"
                                  " type=%hu for sclass=%hu\n",
-                                 nlh->nlmsg_type, isec->sclass);
+                                 nlh->nlmsg_type, sksec->sclass);
                        if (!selinux_enforcing || security_get_allow_unknown())
                                err = 0;
                }
@@ -4404,7 +4379,7 @@ static int selinux_nlmsg_perm(struct sock *sk, struct sk_buff *skb)
                goto out;
        }
 
-       err = socket_has_perm(current, sock, perm);
+       err = sock_has_perm(current, sk, perm);
 out:
        return err;
 }