[AF_UNIX]: Datagram getpeersec
authorCatherine Zhang <cxzhang@watson.ibm.com>
Thu, 29 Jun 2006 19:27:47 +0000 (12:27 -0700)
committerDavid S. Miller <davem@sunset.davemloft.net>
Thu, 29 Jun 2006 23:58:06 +0000 (16:58 -0700)
This patch implements an API whereby an application can determine the
label of its peer's Unix datagram sockets via the auxiliary data mechanism of
recvmsg.

Patch purpose:

This patch enables a security-aware application to retrieve the
security context of the peer of a Unix datagram socket.  The application
can then use this security context to determine the security context for
processing on behalf of the peer who sent the packet.

Patch design and implementation:

The design and implementation is very similar to the UDP case for INET
sockets.  Basically we build upon the existing Unix domain socket API for
retrieving user credentials.  Linux offers the API for obtaining user
credentials via ancillary messages (i.e., out of band/control messages
that are bundled together with a normal message).  To retrieve the security
context, the application first indicates to the kernel such desire by
setting the SO_PASSSEC option via getsockopt.  Then the application
retrieves the security context using the auxiliary data mechanism.

An example server application for Unix datagram socket should look like this:

toggle = 1;
toggle_len = sizeof(toggle);

setsockopt(sockfd, SOL_SOCKET, SO_PASSSEC, &toggle, &toggle_len);
recvmsg(sockfd, &msg_hdr, 0);
if (msg_hdr.msg_controllen > sizeof(struct cmsghdr)) {
    cmsg_hdr = CMSG_FIRSTHDR(&msg_hdr);
    if (cmsg_hdr->cmsg_len <= CMSG_LEN(sizeof(scontext)) &&
        cmsg_hdr->cmsg_level == SOL_SOCKET &&
        cmsg_hdr->cmsg_type == SCM_SECURITY) {
        memcpy(&scontext, CMSG_DATA(cmsg_hdr), sizeof(scontext));
    }
}

sock_setsockopt is enhanced with a new socket option SOCK_PASSSEC to allow
a server socket to receive security context of the peer.

Testing:

We have tested the patch by setting up Unix datagram client and server
applications.  We verified that the server can retrieve the security context
using the auxiliary data mechanism of recvmsg.

Signed-off-by: Catherine Zhang <cxzhang@watson.ibm.com>
Acked-by: Acked-by: James Morris <jmorris@namei.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
26 files changed:
include/asm-alpha/socket.h
include/asm-arm/socket.h
include/asm-arm26/socket.h
include/asm-cris/socket.h
include/asm-frv/socket.h
include/asm-h8300/socket.h
include/asm-i386/socket.h
include/asm-ia64/socket.h
include/asm-m32r/socket.h
include/asm-m68k/socket.h
include/asm-mips/socket.h
include/asm-parisc/socket.h
include/asm-powerpc/socket.h
include/asm-s390/socket.h
include/asm-sh/socket.h
include/asm-sparc/socket.h
include/asm-sparc64/socket.h
include/asm-v850/socket.h
include/asm-x86_64/socket.h
include/asm-xtensa/socket.h
include/linux/net.h
include/net/af_unix.h
include/net/scm.h
net/core/sock.c
net/unix/af_unix.c
security/selinux/hooks.c

index b5193229132a12e5f73bfe510830aef1ab95235b..d22ab97ea72efc27e45ef4573498baef7c3a1059 100644 (file)
@@ -51,6 +51,7 @@
 #define SCM_TIMESTAMP          SO_TIMESTAMP
 
 #define SO_PEERSEC             30
+#define SO_PASSSEC             34
 
 /* Security levels - as per NRL IPv6 - don't actually do anything */
 #define SO_SECURITY_AUTHENTICATION             19
index 3c51da6438c95b6734e38243ebdbb21af5a6972a..19f7df702b069ebb8398dc3f2dc9d16d9564ec95 100644 (file)
@@ -48,5 +48,6 @@
 #define SO_ACCEPTCONN          30
 
 #define SO_PEERSEC             31
