From ce4c52682d78fc08c9b1e2217aae6f00fa02bab3 Mon Sep 17 00:00:00 2001 From: Sasha Levin Date: Fri, 11 Jul 2025 07:42:45 -0400 Subject: kernel/api: introduce kernel API specification framework Add a framework for formally documenting kernel APIs with inline specifications. This framework provides: - Structured API documentation with parameter specifications, return values, error conditions, and execution context requirements - Runtime validation capabilities for debugging (CONFIG_KAPI_RUNTIME_CHECKS) - Support for both internal kernel APIs and system calls The framework stores specifications in a dedicated ELF section and provides infrastructure for: - Runtime querying of API documentation - Integration with existing SYSCALL_DEFINE macros A KUnit suite (CONFIG_KAPI_KUNIT_TEST) covers registration, lookup, parameter and return value validation, and JSON export. No specifications are added here; subsequent patches add them for individual syscalls. With CONFIG_KAPI_SPEC=n the SYSCALL_DEFINEx() expansion is unchanged. CONFIG_KAPI_RUNTIME_CHECKS is a debug option: a syscall whose arguments violate its specification returns -EINVAL without running. Assisted-by: LLM Signed-off-by: Sasha Levin --- include/linux/syscalls.h | 42 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) (limited to 'include/linux/syscalls.h') diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h index 8413b624ad47..b062bac9ea1e 100644 --- a/include/linux/syscalls.h +++ b/include/linux/syscalls.h @@ -94,6 +94,10 @@ struct file_attr; #include #include +#ifdef CONFIG_KAPI_RUNTIME_CHECKS +#include +#endif + #ifdef CONFIG_ARCH_HAS_SYSCALL_WRAPPER /* * It may be useful for an architecture to override the definitions of the @@ -237,6 +241,41 @@ static inline int is_syscall_trace_event(struct trace_event_call *tp_event) #define __PROTECT(...) asmlinkage_protect(__VA_ARGS__) +#ifdef CONFIG_KAPI_RUNTIME_CHECKS +/* + * Convert integers as (s64)(a) does, and pointers through unsigned long so + * they are not sign-extended on 32-bit. (unsigned long)(t)0 is an integer + * constant expression only if t is an integer type. + */ +#define __SC_CAST_TO_S64(t, a) \ + ((__force s64)__builtin_choose_expr( \ + __is_constexpr((__force unsigned long)(t)0), \ + (a), (__force unsigned long)(a))) + +#define __KAPI_DO_SYS(name) __do_kapi_sys##name +#define __KAPI_SYSCALL_DEFINEx(x, name, ...) \ + static inline long __do_kapi_sys##name(__MAP(x, __SC_DECL, __VA_ARGS__)) \ + { \ + const struct kernel_api_spec *__spec = kapi_get_spec("sys" #name); \ + long ret; \ + \ + if (__spec) { \ + s64 __params[x] = { __MAP(x, __SC_CAST_TO_S64, __VA_ARGS__) }; \ + int __ret = kapi_validate_syscall_params(__spec, __params, x); \ + \ + if (__ret) \ + return __ret; \ + } \ + ret = __do_sys##name(__MAP(x, __SC_ARGS, __VA_ARGS__)); \ + if (__spec) \ + kapi_validate_syscall_return(__spec, (s64)ret); \ + return ret; \ + } +#else +#define __KAPI_DO_SYS(name) __do_sys##name +#define __KAPI_SYSCALL_DEFINEx(x, name, ...) +#endif + /* * The asmlinkage stub is aliased to a function named __se_sys_*() which * sign-extends 32-bit ints to longs whenever needed. The actual work is @@ -255,10 +294,11 @@ static inline int is_syscall_trace_event(struct trace_event_call *tp_event) __attribute__((alias(__stringify(__se_sys##name)))); \ ALLOW_ERROR_INJECTION(sys##name, ERRNO); \ static inline long __do_sys##name(__MAP(x,__SC_DECL,__VA_ARGS__));\ + __KAPI_SYSCALL_DEFINEx(x, name, __VA_ARGS__) \ asmlinkage long __se_sys##name(__MAP(x,__SC_LONG,__VA_ARGS__)); \ asmlinkage long __se_sys##name(__MAP(x,__SC_LONG,__VA_ARGS__)) \ { \ - long ret = __do_sys##name(__MAP(x,__SC_CAST,__VA_ARGS__));\ + long ret = __KAPI_DO_SYS(name)(__MAP(x,__SC_CAST,__VA_ARGS__));\ __MAP(x,__SC_TEST,__VA_ARGS__); \ __PROTECT(x, ret,__MAP(x,__SC_ARGS,__VA_ARGS__)); \ return ret; \ -- cgit v1.2.3