diff options
Diffstat (limited to 'net/unix/af_unix.c')
| -rw-r--r-- | net/unix/af_unix.c | 33 |
1 files changed, 25 insertions, 8 deletions
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index dc504d308ec0..eb90f77bb0e2 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 | ||
| 1305 | static void unix_attach_fds(struct scm_cookie *scm, struct sk_buff *skb) | 1305 | static 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 | /* |
| @@ -1368,8 +1377,11 @@ static int unix_dgram_sendmsg(struct kiocb *kiocb, struct socket *sock, | |||
| 1368 | goto out; | 1377 | goto out; |
| 1369 | 1378 | ||
| 1370 | memcpy(UNIXCREDS(skb), &siocb->scm->creds, sizeof(struct ucred)); | 1379 | memcpy(UNIXCREDS(skb), &siocb->scm->creds, sizeof(struct ucred)); |
| 1371 | if (siocb->scm->fp) | 1380 | if (siocb->scm->fp) { |
| 1372 | unix_attach_fds(siocb->scm, skb); | 1381 | err = unix_attach_fds(siocb->scm, skb); |
| 1382 | if (err) | ||
| 1383 | goto out_free; | ||
| 1384 | } | ||
| 1373 | unix_get_secdata(siocb->scm, skb); | 1385 | unix_get_secdata(siocb->scm, skb); |
| 1374 | 1386 | ||
| 1375 | skb_reset_transport_header(skb); | 1387 | skb_reset_transport_header(skb); |
| @@ -1538,8 +1550,13 @@ static int unix_stream_sendmsg(struct kiocb *kiocb, struct socket *sock, | |||
| 1538 | size = min_t(int, size, skb_tailroom(skb)); | 1550 | size = min_t(int, size, skb_tailroom(skb)); |
| 1539 | 1551 | ||
| 1540 | memcpy(UNIXCREDS(skb), &siocb->scm->creds, sizeof(struct ucred)); | 1552 | memcpy(UNIXCREDS(skb), &siocb->scm->creds, sizeof(struct ucred)); |
| 1541 | if (siocb->scm->fp) | 1553 | if (siocb->scm->fp) { |
| 1542 | unix_attach_fds(siocb->scm, skb); | 1554 | err = unix_attach_fds(siocb->scm, skb); |
| 1555 | if (err) { | ||
| 1556 | kfree_skb(skb); | ||
| 1557 | goto out_err; | ||
| 1558 | } | ||
| 1559 | } | ||
| 1543 | 1560 | ||
| 1544 | if ((err = memcpy_fromiovec(skb_put(skb,size), msg->msg_iov, size)) != 0) { | 1561 | if ((err = memcpy_fromiovec(skb_put(skb,size), msg->msg_iov, size)) != 0) { |
| 1545 | kfree_skb(skb); | 1562 | kfree_skb(skb); |
| @@ -2213,7 +2230,7 @@ static int unix_net_init(struct net *net) | |||
| 2213 | #endif | 2230 | #endif |
| 2214 | error = 0; | 2231 | error = 0; |
| 2215 | out: | 2232 | out: |
| 2216 | return 0; | 2233 | return error; |
| 2217 | } | 2234 | } |
| 2218 | 2235 | ||
| 2219 | static void unix_net_exit(struct net *net) | 2236 | static void unix_net_exit(struct net *net) |
