diff options
-rw-r--r-- | include/net/scm.h | 22 | ||||
-rw-r--r-- | net/unix/af_unix.c | 45 |
2 files changed, 48 insertions, 19 deletions
diff --git a/include/net/scm.h b/include/net/scm.h index 745460fa2f02..68e1e481658e 100644 --- a/include/net/scm.h +++ b/include/net/scm.h | |||
@@ -53,6 +53,14 @@ static __inline__ void scm_set_cred(struct scm_cookie *scm, | |||
53 | cred_to_ucred(pid, cred, &scm->creds); | 53 | cred_to_ucred(pid, cred, &scm->creds); |
54 | } | 54 | } |
55 | 55 | ||
56 | static __inline__ void scm_set_cred_noref(struct scm_cookie *scm, | ||
57 | struct pid *pid, const struct cred *cred) | ||
58 | { | ||
59 | scm->pid = pid; | ||
60 | scm->cred = cred; | ||
61 | cred_to_ucred(pid, cred, &scm->creds); | ||
62 | } | ||
63 | |||
56 | static __inline__ void scm_destroy_cred(struct scm_cookie *scm) | 64 | static __inline__ void scm_destroy_cred(struct scm_cookie *scm) |
57 | { | 65 | { |
58 | put_pid(scm->pid); | 66 | put_pid(scm->pid); |
@@ -70,6 +78,15 @@ static __inline__ void scm_destroy(struct scm_cookie *scm) | |||
70 | __scm_destroy(scm); | 78 | __scm_destroy(scm); |
71 | } | 79 | } |
72 | 80 | ||
81 | static __inline__ void scm_release(struct scm_cookie *scm) | ||
82 | { | ||
83 | /* keep ref on pid and cred */ | ||
84 | scm->pid = NULL; | ||
85 | scm->cred = NULL; | ||
86 | if (scm->fp) | ||
87 | __scm_destroy(scm); | ||
88 | } | ||
89 | |||
73 | static __inline__ int scm_send(struct socket *sock, struct msghdr *msg, | 90 | static __inline__ int scm_send(struct socket *sock, struct msghdr *msg, |
74 | struct scm_cookie *scm) | 91 | struct scm_cookie *scm) |
75 | { | 92 | { |
@@ -108,15 +125,14 @@ static __inline__ void scm_recv(struct socket *sock, struct msghdr *msg, | |||
108 | if (!msg->msg_control) { | 125 | if (!msg->msg_control) { |
109 | if (test_bit(SOCK_PASSCRED, &sock->flags) || scm->fp) | 126 | if (test_bit(SOCK_PASSCRED, &sock->flags) || scm->fp) |
110 | msg->msg_flags |= MSG_CTRUNC; | 127 | msg->msg_flags |= MSG_CTRUNC; |
111 | scm_destroy(scm); | 128 | if (scm && scm->fp) |
129 | __scm_destroy(scm); | ||
112 | return; | 130 | return; |
113 | } | 131 | } |
114 | 132 | ||
115 | if (test_bit(SOCK_PASSCRED, &sock->flags)) | 133 | if (test_bit(SOCK_PASSCRED, &sock->flags)) |
116 | put_cmsg(msg, SOL_SOCKET, SCM_CREDENTIALS, sizeof(scm->creds), &scm->creds); | 134 | put_cmsg(msg, SOL_SOCKET, SCM_CREDENTIALS, sizeof(scm->creds), &scm->creds); |
117 | 135 | ||
118 | scm_destroy_cred(scm); | ||
119 | |||
120 | scm_passec(sock, msg, scm); | 136 | scm_passec(sock, msg, scm); |
121 | 137 | ||
122 | if (!scm->fp) | 138 | if (!scm->fp) |
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index ec68e1c05b85..e6d9d1014ed2 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c | |||
@@ -1378,11 +1378,17 @@ static int unix_attach_fds(struct scm_cookie *scm, struct sk_buff *skb) | |||
1378 | return max_level; | 1378 | return max_level; |
1379 | } | 1379 | } |
1380 | 1380 | ||
1381 | static int unix_scm_to_skb(struct scm_cookie *scm, struct sk_buff *skb, bool send_fds) | 1381 | static int unix_scm_to_skb(struct scm_cookie *scm, struct sk_buff *skb, |
1382 | bool send_fds, bool ref) | ||
1382 | { | 1383 | { |
1383 | int err = 0; | 1384 | int err = 0; |
1384 | UNIXCB(skb).pid = get_pid(scm->pid); | 1385 | if (ref) { |
1385 | UNIXCB(skb).cred = get_cred(scm->cred); | 1386 | UNIXCB(skb).pid = get_pid(scm->pid); |
1387 | UNIXCB(skb).cred = get_cred(scm->cred); | ||
1388 | } else { | ||
1389 | UNIXCB(skb).pid = scm->pid; | ||
1390 | UNIXCB(skb).cred = scm->cred; | ||
1391 | } | ||
1386 | UNIXCB(skb).fp = NULL; | 1392 | UNIXCB(skb).fp = NULL; |
1387 | if (scm->fp && send_fds) | 1393 | if (scm->fp && send_fds) |
1388 | err = unix_attach_fds(scm, skb); | 1394 | err = unix_attach_fds(scm, skb); |
@@ -1407,7 +1413,7 @@ static int unix_dgram_sendmsg(struct kiocb *kiocb, struct socket *sock, | |||
1407 | int namelen = 0; /* fake GCC */ | 1413 | int namelen = 0; /* fake GCC */ |
1408 | int err; | 1414 | int err; |
1409 | unsigned hash; | 1415 | unsigned hash; |
1410 | struct sk_buff *skb; | 1416 | struct sk_buff *skb = NULL; |
1411 | long timeo; | 1417 | long timeo; |
1412 | struct scm_cookie tmp_scm; | 1418 | struct scm_cookie tmp_scm; |
1413 | int max_level; | 1419 | int max_level; |
@@ -1448,7 +1454,7 @@ static int unix_dgram_sendmsg(struct kiocb *kiocb, struct socket *sock, | |||
1448 | if (skb == NULL) | 1454 | if (skb == NULL) |
1449 | goto out; | 1455 | goto out; |
1450 | 1456 | ||
1451 | err = unix_scm_to_skb(siocb->scm, skb, true); | 1457 | err = unix_scm_to_skb(siocb->scm, skb, true, false); |
1452 | if (err < 0) | 1458 | if (err < 0) |
1453 | goto out_free; | 1459 | goto out_free; |
1454 | max_level = err + 1; | 1460 | max_level = err + 1; |
@@ -1544,7 +1550,7 @@ restart: | |||
1544 | unix_state_unlock(other); | 1550 | unix_state_unlock(other); |
1545 | other->sk_data_ready(other, len); | 1551 | other->sk_data_ready(other, len); |
1546 | sock_put(other); | 1552 | sock_put(other); |
1547 | scm_destroy(siocb->scm); | 1553 | scm_release(siocb->scm); |
1548 | return len; | 1554 | return len; |
1549 | 1555 | ||
1550 | out_unlock: | 1556 | out_unlock: |
@@ -1554,7 +1560,8 @@ out_free: | |||
1554 | out: | 1560 | out: |
1555 | if (other) | 1561 | if (other) |
1556 | sock_put(other); | 1562 | sock_put(other); |
1557 | scm_destroy(siocb->scm); | 1563 | if (skb == NULL) |
1564 | scm_destroy(siocb->scm); | ||
1558 | return err; | 1565 | return err; |
1559 | } | 1566 | } |
1560 | 1567 | ||
@@ -1566,7 +1573,7 @@ static int unix_stream_sendmsg(struct kiocb *kiocb, struct socket *sock, | |||
1566 | struct sock *sk = sock->sk; | 1573 | struct sock *sk = sock->sk; |
1567 | struct sock *other = NULL; | 1574 | struct sock *other = NULL; |
1568 | int err, size; | 1575 | int err, size; |
1569 | struct sk_buff *skb; | 1576 | struct sk_buff *skb = NULL; |
1570 | int sent = 0; | 1577 | int sent = 0; |
1571 | struct scm_cookie tmp_scm; | 1578 | struct scm_cookie tmp_scm; |
1572 | bool fds_sent = false; | 1579 | bool fds_sent = false; |
@@ -1631,11 +1638,11 @@ static int unix_stream_sendmsg(struct kiocb *kiocb, struct socket *sock, | |||
1631 | size = min_t(int, size, skb_tailroom(skb)); | 1638 | size = min_t(int, size, skb_tailroom(skb)); |
1632 | 1639 | ||
1633 | 1640 | ||
1634 | /* Only send the fds in the first buffer */ | 1641 | /* Only send the fds and no ref to pid in the first buffer */ |
1635 | err = unix_scm_to_skb(siocb->scm, skb, !fds_sent); | 1642 | err = unix_scm_to_skb(siocb->scm, skb, !fds_sent, fds_sent); |
1636 | if (err < 0) { | 1643 | if (err < 0) { |
1637 | kfree_skb(skb); | 1644 | kfree_skb(skb); |
1638 | goto out_err; | 1645 | goto out; |
1639 | } | 1646 | } |
1640 | max_level = err + 1; | 1647 | max_level = err + 1; |
1641 | fds_sent = true; | 1648 | fds_sent = true; |
@@ -1643,7 +1650,7 @@ static int unix_stream_sendmsg(struct kiocb *kiocb, struct socket *sock, | |||
1643 | err = memcpy_fromiovec(skb_put(skb, size), msg->msg_iov, size); | 1650 | err = memcpy_fromiovec(skb_put(skb, size), msg->msg_iov, size); |
1644 | if (err) { | 1651 | if (err) { |
1645 | kfree_skb(skb); | 1652 | kfree_skb(skb); |
1646 | goto out_err; | 1653 | goto out; |
1647 | } | 1654 | } |
1648 | 1655 | ||
1649 | unix_state_lock(other); | 1656 | unix_state_lock(other); |
@@ -1660,7 +1667,10 @@ static int unix_stream_sendmsg(struct kiocb *kiocb, struct socket *sock, | |||
1660 | sent += size; | 1667 | sent += size; |
1661 | } | 1668 | } |
1662 | 1669 | ||
1663 | scm_destroy(siocb->scm); | 1670 | if (skb) |
1671 | scm_release(siocb->scm); | ||
1672 | else | ||
1673 | scm_destroy(siocb->scm); | ||
1664 | siocb->scm = NULL; | 1674 | siocb->scm = NULL; |
1665 | 1675 | ||
1666 | return sent; | 1676 | return sent; |
@@ -1673,7 +1683,9 @@ pipe_err: | |||
1673 | send_sig(SIGPIPE, current, 0); | 1683 | send_sig(SIGPIPE, current, 0); |
1674 | err = -EPIPE; | 1684 | err = -EPIPE; |
1675 | out_err: | 1685 | out_err: |
1676 | scm_destroy(siocb->scm); | 1686 | if (skb == NULL) |
1687 | scm_destroy(siocb->scm); | ||
1688 | out: | ||
1677 | siocb->scm = NULL; | 1689 | siocb->scm = NULL; |
1678 | return sent ? : err; | 1690 | return sent ? : err; |
1679 | } | 1691 | } |
@@ -1777,7 +1789,7 @@ static int unix_dgram_recvmsg(struct kiocb *iocb, struct socket *sock, | |||
1777 | siocb->scm = &tmp_scm; | 1789 | siocb->scm = &tmp_scm; |
1778 | memset(&tmp_scm, 0, sizeof(tmp_scm)); | 1790 | memset(&tmp_scm, 0, sizeof(tmp_scm)); |
1779 | } | 1791 | } |
1780 | scm_set_cred(siocb->scm, UNIXCB(skb).pid, UNIXCB(skb).cred); | 1792 | scm_set_cred_noref(siocb->scm, UNIXCB(skb).pid, UNIXCB(skb).cred); |
1781 | unix_set_secdata(siocb->scm, skb); | 1793 | unix_set_secdata(siocb->scm, skb); |
1782 | 1794 | ||
1783 | if (!(flags & MSG_PEEK)) { | 1795 | if (!(flags & MSG_PEEK)) { |
@@ -1939,7 +1951,8 @@ static int unix_stream_recvmsg(struct kiocb *iocb, struct socket *sock, | |||
1939 | } | 1951 | } |
1940 | } else { | 1952 | } else { |
1941 | /* Copy credentials */ | 1953 | /* Copy credentials */ |
1942 | scm_set_cred(siocb->scm, UNIXCB(skb).pid, UNIXCB(skb).cred); | 1954 | scm_set_cred_noref(siocb->scm, UNIXCB(skb).pid, |
1955 | UNIXCB(skb).cred); | ||
1943 | check_creds = 1; | 1956 | check_creds = 1; |
1944 | } | 1957 | } |
1945 | 1958 | ||