From 00e57aca0c036d5f9949a9b475e020e3dcadd8be Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Sun, 13 Jun 2010 03:32:34 +0000 Subject: [PATCH] --- yaml --- r: 202977 b: refs/heads/master c: 257b5358b32f17e0603b6ff57b13610b0e02348f h: refs/heads/master i: 202975: 24c292aac978b198c6ec2d7ba3ee9b6f0e7c2707 v: v3 --- [refs] | 2 +- trunk/include/net/scm.h | 28 ++++++++++++++++++++++++---- trunk/net/core/scm.c | 24 ++++++++++++++++++++++++ 3 files changed, 49 insertions(+), 5 deletions(-) diff --git a/[refs] b/[refs] index 4c947cb818fa..5efc656da719 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: b47030c71dfd6c8cd5cb6e551b6f7f7cfc96f6a6 +refs/heads/master: 257b5358b32f17e0603b6ff57b13610b0e02348f diff --git a/trunk/include/net/scm.h b/trunk/include/net/scm.h index 17d9d2e75ff1..31656506d967 100644 --- a/trunk/include/net/scm.h +++ b/trunk/include/net/scm.h @@ -19,6 +19,8 @@ struct scm_fp_list { }; struct scm_cookie { + struct pid *pid; /* Skb credentials */ + const struct cred *cred; struct scm_fp_list *fp; /* Passed files */ struct ucred creds; /* Skb credentials */ #ifdef CONFIG_SECURITY_NETWORK @@ -42,8 +44,27 @@ static __inline__ void unix_get_peersec_dgram(struct socket *sock, struct scm_co { } #endif /* CONFIG_SECURITY_NETWORK */ +static __inline__ void scm_set_cred(struct scm_cookie *scm, + struct pid *pid, const struct cred *cred) +{ + scm->pid = get_pid(pid); + scm->cred = get_cred(cred); + cred_to_ucred(pid, cred, &scm->creds); +} + +static __inline__ void scm_destroy_cred(struct scm_cookie *scm) +{ + put_pid(scm->pid); + scm->pid = NULL; + + if (scm->cred) + put_cred(scm->cred); + scm->cred = NULL; +} + static __inline__ void scm_destroy(struct scm_cookie *scm) { + scm_destroy_cred(scm); if (scm && scm->fp) __scm_destroy(scm); } @@ -51,10 +72,7 @@ static __inline__ void scm_destroy(struct scm_cookie *scm) static __inline__ int scm_send(struct socket *sock, struct msghdr *msg, struct scm_cookie *scm) { - struct task_struct *p = current; - scm->creds.uid = current_uid(); - scm->creds.gid = current_gid(); - scm->creds.pid = task_tgid_vnr(p); + scm_set_cred(scm, task_tgid(current), current_cred()); scm->fp = NULL; unix_get_peersec_dgram(sock, scm); if (msg->msg_controllen <= 0) @@ -96,6 +114,8 @@ static __inline__ void scm_recv(struct socket *sock, struct msghdr *msg, if (test_bit(SOCK_PASSCRED, &sock->flags)) put_cmsg(msg, SOL_SOCKET, SCM_CREDENTIALS, sizeof(scm->creds), &scm->creds); + scm_destroy_cred(scm); + scm_passec(sock, msg, scm); if (!scm->fp) diff --git a/trunk/net/core/scm.c b/trunk/net/core/scm.c index b88f6f9d0b97..681c976307b5 100644 --- a/trunk/net/core/scm.c +++ b/trunk/net/core/scm.c @@ -170,6 +170,30 @@ int __scm_send(struct socket *sock, struct msghdr *msg, struct scm_cookie *p) err = scm_check_creds(&p->creds); if (err) goto error; + + if (pid_vnr(p->pid) != p->creds.pid) { + struct pid *pid; + err = -ESRCH; + pid = find_get_pid(p->creds.pid); + if (!pid) + goto error; + put_pid(p->pid); + p->pid = pid; + } + + if ((p->cred->euid != p->creds.uid) || + (p->cred->egid != p->creds.gid)) { + struct cred *cred; + err = -ENOMEM; + cred = prepare_creds(); + if (!cred) + goto error; + + cred->uid = cred->euid = p->creds.uid; + cred->gid = cred->egid = p->creds.uid; + put_cred(p->cred); + p->cred = cred; + } break; default: goto error;