[MLSXFRM]: Add security sid to sock
Venkat Yekkirala [Sat, 5 Aug 2006 06:08:56 +0000 (23:08 -0700)]
This adds security for IP sockets at the sock level. Security at the
sock level is needed to enforce the SELinux security policy for
security associations even when a sock is orphaned (such as in the TCP
LAST_ACK state).

This will also be used to enforce SELinux controls over data arriving
at or leaving a child socket while it's still waiting to be accepted.

Signed-off-by: Venkat Yekkirala <vyekkirala@TrustedCS.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

include/linux/security.h
include/net/sock.h
net/core/sock.c
security/dummy.c
security/selinux/hooks.c
security/selinux/include/objsec.h

index 6bc2aad..4d7fb59 100644 (file)
@@ -812,6 +812,8 @@ struct swap_info_struct;
  *      which is used to copy security attributes between local stream sockets.
  * @sk_free_security:
  *     Deallocate security structure.
+ * @sk_clone_security:
+ *     Clone/copy security structure.
  * @sk_getsid:
  *     Retrieve the LSM-specific sid for the sock to enable caching of network
  *     authorizations.
@@ -1332,6 +1334,7 @@ struct security_operations {
        int (*socket_getpeersec_dgram) (struct socket *sock, struct sk_buff *skb, u32 *secid);
        int (*sk_alloc_security) (struct sock *sk, int family, gfp_t priority);
        void (*sk_free_security) (struct sock *sk);
+       void (*sk_clone_security) (const struct sock *sk, struct sock *newsk);
        unsigned int (*sk_getsid) (struct sock *sk, struct flowi *fl, u8 dir);
 #endif /* CONFIG_SECURITY_NETWORK */
 
@@ -2885,6 +2888,11 @@ static inline void security_sk_free(struct sock *sk)
        return security_ops->sk_free_security(sk);
 }
 
