aboutsummaryrefslogtreecommitdiffstats
path: root/net/unix/af_unix.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/unix/af_unix.c')
-rw-r--r--net/unix/af_unix.c33
1 files changed, 26 insertions, 7 deletions
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index 4d3c6071b9a..66d5ac4773a 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -1302,14 +1302,23 @@ static void unix_destruct_fds(struct sk_buff *skb)
1302 sock_wfree(skb); 1302 sock_wfree(skb);
1303} 1303}
1304 1304
1305static void unix_attach_fds(struct scm_cookie *scm, struct sk_buff *skb) 1305static int unix_attach_fds(struct scm_cookie *scm, struct sk_buff *skb)
1306{ 1306{
1307 int i; 1307 int i;
1308
1309 /*
1310 * Need to duplicate file references for the sake of garbage
1311 * collection. Otherwise a socket in the fps might become a
1312 * candidate for GC while the skb is not yet queued.
1313 */
1314 UNIXCB(skb).fp = scm_fp_dup(scm->fp);
1315 if (!UNIXCB(skb).fp)
1316 return -ENOMEM;
1317
1308 for (i=scm->fp->count-1; i>=0; i--) 1318 for (i=scm->fp->count-1; i>=0; i--)
1309 unix_inflight(scm->fp->fp[i]); 1319 unix_inflight(scm->fp->fp[i]);
1310 UNIXCB(skb).fp = scm->fp;
1311 skb->destructor = unix_destruct_fds; 1320 skb->destructor = unix_destruct_fds;
1312 scm->fp = NULL; 1321 return 0;
1313} 1322}
1314 1323
1315/* 1324/*
@@ -1334,6 +1343,7 @@ static int unix_dgram_sendmsg(struct kiocb *kiocb, struct socket *sock,
1334 1343
1335 if (NULL == siocb->scm) 1344 if (NULL == siocb->scm)
1336 siocb->scm = &tmp_scm; 1345 siocb->scm = &tmp_scm;
1346 wait_for_unix_gc();
1337 err = scm_send(sock, msg, siocb->scm); 1347 err = scm_send(sock, msg, siocb->scm);
1338 if (err < 0) 1348 if (err < 0)
1339 return err; 1349 return err;
@@ -1368,8 +1378,11 @@ static int unix_dgram_sendmsg(struct kiocb *kiocb, struct socket *sock,
1368 goto out; 1378 goto out;
1369 1379
1370 memcpy(UNIXCREDS(skb), &siocb->scm->creds, sizeof(struct ucred)); 1380 memcpy(UNIXCREDS(skb), &siocb->scm->creds, sizeof(struct ucred));
1371 if (siocb->scm->fp) 1381 if (siocb->scm->fp) {
1372 unix_attach_fds(siocb->scm, skb); 1382 err = unix_attach_fds(siocb->scm, skb);
1383 if (err)
1384 goto out_free;
1385 }
1373 unix_get_secdata(siocb->scm, skb); 1386 unix_get_secdata(siocb->scm, skb);
1374 1387
1375 skb_reset_transport_header(skb); 1388 skb_reset_transport_header(skb);
@@ -1481,6 +1494,7 @@ static int unix_stream_sendmsg(struct kiocb *kiocb, struct socket *sock,
1481 1494
1482 if (NULL == siocb->scm) 1495 if (NULL == siocb->scm)
1483 siocb->scm = &tmp_scm; 1496 siocb->scm = &tmp_scm;
1497 wait_for_unix_gc();
1484 err = scm_send(sock, msg, siocb->scm); 1498 err = scm_send(sock, msg, siocb->scm);
1485 if (err < 0) 1499 if (err < 0)
1486 return err; 1500 return err;
@@ -1538,8 +1552,13 @@ static int unix_stream_sendmsg(struct kiocb *kiocb, struct socket *sock,
1538 size = min_t(int, size, skb_tailroom(skb)); 1552 size = min_t(int, size, skb_tailroom(skb));
1539 1553
1540 memcpy(UNIXCREDS(skb), &siocb->scm->creds, sizeof(struct ucred)); 1554 memcpy(UNIXCREDS(skb), &siocb->scm->creds, sizeof(struct ucred));
1541 if (siocb->scm->fp) 1555 if (siocb->scm->fp) {
1542 unix_attach_fds(siocb->scm, skb); 1556 err = unix_attach_fds(siocb->scm, skb);
1557 if (err) {
1558 kfree_skb(skb);
1559 goto out_err;
1560 }
1561 }
1543 1562
1544 if ((err = memcpy_fromiovec(skb_put(skb,size), msg->msg_iov, size)) != 0) { 1563 if ((err = memcpy_fromiovec(skb_put(skb,size), msg->msg_iov, size)) != 0) {
1545 kfree_skb(skb); 1564 kfree_skb(skb);