+#define SO_PASSSEC             34
 
 #endif /* _ASM_SOCKET_H */
index 3c51da6438c95b6734e38243ebdbb21af5a6972a..19f7df702b069ebb8398dc3f2dc9d16d9564ec95 100644 (file)
@@ -48,5 +48,6 @@
 #define SO_ACCEPTCONN          30
 
 #define SO_PEERSEC             31
+#define SO_PASSSEC             34
 
 #endif /* _ASM_SOCKET_H */
index 8b1da3e58c5580468f60961c498592b71c7f56c7..01cfdf1d6d339ab2f0b4a25649989e6cacfa9ea8 100644 (file)
@@ -50,6 +50,7 @@
 #define SO_ACCEPTCONN          30
 
 #define SO_PEERSEC             31
+#define SO_PASSSEC             34
 
 #endif /* _ASM_SOCKET_H */
 
index 7177f8b9817cc3586bf6c4bd4b21662ed32d2d72..31db18fc871fa07af87aad3a932eac3a46003362 100644 (file)
@@ -48,6 +48,7 @@
 #define SO_ACCEPTCONN          30
 
 #define SO_PEERSEC             31
+#define SO_PASSSEC             34
 
 #endif /* _ASM_SOCKET_H */
 
index d98cf85bafc1d667d9d2ebdac62752a7da267214..ebc830fee0d0888ce1f3e938d06d1d1832205ac4 100644 (file)
@@ -48,5 +48,6 @@
 #define SO_ACCEPTCONN          30
 
 #define SO_PEERSEC             31
+#define SO_PASSSEC             34
 
 #endif /* _ASM_SOCKET_H */
index 802ae76195b72a4a09e3f9c052e96968389be694..5755d57c4e952c121a0a215c94778cbf1c1386e6 100644 (file)
@@ -48,5 +48,6 @@
 #define SO_ACCEPTCONN          30
 
 #define SO_PEERSEC             31
+#define SO_PASSSEC             34
 
 #endif /* _ASM_SOCKET_H */
index a255006fb7b51f0db085e82f547f25938ee7c84c..d638ef3d50c3a5767a7d6a50496d47775c2145dc 100644 (file)
@@ -57,5 +57,6 @@
 #define SO_ACCEPTCONN          30
 
 #define SO_PEERSEC             31
+#define SO_PASSSEC             34
 
 #endif /* _ASM_IA64_SOCKET_H */
index 8b6680f223c0b4a5f18781f36129cc1d541b68f8..acdf748fcdc8a38220ffea31e946947ca671bee1 100644 (file)
@@ -48,5 +48,6 @@
 #define SO_ACCEPTCONN          30
 
 #define SO_PEERSEC             31
+#define SO_PASSSEC             34
 
 #endif /* _ASM_M32R_SOCKET_H */
index f578ca4b776a3bfcb45b1e60781ebeb74eac785c..a5966ec005ae67d1bdb338aa209f1cf76f85bf78 100644 (file)
@@ -48,5 +48,6 @@
 #define SO_ACCEPTCONN          30
 
 #define SO_PEERSEC             31
+#define SO_PASSSEC             34
 
 #endif /* _ASM_SOCKET_H */
index 0bb31e5aaca6a23f93ffcf7aaa02ae41118e6be5..36ebe4e186a7a635970909c46f03cd8b394bc367 100644 (file)
@@ -69,6 +69,7 @@ To add: #define SO_REUSEPORT 0x0200   /* Allow local address and port reuse.  */
 #define SO_PEERSEC             30
 #define SO_SNDBUFFORCE         31
 #define SO_RCVBUFFORCE         33
+#define SO_PASSSEC             34
 
 #ifdef __KERNEL__
 
