Commit 877ce7c1b3afd69a9b1caeb1b9964c992641f52a

Authored by Catherine Zhang
Committed by David S. Miller
1 parent d6b4991ad5

[AF_UNIX]: Datagram getpeersec

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>

Showing 26 changed files with 90 additions and 3 deletions Side-by-side Diff

include/asm-alpha/socket.h
... ... @@ -51,6 +51,7 @@
51 51 #define SCM_TIMESTAMP SO_TIMESTAMP
52 52  
53 53 #define SO_PEERSEC 30
  54 +#define SO_PASSSEC 34
54 55  
55 56 /* Security levels - as per NRL IPv6 - don't actually do anything */
56 57 #define SO_SECURITY_AUTHENTICATION 19
include/asm-arm/socket.h
... ... @@ -48,6 +48,7 @@
48 48 #define SO_ACCEPTCONN 30
49 49  
50 50 #define SO_PEERSEC 31
  51 +#define SO_PASSSEC 34
51 52  
52 53 #endif /* _ASM_SOCKET_H */
include/asm-arm26/socket.h
... ... @@ -48,6 +48,7 @@
48 48 #define SO_ACCEPTCONN 30
49 49  
50 50 #define SO_PEERSEC 31
  51 +#define SO_PASSSEC 34
51 52  
52 53 #endif /* _ASM_SOCKET_H */
include/asm-cris/socket.h
... ... @@ -50,6 +50,7 @@
50 50 #define SO_ACCEPTCONN 30
51 51  
52 52 #define SO_PEERSEC 31
  53 +#define SO_PASSSEC 34
53 54  
54 55 #endif /* _ASM_SOCKET_H */
include/asm-frv/socket.h
... ... @@ -48,6 +48,7 @@
48 48 #define SO_ACCEPTCONN 30
49 49  
50 50 #define SO_PEERSEC 31
  51 +#define SO_PASSSEC 34
51 52  
52 53 #endif /* _ASM_SOCKET_H */
include/asm-h8300/socket.h
... ... @@ -48,6 +48,7 @@
48 48 #define SO_ACCEPTCONN 30
49 49  
50 50 #define SO_PEERSEC 31
  51 +#define SO_PASSSEC 34
51 52  
52 53 #endif /* _ASM_SOCKET_H */
include/asm-i386/socket.h
... ... @@ -48,6 +48,7 @@
48 48 #define SO_ACCEPTCONN 30
49 49  
50 50 #define SO_PEERSEC 31
  51 +#define SO_PASSSEC 34
51 52  
52 53 #endif /* _ASM_SOCKET_H */
include/asm-ia64/socket.h
... ... @@ -57,6 +57,7 @@
57 57 #define SO_ACCEPTCONN 30
58 58  
59 59 #define SO_PEERSEC 31
  60 +#define SO_PASSSEC 34
60 61  
61 62 #endif /* _ASM_IA64_SOCKET_H */
include/asm-m32r/socket.h
... ... @@ -48,6 +48,7 @@
48 48 #define SO_ACCEPTCONN 30
49 49  
50 50 #define SO_PEERSEC 31
  51 +#define SO_PASSSEC 34
51 52  
52 53 #endif /* _ASM_M32R_SOCKET_H */
include/asm-m68k/socket.h
... ... @@ -48,6 +48,7 @@
48 48 #define SO_ACCEPTCONN 30
49 49  
50 50 #define SO_PEERSEC 31
  51 +#define SO_PASSSEC 34
51 52  
52 53 #endif /* _ASM_SOCKET_H */
include/asm-mips/socket.h
... ... @@ -69,6 +69,7 @@
69 69 #define SO_PEERSEC 30
70 70 #define SO_SNDBUFFORCE 31
71 71 #define SO_RCVBUFFORCE 33
  72 +#define SO_PASSSEC 34
72 73  
73 74 #ifdef __KERNEL__
74 75  
include/asm-parisc/socket.h
... ... @@ -48,6 +48,7 @@
48 48 #define SO_ACCEPTCONN 0x401c
49 49  
50 50 #define SO_PEERSEC 0x401d
  51 +#define SO_PASSSEC 0x401e
51 52  
52 53 #endif /* _ASM_SOCKET_H */
include/asm-powerpc/socket.h
... ... @@ -55,6 +55,7 @@
55 55 #define SO_ACCEPTCONN 30
56 56  
57 57 #define SO_PEERSEC 31
  58 +#define SO_PASSSEC 34
58 59  
59 60 #endif /* _ASM_POWERPC_SOCKET_H */
include/asm-s390/socket.h
... ... @@ -56,6 +56,7 @@
56 56 #define SO_ACCEPTCONN 30
57 57  
58 58 #define SO_PEERSEC 31
  59 +#define SO_PASSSEC 34
