[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <1315465919.2532.19.camel@edumazet-laptop>
Date: Thu, 08 Sep 2011 09:11:59 +0200
From: Eric Dumazet <eric.dumazet@...il.com>
To: "Yan, Zheng" <zheng.z.yan@...el.com>
Cc: Tim Chen <tim.c.chen@...ux.intel.com>,
"sedat.dilek@...il.com" <sedat.dilek@...il.com>,
"Yan, Zheng" <yanzheng@...n.com>,
"netdev@...r.kernel.org" <netdev@...r.kernel.org>,
"davem@...emloft.net" <davem@...emloft.net>,
"sfr@...b.auug.org.au" <sfr@...b.auug.org.au>,
"jirislaby@...il.com" <jirislaby@...il.com>,
"Shi, Alex" <alex.shi@...el.com>,
Valdis Kletnieks <Valdis.Kletnieks@...edu>
Subject: Re: [PATCH -next v2] unix stream: Fix use-after-free crashes
Le jeudi 08 septembre 2011 à 14:22 +0800, Yan, Zheng a écrit :
> I don't think so. unix_scm_to_skb() calls unix_attach_fds(), it
> always duplicates scm->fp.
What a mess. This code is a nightmare.
Part of the mess comes from scm_destroy() and scm_release() duplication.
We should have scm_destroy() only, as before, and NULLify scm->pid/cred
in unix_scm_to_skb() when we steal references.
It makes more sense and keeps things clearer.
include/net/scm.h | 9 ---------
net/unix/af_unix.c | 27 +++++++++++++++------------
2 files changed, 15 insertions(+), 21 deletions(-)
diff --git a/include/net/scm.h b/include/net/scm.h
index 68e1e48..2a5b42f 100644
--- a/include/net/scm.h
+++ b/include/net/scm.h
@@ -78,15 +78,6 @@ static __inline__ void scm_destroy(struct scm_cookie *scm)
__scm_destroy(scm);
}
-static __inline__ void scm_release(struct scm_cookie *scm)
-{
- /* keep ref on pid and cred */
- scm->pid = NULL;
- scm->cred = NULL;
- if (scm->fp)
- __scm_destroy(scm);
-}
-
static __inline__ int scm_send(struct socket *sock, struct msghdr *msg,
struct scm_cookie *scm)
{
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index e6d9d10..1fa270a 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -1379,15 +1379,18 @@ static int unix_attach_fds(struct scm_cookie *scm, struct sk_buff *skb)
}
static int unix_scm_to_skb(struct scm_cookie *scm, struct sk_buff *skb,
- bool send_fds, bool ref)
+ bool send_fds, bool steal_refs)
{
int err = 0;
- if (ref) {
+
+ if (!steal_refs) {
UNIXCB(skb).pid = get_pid(scm->pid);
UNIXCB(skb).cred = get_cred(scm->cred);
} else {
UNIXCB(skb).pid = scm->pid;
UNIXCB(skb).cred = scm->cred;
+ scm->pid = NULL;
+ scm->cred = NULL;
}
UNIXCB(skb).fp = NULL;
if (scm->fp && send_fds)
@@ -1454,7 +1457,7 @@ static int unix_dgram_sendmsg(struct kiocb *kiocb, struct socket *sock,
if (skb == NULL)
goto out;
- err = unix_scm_to_skb(siocb->scm, skb, true, false);
+ err = unix_scm_to_skb(siocb->scm, skb, true, true);
if (err < 0)
goto out_free;
max_level = err + 1;
@@ -1550,7 +1553,7 @@ restart:
unix_state_unlock(other);
other->sk_data_ready(other, len);
sock_put(other);
- scm_release(siocb->scm);
+ scm_destroy(siocb->scm);
return len;
out_unlock:
@@ -1577,6 +1580,7 @@ static int unix_stream_sendmsg(struct kiocb *kiocb, struct socket *sock,
int sent = 0;
struct scm_cookie tmp_scm;
bool fds_sent = false;
+ bool steal_refs = false;
int max_level;
if (NULL == siocb->scm)
@@ -1638,8 +1642,11 @@ static int unix_stream_sendmsg(struct kiocb *kiocb, struct socket *sock,
size = min_t(int, size, skb_tailroom(skb));
- /* Only send the fds and no ref to pid in the first buffer */
- err = unix_scm_to_skb(siocb->scm, skb, !fds_sent, fds_sent);
+ /* Only send the fds in first buffer
+ * Last buffer can steal our references to pid/cred
+ */
+ steal_refs = (sent + size >= len);
+ err = unix_scm_to_skb(siocb->scm, skb, !fds_sent, steal_refs);
if (err < 0) {
kfree_skb(skb);
goto out;
@@ -1667,10 +1674,7 @@ static int unix_stream_sendmsg(struct kiocb *kiocb, struct socket *sock,
sent += size;
}
- if (skb)
- scm_release(siocb->scm);
- else
- scm_destroy(siocb->scm);
+ scm_destroy(siocb->scm);
siocb->scm = NULL;
return sent;
@@ -1683,8 +1687,7 @@ pipe_err:
send_sig(SIGPIPE, current, 0);
err = -EPIPE;
out_err:
- if (skb == NULL)
- scm_destroy(siocb->scm);
+ scm_destroy(siocb->scm);
out:
siocb->scm = NULL;
return sent ? : err;
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Powered by blists - more mailing lists