selinux: ensure that the cached NetLabel secattr matches the desired SID
authorPaul Moore <pmoore@redhat.com>
Tue, 3 Dec 2013 16:36:11 +0000 (11:36 -0500)
committerPaul Moore <pmoore@redhat.com>
Wed, 4 Dec 2013 21:08:17 +0000 (16:08 -0500)
In selinux_netlbl_skbuff_setsid() we leverage a cached NetLabel
secattr whenever possible.  However, we never check to ensure that
the desired SID matches the cached NetLabel secattr.  This patch
checks the SID against the secattr before use and only uses the
cached secattr when the SID values match.

Signed-off-by: Paul Moore <pmoore@redhat.com>
security/selinux/netlabel.c

index 6235d052338b2e63b838711ed09c7ba1b04c67c6..0364120d1ec8705da7e8c1636f645d0885731509 100644 (file)
@@ -100,6 +100,32 @@ static struct netlbl_lsm_secattr *selinux_netlbl_sock_genattr(struct sock *sk)
        return secattr;
 }
 
+/**
+ * selinux_netlbl_sock_getattr - Get the cached NetLabel secattr
+ * @sk: the socket
+ * @sid: the SID
+ *
+ * Query the socket's cached secattr and if the SID matches the cached value
+ * return the cache, otherwise return NULL.
+ *
+ */
+static struct netlbl_lsm_secattr *selinux_netlbl_sock_getattr(
+                                                       const struct sock *sk,
+                                                       u32 sid)
+{
+       struct sk_security_struct *sksec = sk->sk_security;
+       struct netlbl_lsm_secattr *secattr = sksec->nlbl_secattr;
+
+       if (secattr == NULL)
+               return NULL;
+
+       if ((secattr->flags & NETLBL_SECATTR_SECID) &&
+           (secattr->attr.secid == sid))
+               return secattr;
+
+       return NULL;
+}
+
 /**
  * selinux_netlbl_cache_invalidate - Invalidate the NetLabel cache
  *
@@ -224,7 +250,7 @@ int selinux_netlbl_skbuff_setsid(struct sk_buff *skb,
                struct sk_security_struct *sksec = sk->sk_security;
                if (sksec->nlbl_state != NLBL_REQSKB)
                        return 0;
-               secattr = sksec->nlbl_secattr;
+               secattr = selinux_netlbl_sock_getattr(sk, sid);
        }
        if (secattr == NULL) {
                secattr = &secattr_storage;
@@ -410,6 +436,9 @@ int selinux_netlbl_socket_setsockopt(struct socket *sock,
             sksec->nlbl_state == NLBL_CONNLABELED)) {
                netlbl_secattr_init(&secattr);
                lock_sock(sk);
+               /* call the netlabel function directly as we want to see the
+                * on-the-wire label that is assigned via the socket's options
+                * and not the cached netlabel/lsm attributes */
                rc = netlbl_sock_getattr(sk, &secattr);
                release_sock(sk);
                if (rc == 0)