59 60  
60 61 #endif /* _ASM_SOCKET_H */
include/asm-sh/socket.h
... ... @@ -48,6 +48,7 @@
48 48 #define SO_ACCEPTCONN 30
49 49  
50 50 #define SO_PEERSEC 31
  51 +#define SO_PASSSEC 34
51 52  
52 53 #endif /* __ASM_SH_SOCKET_H */
include/asm-sparc/socket.h
... ... @@ -48,6 +48,7 @@
48 48 #define SCM_TIMESTAMP SO_TIMESTAMP
49 49  
50 50 #define SO_PEERSEC 0x001e
  51 +#define SO_PASSSEC 0x001f
51 52  
52 53 /* Security levels - as per NRL IPv6 - don't actually do anything */
53 54 #define SO_SECURITY_AUTHENTICATION 0x5001
include/asm-sparc64/socket.h
... ... @@ -48,6 +48,7 @@
48 48 #define SCM_TIMESTAMP SO_TIMESTAMP
49 49  
50 50 #define SO_PEERSEC 0x001e
  51 +#define SO_PASSSEC 0x001f
51 52  
52 53 /* Security levels - as per NRL IPv6 - don't actually do anything */
53 54 #define SO_SECURITY_AUTHENTICATION 0x5001
include/asm-v850/socket.h
... ... @@ -48,6 +48,7 @@
48 48 #define SO_ACCEPTCONN 30
49 49  
50 50 #define SO_PEERSEC 31
  51 +#define SO_PASSSEC 34
51 52  
52 53 #endif /* __V850_SOCKET_H__ */
include/asm-x86_64/socket.h
... ... @@ -48,6 +48,7 @@
48 48 #define SO_ACCEPTCONN 30
49 49  
50 50 #define SO_PEERSEC 31
  51 +#define SO_PASSSEC 34
51 52  
52 53 #endif /* _ASM_SOCKET_H */
include/asm-xtensa/socket.h
... ... @@ -59,6 +59,7 @@
59 59  
60 60 #define SO_ACCEPTCONN 30
61 61 #define SO_PEERSEC 31
  62 +#define SO_PASSSEC 34
62 63  
63 64 #endif /* _XTENSA_SOCKET_H */
... ... @@ -61,6 +61,7 @@
61 61 #define SOCK_ASYNC_WAITDATA 1
62 62 #define SOCK_NOSPACE 2
63 63 #define SOCK_PASSCRED 3
  64 +#define SOCK_PASSSEC 4
64 65  
65 66 #ifndef ARCH_HAS_SOCKET_TYPES
66 67 /**
include/net/af_unix.h
... ... @@ -53,10 +53,16 @@
53 53 struct unix_skb_parms {
54 54 struct ucred creds; /* Skb credentials */
55 55 struct scm_fp_list *fp; /* Passed files */
  56 +#ifdef CONFIG_SECURITY_NETWORK
  57 + char *secdata; /* Security context */
  58 + u32 seclen; /* Security length */
  59 +#endif
56 60 };
57 61  
58 62 #define UNIXCB(skb) (*(struct unix_skb_parms*)&((skb)->cb))
59 63 #define UNIXCREDS(skb) (&UNIXCB((skb)).creds)
  64 +#define UNIXSECDATA(skb) (&UNIXCB((skb)).secdata)
  65 +#define UNIXSECLEN(skb) (&UNIXCB((skb)).seclen)
60 66  
61 67 #define unix_state_rlock(s) spin_lock(&unix_sk(s)->lock)
62 68 #define unix_state_runlock(s) spin_unlock(&unix_sk(s)->lock)
... ... @@ -19,6 +19,10 @@
19 19 {
20 20 struct ucred creds; /* Skb credentials */
21 21 struct scm_fp_list *fp; /* Passed files */
  22 +#ifdef CONFIG_SECURITY_NETWORK
  23 + char *secdata; /* Security context */
  24 + u32 seclen; /* Security length */
  25 +#endif
22 26 unsigned long seq; /* Connection seqno */
23 27 };
24 28  
... ... @@ -48,6 +52,17 @@
48 52 return __scm_send(sock, msg, scm);
49 53 }
50 54  
  55 +#ifdef CONFIG_SECURITY_NETWORK
  56 +static inline void scm_passec(struct socket *sock, struct msghdr *msg, struct scm_cookie *scm)
  57 +{
  58 + if (test_bit(SOCK_PASSSEC, &sock->flags) && scm->secdata != NULL)
  59 + put_cmsg(msg, SOL_SOCKET, SCM_SECURITY, scm->seclen, scm->secdata);
  60 +}
  61 +#else
  62 +static inline void scm_passec(struct socket *sock, struct msghdr *msg, struct scm_cookie *scm)
  63 +{ }
  64 +#endif /* CONFIG_SECURITY_NETWORK */
  65 +