+static inline void security_sk_clone(const struct sock *sk, struct sock *newsk)
+{
+       return security_ops->sk_clone_security(sk, newsk);
+}
+
 static inline unsigned int security_sk_sid(struct sock *sk, struct flowi *fl, u8 dir)
 {
        return security_ops->sk_getsid(sk, fl, dir);
@@ -3011,6 +3019,10 @@ static inline void security_sk_free(struct sock *sk)
 {
 }
 
+static inline void security_sk_clone(const struct sock *sk, struct sock *newsk)
+{
+}
+
 static inline unsigned int security_sk_sid(struct sock *sk, struct flowi *fl, u8 dir)
 {
        return 0;
index 324b3ea..91cdceb 100644 (file)
@@ -972,6 +972,19 @@ static inline void sock_graft(struct sock *sk, struct socket *parent)
        write_unlock_bh(&sk->sk_callback_lock);
 }
 
+static inline void sock_copy(struct sock *nsk, const struct sock *osk)
+{
+#ifdef CONFIG_SECURITY_NETWORK
+       void *sptr = nsk->sk_security;
+#endif
+
+       memcpy(nsk, osk, osk->sk_prot->obj_size);
+#ifdef CONFIG_SECURITY_NETWORK
+       nsk->sk_security = sptr;
+       security_sk_clone(osk, nsk);
+#endif
+}
+
 extern int sock_i_uid(struct sock *sk);
 extern unsigned long sock_i_ino(struct sock *sk);
 
index 51fcfbc..b67d868 100644 (file)
@@ -911,7 +911,7 @@ struct sock *sk_clone(const struct sock *sk, const gfp_t priority)
        if (newsk != NULL) {
                struct sk_filter *filter;
 
-               memcpy(newsk, sk, sk->sk_prot->obj_size);
+               sock_copy(newsk, sk);
 
                /* SANITY */
                sk_node_init(&newsk->sk_node);
index 58c6d39..bd3bc5f 100644 (file)
@@ -805,6 +805,10 @@ static inline void dummy_sk_free_security (struct sock *sk)
 {
 }
 
+static inline void dummy_sk_clone_security (const struct sock *sk, struct sock *newsk)
+{
+}
+
 static unsigned int dummy_sk_getsid(struct sock *sk, struct flowi *fl, u8 dir)
 {
        return 0;
@@ -1060,6 +1064,7 @@ void security_fixup_ops (struct security_operations *ops)
        set_to_dummy_if_null(ops, socket_getpeersec_dgram);
        set_to_dummy_if_null(ops, sk_alloc_security);
        set_to_dummy_if_null(ops, sk_free_security);
+       set_to_dummy_if_null(ops, sk_clone_security);
        set_to_dummy_if_null(ops, sk_getsid);
  #endif        /* CONFIG_SECURITY_NETWORK */
 #ifdef  CONFIG_SECURITY_NETWORK_XFRM
index 5d1b8c7..d67abf7 100644 (file)
@@ -269,15 +269,13 @@ static int sk_alloc_security(struct sock *sk, int family, gfp_t priority)
 {
        struct sk_security_struct *ssec;
 
-       if (family != PF_UNIX)
-               return 0;
-
        ssec = kzalloc(sizeof(*ssec), priority);
        if (!ssec)
                return -ENOMEM;
 
        ssec->sk = sk;
        ssec->peer_sid = SECINITSID_UNLABELED;
+       ssec->sid = SECINITSID_UNLABELED;
        sk->sk_security = ssec;
 
        return 0;
@@ -287,9 +285,6 @@ static void sk_free_security(struct sock *sk)
 {
        struct sk_security_struct *ssec = sk->sk_security;
 
-       if (sk->sk_family != PF_UNIX)
-               return;
-
        sk->sk_security = NULL;
        kfree(ssec);
 }
@@ -3068,6 +3063,7 @@ static void selinux_socket_post_create(struct socket *sock, int family,
 {
        struct inode_security_struct *isec;
        struct task_security_struct *tsec;
+       struct sk_security_struct *sksec;
        u32 newsid;
 
        isec = SOCK_INODE(sock)->i_security;
@@ -3078,6 +3074,11 @@ static void selinux_socket_post_create(struct socket *sock, int family,
        isec->sid = kern ? SECINITSID_KERNEL : newsid;
        isec->initialized = 1;
 
+       if (sock->sk) {
+               sksec = sock->sk->sk_security;
+               sksec->sid = isec->sid;
+       }
+
        return;
 }
 
@@ -3551,22 +3552,24 @@ static void selinux_sk_free_security(struct sock *sk)
        sk_free_security(sk);
 }
 
-static unsigned int selinux_sk_getsid_security(struct sock *sk, struct flowi *fl, u8 dir)
+static void selinux_sk_clone_security(const struct sock *sk, struct sock *newsk)
 {
-       struct inode_security_struct *isec;
-       u32 sock_sid = SECINITSID_ANY_SOCKET;
+       struct sk_security_struct *ssec = sk->sk_security;
+       struct sk_security_struct *newssec = newsk->sk_security;
 
+       newssec->sid = ssec->sid;
+       newssec->peer_sid = ssec->peer_sid;
+}
+
+static unsigned int selinux_sk_getsid_security(struct sock *sk, struct flowi *fl, u8 dir)
+{
        if (!sk)
                return selinux_no_sk_sid(fl);
+       else {
+               struct sk_security_struct *sksec = sk->sk_security;
 
-       read_lock_bh(&sk->sk_callback_lock);
-       isec = get_sock_isec(sk);
-
-       if (isec)
-               sock_sid = isec->sid;
-
-       read_unlock_bh(&sk->sk_callback_lock);
-       return sock_sid;
+               return sksec->sid;
+       }
 }
 
 static int selinux_nlmsg_perm(struct sock *sk, struct sk_buff *skb)
@@ -4618,6 +4621,7 @@ static struct security_operations selinux_ops = {
        .socket_getpeersec_dgram =      selinux_socket_getpeersec_dgram,
        .sk_alloc_security =            selinux_sk_alloc_security,
        .sk_free_security =             selinux_sk_free_security,
+       .sk_clone_security =            selinux_sk_clone_security,
        .sk_getsid =                    selinux_sk_getsid_security,
 
 #ifdef CONFIG_SECURITY_NETWORK_XFRM
index 9401788..79b9e0a 100644 (file)
@@ -99,6 +99,7 @@ struct netif_security_struct {
 
 struct sk_security_struct {
        struct sock *sk;                /* back pointer to sk object */
+       u32 sid;                        /* SID of this object */
        u32 peer_sid;                   /* SID of peer */
 };