futex: FLAGS_STRICT
authorpeterz@infradead.org <peterz@infradead.org>
Thu, 21 Sep 2023 10:45:11 +0000 (12:45 +0200)
committerPeter Zijlstra <peterz@infradead.org>
Thu, 21 Sep 2023 17:22:07 +0000 (19:22 +0200)
The current semantics for futex_wake() are a bit loose, specifically
asking for 0 futexes to be woken actually gets you 1.

Adding a !nr check to sys_futex_wake() makes that it would return 0
for unaligned futex words, because that check comes in the shared
futex_wake() function. Adding the !nr check there, would affect the
legacy sys_futex() semantics.

Hence frob a flag :-(

Suggested-by: André Almeida <andrealmeid@igalia.com>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Reviewed-by: Thomas Gleixner <tglx@linutronix.de>
Link: https://lore.kernel.org/r/20230921105248.048643656@noisy.programming.kicks-ass.net
kernel/futex/futex.h
kernel/futex/syscalls.c
kernel/futex/waitwake.c

index a3f1fceafcbe6cfa73d7223869057edd8f1bb296..0e7821a944a27d53d939c18c20d5b144ad286456 100644 (file)
  * Futex flags used to encode options to functions and preserve them across
  * restarts.
  */
-#define FLAGS_SIZE_8           0x00
-#define FLAGS_SIZE_16          0x01
-#define FLAGS_SIZE_32          0x02
-#define FLAGS_SIZE_64          0x03
+#define FLAGS_SIZE_8           0x0000
+#define FLAGS_SIZE_16          0x0001
+#define FLAGS_SIZE_32          0x0002
+#define FLAGS_SIZE_64          0x0003
 
-#define FLAGS_SIZE_MASK                0x03
+#define FLAGS_SIZE_MASK                0x0003
 
 #ifdef CONFIG_MMU
-# define FLAGS_SHARED          0x10
+# define FLAGS_SHARED          0x0010
 #else
 /*
  * NOMMU does not have per process address space. Let the compiler optimize
  * code away.
  */
-# define FLAGS_SHARED          0x00
+# define FLAGS_SHARED          0x0000
 #endif
-#define FLAGS_CLOCKRT          0x20
-#define FLAGS_HAS_TIMEOUT      0x40
-#define FLAGS_NUMA             0x80
+#define FLAGS_CLOCKRT          0x0020
+#define FLAGS_HAS_TIMEOUT      0x0040
+#define FLAGS_NUMA             0x0080
+#define FLAGS_STRICT           0x0100
 
 /* FUTEX_ to FLAGS_ */
 static inline unsigned int futex_to_flags(unsigned int op)
index 7049a52ef68e0ff9d34ca4738a76200efbedb7ff..47398926765e4ef99969c6ee0f712b07e8519b79 100644 (file)
@@ -333,7 +333,7 @@ SYSCALL_DEFINE4(futex_wake,
        if (!futex_validate_input(flags, mask))
                return -EINVAL;
 
-       return futex_wake(uaddr, flags, nr, mask);
+       return futex_wake(uaddr, FLAGS_STRICT | flags, nr, mask);
 }
 
 #ifdef CONFIG_COMPAT
index fa9757766103c913c6693692f65874c1dd452d03..ceb05b876597476fe011d886915b8bbc76d6b20d 100644 (file)
@@ -155,6 +155,9 @@ int futex_wake(u32 __user *uaddr, unsigned int flags, int nr_wake, u32 bitset)
        if (unlikely(ret != 0))
                return ret;
 
+       if ((flags & FLAGS_STRICT) && !nr_wake)
+               return 0;
+
        hb = futex_hash(&key);
 
        /* Make sure we really have tasks to wakeup */