]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/blame - releases/4.4.133/futex-remove-duplicated-code-and-fix-undefined-behaviour.patch
Fixes for 5.10
[thirdparty/kernel/stable-queue.git] / releases / 4.4.133 / futex-remove-duplicated-code-and-fix-undefined-behaviour.patch
CommitLineData
7eb50402
GKH
1From 30d6e0a4190d37740e9447e4e4815f06992dd8c3 Mon Sep 17 00:00:00 2001
2From: Jiri Slaby <jslaby@suse.cz>
3Date: Thu, 24 Aug 2017 09:31:05 +0200
4Subject: futex: Remove duplicated code and fix undefined behaviour
5
6From: Jiri Slaby <jslaby@suse.cz>
7
8commit 30d6e0a4190d37740e9447e4e4815f06992dd8c3 upstream.
9
10There is code duplicated over all architecture's headers for
11futex_atomic_op_inuser. Namely op decoding, access_ok check for uaddr,
12and comparison of the result.
13
14Remove this duplication and leave up to the arches only the needed
15assembly which is now in arch_futex_atomic_op_inuser.
16
17This effectively distributes the Will Deacon's arm64 fix for undefined
18behaviour reported by UBSAN to all architectures. The fix was done in
19commit 5f16a046f8e1 (arm64: futex: Fix undefined behaviour with
20FUTEX_OP_OPARG_SHIFT usage). Look there for an example dump.
21
22And as suggested by Thomas, check for negative oparg too, because it was
23also reported to cause undefined behaviour report.
24
25Note that s390 removed access_ok check in d12a29703 ("s390/uaccess:
26remove pointless access_ok() checks") as access_ok there returns true.
27We introduce it back to the helper for the sake of simplicity (it gets
28optimized away anyway).
29
30Signed-off-by: Jiri Slaby <jslaby@suse.cz>
31Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
32Acked-by: Russell King <rmk+kernel@armlinux.org.uk>
33Acked-by: Michael Ellerman <mpe@ellerman.id.au> (powerpc)
34Acked-by: Heiko Carstens <heiko.carstens@de.ibm.com> [s390]
35Acked-by: Chris Metcalf <cmetcalf@mellanox.com> [for tile]
36Reviewed-by: Darren Hart (VMware) <dvhart@infradead.org>
37Reviewed-by: Will Deacon <will.deacon@arm.com> [core/arm64]
38Cc: linux-mips@linux-mips.org
39Cc: Rich Felker <dalias@libc.org>
40Cc: linux-ia64@vger.kernel.org
41Cc: linux-sh@vger.kernel.org
42Cc: peterz@infradead.org
43Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
44Cc: Max Filippov <jcmvbkbc@gmail.com>
45Cc: Paul Mackerras <paulus@samba.org>
46Cc: sparclinux@vger.kernel.org
47Cc: Jonas Bonn <jonas@southpole.se>
48Cc: linux-s390@vger.kernel.org
49Cc: linux-arch@vger.kernel.org
50Cc: Yoshinori Sato <ysato@users.sourceforge.jp>
51Cc: linux-hexagon@vger.kernel.org
52Cc: Helge Deller <deller@gmx.de>
53Cc: "James E.J. Bottomley" <jejb@parisc-linux.org>
54Cc: Catalin Marinas <catalin.marinas@arm.com>
55Cc: Matt Turner <mattst88@gmail.com>
56Cc: linux-snps-arc@lists.infradead.org
57Cc: Fenghua Yu <fenghua.yu@intel.com>
58Cc: Arnd Bergmann <arnd@arndb.de>
59Cc: linux-xtensa@linux-xtensa.org
60Cc: Stefan Kristiansson <stefan.kristiansson@saunalahti.fi>
61Cc: openrisc@lists.librecores.org
62Cc: Ivan Kokshaysky <ink@jurassic.park.msu.ru>
63Cc: Stafford Horne <shorne@gmail.com>
64Cc: linux-arm-kernel@lists.infradead.org
65Cc: Richard Henderson <rth@twiddle.net>
66Cc: Chris Zankel <chris@zankel.net>
67Cc: Michal Simek <monstr@monstr.eu>
68Cc: Tony Luck <tony.luck@intel.com>
69Cc: linux-parisc@vger.kernel.org
70Cc: Vineet Gupta <vgupta@synopsys.com>
71Cc: Ralf Baechle <ralf@linux-mips.org>
72Cc: Richard Kuo <rkuo@codeaurora.org>
73Cc: linux-alpha@vger.kernel.org
74Cc: Martin Schwidefsky <schwidefsky@de.ibm.com>
75Cc: linuxppc-dev@lists.ozlabs.org
76Cc: "David S. Miller" <davem@davemloft.net>
77Link: http://lkml.kernel.org/r/20170824073105.3901-1-jslaby@suse.cz
78Cc: Ben Hutchings <ben.hutchings@codethink.co.uk>
79Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
80
81---
82 arch/alpha/include/asm/futex.h | 26 +++---------------
83 arch/arc/include/asm/futex.h | 40 +++-------------------------
84 arch/arm/include/asm/futex.h | 26 ++----------------
85 arch/arm64/include/asm/futex.h | 26 ++----------------
86 arch/frv/include/asm/futex.h | 3 +-
87 arch/frv/kernel/futex.c | 27 ++-----------------
88 arch/hexagon/include/asm/futex.h | 38 ++-------------------------
89 arch/ia64/include/asm/futex.h | 25 ++----------------
90 arch/microblaze/include/asm/futex.h | 38 ++-------------------------
91 arch/mips/include/asm/futex.h | 25 ++----------------
92 arch/parisc/include/asm/futex.h | 25 ++----------------
93 arch/powerpc/include/asm/futex.h | 26 +++---------------
94 arch/s390/include/asm/futex.h | 23 +++-------------
95 arch/sh/include/asm/futex.h | 26 ++----------------
96 arch/sparc/include/asm/futex_64.h | 26 +++---------------
97 arch/tile/include/asm/futex.h | 40 +++-------------------------
98 arch/x86/include/asm/futex.h | 40 +++-------------------------
99 arch/xtensa/include/asm/futex.h | 27 +++----------------
100 include/asm-generic/futex.h | 50 ++++++------------------------------
101 kernel/futex.c | 39 ++++++++++++++++++++++++++++
102 20 files changed, 126 insertions(+), 470 deletions(-)
103
104--- a/arch/alpha/include/asm/futex.h
105+++ b/arch/alpha/include/asm/futex.h
106@@ -29,18 +29,10 @@
107 : "r" (uaddr), "r"(oparg) \
108 : "memory")
109
110-static inline int futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr)
111+static inline int arch_futex_atomic_op_inuser(int op, int oparg, int *oval,
112+ u32 __user *uaddr)
113 {
114- int op = (encoded_op >> 28) & 7;
115- int cmp = (encoded_op >> 24) & 15;
116- int oparg = (encoded_op << 8) >> 20;
117- int cmparg = (encoded_op << 20) >> 20;
118 int oldval = 0, ret;
119- if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
120- oparg = 1 << oparg;
121-
122- if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
123- return -EFAULT;
124
125 pagefault_disable();
126
127@@ -66,17 +58,9 @@ static inline int futex_atomic_op_inuser
128
129 pagefault_enable();
130
131- if (!ret) {
132- switch (cmp) {
133- case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
134- case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
135- case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
136- case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
137- case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
138- case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
139- default: ret = -ENOSYS;
140- }
141- }
142+ if (!ret)
143+ *oval = oldval;
144+
145 return ret;
146 }
147
148--- a/arch/arc/include/asm/futex.h
149+++ b/arch/arc/include/asm/futex.h
150@@ -73,20 +73,11 @@
151
152 #endif
153
154-static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
155+static inline int arch_futex_atomic_op_inuser(int op, int oparg, int *oval,
156+ u32 __user *uaddr)
157 {
158- int op = (encoded_op >> 28) & 7;
159- int cmp = (encoded_op >> 24) & 15;
160- int oparg = (encoded_op << 8) >> 20;
161- int cmparg = (encoded_op << 20) >> 20;
162 int oldval = 0, ret;
163
164- if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
165- oparg = 1 << oparg;
166-
167- if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
168- return -EFAULT;
169-
170 #ifndef CONFIG_ARC_HAS_LLSC
171 preempt_disable(); /* to guarantee atomic r-m-w of futex op */
172 #endif
173@@ -118,30 +109,9 @@ static inline int futex_atomic_op_inuser
174 preempt_enable();
175 #endif
176
177- if (!ret) {
178- switch (cmp) {
179- case FUTEX_OP_CMP_EQ:
180- ret = (oldval == cmparg);
181- break;
182- case FUTEX_OP_CMP_NE:
183- ret = (oldval != cmparg);
184- break;
185- case FUTEX_OP_CMP_LT:
186- ret = (oldval < cmparg);
187- break;
188- case FUTEX_OP_CMP_GE:
189- ret = (oldval >= cmparg);
190- break;
191- case FUTEX_OP_CMP_LE:
192- ret = (oldval <= cmparg);
193- break;
194- case FUTEX_OP_CMP_GT:
195- ret = (oldval > cmparg);
196- break;
197- default:
198- ret = -ENOSYS;
199- }
200- }
201+ if (!ret)
202+ *oval = oldval;
203+
204 return ret;
205 }
206
207--- a/arch/arm/include/asm/futex.h
208+++ b/arch/arm/include/asm/futex.h
209@@ -128,20 +128,10 @@ futex_atomic_cmpxchg_inatomic(u32 *uval,
210 #endif /* !SMP */
211
212 static inline int
213-futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr)
214+arch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *uaddr)
215 {
216- int op = (encoded_op >> 28) & 7;
217- int cmp = (encoded_op >> 24) & 15;
218- int oparg = (encoded_op << 8) >> 20;
219- int cmparg = (encoded_op << 20) >> 20;
220 int oldval = 0, ret, tmp;
221
222- if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
223- oparg = 1 << oparg;
224-
225- if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
226- return -EFAULT;
227-
228 #ifndef CONFIG_SMP
229 preempt_disable();
230 #endif
231@@ -172,17 +162,9 @@ futex_atomic_op_inuser (int encoded_op,
232 preempt_enable();
233 #endif
234
235- if (!ret) {
236- switch (cmp) {
237- case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
238- case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
239- case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
240- case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
241- case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
242- case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
243- default: ret = -ENOSYS;
244- }
245- }
246+ if (!ret)
247+ *oval = oldval;
248+
249 return ret;
250 }
251
252--- a/arch/arm64/include/asm/futex.h
253+++ b/arch/arm64/include/asm/futex.h
254@@ -53,20 +53,10 @@
255 : "memory")
256
257 static inline int
258-futex_atomic_op_inuser(unsigned int encoded_op, u32 __user *uaddr)
259+arch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *uaddr)
260 {
261- int op = (encoded_op >> 28) & 7;
262- int cmp = (encoded_op >> 24) & 15;
263- int oparg = (int)(encoded_op << 8) >> 20;
264- int cmparg = (int)(encoded_op << 20) >> 20;
265 int oldval = 0, ret, tmp;
266
267- if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
268- oparg = 1U << (oparg & 0x1f);
269-
270- if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
271- return -EFAULT;
272-
273 pagefault_disable();
274
275 switch (op) {
276@@ -96,17 +86,9 @@ futex_atomic_op_inuser(unsigned int enco
277
278 pagefault_enable();
279
280- if (!ret) {
281- switch (cmp) {
282- case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
283- case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
284- case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
285- case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
286- case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
287- case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
288- default: ret = -ENOSYS;
289- }
290- }
291+ if (!ret)
292+ *oval = oldval;
293+
294 return ret;
295 }
296
297--- a/arch/frv/include/asm/futex.h
298+++ b/arch/frv/include/asm/futex.h
299@@ -7,7 +7,8 @@
300 #include <asm/errno.h>
301 #include <asm/uaccess.h>
302
303-extern int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr);
304+extern int arch_futex_atomic_op_inuser(int op, int oparg, int *oval,
305+ u32 __user *uaddr);
306
307 static inline int
308 futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
309--- a/arch/frv/kernel/futex.c
310+++ b/arch/frv/kernel/futex.c
311@@ -186,20 +186,10 @@ static inline int atomic_futex_op_xchg_x
312 /*
313 * do the futex operations
314 */
315-int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
316+int arch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *uaddr)
317 {
318- int op = (encoded_op >> 28) & 7;
319- int cmp = (encoded_op >> 24) & 15;
320- int oparg = (encoded_op << 8) >> 20;
321- int cmparg = (encoded_op << 20) >> 20;
322 int oldval = 0, ret;
323
324- if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
325- oparg = 1 << oparg;
326-
327- if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
328- return -EFAULT;
329-
330 pagefault_disable();
331
332 switch (op) {
333@@ -225,18 +215,9 @@ int futex_atomic_op_inuser(int encoded_o
334
335 pagefault_enable();
336
337- if (!ret) {
338- switch (cmp) {
339- case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
340- case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
341- case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
342- case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
343- case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
344- case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
345- default: ret = -ENOSYS; break;
346- }
347- }
348+ if (!ret)
349+ *oval = oldval;
350
351 return ret;
352
353-} /* end futex_atomic_op_inuser() */
354+} /* end arch_futex_atomic_op_inuser() */
355--- a/arch/hexagon/include/asm/futex.h
356+++ b/arch/hexagon/include/asm/futex.h
357@@ -31,18 +31,9 @@
358
359
360 static inline int
361-futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
362+arch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *uaddr)
363 {
364- int op = (encoded_op >> 28) & 7;
365- int cmp = (encoded_op >> 24) & 15;
366- int oparg = (encoded_op << 8) >> 20;
367- int cmparg = (encoded_op << 20) >> 20;
368 int oldval = 0, ret;
369- if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
370- oparg = 1 << oparg;
371-
372- if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
373- return -EFAULT;
374
375 pagefault_disable();
376
377@@ -72,30 +63,9 @@ futex_atomic_op_inuser(int encoded_op, i
378
379 pagefault_enable();
380
381- if (!ret) {
382- switch (cmp) {
383- case FUTEX_OP_CMP_EQ:
384- ret = (oldval == cmparg);
385- break;
386- case FUTEX_OP_CMP_NE:
387- ret = (oldval != cmparg);
388- break;
389- case FUTEX_OP_CMP_LT:
390- ret = (oldval < cmparg);
391- break;
392- case FUTEX_OP_CMP_GE:
393- ret = (oldval >= cmparg);
394- break;
395- case FUTEX_OP_CMP_LE:
396- ret = (oldval <= cmparg);
397- break;
398- case FUTEX_OP_CMP_GT:
399- ret = (oldval > cmparg);
400- break;
401- default:
402- ret = -ENOSYS;
403- }
404- }
405+ if (!ret)
406+ *oval = oldval;
407+
408 return ret;
409 }
410
411--- a/arch/ia64/include/asm/futex.h
412+++ b/arch/ia64/include/asm/futex.h
413@@ -45,18 +45,9 @@ do { \
414 } while (0)
415
416 static inline int
417-futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr)
418+arch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *uaddr)
419 {
420- int op = (encoded_op >> 28) & 7;
421- int cmp = (encoded_op >> 24) & 15;
422- int oparg = (encoded_op << 8) >> 20;
423- int cmparg = (encoded_op << 20) >> 20;
424 int oldval = 0, ret;
425- if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
426- oparg = 1 << oparg;
427-
428- if (! access_ok (VERIFY_WRITE, uaddr, sizeof(u32)))
429- return -EFAULT;
430
431 pagefault_disable();
432
433@@ -84,17 +75,9 @@ futex_atomic_op_inuser (int encoded_op,
434
435 pagefault_enable();
436
437- if (!ret) {
438- switch (cmp) {
439- case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
440- case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
441- case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
442- case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
443- case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
444- case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
445- default: ret = -ENOSYS;
446- }
447- }
448+ if (!ret)
449+ *oval = oldval;
450+
451 return ret;
452 }
453
454--- a/arch/microblaze/include/asm/futex.h
455+++ b/arch/microblaze/include/asm/futex.h
456@@ -29,18 +29,9 @@
457 })
458
459 static inline int
460-futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
461+arch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *uaddr)
462 {
463- int op = (encoded_op >> 28) & 7;
464- int cmp = (encoded_op >> 24) & 15;
465- int oparg = (encoded_op << 8) >> 20;
466- int cmparg = (encoded_op << 20) >> 20;
467 int oldval = 0, ret;
468- if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
469- oparg = 1 << oparg;
470-
471- if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
472- return -EFAULT;
473
474 pagefault_disable();
475
476@@ -66,30 +57,9 @@ futex_atomic_op_inuser(int encoded_op, u
477
478 pagefault_enable();
479
480- if (!ret) {
481- switch (cmp) {
482- case FUTEX_OP_CMP_EQ:
483- ret = (oldval == cmparg);
484- break;
485- case FUTEX_OP_CMP_NE:
486- ret = (oldval != cmparg);
487- break;
488- case FUTEX_OP_CMP_LT:
489- ret = (oldval < cmparg);
490- break;
491- case FUTEX_OP_CMP_GE:
492- ret = (oldval >= cmparg);
493- break;
494- case FUTEX_OP_CMP_LE:
495- ret = (oldval <= cmparg);
496- break;
497- case FUTEX_OP_CMP_GT:
498- ret = (oldval > cmparg);
499- break;
500- default:
501- ret = -ENOSYS;
502- }
503- }
504+ if (!ret)
505+ *oval = oldval;
506+
507 return ret;
508 }
509
510--- a/arch/mips/include/asm/futex.h
511+++ b/arch/mips/include/asm/futex.h
512@@ -83,18 +83,9 @@
513 }
514
515 static inline int
516-futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
517+arch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *uaddr)
518 {
519- int op = (encoded_op >> 28) & 7;
520- int cmp = (encoded_op >> 24) & 15;
521- int oparg = (encoded_op << 8) >> 20;
522- int cmparg = (encoded_op << 20) >> 20;
523 int oldval = 0, ret;
524- if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
525- oparg = 1 << oparg;
526-
527- if (! access_ok (VERIFY_WRITE, uaddr, sizeof(u32)))
528- return -EFAULT;
529
530 pagefault_disable();
531
532@@ -125,17 +116,9 @@ futex_atomic_op_inuser(int encoded_op, u
533
534 pagefault_enable();
535
536- if (!ret) {
537- switch (cmp) {
538- case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
539- case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
540- case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
541- case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
542- case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
543- case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
544- default: ret = -ENOSYS;
545- }
546- }
547+ if (!ret)
548+ *oval = oldval;
549+
550 return ret;
551 }
552
553--- a/arch/parisc/include/asm/futex.h
554+++ b/arch/parisc/include/asm/futex.h
555@@ -32,20 +32,11 @@ _futex_spin_unlock_irqrestore(u32 __user
556 }
557
558 static inline int
559-futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr)
560+arch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *uaddr)
561 {
562 unsigned long int flags;
563 u32 val;
564- int op = (encoded_op >> 28) & 7;
565- int cmp = (encoded_op >> 24) & 15;
566- int oparg = (encoded_op << 8) >> 20;
567- int cmparg = (encoded_op << 20) >> 20;
568 int oldval = 0, ret;
569- if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
570- oparg = 1 << oparg;
571-
572- if (!access_ok(VERIFY_WRITE, uaddr, sizeof(*uaddr)))
573- return -EFAULT;
574
575 pagefault_disable();
576
577@@ -98,17 +89,9 @@ futex_atomic_op_inuser (int encoded_op,
578
579 pagefault_enable();
580
581- if (!ret) {
582- switch (cmp) {
583- case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
584- case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
585- case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
586- case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
587- case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
588- case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
589- default: ret = -ENOSYS;
590- }
591- }
592+ if (!ret)
593+ *oval = oldval;
594+
595 return ret;
596 }
597
598--- a/arch/powerpc/include/asm/futex.h
599+++ b/arch/powerpc/include/asm/futex.h
600@@ -31,18 +31,10 @@
601 : "b" (uaddr), "i" (-EFAULT), "r" (oparg) \
602 : "cr0", "memory")
603
604-static inline int futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr)
605+static inline int arch_futex_atomic_op_inuser(int op, int oparg, int *oval,
606+ u32 __user *uaddr)
607 {
608- int op = (encoded_op >> 28) & 7;
609- int cmp = (encoded_op >> 24) & 15;
610- int oparg = (encoded_op << 8) >> 20;
611- int cmparg = (encoded_op << 20) >> 20;
612 int oldval = 0, ret;
613- if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
614- oparg = 1 << oparg;
615-
616- if (! access_ok (VERIFY_WRITE, uaddr, sizeof(u32)))
617- return -EFAULT;
618
619 pagefault_disable();
620
621@@ -68,17 +60,9 @@ static inline int futex_atomic_op_inuser
622
623 pagefault_enable();
624
625- if (!ret) {
626- switch (cmp) {
627- case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
628- case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
629- case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
630- case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
631- case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
632- case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
633- default: ret = -ENOSYS;
634- }
635- }
636+ if (!ret)
637+ *oval = oldval;
638+
639 return ret;
640 }
641
642--- a/arch/s390/include/asm/futex.h
643+++ b/arch/s390/include/asm/futex.h
644@@ -21,17 +21,12 @@
645 : "0" (-EFAULT), "d" (oparg), "a" (uaddr), \
646 "m" (*uaddr) : "cc");
647
648-static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
649+static inline int arch_futex_atomic_op_inuser(int op, int oparg, int *oval,
650+ u32 __user *uaddr)
651 {
652- int op = (encoded_op >> 28) & 7;
653- int cmp = (encoded_op >> 24) & 15;
654- int oparg = (encoded_op << 8) >> 20;
655- int cmparg = (encoded_op << 20) >> 20;
656 int oldval = 0, newval, ret;
657
658 load_kernel_asce();
659- if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
660- oparg = 1 << oparg;
661
662 pagefault_disable();
663 switch (op) {
664@@ -60,17 +55,9 @@ static inline int futex_atomic_op_inuser
665 }
666 pagefault_enable();
667
668- if (!ret) {
669- switch (cmp) {
670- case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
671- case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
672- case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
673- case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
674- case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
675- case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
676- default: ret = -ENOSYS;
677- }
678- }
679+ if (!ret)
680+ *oval = oldval;
681+
682 return ret;
683 }
684
685--- a/arch/sh/include/asm/futex.h
686+++ b/arch/sh/include/asm/futex.h
687@@ -10,20 +10,11 @@
688 /* XXX: UP variants, fix for SH-4A and SMP.. */
689 #include <asm/futex-irq.h>
690
691-static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
692+static inline int arch_futex_atomic_op_inuser(int op, u32 oparg, int *oval,
693+ u32 __user *uaddr)
694 {
695- int op = (encoded_op >> 28) & 7;
696- int cmp = (encoded_op >> 24) & 15;
697- int oparg = (encoded_op << 8) >> 20;
698- int cmparg = (encoded_op << 20) >> 20;
699 int oldval = 0, ret;
700
701- if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
702- oparg = 1 << oparg;
703-
704- if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
705- return -EFAULT;
706-
707 pagefault_disable();
708
709 switch (op) {
710@@ -49,17 +40,8 @@ static inline int futex_atomic_op_inuser
711
712 pagefault_enable();
713
714- if (!ret) {
715- switch (cmp) {
716- case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
717- case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
718- case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
719- case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
720- case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
721- case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
722- default: ret = -ENOSYS;
723- }
724- }
725+ if (!ret)
726+ *oval = oldval;
727
728 return ret;
729 }
730--- a/arch/sparc/include/asm/futex_64.h
731+++ b/arch/sparc/include/asm/futex_64.h
732@@ -29,22 +29,14 @@
733 : "r" (uaddr), "r" (oparg), "i" (-EFAULT) \
734 : "memory")
735
736-static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
737+static inline int arch_futex_atomic_op_inuser(int op, int oparg, int *oval,
738+ u32 __user *uaddr)
739 {
740- int op = (encoded_op >> 28) & 7;
741- int cmp = (encoded_op >> 24) & 15;
742- int oparg = (encoded_op << 8) >> 20;
743- int cmparg = (encoded_op << 20) >> 20;
744 int oldval = 0, ret, tem;
745
746- if (unlikely(!access_ok(VERIFY_WRITE, uaddr, sizeof(u32))))
747- return -EFAULT;
748 if (unlikely((((unsigned long) uaddr) & 0x3UL)))
749 return -EINVAL;
750
751- if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
752- oparg = 1 << oparg;
753-
754 pagefault_disable();
755
756 switch (op) {
757@@ -69,17 +61,9 @@ static inline int futex_atomic_op_inuser
758
759 pagefault_enable();
760
761- if (!ret) {
762- switch (cmp) {
763- case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
764- case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
765- case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
766- case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
767- case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
768- case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
769- default: ret = -ENOSYS;
770- }
771- }
772+ if (!ret)
773+ *oval = oldval;
774+
775 return ret;
776 }
777
778--- a/arch/tile/include/asm/futex.h
779+++ b/arch/tile/include/asm/futex.h
780@@ -106,12 +106,9 @@
781 lock = __atomic_hashed_lock((int __force *)uaddr)
782 #endif
783
784-static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
785+static inline int arch_futex_atomic_op_inuser(int op, u32 oparg, int *oval,
786+ u32 __user *uaddr)
787 {
788- int op = (encoded_op >> 28) & 7;
789- int cmp = (encoded_op >> 24) & 15;
790- int oparg = (encoded_op << 8) >> 20;
791- int cmparg = (encoded_op << 20) >> 20;
792 int uninitialized_var(val), ret;
793
794 __futex_prolog();
795@@ -119,12 +116,6 @@ static inline int futex_atomic_op_inuser
796 /* The 32-bit futex code makes this assumption, so validate it here. */
797 BUILD_BUG_ON(sizeof(atomic_t) != sizeof(int));
798
799- if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
800- oparg = 1 << oparg;
801-
802- if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
803- return -EFAULT;
804-
805 pagefault_disable();
806 switch (op) {
807 case FUTEX_OP_SET:
808@@ -148,30 +139,9 @@ static inline int futex_atomic_op_inuser
809 }
810 pagefault_enable();
811
812- if (!ret) {
813- switch (cmp) {
814- case FUTEX_OP_CMP_EQ:
815- ret = (val == cmparg);
816- break;
817- case FUTEX_OP_CMP_NE:
818- ret = (val != cmparg);
819- break;
820- case FUTEX_OP_CMP_LT:
821- ret = (val < cmparg);
822- break;
823- case FUTEX_OP_CMP_GE:
824- ret = (val >= cmparg);
825- break;
826- case FUTEX_OP_CMP_LE:
827- ret = (val <= cmparg);
828- break;
829- case FUTEX_OP_CMP_GT:
830- ret = (val > cmparg);
831- break;
832- default:
833- ret = -ENOSYS;
834- }
835- }
836+ if (!ret)
837+ *oval = val;
838+
839 return ret;
840 }
841
842--- a/arch/x86/include/asm/futex.h
843+++ b/arch/x86/include/asm/futex.h
844@@ -41,20 +41,11 @@
845 "+m" (*uaddr), "=&r" (tem) \
846 : "r" (oparg), "i" (-EFAULT), "1" (0))
847
848-static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
849+static inline int arch_futex_atomic_op_inuser(int op, int oparg, int *oval,
850+ u32 __user *uaddr)
851 {
852- int op = (encoded_op >> 28) & 7;
853- int cmp = (encoded_op >> 24) & 15;
854- int oparg = (encoded_op << 8) >> 20;
855- int cmparg = (encoded_op << 20) >> 20;
856 int oldval = 0, ret, tem;
857
858- if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
859- oparg = 1 << oparg;
860-
861- if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
862- return -EFAULT;
863-
864 pagefault_disable();
865
866 switch (op) {
867@@ -80,30 +71,9 @@ static inline int futex_atomic_op_inuser
868
869 pagefault_enable();
870
871- if (!ret) {
872- switch (cmp) {
873- case FUTEX_OP_CMP_EQ:
874- ret = (oldval == cmparg);
875- break;
876- case FUTEX_OP_CMP_NE:
877- ret = (oldval != cmparg);
878- break;
879- case FUTEX_OP_CMP_LT:
880- ret = (oldval < cmparg);
881- break;
882- case FUTEX_OP_CMP_GE:
883- ret = (oldval >= cmparg);
884- break;
885- case FUTEX_OP_CMP_LE:
886- ret = (oldval <= cmparg);
887- break;
888- case FUTEX_OP_CMP_GT:
889- ret = (oldval > cmparg);
890- break;
891- default:
892- ret = -ENOSYS;
893- }
894- }
895+ if (!ret)
896+ *oval = oldval;
897+
898 return ret;
899 }
900
901--- a/arch/xtensa/include/asm/futex.h
902+++ b/arch/xtensa/include/asm/futex.h
903@@ -44,18 +44,10 @@
904 : "r" (uaddr), "I" (-EFAULT), "r" (oparg) \
905 : "memory")
906
907-static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
908+static inline int arch_futex_atomic_op_inuser(int op, int oparg, int *oval,
909+ u32 __user *uaddr)
910 {
911- int op = (encoded_op >> 28) & 7;
912- int cmp = (encoded_op >> 24) & 15;
913- int oparg = (encoded_op << 8) >> 20;
914- int cmparg = (encoded_op << 20) >> 20;
915 int oldval = 0, ret;
916- if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
917- oparg = 1 << oparg;
918-
919- if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
920- return -EFAULT;
921
922 #if !XCHAL_HAVE_S32C1I
923 return -ENOSYS;
924@@ -89,19 +81,10 @@ static inline int futex_atomic_op_inuser
925
926 pagefault_enable();
927
928- if (ret)
929- return ret;
930-
931- switch (cmp) {
932- case FUTEX_OP_CMP_EQ: return (oldval == cmparg);
933- case FUTEX_OP_CMP_NE: return (oldval != cmparg);
934- case FUTEX_OP_CMP_LT: return (oldval < cmparg);
935- case FUTEX_OP_CMP_GE: return (oldval >= cmparg);
936- case FUTEX_OP_CMP_LE: return (oldval <= cmparg);
937- case FUTEX_OP_CMP_GT: return (oldval > cmparg);
938- }
939+ if (!ret)
940+ *oval = oldval;
941
942- return -ENOSYS;
943+ return ret;
944 }
945
946 static inline int
947--- a/include/asm-generic/futex.h
948+++ b/include/asm-generic/futex.h
949@@ -13,7 +13,7 @@
950 */
951
952 /**
953- * futex_atomic_op_inuser() - Atomic arithmetic operation with constant
954+ * arch_futex_atomic_op_inuser() - Atomic arithmetic operation with constant
955 * argument and comparison of the previous
956 * futex value with another constant.
957 *
958@@ -25,18 +25,11 @@
959 * <0 - On error
960 */
961 static inline int
962-futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
963+arch_futex_atomic_op_inuser(int op, u32 oparg, int *oval, u32 __user *uaddr)
964 {
965- int op = (encoded_op >> 28) & 7;
966- int cmp = (encoded_op >> 24) & 15;
967- int oparg = (encoded_op << 8) >> 20;
968- int cmparg = (encoded_op << 20) >> 20;
969 int oldval, ret;
970 u32 tmp;
971
972- if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
973- oparg = 1 << oparg;
974-
975 preempt_disable();
976 pagefault_disable();
977
978@@ -74,17 +67,9 @@ out_pagefault_enable:
979 pagefault_enable();
980 preempt_enable();
981
982- if (ret == 0) {
983- switch (cmp) {
984- case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
985- case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
986- case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
987- case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
988- case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
989- case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
990- default: ret = -ENOSYS;
991- }
992- }
993+ if (ret == 0)
994+ *oval = oldval;
995+
996 return ret;
997 }
998
999@@ -126,18 +111,9 @@ futex_atomic_cmpxchg_inatomic(u32 *uval,
1000
1001 #else
1002 static inline int
1003-futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr)
1004+arch_futex_atomic_op_inuser(int op, u32 oparg, int *oval, u32 __user *uaddr)
1005 {
1006- int op = (encoded_op >> 28) & 7;
1007- int cmp = (encoded_op >> 24) & 15;
1008- int oparg = (encoded_op << 8) >> 20;
1009- int cmparg = (encoded_op << 20) >> 20;
1010 int oldval = 0, ret;
1011- if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
1012- oparg = 1 << oparg;
1013-
1014- if (! access_ok (VERIFY_WRITE, uaddr, sizeof(u32)))
1015- return -EFAULT;
1016
1017 pagefault_disable();
1018
1019@@ -153,17 +129,9 @@ futex_atomic_op_inuser (int encoded_op,
1020
1021 pagefault_enable();
1022
1023- if (!ret) {
1024- switch (cmp) {
1025- case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
1026- case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
1027- case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
1028- case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
1029- case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
1030- case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
1031- default: ret = -ENOSYS;
1032- }
1033- }
1034+ if (!ret)
1035+ *oval = oldval;
1036+
1037 return ret;
1038 }
1039
1040--- a/kernel/futex.c
1041+++ b/kernel/futex.c
1042@@ -1453,6 +1453,45 @@ out:
1043 return ret;
1044 }
1045
1046+static int futex_atomic_op_inuser(unsigned int encoded_op, u32 __user *uaddr)
1047+{
1048+ unsigned int op = (encoded_op & 0x70000000) >> 28;
1049+ unsigned int cmp = (encoded_op & 0x0f000000) >> 24;
1050+ int oparg = sign_extend32((encoded_op & 0x00fff000) >> 12, 12);
1051+ int cmparg = sign_extend32(encoded_op & 0x00000fff, 12);
1052+ int oldval, ret;
1053+
1054+ if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28)) {
1055+ if (oparg < 0 || oparg > 31)
1056+ return -EINVAL;
1057+ oparg = 1 << oparg;
1058+ }
1059+
1060+ if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
1061+ return -EFAULT;
1062+
1063+ ret = arch_futex_atomic_op_inuser(op, oparg, &oldval, uaddr);
1064+ if (ret)
1065+ return ret;
1066+
1067+ switch (cmp) {
1068+ case FUTEX_OP_CMP_EQ:
1069+ return oldval == cmparg;
1070+ case FUTEX_OP_CMP_NE:
1071+ return oldval != cmparg;
1072+ case FUTEX_OP_CMP_LT:
1073+ return oldval < cmparg;
1074+ case FUTEX_OP_CMP_GE:
1075+ return oldval >= cmparg;
1076+ case FUTEX_OP_CMP_LE:
1077+ return oldval <= cmparg;
1078+ case FUTEX_OP_CMP_GT:
1079+ return oldval > cmparg;
1080+ default:
1081+ return -ENOSYS;
1082+ }
1083+}
1084+
1085 /*
1086 * Wake up all waiters hashed on the physical page that is mapped
1087 * to this virtual address: