diff options
Diffstat (limited to 'net/unix/af_unix.c')
-rw-r--r-- | net/unix/af_unix.c | 53 |
1 files changed, 36 insertions, 17 deletions
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index 015606b54d9b..eb90f77bb0e2 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * NET4: Implementation of BSD Unix domain sockets. | 2 | * NET4: Implementation of BSD Unix domain sockets. |
3 | * | 3 | * |
4 | * Authors: Alan Cox, <alan.cox@linux.org> | 4 | * Authors: Alan Cox, <alan@lxorguk.ukuu.org.uk> |
5 | * | 5 | * |
6 | * This program is free software; you can redistribute it and/or | 6 | * This program is free software; you can redistribute it and/or |
7 | * modify it under the terms of the GNU General Public License | 7 | * modify it under the terms of the GNU General Public License |
@@ -711,28 +711,30 @@ static struct sock *unix_find_other(struct net *net, | |||
711 | int type, unsigned hash, int *error) | 711 | int type, unsigned hash, int *error) |
712 | { | 712 | { |
713 | struct sock *u; | 713 | struct sock *u; |
714 | struct nameidata nd; | 714 | struct path path; |
715 | int err = 0; | 715 | int err = 0; |
716 | 716 | ||
717 | if (sunname->sun_path[0]) { | 717 | if (sunname->sun_path[0]) { |
718 | err = path_lookup(sunname->sun_path, LOOKUP_FOLLOW, &nd); | 718 | struct inode *inode; |
719 | err = kern_path(sunname->sun_path, LOOKUP_FOLLOW, &path); | ||
719 | if (err) | 720 | if (err) |
720 | goto fail; | 721 | goto fail; |
721 | err = vfs_permission(&nd, MAY_WRITE); | 722 | inode = path.dentry->d_inode; |
723 | err = inode_permission(inode, MAY_WRITE); | ||
722 | if (err) | 724 | if (err) |
723 | goto put_fail; | 725 | goto put_fail; |
724 | 726 | ||
725 | err = -ECONNREFUSED; | 727 | err = -ECONNREFUSED; |
726 | if (!S_ISSOCK(nd.path.dentry->d_inode->i_mode)) | 728 | if (!S_ISSOCK(inode->i_mode)) |
727 | goto put_fail; | 729 | goto put_fail; |
728 | u = unix_find_socket_byinode(net, nd.path.dentry->d_inode); | 730 | u = unix_find_socket_byinode(net, inode); |
729 | if (!u) | 731 | if (!u) |
730 | goto put_fail; | 732 | goto put_fail; |
731 | 733 | ||
732 | if (u->sk_type == type) | 734 | if (u->sk_type == type) |
733 | touch_atime(nd.path.mnt, nd.path.dentry); | 735 | touch_atime(path.mnt, path.dentry); |
734 | 736 | ||
735 | path_put(&nd.path); | 737 | path_put(&path); |
736 | 738 | ||
737 | err=-EPROTOTYPE; | 739 | err=-EPROTOTYPE; |
738 | if (u->sk_type != type) { | 740 | if (u->sk_type != type) { |
@@ -753,7 +755,7 @@ static struct sock *unix_find_other(struct net *net, | |||
753 | return u; | 755 | return u; |
754 | 756 | ||
755 | put_fail: | 757 | put_fail: |
756 | path_put(&nd.path); | 758 | path_put(&path); |
757 | fail: | 759 | fail: |
758 | *error=err; | 760 | *error=err; |
759 | return NULL; | 761 | return NULL; |
@@ -1300,14 +1302,23 @@ static void unix_destruct_fds(struct sk_buff *skb) | |||
1300 | sock_wfree(skb); | 1302 | sock_wfree(skb); |
1301 | } | 1303 | } |
1302 | 1304 | ||
1303 | 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) |
1304 | { | 1306 | { |
1305 | 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 | |||
1306 | for (i=scm->fp->count-1; i>=0; i--) | 1318 | for (i=scm->fp->count-1; i>=0; i--) |
1307 | unix_inflight(scm->fp->fp[i]); | 1319 | unix_inflight(scm->fp->fp[i]); |
1308 | UNIXCB(skb).fp = scm->fp; | ||
1309 | skb->destructor = unix_destruct_fds; | 1320 | skb->destructor = unix_destruct_fds; |
1310 | scm->fp = NULL; | 1321 | return 0; |
1311 | } | 1322 | } |
1312 | 1323 | ||
1313 | /* | 1324 | /* |
@@ -1366,8 +1377,11 @@ static int unix_dgram_sendmsg(struct kiocb *kiocb, struct socket *sock, | |||
1366 | goto out; | 1377 | goto out; |
1367 | 1378 | ||
1368 | memcpy(UNIXCREDS(skb), &siocb->scm->creds, sizeof(struct ucred)); | 1379 | memcpy(UNIXCREDS(skb), &siocb->scm->creds, sizeof(struct ucred)); |
1369 | if (siocb->scm->fp) | 1380 | if (siocb->scm->fp) { |
1370 | unix_attach_fds(siocb->scm, skb); | 1381 | err = unix_attach_fds(siocb->scm, skb); |
1382 | if (err) | ||
1383 | goto out_free; | ||
1384 | } | ||
1371 | unix_get_secdata(siocb->scm, skb); | 1385 | unix_get_secdata(siocb->scm, skb); |
1372 | 1386 | ||
1373 | skb_reset_transport_header(skb); | 1387 | skb_reset_transport_header(skb); |
@@ -1536,8 +1550,13 @@ static int unix_stream_sendmsg(struct kiocb *kiocb, struct socket *sock, | |||
1536 | size = min_t(int, size, skb_tailroom(skb)); | 1550 | size = min_t(int, size, skb_tailroom(skb)); |
1537 | 1551 | ||
1538 | memcpy(UNIXCREDS(skb), &siocb->scm->creds, sizeof(struct ucred)); | 1552 | memcpy(UNIXCREDS(skb), &siocb->scm->creds, sizeof(struct ucred)); |
1539 | if (siocb->scm->fp) | 1553 | if (siocb->scm->fp) { |
1540 | 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 | } | ||
1541 | 1560 | ||
1542 | 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) { |
1543 | kfree_skb(skb); | 1562 | kfree_skb(skb); |
@@ -2211,7 +2230,7 @@ static int unix_net_init(struct net *net) | |||
2211 | #endif | 2230 | #endif |
2212 | error = 0; | 2231 | error = 0; |
2213 | out: | 2232 | out: |
2214 | return 0; | 2233 | return error; |
2215 | } | 2234 | } |
2216 | 2235 | ||
2217 | static void unix_net_exit(struct net *net) | 2236 | static void unix_net_exit(struct net *net) |