Commit dbe9a417 authored by Eric W. Biederman's avatar Eric W. Biederman Committed by David S. Miller

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: default avatar"Eric W. Biederman" <ebiederm@xmission.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent d679c532
...@@ -153,6 +153,7 @@ struct nlattr { ...@@ -153,6 +153,7 @@ struct nlattr {
#include <linux/capability.h> #include <linux/capability.h>
#include <linux/skbuff.h> #include <linux/skbuff.h>
#include <net/scm.h>
struct net; struct net;
...@@ -162,7 +163,7 @@ static inline struct nlmsghdr *nlmsg_hdr(const struct sk_buff *skb) ...@@ -162,7 +163,7 @@ static inline struct nlmsghdr *nlmsg_hdr(const struct sk_buff *skb)
} }
struct netlink_skb_parms { struct netlink_skb_parms {
struct ucred creds; /* Skb credentials */ struct scm_creds creds; /* Skb credentials */
__u32 pid; __u32 pid;
__u32 dst_group; __u32 dst_group;
struct sock *ssk; struct sock *ssk;
......
...@@ -12,6 +12,12 @@ ...@@ -12,6 +12,12 @@
*/ */
#define SCM_MAX_FD 253 #define SCM_MAX_FD 253
struct scm_creds {
u32 pid;
kuid_t uid;
kgid_t gid;
};
struct scm_fp_list { struct scm_fp_list {
short count; short count;
short max; short max;
...@@ -22,7 +28,7 @@ struct scm_cookie { ...@@ -22,7 +28,7 @@ struct scm_cookie {
struct pid *pid; /* Skb credentials */ struct pid *pid; /* Skb credentials */
const struct cred *cred; const struct cred *cred;
struct scm_fp_list *fp; /* Passed files */ struct scm_fp_list *fp; /* Passed files */
struct ucred creds; /* Skb credentials */ struct scm_creds creds; /* Skb credentials */
#ifdef CONFIG_SECURITY_NETWORK #ifdef CONFIG_SECURITY_NETWORK
u32 secid; /* Passed security ID */ u32 secid; /* Passed security ID */
#endif #endif
...@@ -49,7 +55,9 @@ static __inline__ void scm_set_cred(struct scm_cookie *scm, ...@@ -49,7 +55,9 @@ static __inline__ void scm_set_cred(struct scm_cookie *scm,
{ {
scm->pid = get_pid(pid); scm->pid = get_pid(pid);
scm->cred = cred ? get_cred(cred) : NULL; scm->cred = cred ? get_cred(cred) : NULL;
cred_to_ucred(pid, cred, &scm->creds); scm->creds.pid = pid_vnr(pid);
scm->creds.uid = cred ? cred->euid : INVALID_UID;
scm->creds.gid = cred ? cred->egid : INVALID_GID;
} }
static __inline__ void scm_destroy_cred(struct scm_cookie *scm) static __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,8 +120,15 @@ static __inline__ void scm_recv(struct socket *sock, struct msghdr *msg,
return; return;
} }
if (test_bit(SOCK_PASSCRED, &sock->flags)) if (test_bit(SOCK_PASSCRED, &sock->flags)) {
put_cmsg(msg, SOL_SOCKET, SCM_CREDENTIALS, sizeof(scm->creds), &scm->creds); struct user_namespace *current_ns = current_user_ns();
struct ucred ucreds = {
.pid = scm->creds.pid,
.uid = from_kuid_munged(current_ns, scm->creds.uid),
.gid = from_kgid_munged(current_ns, scm->creds.gid),
};
put_cmsg(msg, SOL_SOCKET, SCM_CREDENTIALS, sizeof(ucreds), &ucreds);
}
scm_destroy_cred(scm); scm_destroy_cred(scm);
......
...@@ -155,19 +155,21 @@ int __scm_send(struct socket *sock, struct msghdr *msg, struct scm_cookie *p) ...@@ -155,19 +155,21 @@ int __scm_send(struct socket *sock, struct msghdr *msg, struct scm_cookie *p)
break; break;
case SCM_CREDENTIALS: case SCM_CREDENTIALS:
{ {
struct ucred creds;
kuid_t uid; kuid_t uid;
kgid_t gid; kgid_t gid;
if (cmsg->cmsg_len != CMSG_LEN(sizeof(struct ucred))) if (cmsg->cmsg_len != CMSG_LEN(sizeof(struct ucred)))
goto error; goto error;
memcpy(&p->creds, CMSG_DATA(cmsg), sizeof(struct ucred)); memcpy(&creds, CMSG_DATA(cmsg), sizeof(struct ucred));
err = scm_check_creds(&p->creds); err = scm_check_creds(&creds);
if (err) if (err)
goto error; goto error;
if (!p->pid || pid_vnr(p->pid) != p->creds.pid) { p->creds.pid = creds.pid;
if (!p->pid || pid_vnr(p->pid) != creds.pid) {
struct pid *pid; struct pid *pid;
err = -ESRCH; err = -ESRCH;
pid = find_get_pid(p->creds.pid); pid = find_get_pid(creds.pid);
if (!pid) if (!pid)
goto error; goto error;
put_pid(p->pid); put_pid(p->pid);
...@@ -175,11 +177,14 @@ int __scm_send(struct socket *sock, struct msghdr *msg, struct scm_cookie *p) ...@@ -175,11 +177,14 @@ int __scm_send(struct socket *sock, struct msghdr *msg, struct scm_cookie *p)
} }
err = -EINVAL; err = -EINVAL;
uid = make_kuid(current_user_ns(), p->creds.uid); uid = make_kuid(current_user_ns(), creds.uid);
gid = make_kgid(current_user_ns(), p->creds.gid); gid = make_kgid(current_user_ns(), creds.gid);
if (!uid_valid(uid) || !gid_valid(gid)) if (!uid_valid(uid) || !gid_valid(gid))
goto error; goto error;
p->creds.uid = uid;
p->creds.gid = gid;
if (!p->cred || if (!p->cred ||
!uid_eq(p->cred->euid, uid) || !uid_eq(p->cred->euid, uid) ||
!gid_eq(p->cred->egid, gid)) { !gid_eq(p->cred->egid, gid)) {
......
...@@ -1399,7 +1399,7 @@ static int netlink_sendmsg(struct kiocb *kiocb, struct socket *sock, ...@@ -1399,7 +1399,7 @@ static int netlink_sendmsg(struct kiocb *kiocb, struct socket *sock,
NETLINK_CB(skb).pid = nlk->pid; NETLINK_CB(skb).pid = nlk->pid;
NETLINK_CB(skb).dst_group = dst_group; NETLINK_CB(skb).dst_group = dst_group;
memcpy(NETLINK_CREDS(skb), &siocb->scm->creds, sizeof(struct ucred)); NETLINK_CB(skb).creds = siocb->scm->creds;
err = -EFAULT; err = -EFAULT;
if (memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len)) { if (memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len)) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment