|
@@ -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 */
|
|
@@ -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.
|
|
|
*/
|
|
@@ -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);
|
|
@@ -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) {
|
|
@@ -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)) {
|
|
@@ -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;
|
|
|
}
|
|
|
|