]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/blame - releases/4.4.133/net-support-compat-64-bit-time-in-s-g-etsockopt.patch
4.14-stable patches
[thirdparty/kernel/stable-queue.git] / releases / 4.4.133 / net-support-compat-64-bit-time-in-s-g-etsockopt.patch
CommitLineData
d55578af
GKH
1From foo@baz Wed May 16 16:57:32 CEST 2018
2From: Lance Richardson <lance.richardson.net@gmail.com>
3Date: Wed, 25 Apr 2018 10:21:54 -0400
4Subject: net: support compat 64-bit time in {s,g}etsockopt
5
6From: Lance Richardson <lance.richardson.net@gmail.com>
7
8[ Upstream commit 988bf7243e03ef69238381594e0334a79cef74a6 ]
9
10For the x32 ABI, struct timeval has two 64-bit fields. However
11the kernel currently interprets the user-space values used for
12the SO_RCVTIMEO and SO_SNDTIMEO socket options as having a pair
13of 32-bit fields.
14
15When the seconds portion of the requested timeout is less than 2**32,
16the seconds portion of the effective timeout is correct but the
17microseconds portion is zero. When the seconds portion of the
18requested timeout is zero and the microseconds portion is non-zero,
19the kernel interprets the timeout as zero (never timeout).
20
21Fix by using 64-bit time for SO_RCVTIMEO/SO_SNDTIMEO as required
22for the ABI.
23
24The code included below demonstrates the problem.
25
26Results 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
39Results 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
110Fixes: 515c7af85ed9 ("x32: Use compat shims for {g,s}etsockopt")
111Reported-by: Gopal RajagopalSai <gopalsr83@gmail.com>
112Signed-off-by: Lance Richardson <lance.richardson.net@gmail.com>
113Signed-off-by: David S. Miller <davem@davemloft.net>
114Signed-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 }