Module Name:    src
Committed By:   riastradh
Date:           Wed Mar  5 12:02:00 UTC 2025

Modified Files:
        src/sys/kern: sys_futex.c
        src/sys/sys: futex.h
        src/tests/lib/libc/sys: t_futex_ops.c

Log Message:
futex(2): Sign-extend FUTEX_WAKE_OP oparg/cmparg as Linux does.

Also mask off bits in the FUTEX_OP macro as Linux does so that passing
negative arguments works like in Linux.

PR kern/59129: futex(3): missing sign extension in FUTEX_WAKE_OP


To generate a diff of this commit:
cvs rdiff -u -r1.22 -r1.23 src/sys/kern/sys_futex.c
cvs rdiff -u -r1.6 -r1.7 src/sys/sys/futex.h
cvs rdiff -u -r1.13 -r1.14 src/tests/lib/libc/sys/t_futex_ops.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/kern/sys_futex.c
diff -u src/sys/kern/sys_futex.c:1.22 src/sys/kern/sys_futex.c:1.23
--- src/sys/kern/sys_futex.c:1.22	Sat Jan 18 07:26:21 2025
+++ src/sys/kern/sys_futex.c	Wed Mar  5 12:02:00 2025
@@ -1,4 +1,4 @@
-/*	$NetBSD: sys_futex.c,v 1.22 2025/01/18 07:26:21 riastradh Exp $	*/
+/*	$NetBSD: sys_futex.c,v 1.23 2025/03/05 12:02:00 riastradh Exp $	*/
 
 /*-
  * Copyright (c) 2018, 2019, 2020 The NetBSD Foundation, Inc.
@@ -30,7 +30,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: sys_futex.c,v 1.22 2025/01/18 07:26:21 riastradh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: sys_futex.c,v 1.23 2025/03/05 12:02:00 riastradh Exp $");
 
 /*
  * Futexes
@@ -1401,6 +1401,22 @@ out:
 }
 
 /*
+ * futex_opcmp_arg(arg)
+ *
+ *	arg is either the oparg or cmparg field of a FUTEX_WAKE_OP
+ *	operation, a 12-bit string in either case.  Map it to a numeric
+ *	argument value by sign-extending it in two's-complement
+ *	representation.
+ */
+static int
+futex_opcmp_arg(int arg)
+{
+
+	KASSERT(arg == (arg & __BITS(11,0)));
+	return arg - 0x1000*__SHIFTOUT(arg, __BIT(11));
+}
+
+/*
  * futex_validate_op_cmp(val3)
  *
  *	Validate an op/cmp argument for FUTEX_WAKE_OP.
@@ -1412,7 +1428,8 @@ futex_validate_op_cmp(int val3)
 	int cmp = __SHIFTOUT(val3, FUTEX_OP_CMP_MASK);
 
 	if (op & FUTEX_OP_OPARG_SHIFT) {
-		int oparg = __SHIFTOUT(val3, FUTEX_OP_OPARG_MASK);
+		int oparg =
+		    futex_opcmp_arg(__SHIFTOUT(val3, FUTEX_OP_OPARG_MASK));
 		if (oparg < 0)
 			return EINVAL;
 		if (oparg >= 32)
@@ -1449,13 +1466,13 @@ futex_validate_op_cmp(int val3)
 /*
  * futex_compute_op(oldval, val3)
  *
- *	Apply a FUTEX_WAIT_OP operation to oldval.
+ *	Apply a FUTEX_WAKE_OP operation to oldval.
  */
 static int
 futex_compute_op(int oldval, int val3)
 {
 	int op = __SHIFTOUT(val3, FUTEX_OP_OP_MASK);
-	int oparg = __SHIFTOUT(val3, FUTEX_OP_OPARG_MASK);
+	int oparg = futex_opcmp_arg(__SHIFTOUT(val3, FUTEX_OP_OPARG_MASK));
 
 	if (op & FUTEX_OP_OPARG_SHIFT) {
 		KASSERT(oparg >= 0);
@@ -1493,13 +1510,13 @@ futex_compute_op(int oldval, int val3)
 /*
  * futex_compute_cmp(oldval, val3)
  *
- *	Apply a FUTEX_WAIT_OP comparison to oldval.
+ *	Apply a FUTEX_WAKE_OP comparison to oldval.
  */
 static bool
 futex_compute_cmp(int oldval, int val3)
 {
 	int cmp = __SHIFTOUT(val3, FUTEX_OP_CMP_MASK);
-	int cmparg = __SHIFTOUT(val3, FUTEX_OP_CMPARG_MASK);
+	int cmparg = futex_opcmp_arg(__SHIFTOUT(val3, FUTEX_OP_CMPARG_MASK));
 
 	switch (cmp) {
 	case FUTEX_OP_CMP_EQ:

Index: src/sys/sys/futex.h
diff -u src/sys/sys/futex.h:1.6 src/sys/sys/futex.h:1.7
--- src/sys/sys/futex.h:1.6	Tue Mar  4 12:43:40 2025
+++ src/sys/sys/futex.h	Wed Mar  5 12:02:00 2025
@@ -1,4 +1,4 @@
-/*	$NetBSD: futex.h,v 1.6 2025/03/04 12:43:40 riastradh Exp $	*/
+/*	$NetBSD: futex.h,v 1.7 2025/03/05 12:02:00 riastradh Exp $	*/
 
 /*-
  * Copyright (c) 2018, 2019 The NetBSD Foundation, Inc.
@@ -98,10 +98,10 @@
 #define FUTEX_OP_CMPARG_MASK		__BITS(0,11)
 
 #define FUTEX_OP(op, oparg, cmp, cmparg)		 \
-	(__SHIFTIN(op, FUTEX_OP_OP_MASK)		|\
-	 __SHIFTIN(oparg, FUTEX_OP_OPARG_MASK)		|\
-	 __SHIFTIN(cmp, FUTEX_OP_CMP_MASK)		|\
-	 __SHIFTIN(cmparg, FUTEX_OP_CMPARG_MASK))
+	(__SHIFTIN((op) & 0xf, FUTEX_OP_OP_MASK)	|\
+	 __SHIFTIN((oparg) & 0xfff, FUTEX_OP_OPARG_MASK)|\
+	 __SHIFTIN((cmp) & 0xf, FUTEX_OP_CMP_MASK)	|\
+	 __SHIFTIN((cmparg) & 0xfff, FUTEX_OP_CMPARG_MASK))
 
 #define FUTEX_OP_SET		0
 #define FUTEX_OP_ADD		1

Index: src/tests/lib/libc/sys/t_futex_ops.c
diff -u src/tests/lib/libc/sys/t_futex_ops.c:1.13 src/tests/lib/libc/sys/t_futex_ops.c:1.14
--- src/tests/lib/libc/sys/t_futex_ops.c:1.13	Wed Mar  5 00:03:12 2025
+++ src/tests/lib/libc/sys/t_futex_ops.c	Wed Mar  5 12:02:00 2025
@@ -1,4 +1,4 @@
-/* $NetBSD: t_futex_ops.c,v 1.13 2025/03/05 00:03:12 riastradh Exp $ */
+/* $NetBSD: t_futex_ops.c,v 1.14 2025/03/05 12:02:00 riastradh Exp $ */
 
 /*-
  * Copyright (c) 2019, 2020 The NetBSD Foundation, Inc.
@@ -29,7 +29,7 @@
 #include <sys/cdefs.h>
 __COPYRIGHT("@(#) Copyright (c) 2019, 2020\
  The NetBSD Foundation, inc. All rights reserved.");
-__RCSID("$NetBSD: t_futex_ops.c,v 1.13 2025/03/05 00:03:12 riastradh Exp $");
+__RCSID("$NetBSD: t_futex_ops.c,v 1.14 2025/03/05 12:02:00 riastradh Exp $");
 
 #include <sys/fcntl.h>
 #include <sys/mman.h>
@@ -1046,8 +1046,6 @@ do_futex_wake_op_op_test(int flags)
 	/*
 	 * Verify oparg is sign-extended.
 	 */
-	atf_tc_expect_fail("PR kern/59129: futex(3):"
-	    " missing sign extension in FUTEX_WAKE_OP");
 	futex_word1 = 0;
 	op = FUTEX_OP(FUTEX_OP_SET, 0xfff, FUTEX_OP_CMP_EQ, 0);
 	RL(n = __futex(&futex_word, FUTEX_WAKE_OP | flags,
@@ -1056,7 +1054,7 @@ do_futex_wake_op_op_test(int flags)
 	ATF_CHECK_EQ_MSG(futex_word1, -1, "futex_word1=%d", futex_word1);
 
 	futex_word1 = 0;
-	op = (int)FUTEX_OP(FUTEX_OP_SET, -1, FUTEX_OP_CMP_EQ, 0);
+	op = FUTEX_OP(FUTEX_OP_SET, -1, FUTEX_OP_CMP_EQ, 0);
 	RL(n = __futex(&futex_word, FUTEX_WAKE_OP | flags,
 		0, NULL, &futex_word1, 0, op));
 	ATF_CHECK_EQ_MSG(n, 0, "n=%d woken", n);
@@ -1141,8 +1139,6 @@ do_futex_wake_op_cmp_test(int flags)
 	create_wake_op_test_lwps(flags);
 
 	/* #LWPs = 6 */
-	atf_tc_expect_fail("PR kern/59129: futex(3):"
-	    " missing sign extension in FUTEX_WAKE_OP");
 	futex_word1 = 0xfff;
 	op = FUTEX_OP(FUTEX_OP_SET, 0, FUTEX_OP_CMP_EQ, 0xfff);
 	RL(n = __futex(&futex_word, FUTEX_WAKE_OP | flags,
@@ -1151,7 +1147,7 @@ do_futex_wake_op_cmp_test(int flags)
 	ATF_CHECK_EQ_MSG(futex_word1, 0, "futex_word1=%d", futex_word1);
 
 	futex_word1 = 0xfff;
-	op = (int)FUTEX_OP(FUTEX_OP_SET, 0, FUTEX_OP_CMP_EQ, -1);
+	op = FUTEX_OP(FUTEX_OP_SET, 0, FUTEX_OP_CMP_EQ, -1);
 	RL(n = __futex(&futex_word, FUTEX_WAKE_OP | flags,
 		0, NULL, &futex_word1, 1, op));
 	ATF_CHECK_EQ_MSG(n, 0, "n=%d woken", n);

Reply via email to