GIT: unionfs2-2.6.27.y: net: unix: fix sending fds in multiple buffers

Erez Zadok ezk at fsl.cs.sunysb.edu
Thu Aug 12 23:15:07 EDT 2010


commit 140d894f72c42b58de16c7587241fdd369fc81da
Author: Miklos Szeredi <mszeredi at suse.cz>
Date:   Fri Sep 11 11:31:45 2009 -0700

    net: unix: fix sending fds in multiple buffers
    
    commit 8ba69ba6a324b13e1190fc31e41954d190fd4f1d upstream.
    
    Kalle Olavi Niemitalo reported that:
    
      "..., when one process calls sendmsg once to send 43804 bytes of
      data and one file descriptor, and another process then calls recvmsg
      three times to receive the 16032+16032+11740 bytes, each of those
      recvmsg calls returns the file descriptor in the ancillary data.  I
      confirmed this with strace.  The behaviour differs from Linux
      2.6.26, where reportedly only one of those recvmsg calls (I think
      the first one) returned the file descriptor."
    
    This bug was introduced by a patch from me titled "net: unix: fix inflight
    counting bug in garbage collector", commit 6209344f5.
    
    And the reason is, quoting Kalle:
    
      "Before your patch, unix_attach_fds() would set scm->fp = NULL, so
      that if the loop in unix_stream_sendmsg() ran multiple iterations,
      it could not call unix_attach_fds() again.  But now,
      unix_attach_fds() leaves scm->fp unchanged, and I think this causes
      it to be called multiple times and duplicate the same file
      descriptors to each struct sk_buff."
    
    Fix this by introducing a flag that is cleared at the start and set
    when the fds attached to the first buffer.  The resulting code should
    work equivalently to the one on 2.6.26.
    
    Reported-by: Kalle Olavi Niemitalo <kon at iki.fi>
    Signed-off-by: Miklos Szeredi <mszeredi at suse.cz>
    Signed-off-by: David S. Miller <davem at davemloft.net>
    Signed-off-by: Greg Kroah-Hartman <gregkh at suse.de>

diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index facdaa9..3c33817 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -1491,6 +1491,7 @@ static int unix_stream_sendmsg(struct kiocb *kiocb, struct socket *sock,
 	struct sk_buff *skb;
 	int sent=0;
 	struct scm_cookie tmp_scm;
+	bool fds_sent = false;
 
 	if (NULL == siocb->scm)
 		siocb->scm = &tmp_scm;
@@ -1552,12 +1553,14 @@ static int unix_stream_sendmsg(struct kiocb *kiocb, struct socket *sock,
 		size = min_t(int, size, skb_tailroom(skb));
 
 		memcpy(UNIXCREDS(skb), &siocb->scm->creds, sizeof(struct ucred));
-		if (siocb->scm->fp) {
+		/* Only send the fds in the first buffer */
+		if (siocb->scm->fp && !fds_sent) {
 			err = unix_attach_fds(siocb->scm, skb);
 			if (err) {
 				kfree_skb(skb);
 				goto out_err;
 			}
+			fds_sent = true;
 		}
 
 		if ((err = memcpy_fromiovec(skb_put(skb,size), msg->msg_iov, size)) != 0) {


More information about the unionfs-cvs mailing list