51 66 static __inline__ void scm_recv(struct socket *sock, struct msghdr *msg,
52 67 struct scm_cookie *scm, int flags)
53 68 {
... ... @@ -61,6 +76,8 @@
61 76  
62 77 if (test_bit(SOCK_PASSCRED, &sock->flags))
63 78 put_cmsg(msg, SOL_SOCKET, SCM_CREDENTIALS, sizeof(scm->creds), &scm->creds);
  79 +
  80 + scm_passec(sock, msg, scm);
64 81  
65 82 if (!scm->fp)
66 83 return;
... ... @@ -565,6 +565,13 @@
565 565 ret = -ENONET;
566 566 break;
567 567  
  568 + case SO_PASSSEC:
  569 + if (valbool)
  570 + set_bit(SOCK_PASSSEC, &sock->flags);
  571 + else
  572 + clear_bit(SOCK_PASSSEC, &sock->flags);
  573 + break;
  574 +
568 575 /* We implement the SO_SNDLOWAT etc to
569 576 not be settable (1003.1g 5.3) */
570 577 default:
... ... @@ -721,6 +728,10 @@
721 728 */
722 729 case SO_ACCEPTCONN:
723 730 v.val = sk->sk_state == TCP_LISTEN;
  731 + break;
  732 +
  733 + case SO_PASSSEC:
  734 + v.val = test_bit(SOCK_PASSSEC, &sock->flags) ? 1 : 0;
724 735 break;
725 736  
726 737 case SO_PEERSEC:
... ... @@ -128,6 +128,30 @@
128 128  
129 129 #define UNIX_ABSTRACT(sk) (unix_sk(sk)->addr->hash != UNIX_HASH_SIZE)
130 130  
  131 +#ifdef CONFIG_SECURITY_NETWORK
  132 +static void unix_get_peersec_dgram(struct sk_buff *skb)
  133 +{
  134 + int err;
  135 +
  136 + err = security_socket_getpeersec_dgram(skb, UNIXSECDATA(skb),
  137 + UNIXSECLEN(skb));
  138 + if (err)
  139 + *(UNIXSECDATA(skb)) = NULL;
  140 +}
  141 +
  142 +static inline void unix_set_secdata(struct scm_cookie *scm, struct sk_buff *skb)
  143 +{
  144 + scm->secdata = *UNIXSECDATA(skb);
  145 + scm->seclen = *UNIXSECLEN(skb);
  146 +}
  147 +#else
  148 +static void unix_get_peersec_dgram(struct sk_buff *skb)
  149 +{ }
  150 +
  151 +static inline void unix_set_secdata(struct scm_cookie *scm, struct sk_buff *skb)
  152 +{ }
  153 +#endif /* CONFIG_SECURITY_NETWORK */
  154 +
131 155 /*
132 156 * SMP locking strategy:
133 157 * hash table is protected with spinlock unix_table_lock
... ... @@ -1291,6 +1315,8 @@
1291 1315 if (siocb->scm->fp)
1292 1316 unix_attach_fds(siocb->scm, skb);
1293 1317  
  1318 + unix_get_peersec_dgram(skb);
  1319 +
1294 1320 skb->h.raw = skb->data;
1295 1321 err = memcpy_fromiovec(skb_put(skb,len), msg->msg_iov, len);
1296 1322 if (err)
... ... @@ -1570,6 +1596,7 @@
1570 1596 memset(&tmp_scm, 0, sizeof(tmp_scm));
1571 1597 }
1572 1598 siocb->scm->creds = *UNIXCREDS(skb);
  1599 + unix_set_secdata(siocb->scm, skb);
1573 1600  
1574 1601 if (!(flags & MSG_PEEK))
1575 1602 {
security/selinux/hooks.c
... ... @@ -69,6 +69,7 @@
69 69 #include <linux/sysctl.h>
70 70 #include <linux/audit.h>
71 71 #include <linux/string.h>
  72 +#include <linux/selinux.h>
72 73  
73 74 #include "avc.h"
74 75 #include "objsec.h"
75 76  
... ... @@ -3420,8 +3421,14 @@
3420 3421 static int selinux_socket_getpeersec_dgram(struct sk_buff *skb, char **secdata, u32 *seclen)
3421 3422 {
3422 3423 int err = 0;
3423   - u32 peer_sid = selinux_socket_getpeer_dgram(skb);
  3424 + u32 peer_sid;
3424 3425  
  3426 + if (skb->sk->sk_family == PF_UNIX)
  3427 + selinux_get_inode_sid(SOCK_INODE(skb->sk->sk_socket),
  3428 + &peer_sid);
  3429 + else
  3430 + peer_sid = selinux_socket_getpeer_dgram(skb);
  3431 +
3425 3432 if (peer_sid == SECSID_NULL)
3426 3433 return -EINVAL;
3427 3434  
... ... @@ -3431,8 +3438,6 @@
3431 3438  
3432 3439 return 0;
3433 3440 }
3434   -
3435   -
3436 3441  
3437 3442 static int selinux_sk_alloc_security(struct sock *sk, int family, gfp_t priority)
3438 3443 {