index 1bf54dc53c101337200deeaafa7adcf27daf97ff..ce2eae1708b5ec84ad7976c83984c35ceb5b2122 100644 (file)
@@ -48,5 +48,6 @@
 #define SO_ACCEPTCONN          0x401c
 
 #define SO_PEERSEC             0x401d
+#define SO_PASSSEC             0x401e
 
 #endif /* _ASM_SOCKET_H */
index e4b8177d4acc48313dbb905bbf59400d659f0253..c8b1da50e72db7df8be5c61b36d8f6694461fd55 100644 (file)
@@ -55,5 +55,6 @@
 #define SO_ACCEPTCONN          30
 
 #define SO_PEERSEC             31
+#define SO_PASSSEC             34
 
 #endif /* _ASM_POWERPC_SOCKET_H */
index 15a5298c8744bf1401be8b0cb736b406b410d55d..1778a49a74c5b0fd24facee8d5d49fc3657f3600 100644 (file)
@@ -56,5 +56,6 @@
 #define SO_ACCEPTCONN          30
 
 #define SO_PEERSEC             31
+#define SO_PASSSEC             34
 
 #endif /* _ASM_SOCKET_H */
index 553904ff9336c2e26304810e0f0db20e0f4a4220..ca70362eb563bf7224d743340dde1364dc824242 100644 (file)
@@ -48,5 +48,6 @@
 #define SO_ACCEPTCONN          30
 
 #define SO_PEERSEC             31
+#define SO_PASSSEC             34
 
 #endif /* __ASM_SH_SOCKET_H */
index 4e0ce3a35ea9d48b62a5195b49daba535fa1e596..f6c4e5baf3f7bd4ea9c065b25c9d49d723de1ace 100644 (file)
@@ -48,6 +48,7 @@
 #define SCM_TIMESTAMP          SO_TIMESTAMP
 
 #define SO_PEERSEC             0x001e
+#define SO_PASSSEC             0x001f
 
 /* Security levels - as per NRL IPv6 - don't actually do anything */
 #define SO_SECURITY_AUTHENTICATION             0x5001
index 59987dad3359912059a37039512dafc807c5d2df..754d46a50af30af85564808262592cc16f59fe48 100644 (file)
@@ -48,6 +48,7 @@
 #define SCM_TIMESTAMP          SO_TIMESTAMP
 
 #define SO_PEERSEC             0x001e
+#define SO_PASSSEC             0x001f
 
 /* Security levels - as per NRL IPv6 - don't actually do anything */
 #define SO_SECURITY_AUTHENTICATION             0x5001
index 0240d366a0a4db32672c6e20c734efe21e32aa17..0dfe55ac2ef2acf1deeb4e72e8ca112a770d8c8a 100644 (file)
@@ -48,5 +48,6 @@
 #define SO_ACCEPTCONN          30
 
 #define SO_PEERSEC             31
+#define SO_PASSSEC             34
 
 #endif /* __V850_SOCKET_H__ */
index f2cdbeae5d5ba17e453f24aa172f6076f9441f9b..b46702607933ddedf9e5dc323da8d4c787799e94 100644 (file)
@@ -48,5 +48,6 @@
 #define SO_ACCEPTCONN          30
 
 #define SO_PEERSEC             31
+#define SO_PASSSEC             34
 
 #endif /* _ASM_SOCKET_H */
index 00f83f3a6d72194ad0b0f3059897cecde2d61e0f..971d231be60ebe095f9a5b29e21831662df2e1f8 100644 (file)
@@ -59,5 +59,6 @@
 
 #define SO_ACCEPTCONN          30
 #define SO_PEERSEC             31
+#define SO_PASSSEC             34
 
 #endif /* _XTENSA_SOCKET_H */
index 385e68f5bd93264c96f1e29c3f720f3b3921a8be..b20c53c744130384ae7ad28a9b8a6d1bdf5ff716 100644 (file)
@@ -61,6 +61,7 @@ typedef enum {
 #define SOCK_ASYNC_WAITDATA    1
 #define SOCK_NOSPACE           2
 #define SOCK_PASSCRED          3
+#define SOCK_PASSSEC           4
 
 #ifndef ARCH_HAS_SOCKET_TYPES
 /**
index 795f81f9ec7ff9c4e064e085d6c491d351a39f19..5ba72d95280c3f87a4aa3f434805e375f69dc9e6 100644 (file)
@@ -53,10 +53,16 @@ struct unix_address {
 struct unix_skb_parms {
        struct ucred            creds;          /* Skb credentials      */
        struct scm_fp_list      *fp;            /* Passed files         */
+#ifdef CONFIG_SECURITY_NETWORK
+       char                    *secdata;       /* Security context     */
+       u32                     seclen;         /* Security length      */
+#endif
 };
 
 #define UNIXCB(skb)    (*(struct unix_skb_parms*)&((skb)->cb))
 #define UNIXCREDS(skb) (&UNIXCB((skb)).creds)
+#define UNIXSECDATA(skb)       (&UNIXCB((skb)).secdata)
+#define UNIXSECLEN(skb)                (&UNIXCB((skb)).seclen)
 
 #define unix_state_rlock(s)    spin_lock(&unix_sk(s)->lock)
 #define unix_state_runlock(s)  spin_unlock(&unix_sk(s)->lock)
index 540619cb7160f20e590471110ce63811c1d6e267..02daa097cdcd0cefcf81be18e75667a910ccf1a6 100644 (file)
@@ -19,6 +19,10 @@ struct scm_cookie
 {
        struct ucred            creds;          /* Skb credentials      */
        struct scm_fp_list      *fp;            /* Passed files         */
+#ifdef CONFIG_SECURITY_NETWORK
+       char                    *secdata;       /* Security context     */
+       u32                     seclen;         /* Security length      */
+#endif
        unsigned long           seq;            /* Connection seqno     */
 };
 
@@ -48,6 +52,17 @@ static __inline__ int scm_send(struct socket *sock, struct msghdr *msg,
        return __scm_send(sock, msg, scm);
 }
 
