]>
Commit | Line | Data |
---|---|---|
963efa89 GKH |
1 | From foo@baz Mon Jan 13 09:28:30 PST 2014 |
2 | From: Sasha Levin <sasha.levin@oracle.com> | |
3 | Date: Sat, 7 Dec 2013 17:26:27 -0500 | |
4 | Subject: net: unix: allow set_peek_off to fail | |
5 | ||
6 | From: Sasha Levin <sasha.levin@oracle.com> | |
7 | ||
8 | [ Upstream commit 12663bfc97c8b3fdb292428105dd92d563164050 ] | |
9 | ||
10 | unix_dgram_recvmsg() will hold the readlock of the socket until recv | |
11 | is complete. | |
12 | ||
13 | In the same time, we may try to setsockopt(SO_PEEK_OFF) which will hang until | |
14 | unix_dgram_recvmsg() will complete (which can take a while) without allowing | |
15 | us to break out of it, triggering a hung task spew. | |
16 | ||
17 | Instead, allow set_peek_off to fail, this way userspace will not hang. | |
18 | ||
19 | Signed-off-by: Sasha Levin <sasha.levin@oracle.com> | |
20 | Acked-by: Pavel Emelyanov <xemul@parallels.com> | |
21 | Signed-off-by: David S. Miller <davem@davemloft.net> | |
22 | Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> | |
23 | --- | |
24 | include/linux/net.h | 2 +- | |
25 | net/core/sock.c | 2 +- | |
26 | net/unix/af_unix.c | 8 ++++++-- | |
27 | 3 files changed, 8 insertions(+), 4 deletions(-) | |
28 | ||
29 | --- a/include/linux/net.h | |
30 | +++ b/include/linux/net.h | |
31 | @@ -215,7 +215,7 @@ struct proto_ops { | |
32 | int offset, size_t size, int flags); | |
33 | ssize_t (*splice_read)(struct socket *sock, loff_t *ppos, | |
34 | struct pipe_inode_info *pipe, size_t len, unsigned int flags); | |
35 | - void (*set_peek_off)(struct sock *sk, int val); | |
36 | + int (*set_peek_off)(struct sock *sk, int val); | |
37 | }; | |
38 | ||
39 | #define DECLARE_SOCKADDR(type, dst, src) \ | |
40 | --- a/net/core/sock.c | |
41 | +++ b/net/core/sock.c | |
42 | @@ -795,7 +795,7 @@ set_rcvbuf: | |
43 | ||
44 | case SO_PEEK_OFF: | |
45 | if (sock->ops->set_peek_off) | |
46 | - sock->ops->set_peek_off(sk, val); | |
47 | + ret = sock->ops->set_peek_off(sk, val); | |
48 | else | |
49 | ret = -EOPNOTSUPP; | |
50 | break; | |
51 | --- a/net/unix/af_unix.c | |
52 | +++ b/net/unix/af_unix.c | |
53 | @@ -524,13 +524,17 @@ static int unix_seqpacket_sendmsg(struct | |
54 | static int unix_seqpacket_recvmsg(struct kiocb *, struct socket *, | |
55 | struct msghdr *, size_t, int); | |
56 | ||
57 | -static void unix_set_peek_off(struct sock *sk, int val) | |
58 | +static int unix_set_peek_off(struct sock *sk, int val) | |
59 | { | |
60 | struct unix_sock *u = unix_sk(sk); | |
61 | ||
62 | - mutex_lock(&u->readlock); | |
63 | + if (mutex_lock_interruptible(&u->readlock)) | |
64 | + return -EINTR; | |
65 | + | |
66 | sk->sk_peek_off = val; | |
67 | mutex_unlock(&u->readlock); | |
68 | + | |
69 | + return 0; | |
70 | } | |
71 | ||
72 |