aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric W. Biederman <ebiederm@xmission.com>2010-06-12 23:30:14 -0400
committerDavid S. Miller <davem@davemloft.net>2010-06-16 17:55:55 -0400
commit109f6e39fa07c48f580125f531f46cb7c245b528 (patch)
tree9ec97679c227394a44ebede5768f92d970cea6eb
parent3f551f9436c05a3b5eccdd6e94733df5bb98d2a5 (diff)
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>
-rw-r--r--include/net/sock.h3
-rw-r--r--net/core/sock.c18
-rw-r--r--net/unix/af_unix.c37
3 files changed, 42 insertions, 16 deletions
diff --git a/include/net/sock.h b/include/net/sock.h
index f8acf38f092f..4f26f2f83be9 100644
--- a/include/net/sock.h
+++ b/include/net/sock.h
@@ -295,7 +295,8 @@ struct sock {
295 unsigned short sk_ack_backlog; 295 unsigned short sk_ack_backlog;
296 unsigned short sk_max_ack_backlog; 296 unsigned short sk_max_ack_backlog;
297 __u32 sk_priority; 297 __u32 sk_priority;
298 struct ucred sk_peercred; 298 struct pid *sk_peer_pid;
299 const struct cred *sk_peer_cred;
299 long sk_rcvtimeo; 300 long sk_rcvtimeo;
300 long sk_sndtimeo; 301 long sk_sndtimeo;
301 struct sk_filter *sk_filter; 302 struct sk_filter *sk_filter;
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,
915 break; 915 break;
916 916
917 case SO_PEERCRED: 917 case SO_PEERCRED:
918 if (len > sizeof(sk->sk_peercred)) 918 {
919 len = sizeof(sk->sk_peercred); 919 struct ucred peercred;
920 if (copy_to_user(optval, &sk->sk_peercred, len)) 920 if (len > sizeof(peercred))
921 len = sizeof(peercred);
922 cred_to_ucred(sk->sk_peer_pid, sk->sk_peer_cred, &peercred);
923 if (copy_to_user(optval, &peercred, len))
921 return -EFAULT; 924 return -EFAULT;
922 goto lenout; 925 goto lenout;
926 }
923 927
924 case SO_PEERNAME: 928 case SO_PEERNAME:
925 { 929 {
@@ -1133,6 +1137,9 @@ static void __sk_free(struct sock *sk)
1133 printk(KERN_DEBUG "%s: optmem leakage (%d bytes) detected.\n", 1137 printk(KERN_DEBUG "%s: optmem leakage (%d bytes) detected.\n",
1134 __func__, atomic_read(&sk->sk_omem_alloc)); 1138 __func__, atomic_read(&sk->sk_omem_alloc));
1135 1139
1140 if (sk->sk_peer_cred)
1141 put_cred(sk->sk_peer_cred);
1142 put_pid(sk->sk_peer_pid);
1136 put_net(sock_net(sk)); 1143 put_net(sock_net(sk));
1137 sk_prot_free(sk->sk_prot_creator, sk); 1144 sk_prot_free(sk->sk_prot_creator, sk);
1138} 1145}
@@ -1968,9 +1975,8 @@ void sock_init_data(struct socket *sock, struct sock *sk)
1968 sk->sk_sndmsg_page = NULL; 1975 sk->sk_sndmsg_page = NULL;
1969 sk->sk_sndmsg_off = 0; 1976 sk->sk_sndmsg_off = 0;
1970 1977
1971 sk->sk_peercred.pid = 0; 1978 sk->sk_peer_pid = NULL;
1972 sk->sk_peercred.uid = -1; 1979 sk->sk_peer_cred = NULL;
1973 sk->sk_peercred.gid = -1;
1974 sk->sk_write_pending = 0; 1980 sk->sk_write_pending = 0;
1975 sk->sk_rcvlowat = 1; 1981 sk->sk_rcvlowat = 1;
1976 sk->sk_rcvtimeo = MAX_SCHEDULE_TIMEOUT; 1982 sk->sk_rcvtimeo = MAX_SCHEDULE_TIMEOUT;
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index fef2cc5e9d2b..e1f1349fae86 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -450,11 +450,31 @@ static int unix_release_sock(struct sock *sk, int embrion)
450 return 0; 450 return 0;
451} 451}
452 452
453static void init_peercred(struct sock *sk)
454{
455 put_pid(sk->sk_peer_pid);
456 if (sk->sk_peer_cred)
457 put_cred(sk->sk_peer_cred);
458 sk->sk_peer_pid = get_pid(task_tgid(current));
459 sk->sk_peer_cred = get_current_cred();
460}
461
462static void copy_peercred(struct sock *sk, struct sock *peersk)
463{
464 put_pid(sk->sk_peer_pid);
465 if (sk->sk_peer_cred)
466 put_cred(sk->sk_peer_cred);
467 sk->sk_peer_pid = get_pid(peersk->sk_peer_pid);
468 sk->sk_peer_cred = get_cred(peersk->sk_peer_cred);
469}
470
453static int unix_listen(struct socket *sock, int backlog) 471static int unix_listen(struct socket *sock, int backlog)
454{ 472{
455 int err; 473 int err;
456 struct sock *sk = sock->sk; 474 struct sock *sk = sock->sk;
457 struct unix_sock *u = unix_sk(sk); 475 struct unix_sock *u = unix_sk(sk);
476 struct pid *old_pid = NULL;
477 const struct cred *old_cred = NULL;
458 478
459 err = -EOPNOTSUPP; 479 err = -EOPNOTSUPP;
460 if (sock->type != SOCK_STREAM && sock->type != SOCK_SEQPACKET) 480 if (sock->type != SOCK_STREAM && sock->type != SOCK_SEQPACKET)
@@ -470,12 +490,14 @@ static int unix_listen(struct socket *sock, int backlog)
470 sk->sk_max_ack_backlog = backlog; 490 sk->sk_max_ack_backlog = backlog;
471 sk->sk_state = TCP_LISTEN; 491 sk->sk_state = TCP_LISTEN;
472 /* set credentials so connect can copy them */ 492 /* set credentials so connect can copy them */
473 sk->sk_peercred.pid = task_tgid_vnr(current); 493 init_peercred(sk);
474 current_euid_egid(&sk->sk_peercred.uid, &sk->sk_peercred.gid);
475 err = 0; 494 err = 0;
476 495
477out_unlock: 496out_unlock:
478 unix_state_unlock(sk); 497 unix_state_unlock(sk);
498 put_pid(old_pid);
499 if (old_cred)
500 put_cred(old_cred);
479out: 501out:
480 return err; 502 return err;
481} 503}
@@ -1140,8 +1162,7 @@ restart:
1140 unix_peer(newsk) = sk; 1162 unix_peer(newsk) = sk;
1141 newsk->sk_state = TCP_ESTABLISHED; 1163 newsk->sk_state = TCP_ESTABLISHED;
1142 newsk->sk_type = sk->sk_type; 1164 newsk->sk_type = sk->sk_type;
1143 newsk->sk_peercred.pid = task_tgid_vnr(current); 1165 init_peercred(newsk);
1144 current_euid_egid(&newsk->sk_peercred.uid, &newsk->sk_peercred.gid);
1145 newu = unix_sk(newsk); 1166 newu = unix_sk(newsk);
1146 newsk->sk_wq = &newu->peer_wq; 1167 newsk->sk_wq = &newu->peer_wq;
1147 otheru = unix_sk(other); 1168 otheru = unix_sk(other);
@@ -1157,7 +1178,7 @@ restart:
1157 } 1178 }
1158 1179
1159 /* Set credentials */ 1180 /* Set credentials */
1160 sk->sk_peercred = other->sk_peercred; 1181 copy_peercred(sk, other);
1161 1182
1162 sock->state = SS_CONNECTED; 1183 sock->state = SS_CONNECTED;
1163 sk->sk_state = TCP_ESTABLISHED; 1184 sk->sk_state = TCP_ESTABLISHED;
@@ -1199,10 +1220,8 @@ static int unix_socketpair(struct socket *socka, struct socket *sockb)
1199 sock_hold(skb); 1220 sock_hold(skb);
1200 unix_peer(ska) = skb; 1221 unix_peer(ska) = skb;
1201 unix_peer(skb) = ska; 1222 unix_peer(skb) = ska;
1202 ska->sk_peercred.pid = skb->sk_peercred.pid = task_tgid_vnr(current); 1223 init_peercred(ska);
1203 current_euid_egid(&skb->sk_peercred.uid, &skb->sk_peercred.gid); 1224 init_peercred(skb);
1204 ska->sk_peercred.uid = skb->sk_peercred.uid;
1205 ska->sk_peercred.gid = skb->sk_peercred.gid;
1206 1225
1207 if (ska->sk_type != SOCK_DGRAM) { 1226 if (ska->sk_type != SOCK_DGRAM) {
1208 ska->sk_state = TCP_ESTABLISHED; 1227 ska->sk_state = TCP_ESTABLISHED;