diff options
Diffstat (limited to 'net/unix')
-rw-r--r-- | net/unix/af_unix.c | 53 |
1 files changed, 31 insertions, 22 deletions
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index e1f1349fae8..5fe9d6fe08b 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 | ||
1326 | static void unix_destruct_fds(struct sk_buff *skb) | 1325 | static 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 | ||
1358 | static 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 | ||