af_unix: Allow SO_PEERCRED to work across namespaces.

Use struct pid and struct cred to store the peer credentials on struct
sock.  This gives enough information to convert the peer credential
information to a value relative to whatever namespace the socket is in
at the time.

This removes nasty surprises when using SO_PEERCRED on socket
connetions where the processes on either side are in different pid and
user namespaces.

Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>
Acked-by: Daniel Lezcano <daniel.lezcano@free.fr>
Acked-by: Pavel Emelyanov <xemul@openvz.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Eric W. Biederman
2010-06-13 03:30:14 +00:00
committed by David S. Miller
parent 3f551f9436
commit 109f6e39fa
3 changed files with 42 additions and 16 deletions

View 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;