diff options
Diffstat (limited to 'net/unix/af_unix.c')
| -rw-r--r-- | net/unix/af_unix.c | 45 | 
1 files changed, 23 insertions, 22 deletions
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index 2db702d82e7..826e09938bf 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -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)) {  		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 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)  |