aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
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