]>
Commit | Line | Data |
---|---|---|
d55578af GKH |
1 | From foo@baz Wed May 16 16:57:32 CEST 2018 |
2 | From: Lance Richardson <lance.richardson.net@gmail.com> | |
3 | Date: Wed, 25 Apr 2018 10:21:54 -0400 | |
4 | Subject: net: support compat 64-bit time in {s,g}etsockopt | |
5 | ||
6 | From: Lance Richardson <lance.richardson.net@gmail.com> | |
7 | ||
8 | [ Upstream commit 988bf7243e03ef69238381594e0334a79cef74a6 ] | |
9 | ||
10 | For the x32 ABI, struct timeval has two 64-bit fields. However | |
11 | the kernel currently interprets the user-space values used for | |
12 | the SO_RCVTIMEO and SO_SNDTIMEO socket options as having a pair | |
13 | of 32-bit fields. | |
14 | ||
15 | When the seconds portion of the requested timeout is less than 2**32, | |
16 | the seconds portion of the effective timeout is correct but the | |
17 | microseconds portion is zero. When the seconds portion of the | |
18 | requested timeout is zero and the microseconds portion is non-zero, | |
19 | the kernel interprets the timeout as zero (never timeout). | |
20 | ||
21 | Fix by using 64-bit time for SO_RCVTIMEO/SO_SNDTIMEO as required | |
22 | for the ABI. | |
23 | ||
24 | The code included below demonstrates the problem. | |
25 | ||
26 | Results before patch: | |
27 | $ gcc -m64 -Wall -O2 -o socktmo socktmo.c && ./socktmo | |
28 | recv time: 2.008181 seconds | |
29 | send time: 2.015985 seconds | |
30 | ||
31 | $ gcc -m32 -Wall -O2 -o socktmo socktmo.c && ./socktmo | |
32 | recv time: 2.016763 seconds | |
33 | send time: 2.016062 seconds | |
34 | ||
35 | $ gcc -mx32 -Wall -O2 -o socktmo socktmo.c && ./socktmo | |
36 | recv time: 1.007239 seconds | |
37 | send time: 1.023890 seconds | |
38 | ||
39 | Results after patch: | |
40 | $ gcc -m64 -O2 -Wall -o socktmo socktmo.c && ./socktmo | |
41 | recv time: 2.010062 seconds | |
42 | send time: 2.015836 seconds | |
43 | ||
44 | $ gcc -m32 -O2 -Wall -o socktmo socktmo.c && ./socktmo | |
45 | recv time: 2.013974 seconds | |
46 | send time: 2.015981 seconds | |
47 | ||
48 | $ gcc -mx32 -O2 -Wall -o socktmo socktmo.c && ./socktmo | |
49 | recv time: 2.030257 seconds | |
50 | send time: 2.013383 seconds | |
51 | ||
52 | #include <stdio.h> | |
53 | #include <stdlib.h> | |
54 | #include <sys/socket.h> | |
55 | #include <sys/types.h> | |
56 | #include <sys/time.h> | |
57 | ||
58 | void checkrc(char *str, int rc) | |
59 | { | |
60 | if (rc >= 0) | |
61 | return; | |
62 | ||
63 | perror(str); | |
64 | exit(1); | |
65 | } | |
66 | ||
67 | static char buf[1024]; | |
68 | int main(int argc, char **argv) | |
69 | { | |
70 | int rc; | |
71 | int socks[2]; | |
72 | struct timeval tv; | |
73 | struct timeval start, end, delta; | |
74 | ||
75 | rc = socketpair(AF_UNIX, SOCK_STREAM, 0, socks); | |
76 | checkrc("socketpair", rc); | |
77 | ||
78 | /* set timeout to 1.999999 seconds */ | |
79 | tv.tv_sec = 1; | |
80 | tv.tv_usec = 999999; | |
81 | rc = setsockopt(socks[0], SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof tv); | |
82 | rc = setsockopt(socks[0], SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof tv); | |
83 | checkrc("setsockopt", rc); | |
84 | ||
85 | /* measure actual receive timeout */ | |
86 | gettimeofday(&start, NULL); | |
87 | rc = recv(socks[0], buf, sizeof buf, 0); | |
88 | gettimeofday(&end, NULL); | |
89 | timersub(&end, &start, &delta); | |
90 | ||
91 | printf("recv time: %ld.%06ld seconds\n", | |
92 | (long)delta.tv_sec, (long)delta.tv_usec); | |
93 | ||
94 | /* fill send buffer */ | |
95 | do { | |
96 | rc = send(socks[0], buf, sizeof buf, 0); | |
97 | } while (rc > 0); | |
98 | ||
99 | /* measure actual send timeout */ | |
100 | gettimeofday(&start, NULL); | |
101 | rc = send(socks[0], buf, sizeof buf, 0); | |
102 | gettimeofday(&end, NULL); | |
103 | timersub(&end, &start, &delta); | |
104 | ||
105 | printf("send time: %ld.%06ld seconds\n", | |
106 | (long)delta.tv_sec, (long)delta.tv_usec); | |
107 | exit(0); | |
108 | } | |
109 | ||
110 | Fixes: 515c7af85ed9 ("x32: Use compat shims for {g,s}etsockopt") | |
111 | Reported-by: Gopal RajagopalSai <gopalsr83@gmail.com> | |
112 | Signed-off-by: Lance Richardson <lance.richardson.net@gmail.com> | |
113 | Signed-off-by: David S. Miller <davem@davemloft.net> | |
114 | Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> | |
115 | --- | |
116 | net/compat.c | 6 ++++-- | |
117 | 1 file changed, 4 insertions(+), 2 deletions(-) | |
118 | ||
119 | --- a/net/compat.c | |
120 | +++ b/net/compat.c | |
121 | @@ -358,7 +358,8 @@ static int compat_sock_setsockopt(struct | |
122 | if (optname == SO_ATTACH_FILTER) | |
123 | return do_set_attach_filter(sock, level, optname, | |
124 | optval, optlen); | |
125 | - if (optname == SO_RCVTIMEO || optname == SO_SNDTIMEO) | |
126 | + if (!COMPAT_USE_64BIT_TIME && | |
127 | + (optname == SO_RCVTIMEO || optname == SO_SNDTIMEO)) | |
128 | return do_set_sock_timeout(sock, level, optname, optval, optlen); | |
129 | ||
130 | return sock_setsockopt(sock, level, optname, optval, optlen); | |
131 | @@ -423,7 +424,8 @@ static int do_get_sock_timeout(struct so | |
132 | static int compat_sock_getsockopt(struct socket *sock, int level, int optname, | |
133 | char __user *optval, int __user *optlen) | |
134 | { | |
135 | - if (optname == SO_RCVTIMEO || optname == SO_SNDTIMEO) | |
136 | + if (!COMPAT_USE_64BIT_TIME && | |
137 | + (optname == SO_RCVTIMEO || optname == SO_SNDTIMEO)) | |
138 | return do_get_sock_timeout(sock, level, optname, optval, optlen); | |
139 | return sock_getsockopt(sock, level, optname, optval, optlen); | |
140 | } |