Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

net/unix: support SCM_SECURITY for stream sockets

SCM_SECURITY was originally only implemented for datagram sockets,
not for stream sockets. However, SCM_CREDENTIALS is supported on
Unix stream sockets. For consistency, implement Unix stream support
for SCM_SECURITY as well. Also clean up the existing code and get
rid of the superfluous UNIXSID macro.

Motivated by https://bugzilla.redhat.com/show_bug.cgi?id=1224211,
where systemd was using SCM_CREDENTIALS and assumed wrongly that
SCM_SECURITY was also supported on Unix stream sockets.

Signed-off-by: Stephen Smalley <sds@tycho.nsa.gov>
Acked-by: Paul Moore <paul@paul-moore.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Stephen Smalley and committed by
David S. Miller
37a9a8df bae23b68

+16 -5
-1
include/net/af_unix.h
··· 39 39 }; 40 40 41 41 #define UNIXCB(skb) (*(struct unix_skb_parms *)&((skb)->cb)) 42 - #define UNIXSID(skb) (&UNIXCB((skb)).secid) 43 42 44 43 #define unix_state_lock(s) spin_lock(&unix_sk(s)->lock) 45 44 #define unix_state_unlock(s) spin_unlock(&unix_sk(s)->lock)
+16 -4
net/unix/af_unix.c
··· 140 140 #ifdef CONFIG_SECURITY_NETWORK 141 141 static void unix_get_secdata(struct scm_cookie *scm, struct sk_buff *skb) 142 142 { 143 - memcpy(UNIXSID(skb), &scm->secid, sizeof(u32)); 143 + UNIXCB(skb).secid = scm->secid; 144 144 } 145 145 146 146 static inline void unix_set_secdata(struct scm_cookie *scm, struct sk_buff *skb) 147 147 { 148 - scm->secid = *UNIXSID(skb); 148 + scm->secid = UNIXCB(skb).secid; 149 + } 150 + 151 + static inline bool unix_secdata_eq(struct scm_cookie *scm, struct sk_buff *skb) 152 + { 153 + return (scm->secid == UNIXCB(skb).secid); 149 154 } 150 155 #else 151 156 static inline void unix_get_secdata(struct scm_cookie *scm, struct sk_buff *skb) ··· 158 153 159 154 static inline void unix_set_secdata(struct scm_cookie *scm, struct sk_buff *skb) 160 155 { } 156 + 157 + static inline bool unix_secdata_eq(struct scm_cookie *scm, struct sk_buff *skb) 158 + { 159 + return true; 160 + } 161 161 #endif /* CONFIG_SECURITY_NETWORK */ 162 162 163 163 /* ··· 1424 1414 UNIXCB(skb).uid = scm->creds.uid; 1425 1415 UNIXCB(skb).gid = scm->creds.gid; 1426 1416 UNIXCB(skb).fp = NULL; 1417 + unix_get_secdata(scm, skb); 1427 1418 if (scm->fp && send_fds) 1428 1419 err = unix_attach_fds(scm, skb); 1429 1420 ··· 1520 1509 if (err < 0) 1521 1510 goto out_free; 1522 1511 max_level = err + 1; 1523 - unix_get_secdata(&scm, skb); 1524 1512 1525 1513 skb_put(skb, len - data_len); 1526 1514 skb->data_len = data_len; ··· 2128 2118 /* Never glue messages from different writers */ 2129 2119 if ((UNIXCB(skb).pid != scm.pid) || 2130 2120 !uid_eq(UNIXCB(skb).uid, scm.creds.uid) || 2131 - !gid_eq(UNIXCB(skb).gid, scm.creds.gid)) 2121 + !gid_eq(UNIXCB(skb).gid, scm.creds.gid) || 2122 + !unix_secdata_eq(&scm, skb)) 2132 2123 break; 2133 2124 } else if (test_bit(SOCK_PASSCRED, &sock->flags)) { 2134 2125 /* Copy credentials */ 2135 2126 scm_set_cred(&scm, UNIXCB(skb).pid, UNIXCB(skb).uid, UNIXCB(skb).gid); 2127 + unix_set_secdata(&scm, skb); 2136 2128 check_creds = true; 2137 2129 } 2138 2130