Skip to content

Commit

Permalink
af_unix: Allow credentials to work across user and pid namespaces.
Browse files Browse the repository at this point in the history
In unix_skb_parms store pointers to struct pid and struct cred instead
of raw uid, gid, and pid values, then translate the credentials on
reception into values that are meaningful in the receiving processes
namespaces.

Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>
Acked-by: Pavel Emelyanov <xemul@openvz.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
ebiederm authored and davem330 committed Jun 16, 2010
1 parent 257b535 commit 7361c36
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 24 deletions.
4 changes: 2 additions & 2 deletions include/net/af_unix.h
Expand Up @@ -23,15 +23,15 @@ struct unix_address {
};

struct unix_skb_parms {
struct ucred creds; /* Skb credentials */
struct pid *pid; /* Skb credentials */
const struct cred *cred;
struct scm_fp_list *fp; /* Passed files */
#ifdef CONFIG_SECURITY_NETWORK
u32 secid; /* Security ID */
#endif
};

#define UNIXCB(skb) (*(struct unix_skb_parms *)&((skb)->cb))
#define UNIXCREDS(skb) (&UNIXCB((skb)).creds)
#define UNIXSID(skb) (&UNIXCB((skb)).secid)

#define unix_state_lock(s) spin_lock(&unix_sk(s)->lock)
Expand Down
53 changes: 31 additions & 22 deletions net/unix/af_unix.c
Expand Up @@ -1316,18 +1316,20 @@ static void unix_detach_fds(struct scm_cookie *scm, struct sk_buff *skb)
int i;

scm->fp = UNIXCB(skb).fp;
skb->destructor = sock_wfree;
UNIXCB(skb).fp = NULL;

for (i = scm->fp->count-1; i >= 0; i--)
unix_notinflight(scm->fp->fp[i]);
}

static void unix_destruct_fds(struct sk_buff *skb)
static void unix_destruct_scm(struct sk_buff *skb)
{
struct scm_cookie scm;
memset(&scm, 0, sizeof(scm));
unix_detach_fds(&scm, skb);
scm.pid = UNIXCB(skb).pid;
scm.cred = UNIXCB(skb).cred;
if (UNIXCB(skb).fp)
unix_detach_fds(&scm, skb);

/* Alas, it calls VFS */
/* So fscking what? fput() had been SMP-safe since the last Summer */
Expand All @@ -1350,10 +1352,22 @@ static int unix_attach_fds(struct scm_cookie *scm, struct sk_buff *skb)

for (i = scm->fp->count-1; i >= 0; i--)
unix_inflight(scm->fp->fp[i]);
skb->destructor = unix_destruct_fds;
return 0;
}

static int unix_scm_to_skb(struct scm_cookie *scm, struct sk_buff *skb, bool send_fds)
{
int err = 0;
UNIXCB(skb).pid = get_pid(scm->pid);
UNIXCB(skb).cred = get_cred(scm->cred);
UNIXCB(skb).fp = NULL;
if (scm->fp && send_fds)
err = unix_attach_fds(scm, skb);

skb->destructor = unix_destruct_scm;
return err;
}

/*
* Send AF_UNIX data.
*/
Expand Down Expand Up @@ -1410,12 +1424,9 @@ static int unix_dgram_sendmsg(struct kiocb *kiocb, struct socket *sock,
if (skb == NULL)
goto out;

memcpy(UNIXCREDS(skb), &siocb->scm->creds, sizeof(struct ucred));
if (siocb->scm->fp) {
err = unix_attach_fds(siocb->scm, skb);
if (err)
goto out_free;
}
err = unix_scm_to_skb(siocb->scm, skb, true);
if (err)
goto out_free;
unix_get_secdata(siocb->scm, skb);

skb_reset_transport_header(skb);
Expand Down Expand Up @@ -1585,16 +1596,14 @@ static int unix_stream_sendmsg(struct kiocb *kiocb, struct socket *sock,
*/
size = min_t(int, size, skb_tailroom(skb));

memcpy(UNIXCREDS(skb), &siocb->scm->creds, sizeof(struct ucred));

/* Only send the fds in the first buffer */
if (siocb->scm->fp && !fds_sent) {
err = unix_attach_fds(siocb->scm, skb);
if (err) {
kfree_skb(skb);
goto out_err;
}
fds_sent = true;
err = unix_scm_to_skb(siocb->scm, skb, !fds_sent);
if (err) {
kfree_skb(skb);
goto out_err;
}
fds_sent = true;

err = memcpy_fromiovec(skb_put(skb, size), msg->msg_iov, size);
if (err) {
Expand Down Expand Up @@ -1711,7 +1720,7 @@ static int unix_dgram_recvmsg(struct kiocb *iocb, struct socket *sock,
siocb->scm = &tmp_scm;
memset(&tmp_scm, 0, sizeof(tmp_scm));
}
siocb->scm->creds = *UNIXCREDS(skb);
scm_set_cred(siocb->scm, UNIXCB(skb).pid, UNIXCB(skb).cred);
unix_set_secdata(siocb->scm, skb);

if (!(flags & MSG_PEEK)) {
Expand Down Expand Up @@ -1860,14 +1869,14 @@ static int unix_stream_recvmsg(struct kiocb *iocb, struct socket *sock,

if (check_creds) {
/* Never glue messages from different writers */
if (memcmp(UNIXCREDS(skb), &siocb->scm->creds,
sizeof(siocb->scm->creds)) != 0) {
if ((UNIXCB(skb).pid != siocb->scm->pid) ||
(UNIXCB(skb).cred != siocb->scm->cred)) {
skb_queue_head(&sk->sk_receive_queue, skb);
break;
}
} else {
/* Copy credentials */
siocb->scm->creds = *UNIXCREDS(skb);
scm_set_cred(siocb->scm, UNIXCB(skb).pid, UNIXCB(skb).cred);
check_creds = 1;
}

Expand Down

0 comments on commit 7361c36

Please sign in to comment.