+#ifdef CONFIG_SECURITY_NETWORK
+static inline void scm_passec(struct socket *sock, struct msghdr *msg, struct scm_cookie *scm)
+{
+       if (test_bit(SOCK_PASSSEC, &sock->flags) && scm->secdata != NULL)
+               put_cmsg(msg, SOL_SOCKET, SCM_SECURITY, scm->seclen, scm->secdata);
+}
+#else
+static inline void scm_passec(struct socket *sock, struct msghdr *msg, struct scm_cookie *scm)
+{ }
+#endif /* CONFIG_SECURITY_NETWORK */
+
 static __inline__ void scm_recv(struct socket *sock, struct msghdr *msg,
                                struct scm_cookie *scm, int flags)
 {
@@ -62,6 +77,8 @@ static __inline__ void scm_recv(struct socket *sock, struct msghdr *msg,
        if (test_bit(SOCK_PASSCRED, &sock->flags))
                put_cmsg(msg, SOL_SOCKET, SCM_CREDENTIALS, sizeof(scm->creds), &scm->creds);
 
+       scm_passec(sock, msg, scm);
+
        if (!scm->fp)
                return;
        
index 5d820c3766530a991056050d23be7013107ae20c..204a8dec65cc76503ff6bf209b8ec6c8956ac17e 100644 (file)
@@ -565,6 +565,13 @@ set_rcvbuf:
                        ret = -ENONET;
                        break;
 
+               case SO_PASSSEC:
+                       if (valbool)
+                               set_bit(SOCK_PASSSEC, &sock->flags);
+                       else
+                               clear_bit(SOCK_PASSSEC, &sock->flags);
+                       break;
+
                /* We implement the SO_SNDLOWAT etc to
                   not be settable (1003.1g 5.3) */
                default:
@@ -723,6 +730,10 @@ int sock_getsockopt(struct socket *sock, int level, int optname,
                        v.val = sk->sk_state == TCP_LISTEN;
                        break;
 
+               case SO_PASSSEC:
+                       v.val = test_bit(SOCK_PASSSEC, &sock->flags) ? 1 : 0;
+                       break;
+
                case SO_PEERSEC:
                        return security_socket_getpeersec_stream(sock, optval, optlen, len);
 
index d901465ce0135093276d55adabbb7691591097c3..fd11d4048b5223c1fe7b39e4dc66f82b0f988f67 100644 (file)
@@ -128,6 +128,30 @@ static atomic_t unix_nr_socks = ATOMIC_INIT(0);
 
 #define UNIX_ABSTRACT(sk)      (unix_sk(sk)->addr->hash != UNIX_HASH_SIZE)
 
+#ifdef CONFIG_SECURITY_NETWORK
+static void unix_get_peersec_dgram(struct sk_buff *skb)
+{
+       int err;
+
+       err = security_socket_getpeersec_dgram(skb, UNIXSECDATA(skb),
+                                              UNIXSECLEN(skb));
+       if (err)
+               *(UNIXSECDATA(skb)) = NULL;
+}
+
+static inline void unix_set_secdata(struct scm_cookie *scm, struct sk_buff *skb)
+{
+       scm->secdata = *UNIXSECDATA(skb);
+       scm->seclen = *UNIXSECLEN(skb);
+}
+#else
+static void unix_get_peersec_dgram(struct sk_buff *skb)
+{ }
+
+static inline void unix_set_secdata(struct scm_cookie *scm, struct sk_buff *skb)
+{ }
+#endif /* CONFIG_SECURITY_NETWORK */
+
 /*
  *  SMP locking strategy:
  *    hash table is protected with spinlock unix_table_lock
@@ -1291,6 +1315,8 @@ static int unix_dgram_sendmsg(struct kiocb *kiocb, struct socket *sock,
        if (siocb->scm->fp)
                unix_attach_fds(siocb->scm, skb);
 
+       unix_get_peersec_dgram(skb);
+
        skb->h.raw = skb->data;
        err = memcpy_fromiovec(skb_put(skb,len), msg->msg_iov, len);
        if (err)
@@ -1570,6 +1596,7 @@ static int unix_dgram_recvmsg(struct kiocb *iocb, struct socket *sock,
                memset(&tmp_scm, 0, sizeof(tmp_scm));
        }
        siocb->scm->creds = *UNIXCREDS(skb);
+       unix_set_secdata(siocb->scm, skb);
 
        if (!(flags & MSG_PEEK))
        {
index b6c378dd4f122345a48db105c848f13f0a3ad214..b85afcf3852774166aeb5b9b65200388e8ee4a72 100644 (file)
@@ -69,6 +69,7 @@
 #include <linux/sysctl.h>
 #include <linux/audit.h>
 #include <linux/string.h>
+#include <linux/selinux.h>
 
 #include "avc.h"
 #include "objsec.h"
@@ -3420,7 +3421,13 @@ out:
 static int selinux_socket_getpeersec_dgram(struct sk_buff *skb, char **secdata, u32 *seclen)
 {
        int err = 0;
-       u32 peer_sid = selinux_socket_getpeer_dgram(skb);
+       u32 peer_sid;
+
+       if (skb->sk->sk_family == PF_UNIX)
+               selinux_get_inode_sid(SOCK_INODE(skb->sk->sk_socket),
+                                     &peer_sid);
+       else
+               peer_sid = selinux_socket_getpeer_dgram(skb);
 
        if (peer_sid == SECSID_NULL)
                return -EINVAL;
@@ -3432,8 +3439,6 @@ static int selinux_socket_getpeersec_dgram(struct sk_buff *skb, char **secdata,
        return 0;
 }
 
-
-
 static int selinux_sk_alloc_security(struct sock *sk, int family, gfp_t priority)
 {
        return sk_alloc_security(sk, family, priority);