aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric W. Biederman <ebiederm@xmission.com>2012-09-06 14:20:01 -0400
committerDavid S. Miller <davem@davemloft.net>2012-09-07 14:42:05 -0400
commitdbe9a4173ea53b72b2c35d19f676a85b69f1c9fe (patch)
tree49952d501032a2bc303d1d646ec6b1f00773b266
parentd679c5324d9a87c6295f56c2dea52d5f68834f41 (diff)
scm: Don't use struct ucred in NETLINK_CB and struct scm_cookie.
Passing uids and gids on NETLINK_CB from a process in one user namespace to a process in another user namespace can result in the wrong uid or gid being presented to userspace. Avoid that problem by passing kuids and kgids instead. - define struct scm_creds for use in scm_cookie and netlink_skb_parms that holds uid and gid information in kuid_t and kgid_t. - Modify scm_set_cred to fill out scm_creds by heand instead of using cred_to_ucred to fill out struct ucred. This conversion ensures userspace does not get incorrect uid or gid values to look at. - Modify scm_recv to convert from struct scm_creds to struct ucred before copying credential values to userspace. - Modify __scm_send to populate struct scm_creds on in the scm_cookie, instead of just copying struct ucred from userspace. - Modify netlink_sendmsg to copy scm_creds instead of struct ucred into the NETLINK_CB. Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/linux/netlink.h3
-rw-r--r--include/net/scm.h23
-rw-r--r--net/core/scm.c17
-rw-r--r--net/netlink/af_netlink.c2
4 files changed, 33 insertions, 12 deletions
diff --git a/include/linux/netlink.h b/include/linux/netlink.h
index c9fdde2bc73f..df73cf4b0290 100644
--- a/include/linux/netlink.h
+++ b/include/linux/netlink.h
@@ -153,6 +153,7 @@ struct nlattr {
153 153
154#include <linux/capability.h> 154#include <linux/capability.h>
155#include <linux/skbuff.h> 155#include <linux/skbuff.h>
156#include <net/scm.h>
156 157
157struct net; 158struct net;
158 159
@@ -162,7 +163,7 @@ static inline struct nlmsghdr *nlmsg_hdr(const struct sk_buff *skb)
162} 163}
163 164
164struct netlink_skb_parms { 165struct netlink_skb_parms {
165 struct ucred creds; /* Skb credentials */ 166 struct scm_creds creds; /* Skb credentials */
166 __u32 pid; 167 __u32 pid;
167 __u32 dst_group; 168 __u32 dst_group;
168 struct sock *ssk; 169 struct sock *ssk;
diff --git a/include/net/scm.h b/include/net/scm.h
index 7dc0854f0b38..456695f5cbc4 100644
--- a/include/net/scm.h
+++ b/include/net/scm.h
@@ -12,6 +12,12 @@
12 */ 12 */
13#define SCM_MAX_FD 253 13#define SCM_MAX_FD 253
14 14
15struct scm_creds {
16 u32 pid;
17 kuid_t uid;
18 kgid_t gid;
19};
20
15struct scm_fp_list { 21struct scm_fp_list {
16 short count; 22 short count;
17 short max; 23 short max;
@@ -22,7 +28,7 @@ struct scm_cookie {
22 struct pid *pid; /* Skb credentials */ 28 struct pid *pid; /* Skb credentials */
23 const struct cred *cred; 29 const struct cred *cred;
24 struct scm_fp_list *fp; /* Passed files */ 30 struct scm_fp_list *fp; /* Passed files */
25 struct ucred creds; /* Skb credentials */ 31 struct scm_creds creds; /* Skb credentials */
26#ifdef CONFIG_SECURITY_NETWORK 32#ifdef CONFIG_SECURITY_NETWORK
27 u32 secid; /* Passed security ID */ 33 u32 secid; /* Passed security ID */
28#endif 34#endif
@@ -49,7 +55,9 @@ static __inline__ void scm_set_cred(struct scm_cookie *scm,
49{ 55{
50 scm->pid = get_pid(pid); 56 scm->pid = get_pid(pid);
51 scm->cred = cred ? get_cred(cred) : NULL; 57 scm->cred = cred ? get_cred(cred) : NULL;
52 cred_to_ucred(pid, cred, &scm->creds); 58 scm->creds.pid = pid_vnr(pid);
59 scm->creds.uid = cred ? cred->euid : INVALID_UID;
60 scm->creds.gid = cred ? cred->egid : INVALID_GID;
53} 61}
54 62
55static __inline__ void scm_destroy_cred(struct scm_cookie *scm) 63static __inline__ void scm_destroy_cred(struct scm_cookie *scm)
@@ -112,8 +120,15 @@ static __inline__ void scm_recv(struct socket *sock, struct msghdr *msg,
112 return; 120 return;
113 } 121 }
114 122
115 if (test_bit(SOCK_PASSCRED, &sock->flags)) 123 if (test_bit(SOCK_PASSCRED, &sock->flags)) {
116 put_cmsg(msg, SOL_SOCKET, SCM_CREDENTIALS, sizeof(scm->creds), &scm->creds); 124 struct user_namespace *current_ns = current_user_ns();
125 struct ucred ucreds = {
126 .pid = scm->creds.pid,
127 .uid = from_kuid_munged(current_ns, scm->creds.uid),
128 .gid = from_kgid_munged(current_ns, scm->creds.gid),
129 };
130 put_cmsg(msg, SOL_SOCKET, SCM_CREDENTIALS, sizeof(ucreds), &ucreds);
131 }
117 132
118 scm_destroy_cred(scm); 133 scm_destroy_cred(scm);
119 134
diff --git a/net/core/scm.c b/net/core/scm.c
index 6ab491d6c26f..9c1c63da3ca8 100644
--- a/net/core/scm.c
+++ b/net/core/scm.c
@@ -155,19 +155,21 @@ int __scm_send(struct socket *sock, struct msghdr *msg, struct scm_cookie *p)
155 break; 155 break;
156 case SCM_CREDENTIALS: 156 case SCM_CREDENTIALS:
157 { 157 {
158 struct ucred creds;
158 kuid_t uid; 159 kuid_t uid;
159 kgid_t gid; 160 kgid_t gid;
160 if (cmsg->cmsg_len != CMSG_LEN(sizeof(struct ucred))) 161 if (cmsg->cmsg_len != CMSG_LEN(sizeof(struct ucred)))
161 goto error; 162 goto error;
162 memcpy(&p->creds, CMSG_DATA(cmsg), sizeof(struct ucred)); 163 memcpy(&creds, CMSG_DATA(cmsg), sizeof(struct ucred));
163 err = scm_check_creds(&p->creds); 164 err = scm_check_creds(&creds);
164 if (err) 165 if (err)
165 goto error; 166 goto error;
166 167
167 if (!p->pid || pid_vnr(p->pid) != p->creds.pid) { 168 p->creds.pid = creds.pid;
169 if (!p->pid || pid_vnr(p->pid) != creds.pid) {
168 struct pid *pid; 170 struct pid *pid;
169 err = -ESRCH; 171 err = -ESRCH;
170 pid = find_get_pid(p->creds.pid); 172 pid = find_get_pid(creds.pid);
171 if (!pid) 173 if (!pid)
172 goto error; 174 goto error;
173 put_pid(p->pid); 175 put_pid(p->pid);
@@ -175,11 +177,14 @@ int __scm_send(struct socket *sock, struct msghdr *msg, struct scm_cookie *p)
175 } 177 }
176 178
177 err = -EINVAL; 179 err = -EINVAL;
178 uid = make_kuid(current_user_ns(), p->creds.uid); 180 uid = make_kuid(current_user_ns(), creds.uid);
179 gid = make_kgid(current_user_ns(), p->creds.gid); 181 gid = make_kgid(current_user_ns(), creds.gid);
180 if (!uid_valid(uid) || !gid_valid(gid)) 182 if (!uid_valid(uid) || !gid_valid(gid))
181 goto error; 183 goto error;
182 184
185 p->creds.uid = uid;
186 p->creds.gid = gid;
187
183 if (!p->cred || 188 if (!p->cred ||
184 !uid_eq(p->cred->euid, uid) || 189 !uid_eq(p->cred->euid, uid) ||
185 !gid_eq(p->cred->egid, gid)) { 190 !gid_eq(p->cred->egid, gid)) {
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
index 382119917166..f530b1ca1773 100644
--- a/net/netlink/af_netlink.c
+++ b/net/netlink/af_netlink.c
@@ -1399,7 +1399,7 @@ static int netlink_sendmsg(struct kiocb *kiocb, struct socket *sock,
1399 1399
1400 NETLINK_CB(skb).pid = nlk->pid; 1400 NETLINK_CB(skb).pid = nlk->pid;
1401 NETLINK_CB(skb).dst_group = dst_group; 1401 NETLINK_CB(skb).dst_group = dst_group;
1402 memcpy(NETLINK_CREDS(skb), &siocb->scm->creds, sizeof(struct ucred)); 1402 NETLINK_CB(skb).creds = siocb->scm->creds;
1403 1403
1404 err = -EFAULT; 1404 err = -EFAULT;
1405 if (memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len)) { 1405 if (memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len)) {