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);