af_unix: Allow SO_PEERCRED to work across namespaces.
[linux-3.10.git] / net / core / sock.c
index db8335a..0229d55 100644 (file)
@@ -915,11 +915,15 @@ int sock_getsockopt(struct socket *sock, int level, int optname,
                break;
 
        case SO_PEERCRED:
-               if (len > sizeof(sk->sk_peercred))
-                       len = sizeof(sk->sk_peercred);
-               if (copy_to_user(optval, &sk->sk_peercred, len))
+       {
+               struct ucred peercred;
+               if (len > sizeof(peercred))
+                       len = sizeof(peercred);
+               cred_to_ucred(sk->sk_peer_pid, sk->sk_peer_cred, &peercred);
+               if (copy_to_user(optval, &peercred, len))
                        return -EFAULT;
                goto lenout;
+       }
 
        case SO_PEERNAME:
        {
@@ -1133,6 +1137,9 @@ static void __sk_free(struct sock *sk)
                printk(KERN_DEBUG "%s: optmem leakage (%d bytes) detected.\n",
                       __func__, atomic_read(&sk->sk_omem_alloc));
 
+       if (sk->sk_peer_cred)
+               put_cred(sk->sk_peer_cred);
+       put_pid(sk->sk_peer_pid);
        put_net(sock_net(sk));
        sk_prot_free(sk->sk_prot_creator, sk);
 }
@@ -1968,9 +1975,8 @@ void sock_init_data(struct socket *sock, struct sock *sk)
        sk->sk_sndmsg_page      =       NULL;
        sk->sk_sndmsg_off       =       0;
 
-       sk->sk_peercred.pid     =       0;
-       sk->sk_peercred.uid     =       -1;
-       sk->sk_peercred.gid     =       -1;
+       sk->sk_peer_pid         =       NULL;
+       sk->sk_peer_cred        =       NULL;
        sk->sk_write_pending    =       0;
        sk->sk_rcvlowat         =       1;
        sk->sk_rcvtimeo         =       MAX_SCHEDULE_TIMEOUT;