[PATCH v2 1/4] sched_ext: Don't sign-extend unsigned enums in __COMPAT_read_enum()

From: Tejun Heo

Date: Mon Oct 26 2026 - 13:36:45 EST


__COMPAT_read_enum() looks an enumerator up in the running kernel's BTF. For
a 4-byte enum, it assigns struct btf_enum.val, an __s32, to the u64 result,
which sign-extends. BTF records the enum's signedness in the type's kflag.
The code ignores it, so an unsigned enumerator with bit 31 set is
sign-extended too.

b1c2a6b0d90d ("sched_ext: scx_qmap: Read SCX_RESCUE_DISABLE through the enum
lookup tables") added SCX_RESCUE_DISABLE to the enum lookup tables. It is
U32_MAX in enum scx_consts and the only such enumerator in the tables. BPF
code sees it as 0xffffffffffffffff instead of 0xffffffff, so a comparison
against a u32 holding the real value never matches.

scx_qmap, its only user, narrows the value to u32 in userspace and is
unaffected.

Sign-extend only when the kflag says the enum is signed and zero-extend
otherwise. A signed enum keeps the sign extension, which is what C gives
when the enumerator converts to u64. SCX_TASK_CURSOR, 1 << 31 in a signed
enum, still reads 0xffffffff80000000. Verified with a probe against a built
kernel's BTF.

v2: Note in the comment that pahole < 1.24 never sets the kflag (Andrea).

Signed-off-by: Tejun Heo <tj@xxxxxxxxxx>
Reviewed-by: Andrea Righi <arighi@xxxxxxxxxx>
---
Applied to sched_ext/for-7.5.

tools/sched_ext/include/scx/compat.h | 10 +++++++++-
1 file changed, 9 insertions(+), 1 deletion(-)

diff --git a/tools/sched_ext/include/scx/compat.h b/tools/sched_ext/include/scx/compat.h
index 07fb55e63c57..8a17854cc626 100644
--- a/tools/sched_ext/include/scx/compat.h
+++ b/tools/sched_ext/include/scx/compat.h
@@ -143,7 +143,15 @@ static inline bool __COMPAT_read_enum(const char *type, const char *name, u64 *v
if (t->size == 8 && !strncmp(type, "scx_", 4))
return __COMPAT_recover_truncated_enum64(type, name,
(u32)e[i].val, v);
- *v = e[i].val;
+ /*
+ * kflag marks a signed enum. BTF generated by
+ * pahole < 1.24 never sets it, so signed enums
+ * are zero-extended there too.
+ */
+ if (btf_kflag(t))
+ *v = (s64)e[i].val;
+ else
+ *v = (u32)e[i].val;
return true;
}
}
--
2.56.0