diff options
author | Eric W. Biederman <ebiederm@xmission.com> | 2010-06-13 03:30:14 +0000 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-06-16 14:55:55 -0700 |
commit | 109f6e39fa07c48f580125f531f46cb7c245b528 (patch) | |
tree | 9ec97679c227394a44ebede5768f92d970cea6eb /net/core/sock.c | |
parent | 3f551f9436c05a3b5eccdd6e94733df5bb98d2a5 (diff) | |
download | blackbird-op-linux-109f6e39fa07c48f580125f531f46cb7c245b528.tar.gz blackbird-op-linux-109f6e39fa07c48f580125f531f46cb7c245b528.zip |
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>
Diffstat (limited to 'net/core/sock.c')
-rw-r--r-- | net/core/sock.c | 18 |
1 files changed, 12 insertions, 6 deletions
diff --git a/net/core/sock.c b/net/core/sock.c index db8335ad7559..0229d5566a46 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -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; |