]> rtime.felk.cvut.cz Git - linux-imx.git/commitdiff
scm: Capture the full credentials of the scm sender.
authorEric W. Biederman <ebiederm@xmission.com>
Sun, 13 Jun 2010 03:32:34 +0000 (03:32 +0000)
committerAK <andi@firstfloor.org>
Sun, 6 Feb 2011 19:03:35 +0000 (11:03 -0800)
Upstream commit 257b5358b32f17e0603b6ff57b13610b0e02348f

Start capturing not only the userspace pid, uid and gid values of the
sending process but also the struct pid and struct cred of the sending
process as well.

This is in preparation for properly supporting SCM_CREDENTIALS for
sockets that have different uid and/or pid namespaces at the different
ends.

Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>
Acked-by: Serge E. Hallyn <serge@hallyn.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Signed-off-by: Andi Kleen <ak@linux.intel.com>
include/net/scm.h
net/core/scm.c

index 8360e47aa7e322336099d09163db1b4254e47016..096286d053318eee23216649a444da37d789a969 100644 (file)
@@ -19,6 +19,8 @@ struct scm_fp_list {
 };
 
 struct scm_cookie {
+       struct pid              *pid;           /* Skb credentials */
+       const struct cred       *cred;
        struct ucred            creds;          /* Skb credentials      */
        struct scm_fp_list      *fp;            /* Passed files         */
 #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)
index b88f6f9d0b97503ddd353e163e73680704cde79a..681c976307b5be1fbfb28ca290847cc4cb06532f 100644 (file)
@@ -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;