summaryrefslogtreecommitdiff
path: root/net/unix/af_unix.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/unix/af_unix.c')
-rw-r--r--net/unix/af_unix.c83
1 files changed, 42 insertions, 41 deletions
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index 1cbf36ea043b..42cffeafc8c1 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -823,6 +823,7 @@ static int unix_listen(struct socket *sock, int backlog)
if (err)
goto out;
unix_state_lock(sk);
+ err = -EINVAL;
if (sk->sk_state != TCP_CLOSE && sk->sk_state != TCP_LISTEN)
goto out_unlock;
if (backlog > sk->sk_max_ack_backlog)
@@ -921,6 +922,7 @@ static bool unix_custom_sockopt(int optname)
{
switch (optname) {
case SO_INQ:
+ case SO_RIGHTS_NOTRUNC:
return true;
default:
return false;
@@ -949,13 +951,21 @@ static int unix_setsockopt(struct socket *sock, int level, int optname,
switch (optname) {
case SO_INQ:
if (sk->sk_type != SOCK_STREAM)
- return -EINVAL;
+ return -ENOPROTOOPT;
if (val > 1 || val < 0)
return -EINVAL;
WRITE_ONCE(u->recvmsg_inq, val);
break;
+
+ case SO_RIGHTS_NOTRUNC:
+ if (val > 1 || val < 0)
+ return -EINVAL;
+
+ WRITE_ONCE(u->scm_rights_notrunc, val);
+ break;
+
default:
return -ENOPROTOOPT;
}
@@ -1005,6 +1015,7 @@ static const struct proto_ops unix_dgram_ops = {
#endif
.listen = sock_no_listen,
.shutdown = unix_shutdown,
+ .setsockopt = unix_setsockopt,
.sendmsg = unix_dgram_sendmsg,
.read_skb = unix_read_skb,
.recvmsg = unix_dgram_recvmsg,
@@ -1029,6 +1040,7 @@ static const struct proto_ops unix_seqpacket_ops = {
#endif
.listen = unix_listen,
.shutdown = unix_shutdown,
+ .setsockopt = unix_setsockopt,
.sendmsg = unix_seqpacket_sendmsg,
.recvmsg = unix_seqpacket_recvmsg,
.mmap = sock_no_mmap,
@@ -1142,11 +1154,10 @@ static int unix_create(struct net *net, struct socket *sock, int protocol,
if (protocol && protocol != PF_UNIX)
return -EPROTONOSUPPORT;
- sock->state = SS_UNCONNECTED;
+ set_bit(SOCK_CUSTOM_SOCKOPT, &sock->flags);
switch (sock->type) {
case SOCK_STREAM:
- set_bit(SOCK_CUSTOM_SOCKOPT, &sock->flags);
sock->ops = &unix_stream_ops;
break;
/*
@@ -1198,17 +1209,12 @@ static struct sock *unix_find_bsd(struct sockaddr_un *sunaddr, int addr_len,
unix_mkname_bsd(sunaddr, addr_len);
if (flags & SOCK_COREDUMP) {
- struct path root;
-
- task_lock(&init_task);
- get_fs_root(init_task.fs, &root);
- task_unlock(&init_task);
-
- scoped_with_kernel_creds()
- err = vfs_path_lookup(root.dentry, root.mnt, sunaddr->sun_path,
- LOOKUP_BENEATH | LOOKUP_NO_SYMLINKS |
- LOOKUP_NO_MAGICLINKS, &path);
- path_put(&root);
+ scoped_with_init_fs() {
+ scoped_with_kernel_creds()
+ err = kern_path(sunaddr->sun_path,
+ LOOKUP_NO_SYMLINKS |
+ LOOKUP_NO_MAGICLINKS, &path);
+ }
if (err)
goto fail;
} else {
@@ -1744,9 +1750,10 @@ restart:
init_peercred(newsk, &peercred);
newu = unix_sk(newsk);
+ otheru = unix_sk(other);
newu->listener = other;
+ newu->scm_rights_notrunc = READ_ONCE(otheru->scm_rights_notrunc);
RCU_INIT_POINTER(newsk->sk_wq, &newu->peer_wq);
- otheru = unix_sk(other);
/* copy address information from listening to new sock
*
@@ -1775,7 +1782,6 @@ restart:
/* Set credentials */
copy_peercred(sk, other);
- sock->state = SS_CONNECTED;
WRITE_ONCE(sk->sk_state, TCP_ESTABLISHED);
sock_hold(newsk);
@@ -1831,8 +1837,7 @@ static int unix_socketpair(struct socket *socka, struct socket *sockb)
ska->sk_state = TCP_ESTABLISHED;
skb->sk_state = TCP_ESTABLISHED;
- socka->state = SS_CONNECTED;
- sockb->state = SS_CONNECTED;
+
return 0;
}
@@ -1868,13 +1873,11 @@ static int unix_accept(struct socket *sock, struct socket *newsock,
skb_free_datagram(sk, skb);
wake_up_interruptible(&unix_sk(sk)->peer_wait);
- if (tsk->sk_type == SOCK_STREAM)
- set_bit(SOCK_CUSTOM_SOCKOPT, &newsock->flags);
+ set_bit(SOCK_CUSTOM_SOCKOPT, &newsock->flags);
/* attach accepted sock to socket */
unix_state_lock(tsk);
unix_update_edges(unix_sk(tsk));
- newsock->state = SS_CONNECTED;
sock_graft(tsk, newsock);
unix_state_unlock(tsk);
return 0;
@@ -2711,8 +2714,7 @@ static int unix_read_skb(struct sock *sk, skb_read_actor_t recv_actor)
* Sleep until more data has arrived. But check for races..
*/
static long unix_stream_data_wait(struct sock *sk, long timeo,
- struct sk_buff *last, unsigned int last_len,
- bool freezable)
+ struct sk_buff *last, bool freezable)
{
unsigned int state = TASK_INTERRUPTIBLE | freezable * TASK_FREEZABLE;
struct sk_buff *tail;
@@ -2725,7 +2727,6 @@ static long unix_stream_data_wait(struct sock *sk, long timeo,
tail = skb_peek_tail(&sk->sk_receive_queue);
if (tail != last ||
- (tail && tail->len != last_len) ||
sk->sk_err ||
(sk->sk_shutdown & RCV_SHUTDOWN) ||
signal_pending(current) ||
@@ -2811,8 +2812,8 @@ static int unix_stream_recv_urg(struct unix_stream_read_state *state)
return 1;
}
-static struct sk_buff *manage_oob(struct sk_buff *skb, struct sock *sk,
- int flags, int copied)
+static struct sk_buff *manage_oob(struct sk_buff *skb, struct sk_buff **last,
+ struct sock *sk, int flags, int copied)
{
struct sk_buff *read_skb = NULL, *unread_skb = NULL;
struct unix_sock *u = unix_sk(sk);
@@ -2826,11 +2827,13 @@ static struct sk_buff *manage_oob(struct sk_buff *skb, struct sock *sk,
if (copied && (!u->oob_skb || skb == u->oob_skb)) {
skb = NULL;
} else if (flags & MSG_PEEK) {
+ *last = skb;
skb = skb_peek_next(skb, &sk->sk_receive_queue);
} else {
read_skb = skb;
skb = skb_peek_next(skb, &sk->sk_receive_queue);
__skb_unlink(read_skb, &sk->sk_receive_queue);
+ *last = skb;
}
if (!skb)
@@ -2849,8 +2852,10 @@ static struct sk_buff *manage_oob(struct sk_buff *skb, struct sock *sk,
__skb_unlink(skb, &sk->sk_receive_queue);
unread_skb = skb;
skb = skb_peek(&sk->sk_receive_queue);
+ *last = skb;
}
} else if (!sock_flag(sk, SOCK_URGINLINE)) {
+ *last = skb;
skb = skb_peek_next(skb, &sk->sk_receive_queue);
}
@@ -2888,7 +2893,7 @@ static int unix_stream_read_skb(struct sock *sk, skb_read_actor_t recv_actor)
return -EAGAIN;
}
- WRITE_ONCE(u->inq_len, u->inq_len - skb->len);
+ WRITE_ONCE(u->inq_len, u->inq_len - unix_skb_len(skb));
#if IS_ENABLED(CONFIG_AF_UNIX_OOB)
if (skb == u->oob_skb) {
@@ -2921,7 +2926,6 @@ static int unix_stream_read_generic(struct unix_stream_read_state *state,
int flags = state->flags;
bool check_creds = false;
struct scm_cookie scm;
- unsigned int last_len;
struct unix_sock *u;
int copied = 0;
int err = 0;
@@ -2967,13 +2971,12 @@ redo:
goto unlock;
}
last = skb = skb_peek(&sk->sk_receive_queue);
- last_len = last ? last->len : 0;
again:
#if IS_ENABLED(CONFIG_AF_UNIX_OOB)
if (skb) {
- skb = manage_oob(skb, sk, flags, copied);
- if (!skb && copied) {
+ skb = manage_oob(skb, &last, sk, flags, copied);
+ if (!skb && (copied || !state->size)) {
unix_state_unlock(sk);
break;
}
@@ -3001,8 +3004,7 @@ again:
mutex_unlock(&u->iolock);
- timeo = unix_stream_data_wait(sk, timeo, last,
- last_len, freezable);
+ timeo = unix_stream_data_wait(sk, timeo, last, freezable);
if (signal_pending(current)) {
err = sock_intr_errno(timeo);
@@ -3019,7 +3021,6 @@ unlock:
while (skip >= unix_skb_len(skb)) {
skip -= unix_skb_len(skb);
last = skb;
- last_len = skb->len;
skb = skb_peek_next(skb, &sk->sk_receive_queue);
if (!skb)
goto again;
@@ -3069,11 +3070,12 @@ unlock:
unix_detach_fds(&scm, skb);
}
- if (unix_skb_len(skb))
- break;
-
spin_lock(&sk->sk_receive_queue.lock);
- WRITE_ONCE(u->inq_len, u->inq_len - skb->len);
+ WRITE_ONCE(u->inq_len, u->inq_len - chunk);
+ if (unix_skb_len(skb)) {
+ spin_unlock(&sk->sk_receive_queue.lock);
+ break;
+ }
__skb_unlink(skb, &sk->sk_receive_queue);
spin_unlock(&sk->sk_receive_queue.lock);
@@ -3094,7 +3096,6 @@ unlock:
skip = 0;
last = skb;
- last_len = skb->len;
unix_state_lock(sk);
skb = skb_peek_next(skb, &sk->sk_receive_queue);
if (skb)
@@ -3670,8 +3671,8 @@ static int bpf_iter_unix_realloc_batch(struct bpf_unix_iter_state *iter,
{
struct sock **new_batch;
- new_batch = kvmalloc(sizeof(*new_batch) * new_batch_sz,
- GFP_USER | __GFP_NOWARN);
+ new_batch = kvmalloc_objs(*new_batch, new_batch_sz,
+ GFP_USER | __GFP_NOWARN);
if (!new_batch)
return -ENOMEM;