]> Pileus Git - ~andy/linux/blobdiff - net/unix/af_unix.c
Merge branch 'misc-3.2' of git://git.kernel.org/pub/scm/linux/kernel/git/aegl/linux
[~andy/linux] / net / unix / af_unix.c
index ec68e1c05b85ee23552961d542ed1fc489a0de7b..466fbcc5cf77a92ef491be50eb836f652165da16 100644 (file)
@@ -1381,8 +1381,10 @@ 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)
 {
        int err = 0;
+
        UNIXCB(skb).pid  = get_pid(scm->pid);
-       UNIXCB(skb).cred = get_cred(scm->cred);
+       if (scm->cred)
+               UNIXCB(skb).cred = get_cred(scm->cred);
        UNIXCB(skb).fp = NULL;
        if (scm->fp && send_fds)
                err = unix_attach_fds(scm, skb);
@@ -1391,6 +1393,24 @@ static int unix_scm_to_skb(struct scm_cookie *scm, struct sk_buff *skb, bool sen
        return err;
 }
 
+/*
+ * Some apps rely on write() giving SCM_CREDENTIALS
+ * We include credentials if source or destination socket
+ * asserted SOCK_PASSCRED.
+ */
+static void maybe_add_creds(struct sk_buff *skb, const struct socket *sock,
+                           const struct sock *other)
+{
+       if (UNIXCB(skb).cred)
+               return;
+       if (test_bit(SOCK_PASSCRED, &sock->flags) ||
+           !other->sk_socket ||
+           test_bit(SOCK_PASSCRED, &other->sk_socket->flags)) {
+               UNIXCB(skb).pid  = get_pid(task_tgid(current));
+               UNIXCB(skb).cred = get_current_cred();
+       }
+}
+
 /*
  *     Send AF_UNIX data.
  */
@@ -1538,6 +1558,7 @@ restart:
 
        if (sock_flag(other, SOCK_RCVTSTAMP))
                __net_timestamp(skb);
+       maybe_add_creds(skb, sock, other);
        skb_queue_tail(&other->sk_receive_queue, skb);
        if (max_level > unix_sk(other)->recursion_level)
                unix_sk(other)->recursion_level = max_level;
@@ -1652,6 +1673,7 @@ static int unix_stream_sendmsg(struct kiocb *kiocb, struct socket *sock,
                    (other->sk_shutdown & RCV_SHUTDOWN))
                        goto pipe_err_free;
 
+               maybe_add_creds(skb, sock, other);
                skb_queue_tail(&other->sk_receive_queue, skb);
                if (max_level > unix_sk(other)->recursion_level)
                        unix_sk(other)->recursion_level = max_level;