aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/net/scm.h22
-rw-r--r--net/unix/af_unix.c45
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
56static __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
56static __inline__ void scm_destroy_cred(struct scm_cookie *scm) 64static __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
81static __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
73static __inline__ int scm_send(struct socket *sock, struct msghdr *msg, 90static __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
1381static int unix_scm_to_skb(struct scm_cookie *scm, struct sk_buff *skb, bool send_fds) 1381static 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
1550out_unlock: 1556out_unlock:
@@ -1554,7 +1560,8 @@ out_free:
1554out: 1560out:
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;
1675out_err: 1685out_err:
1676 scm_destroy(siocb->scm); 1686 if (skb == NULL)
1687 scm_destroy(siocb->scm);
1688out:
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