]>
Commit | Line | Data |
---|---|---|
ce923a57 GKH |
1 | From zhengjunling@huawei.com Tue Jun 2 15:26:33 2015 |
2 | From: Junling Zheng <zhengjunling@huawei.com> | |
3 | Date: Mon, 1 Jun 2015 09:28:00 +0000 | |
4 | Subject: net: socket: Fix the wrong returns for recvmsg and sendmsg | |
5 | To: <gregkh@linuxfoundation.org> | |
6 | Cc: <lizefan@huawei.com>, <viro@zeniv.linux.org.uk>, <davem@davemloft.net>, <xuhanbing@huawei.com>, <stable@vger.kernel.org>, <netdev@vger.kernel.org> | |
7 | Message-ID: <1433150880-9976-1-git-send-email-zhengjunling@huawei.com> | |
8 | ||
9 | From: Junling Zheng <zhengjunling@huawei.com> | |
10 | ||
11 | Based on 08adb7dabd4874cc5666b4490653b26534702ce0 upstream. | |
12 | ||
13 | We found that after v3.10.73, recvmsg might return -EFAULT while -EINVAL | |
14 | was expected. | |
15 | ||
16 | We tested it through the recvmsg01 testcase come from LTP testsuit. It set | |
17 | msg->msg_namelen to -1 and the recvmsg syscall returned errno 14, which is | |
18 | unexpected (errno 22 is expected): | |
19 | ||
20 | recvmsg01 4 TFAIL : invalid socket length ; returned -1 (expected -1), | |
21 | errno 14 (expected 22) | |
22 | ||
23 | Linux mainline has no this bug for commit 08adb7dab fixes it accidentally. | |
24 | However, it is too large and complex to be backported to LTS 3.10. | |
25 | ||
26 | Commit 281c9c36 (net: compat: Update get_compat_msghdr() to match | |
27 | copy_msghdr_from_user() behaviour) made get_compat_msghdr() return | |
28 | error if msg_sys->msg_namelen was negative, which changed the behaviors | |
29 | of recvmsg and sendmsg syscall in a lib32 system: | |
30 | ||
31 | Before commit 281c9c36, get_compat_msghdr() wouldn't fail and it would | |
32 | return -EINVAL in move_addr_to_user() or somewhere if msg_sys->msg_namelen | |
33 | was invalid and then syscall returned -EINVAL, which is correct. | |
34 | ||
35 | And now, when msg_sys->msg_namelen is negative, get_compat_msghdr() will | |
36 | fail and wants to return -EINVAL, however, the outer syscall will return | |
37 | -EFAULT directly, which is unexpected. | |
38 | ||
39 | This patch gets the return value of get_compat_msghdr() as well as | |
40 | copy_msghdr_from_user(), then returns this expected value if | |
41 | get_compat_msghdr() fails. | |
42 | ||
43 | Fixes: 281c9c36 (net: compat: Update get_compat_msghdr() to match copy_msghdr_from_user() behaviour) | |
44 | Signed-off-by: Junling Zheng <zhengjunling@huawei.com> | |
45 | Signed-off-by: Hanbing Xu <xuhanbing@huawei.com> | |
46 | Cc: Li Zefan <lizefan@huawei.com> | |
47 | Cc: Al Viro <viro@zeniv.linux.org.uk> | |
48 | Cc: David Miller <davem@davemloft.net> | |
49 | Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> | |
50 | ||
51 | --- | |
52 | net/socket.c | 24 ++++++++++-------------- | |
53 | 1 file changed, 10 insertions(+), 14 deletions(-) | |
54 | ||
55 | --- a/net/socket.c | |
56 | +++ b/net/socket.c | |
57 | @@ -2007,14 +2007,12 @@ static int ___sys_sendmsg(struct socket | |
58 | int err, ctl_len, total_len; | |
59 | ||
60 | err = -EFAULT; | |
61 | - if (MSG_CMSG_COMPAT & flags) { | |
62 | - if (get_compat_msghdr(msg_sys, msg_compat)) | |
63 | - return -EFAULT; | |
64 | - } else { | |
65 | + if (MSG_CMSG_COMPAT & flags) | |
66 | + err = get_compat_msghdr(msg_sys, msg_compat); | |
67 | + else | |
68 | err = copy_msghdr_from_user(msg_sys, msg); | |
69 | - if (err) | |
70 | - return err; | |
71 | - } | |
72 | + if (err) | |
73 | + return err; | |
74 | ||
75 | if (msg_sys->msg_iovlen > UIO_FASTIOV) { | |
76 | err = -EMSGSIZE; | |
77 | @@ -2219,14 +2217,12 @@ static int ___sys_recvmsg(struct socket | |
78 | struct sockaddr __user *uaddr; | |
79 | int __user *uaddr_len; | |
80 | ||
81 | - if (MSG_CMSG_COMPAT & flags) { | |
82 | - if (get_compat_msghdr(msg_sys, msg_compat)) | |
83 | - return -EFAULT; | |
84 | - } else { | |
85 | + if (MSG_CMSG_COMPAT & flags) | |
86 | + err = get_compat_msghdr(msg_sys, msg_compat); | |
87 | + else | |
88 | err = copy_msghdr_from_user(msg_sys, msg); | |
89 | - if (err) | |
90 | - return err; | |
91 | - } | |
92 | + if (err) | |
93 | + return err; | |
94 | ||
95 | if (msg_sys->msg_iovlen > UIO_FASTIOV) { | |
96 | err = -EMSGSIZE; |