]> git.karo-electronics.de Git - linux-beck.git/blobdiff - net/unix/af_unix.c
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
[linux-beck.git] / net / unix / af_unix.c
index 971282b6f6a38fd056dd65d127b85f044b7c6041..826e09938bff4203def6e5af33db49c4360f3019 100644 (file)
@@ -1340,7 +1340,6 @@ static void unix_destruct_scm(struct sk_buff *skb)
        struct scm_cookie scm;
        memset(&scm, 0, sizeof(scm));
        scm.pid  = UNIXCB(skb).pid;
-       scm.cred = UNIXCB(skb).cred;
        if (UNIXCB(skb).fp)
                unix_detach_fds(&scm, skb);
 
@@ -1391,8 +1390,8 @@ static int unix_scm_to_skb(struct scm_cookie *scm, struct sk_buff *skb, bool sen
        int err = 0;
 
        UNIXCB(skb).pid  = get_pid(scm->pid);
-       if (scm->cred)
-               UNIXCB(skb).cred = get_cred(scm->cred);
+       UNIXCB(skb).uid = scm->creds.uid;
+       UNIXCB(skb).gid = scm->creds.gid;
        UNIXCB(skb).fp = NULL;
        if (scm->fp && send_fds)
                err = unix_attach_fds(scm, skb);
@@ -1409,13 +1408,13 @@ static int unix_scm_to_skb(struct scm_cookie *scm, struct sk_buff *skb, bool sen
 static void maybe_add_creds(struct sk_buff *skb, const struct socket *sock,
                            const struct sock *other)
 {
-       if (UNIXCB(skb).cred)
+       if (UNIXCB(skb).pid)
                return;
        if (test_bit(SOCK_PASSCRED, &sock->flags) ||
-           (other->sk_socket &&
-           test_bit(SOCK_PASSCRED, &other->sk_socket->flags))) {
+           !other->sk_socket ||
+           test_bit(SOCK_PASSCRED, &other->sk_socket->flags)) {
                UNIXCB(skb).pid  = get_pid(task_tgid(current));
-               UNIXCB(skb).cred = get_current_cred();
+               current_uid_gid(&UNIXCB(skb).uid, &UNIXCB(skb).gid);
        }
 }
 
@@ -1819,7 +1818,7 @@ static int unix_dgram_recvmsg(struct kiocb *iocb, struct socket *sock,
                siocb->scm = &tmp_scm;
                memset(&tmp_scm, 0, sizeof(tmp_scm));
        }
-       scm_set_cred(siocb->scm, UNIXCB(skb).pid, UNIXCB(skb).cred);
+       scm_set_cred(siocb->scm, UNIXCB(skb).pid, UNIXCB(skb).uid, UNIXCB(skb).gid);
        unix_set_secdata(siocb->scm, skb);
 
        if (!(flags & MSG_PEEK)) {
@@ -1859,10 +1858,10 @@ out:
 }
 
 /*
- *     Sleep until data has arrive. But check for races..
+ *     Sleep until more data has arrived. But check for races..
  */
-
-static long unix_stream_data_wait(struct sock *sk, long timeo)
+static long unix_stream_data_wait(struct sock *sk, long timeo,
+                                 struct sk_buff *last)
 {
        DEFINE_WAIT(wait);
 
@@ -1871,7 +1870,7 @@ static long unix_stream_data_wait(struct sock *sk, long timeo)
        for (;;) {
                prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
 
-               if (!skb_queue_empty(&sk->sk_receive_queue) ||
+               if (skb_peek_tail(&sk->sk_receive_queue) != last ||
                    sk->sk_err ||
                    (sk->sk_shutdown & RCV_SHUTDOWN) ||
                    signal_pending(current) ||
@@ -1890,8 +1889,6 @@ static long unix_stream_data_wait(struct sock *sk, long timeo)
        return timeo;
 }
 
-
-
 static int unix_stream_recvmsg(struct kiocb *iocb, struct socket *sock,
                               struct msghdr *msg, size_t size,
                               int flags)
@@ -1936,14 +1933,12 @@ static int unix_stream_recvmsg(struct kiocb *iocb, struct socket *sock,
                goto out;
        }
 
-       skip = sk_peek_offset(sk, flags);
-
        do {
                int chunk;
-               struct sk_buff *skb;
+               struct sk_buff *skb, *last;
 
                unix_state_lock(sk);
-               skb = skb_peek(&sk->sk_receive_queue);
+               last = skb = skb_peek(&sk->sk_receive_queue);
 again:
                if (skb == NULL) {
                        unix_sk(sk)->recursion_level = 0;
@@ -1966,7 +1961,7 @@ again:
                                break;
                        mutex_unlock(&u->readlock);
 
-                       timeo = unix_stream_data_wait(sk, timeo);
+                       timeo = unix_stream_data_wait(sk, timeo, last);
 
                        if (signal_pending(current)
                            ||  mutex_lock_interruptible(&u->readlock)) {
@@ -1980,10 +1975,13 @@ again:
                        break;
                }
 
-               if (skip >= skb->len) {
+               skip = sk_peek_offset(sk, flags);
+               while (skip >= skb->len) {
                        skip -= skb->len;
+                       last = skb;
                        skb = skb_peek_next(skb, &sk->sk_receive_queue);
-                       goto again;
+                       if (!skb)
+                               goto again;
                }
 
                unix_state_unlock(sk);
@@ -1991,11 +1989,12 @@ again:
                if (check_creds) {
                        /* Never glue messages from different writers */
                        if ((UNIXCB(skb).pid  != siocb->scm->pid) ||
-                           (UNIXCB(skb).cred != siocb->scm->cred))
+                           !uid_eq(UNIXCB(skb).uid, siocb->scm->creds.uid) ||
+                           !gid_eq(UNIXCB(skb).gid, siocb->scm->creds.gid))
                                break;
-               } else {
+               } else if (test_bit(SOCK_PASSCRED, &sock->flags)) {
                        /* Copy credentials */
-                       scm_set_cred(siocb->scm, UNIXCB(skb).pid, UNIXCB(skb).cred);
+                       scm_set_cred(siocb->scm, UNIXCB(skb).pid, UNIXCB(skb).uid, UNIXCB(skb).gid);
                        check_creds = 1;
                }
 
@@ -2196,7 +2195,9 @@ static unsigned int unix_dgram_poll(struct file *file, struct socket *sock,
 
        /* exceptional events? */
        if (sk->sk_err || !skb_queue_empty(&sk->sk_error_queue))
-               mask |= POLLERR;
+               mask |= POLLERR |
+                       (sock_flag(sk, SOCK_SELECT_ERR_QUEUE) ? POLLPRI : 0);
+
        if (sk->sk_shutdown & RCV_SHUTDOWN)
                mask |= POLLRDHUP | POLLIN | POLLRDNORM;
        if (sk->sk_shutdown == SHUTDOWN_MASK)