aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorEric W. Biederman <ebiederm@xmission.com>2010-06-12 23:34:33 -0400
committerDavid S. Miller <davem@davemloft.net>2010-06-16 17:58:16 -0400
commit7361c36c5224519b258219fe3d0e8abc865d8134 (patch)
tree7987367633b4729dff0afa2180862a2ce919f3cb /net
parent257b5358b32f17e0603b6ff57b13610b0e02348f (diff)
af_unix: Allow credentials to work across user and pid namespaces.
In unix_skb_parms store pointers to struct pid and struct cred instead of raw uid, gid, and pid values, then translate the credentials on reception into values that are meaningful in the receiving processes namespaces. Signed-off-by: Eric W. Biederman <ebiederm@xmission.com> Acked-by: Pavel Emelyanov <xemul@openvz.org> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r--net/unix/af_unix.c53
1 files changed, 31 insertions, 22 deletions
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index e1f1349fae86..5fe9d6fe08b8 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -1316,18 +1316,20 @@ static void unix_detach_fds(struct scm_cookie *scm, struct sk_buff *skb)
1316 int i; 1316 int i;
1317 1317
1318 scm->fp = UNIXCB(skb).fp; 1318 scm->fp = UNIXCB(skb).fp;
1319 skb->destructor = sock_wfree;
1320 UNIXCB(skb).fp = NULL; 1319 UNIXCB(skb).fp = NULL;
1321 1320
1322 for (i = scm->fp->count-1; i >= 0; i--) 1321 for (i = scm->fp->count-1; i >= 0; i--)
1323 unix_notinflight(scm->fp->fp[i]); 1322 unix_notinflight(scm->fp->fp[i]);
1324} 1323}
1325 1324
1326static void unix_destruct_fds(struct sk_buff *skb) 1325static void unix_destruct_scm(struct sk_buff *skb)
1327{ 1326{
1328 struct scm_cookie scm; 1327 struct scm_cookie scm;
1329 memset(&scm, 0, sizeof(scm)); 1328 memset(&scm, 0, sizeof(scm));
1330 unix_detach_fds(&scm, skb); 1329 scm.pid = UNIXCB(skb).pid;
1330 scm.cred = UNIXCB(skb).cred;
1331 if (UNIXCB(skb).fp)
1332 unix_detach_fds(&scm, skb);
1331 1333
1332 /* Alas, it calls VFS */ 1334 /* Alas, it calls VFS */
1333 /* So fscking what? fput() had been SMP-safe since the last Summer */ 1335 /* So fscking what? fput() had been SMP-safe since the last Summer */
@@ -1350,10 +1352,22 @@ static int unix_attach_fds(struct scm_cookie *scm, struct sk_buff *skb)
1350 1352
1351 for (i = scm->fp->count-1; i >= 0; i--) 1353 for (i = scm->fp->count-1; i >= 0; i--)
1352 unix_inflight(scm->fp->fp[i]); 1354 unix_inflight(scm->fp->fp[i]);
1353 skb->destructor = unix_destruct_fds;
1354 return 0; 1355 return 0;
1355} 1356}
1356 1357
1358static int unix_scm_to_skb(struct scm_cookie *scm, struct sk_buff *skb, bool send_fds)
1359{
1360 int err = 0;
1361 UNIXCB(skb).pid = get_pid(scm->pid);
1362 UNIXCB(skb).cred = get_cred(scm->cred);
1363 UNIXCB(skb).fp = NULL;
1364 if (scm->fp && send_fds)
1365 err = unix_attach_fds(scm, skb);
1366
1367 skb->destructor = unix_destruct_scm;
1368 return err;
1369}
1370
1357/* 1371/*
1358 * Send AF_UNIX data. 1372 * Send AF_UNIX data.
1359 */ 1373 */
@@ -1410,12 +1424,9 @@ static int unix_dgram_sendmsg(struct kiocb *kiocb, struct socket *sock,
1410 if (skb == NULL) 1424 if (skb == NULL)
1411 goto out; 1425 goto out;
1412 1426
1413 memcpy(UNIXCREDS(skb), &siocb->scm->creds, sizeof(struct ucred)); 1427 err = unix_scm_to_skb(siocb->scm, skb, true);
1414 if (siocb->scm->fp) { 1428 if (err)
1415 err = unix_attach_fds(siocb->scm, skb); 1429 goto out_free;
1416 if (err)
1417 goto out_free;
1418 }
1419 unix_get_secdata(siocb->scm, skb); 1430 unix_get_secdata(siocb->scm, skb);
1420 1431
1421 skb_reset_transport_header(skb); 1432 skb_reset_transport_header(skb);
@@ -1585,16 +1596,14 @@ static int unix_stream_sendmsg(struct kiocb *kiocb, struct socket *sock,
1585 */ 1596 */
1586 size = min_t(int, size, skb_tailroom(skb)); 1597 size = min_t(int, size, skb_tailroom(skb));
1587 1598
1588 memcpy(UNIXCREDS(skb), &siocb->scm->creds, sizeof(struct ucred)); 1599
1589 /* Only send the fds in the first buffer */ 1600 /* Only send the fds in the first buffer */
1590 if (siocb->scm->fp && !fds_sent) { 1601 err = unix_scm_to_skb(siocb->scm, skb, !fds_sent);
1591 err = unix_attach_fds(siocb->scm, skb); 1602 if (err) {
1592 if (err) { 1603 kfree_skb(skb);
1593 kfree_skb(skb); 1604 goto out_err;
1594 goto out_err;
1595 }
1596 fds_sent = true;
1597 } 1605 }
1606 fds_sent = true;
1598 1607
1599 err = memcpy_fromiovec(skb_put(skb, size), msg->msg_iov, size); 1608 err = memcpy_fromiovec(skb_put(skb, size), msg->msg_iov, size);
1600 if (err) { 1609 if (err) {
@@ -1711,7 +1720,7 @@ static int unix_dgram_recvmsg(struct kiocb *iocb, struct socket *sock,
1711 siocb->scm = &tmp_scm; 1720 siocb->scm = &tmp_scm;
1712 memset(&tmp_scm, 0, sizeof(tmp_scm)); 1721 memset(&tmp_scm, 0, sizeof(tmp_scm));
1713 } 1722 }
1714 siocb->scm->creds = *UNIXCREDS(skb); 1723 scm_set_cred(siocb->scm, UNIXCB(skb).pid, UNIXCB(skb).cred);
1715 unix_set_secdata(siocb->scm, skb); 1724 unix_set_secdata(siocb->scm, skb);
1716 1725
1717 if (!(flags & MSG_PEEK)) { 1726 if (!(flags & MSG_PEEK)) {
@@ -1860,14 +1869,14 @@ static int unix_stream_recvmsg(struct kiocb *iocb, struct socket *sock,
1860 1869
1861 if (check_creds) { 1870 if (check_creds) {
1862 /* Never glue messages from different writers */ 1871 /* Never glue messages from different writers */
1863 if (memcmp(UNIXCREDS(skb), &siocb->scm->creds, 1872 if ((UNIXCB(skb).pid != siocb->scm->pid) ||
1864 sizeof(siocb->scm->creds)) != 0) { 1873 (UNIXCB(skb).cred != siocb->scm->cred)) {
1865 skb_queue_head(&sk->sk_receive_queue, skb); 1874 skb_queue_head(&sk->sk_receive_queue, skb);
1866 break; 1875 break;
1867 } 1876 }
1868 } else { 1877 } else {
1869 /* Copy credentials */ 1878 /* Copy credentials */
1870 siocb->scm->creds = *UNIXCREDS(skb); 1879 scm_set_cred(siocb->scm, UNIXCB(skb).pid, UNIXCB(skb).cred);
1871 check_creds = 1; 1880 check_creds = 1;
1872 } 1881 }
1873 1882