From nobody Fri Oct 3 21:07:29 2025 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id B077E30E820; Mon, 25 Aug 2025 18:14:38 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1756145678; cv=none; b=QF5/+HeTR+eKoX8asiBi3zzqhjIH5pteAdYVE4vmUWAHSztPU9DPNGTkAfiL2PVpH4c44bQqdH1LVWWre1BrIZDbt6SOUwBMdsosyYNggNaevyGHExGRmW8YxR/lslJzDgxcWYKIdThboEuEI/s+tCJrpO06H6RF4Q6tOca4J7Y= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1756145678; c=relaxed/simple; bh=79hx1HKScMw1kX1Nx6o15bkcRpX6mXc6wmoL+0IeHF4=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=LTISScy06vYCmD/PyGW8VNhVFo+RXV4Grn1spHvm3XnLN9kKLHzw1X0LZJYaVlLjynMEQAv/wdw23jsTHiWLBtSilILb0ozyO8iGl3um0mv3xe6y5Oiu6o9oYf8XfxKYsQcBWiUFC1pJngp3FDPM8srzZ46H3gXRWfdrm9C8M+0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=FQ9XDQ0f; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="FQ9XDQ0f" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 7D2B8C116D0; Mon, 25 Aug 2025 18:14:37 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1756145678; bh=79hx1HKScMw1kX1Nx6o15bkcRpX6mXc6wmoL+0IeHF4=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=FQ9XDQ0fFIUSDKbQPAPRP3OrwJ0YXpVXmO7/vhqxPaH/BMEO2TQurS51aEo5baAN8 rQX8EUcG+rgM24Evt+rxpq2KwY+Bd4ujMDX3a4A4iUFHuVW3WzBDMyg4rhH657Caac zbc4riCzxfcOHEwIAFahNVyJtpkda52lYzWCICncAup1um2bMhve4yp2q8Zw+zwNvr 46z2aZuQSw6MQUX5rOJe+DqVBLlfwc93CuDHXIL8bcWb+1KGkszDNdIXWLfy9A2Blt ADFCukaqDau8HiEmEE2LVS9T8wZNqqftEHG1fNtAOwt+sHrRBoKYDDE791IWlQo5ne ua8uBprKZwB8g== From: Sasha Levin To: linux-api@vger.kernel.org, linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, tools@kernel.org Cc: Sasha Levin Subject: [RFC PATCH v4 1/7] kernel/api: introduce kernel API specification framework Date: Mon, 25 Aug 2025 14:14:28 -0400 Message-ID: <20250825181434.3340805-2-sashal@kernel.org> X-Mailer: git-send-email 2.50.1 In-Reply-To: <20250825181434.3340805-1-sashal@kernel.org> References: <20250825181434.3340805-1-sashal@kernel.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Add a comprehensive 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) - Export of specifications via debugfs for tooling integration - Support for both internal kernel APIs and system calls The framework stores specifications in a dedicated ELF section and provides infrastructure for: - Compile-time validation of specifications - Runtime querying of API documentation - Machine-readable export formats - Integration with existing SYSCALL_DEFINE macros This commit introduces the core infrastructure without modifying any existing APIs. Subsequent patches will add specifications to individual subsystems. Signed-off-by: Sasha Levin --- .gitignore | 1 + Documentation/admin-guide/kernel-api-spec.rst | 507 ++++++ MAINTAINERS | 9 + arch/um/kernel/dyn.lds.S | 3 + arch/um/kernel/uml.lds.S | 3 + arch/x86/kernel/vmlinux.lds.S | 3 + include/asm-generic/vmlinux.lds.h | 20 + include/linux/kernel_api_spec.h | 1559 +++++++++++++++++ include/linux/syscall_api_spec.h | 125 ++ include/linux/syscalls.h | 38 + init/Kconfig | 2 + kernel/Makefile | 1 + kernel/api/Kconfig | 35 + kernel/api/Makefile | 7 + kernel/api/kernel_api_spec.c | 1155 ++++++++++++ 15 files changed, 3468 insertions(+) create mode 100644 Documentation/admin-guide/kernel-api-spec.rst create mode 100644 include/linux/kernel_api_spec.h create mode 100644 include/linux/syscall_api_spec.h create mode 100644 kernel/api/Kconfig create mode 100644 kernel/api/Makefile create mode 100644 kernel/api/kernel_api_spec.c diff --git a/.gitignore b/.gitignore index 929054df5212..e5aaa26d1b68 100644 --- a/.gitignore +++ b/.gitignore @@ -12,6 +12,7 @@ # .* *.a +*.apispec.h *.asn1.[ch] *.bin *.bz2 diff --git a/Documentation/admin-guide/kernel-api-spec.rst b/Documentation/= admin-guide/kernel-api-spec.rst new file mode 100644 index 000000000000..3a63f6711e27 --- /dev/null +++ b/Documentation/admin-guide/kernel-api-spec.rst @@ -0,0 +1,507 @@ +.. SPDX-License-Identifier: GPL-2.0 + +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D +Kernel API Specification Framework +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +:Author: Sasha Levin +:Date: June 2025 + +.. contents:: Table of Contents + :depth: 3 + :local: + +Introduction +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +The Kernel API Specification Framework (KAPI) provides a comprehensive sys= tem for +formally documenting, validating, and introspecting kernel APIs. This fram= ework +addresses the long-standing challenge of maintaining accurate, machine-rea= dable +documentation for the thousands of internal kernel APIs and system calls. + +Purpose and Goals +----------------- + +The framework aims to: + +1. **Improve API Documentation**: Provide structured, inline documentation= that + lives alongside the code and is maintained as part of the development p= rocess. + +2. **Enable Runtime Validation**: Optionally validate API usage at runtime= to catch + common programming errors during development and testing. + +3. **Support Tooling**: Export API specifications in machine-readable form= ats for + use by static analyzers, documentation generators, and development tool= s. + +4. **Enhance Debugging**: Provide detailed API information at runtime thro= ugh debugfs + for debugging and introspection. + +5. **Formalize Contracts**: Explicitly document API contracts including pa= rameter + constraints, execution contexts, locking requirements, and side effects. + +Architecture Overview +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +Components +---------- + +The framework consists of several key components: + +1. **Core Framework** (``kernel/api/kernel_api_spec.c``) + + - API specification registration and storage + - Runtime validation engine + - Specification lookup and querying + +2. **DebugFS Interface** (``kernel/api/kapi_debugfs.c``) + + - Runtime introspection via ``/sys/kernel/debug/kapi/`` + - JSON and XML export formats + - Per-API detailed information + +3. **IOCTL Support** (``kernel/api/ioctl_validation.c``) + + - Extended framework for IOCTL specifications + - Automatic validation wrappers + - Structure field validation + +4. **Specification Macros** (``include/linux/kernel_api_spec.h``) + + - Declarative macros for API documentation + - Type-safe parameter specifications + - Context and constraint definitions + +Data Model +---------- + +The framework uses a hierarchical data model:: + + kernel_api_spec + =E2=94=9C=E2=94=80=E2=94=80 Basic Information + =E2=94=82 =E2=94=9C=E2=94=80=E2=94=80 name (API function name) + =E2=94=82 =E2=94=9C=E2=94=80=E2=94=80 version (specification version) + =E2=94=82 =E2=94=9C=E2=94=80=E2=94=80 description (human-readable de= scription) + =E2=94=82 =E2=94=94=E2=94=80=E2=94=80 kernel_version (when API was i= ntroduced) + =E2=94=82 + =E2=94=9C=E2=94=80=E2=94=80 Parameters (up to 16) + =E2=94=82 =E2=94=94=E2=94=80=E2=94=80 kapi_param_spec + =E2=94=82 =E2=94=9C=E2=94=80=E2=94=80 name + =E2=94=82 =E2=94=9C=E2=94=80=E2=94=80 type (int, pointer, string= , etc.) + =E2=94=82 =E2=94=9C=E2=94=80=E2=94=80 direction (in, out, inout) + =E2=94=82 =E2=94=9C=E2=94=80=E2=94=80 constraints (range, mask, = enum values) + =E2=94=82 =E2=94=94=E2=94=80=E2=94=80 validation rules + =E2=94=82 + =E2=94=9C=E2=94=80=E2=94=80 Return Value + =E2=94=82 =E2=94=94=E2=94=80=E2=94=80 kapi_return_spec + =E2=94=82 =E2=94=9C=E2=94=80=E2=94=80 type + =E2=94=82 =E2=94=9C=E2=94=80=E2=94=80 success conditions + =E2=94=82 =E2=94=94=E2=94=80=E2=94=80 validation rules + =E2=94=82 + =E2=94=9C=E2=94=80=E2=94=80 Error Conditions (up to 32) + =E2=94=82 =E2=94=94=E2=94=80=E2=94=80 kapi_error_spec + =E2=94=82 =E2=94=9C=E2=94=80=E2=94=80 error code + =E2=94=82 =E2=94=9C=E2=94=80=E2=94=80 condition description + =E2=94=82 =E2=94=94=E2=94=80=E2=94=80 recovery advice + =E2=94=82 + =E2=94=9C=E2=94=80=E2=94=80 Execution Context + =E2=94=82 =E2=94=9C=E2=94=80=E2=94=80 allowed contexts (process, int= errupt, etc.) + =E2=94=82 =E2=94=9C=E2=94=80=E2=94=80 locking requirements + =E2=94=82 =E2=94=94=E2=94=80=E2=94=80 preemption/interrupt state + =E2=94=82 + =E2=94=94=E2=94=80=E2=94=80 Side Effects + =E2=94=9C=E2=94=80=E2=94=80 memory allocation + =E2=94=9C=E2=94=80=E2=94=80 state changes + =E2=94=94=E2=94=80=E2=94=80 signal handling + +Usage Guide +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +Basic API Specification +----------------------- + +To document a kernel API, use the specification macros in the implementati= on file: + +.. code-block:: c + + #include + + KAPI_DEFINE_SPEC(kmalloc_spec, kmalloc, "3.0") + KAPI_DESCRIPTION("Allocate kernel memory") + KAPI_PARAM(0, size, KAPI_TYPE_SIZE_T, KAPI_DIR_IN, + "Number of bytes to allocate") + KAPI_PARAM_RANGE(0, 0, KMALLOC_MAX_SIZE) + KAPI_PARAM(1, flags, KAPI_TYPE_FLAGS, KAPI_DIR_IN, + "Allocation flags (GFP_*)") + KAPI_PARAM_MASK(1, __GFP_BITS_MASK) + KAPI_RETURN(KAPI_TYPE_POINTER, "Pointer to allocated memory or NULL") + KAPI_ERROR(ENOMEM, "Out of memory") + KAPI_CONTEXT(KAPI_CTX_PROCESS | KAPI_CTX_SOFTIRQ | KAPI_CTX_HARDIRQ) + KAPI_SIDE_EFFECT("Allocates memory from kernel heap") + KAPI_LOCK_NOT_REQUIRED("Any lock") + KAPI_END_SPEC + + void *kmalloc(size_t size, gfp_t flags) + { + /* Implementation */ + } + +System Call Specification +------------------------- + +System calls use specialized macros: + +.. code-block:: c + + KAPI_DEFINE_SYSCALL_SPEC(open_spec, open, "1.0") + KAPI_DESCRIPTION("Open a file") + KAPI_PARAM(0, pathname, KAPI_TYPE_USER_STRING, KAPI_DIR_IN, + "Path to file") + KAPI_PARAM_PATH(0, PATH_MAX) + KAPI_PARAM(1, flags, KAPI_TYPE_FLAGS, KAPI_DIR_IN, + "Open flags (O_*)") + KAPI_PARAM(2, mode, KAPI_TYPE_MODE_T, KAPI_DIR_IN, + "File permissions (if creating)") + KAPI_RETURN(KAPI_TYPE_INT, "File descriptor or -1") + KAPI_ERROR(EACCES, "Permission denied") + KAPI_ERROR(ENOENT, "File does not exist") + KAPI_ERROR(EMFILE, "Too many open files") + KAPI_CONTEXT(KAPI_CTX_PROCESS | KAPI_CTX_SLEEPABLE) + KAPI_SIGNAL(EINTR, "Open can be interrupted by signal") + KAPI_END_SYSCALL_SPEC + +IOCTL Specification +------------------- + +IOCTLs have extended support for structure validation: + +.. code-block:: c + + KAPI_DEFINE_IOCTL_SPEC(vidioc_querycap_spec, VIDIOC_QUERYCAP, + "VIDIOC_QUERYCAP", + sizeof(struct v4l2_capability), + sizeof(struct v4l2_capability), + "video_fops") + KAPI_DESCRIPTION("Query device capabilities") + KAPI_IOCTL_FIELD(driver, KAPI_TYPE_CHAR_ARRAY, KAPI_DIR_OUT, + "Driver name", 16) + KAPI_IOCTL_FIELD(card, KAPI_TYPE_CHAR_ARRAY, KAPI_DIR_OUT, + "Device name", 32) + KAPI_IOCTL_FIELD(version, KAPI_TYPE_U32, KAPI_DIR_OUT, + "Driver version") + KAPI_IOCTL_FIELD(capabilities, KAPI_TYPE_FLAGS, KAPI_DIR_OUT, + "Device capabilities") + KAPI_END_IOCTL_SPEC + +Runtime Validation +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +Enabling Validation +------------------- + +Runtime validation is controlled by kernel configuration: + +1. Enable ``CONFIG_KAPI_SPEC`` to build the framework +2. Enable ``CONFIG_KAPI_RUNTIME_CHECKS`` for runtime validation +3. Optionally enable ``CONFIG_KAPI_SPEC_DEBUGFS`` for debugfs interface + +Validation Modes +---------------- + +The framework supports several validation modes: + +.. code-block:: c + + /* Enable validation for specific API */ + kapi_enable_validation("kmalloc"); + + /* Enable validation for all APIs */ + kapi_enable_all_validation(); + + /* Set validation level */ + kapi_set_validation_level(KAPI_VALIDATE_FULL); + +Validation Levels: + +- ``KAPI_VALIDATE_NONE``: No validation +- ``KAPI_VALIDATE_BASIC``: Type and NULL checks only +- ``KAPI_VALIDATE_NORMAL``: Basic + range and constraint checks +- ``KAPI_VALIDATE_FULL``: All checks including custom validators + +Custom Validators +----------------- + +APIs can register custom validation functions: + +.. code-block:: c + + static bool validate_buffer_size(const struct kapi_param_spec *spec, + const void *value, void *context) + { + size_t size =3D *(size_t *)value; + struct my_context *ctx =3D context; + + return size > 0 && size <=3D ctx->max_buffer_size; + } + + KAPI_PARAM_CUSTOM_VALIDATOR(0, validate_buffer_size) + +DebugFS Interface +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +The debugfs interface provides runtime access to API specifications: + +Directory Structure +------------------- + +:: + + /sys/kernel/debug/kapi/ + =E2=94=9C=E2=94=80=E2=94=80 apis/ # All registered = APIs + =E2=94=82 =E2=94=9C=E2=94=80=E2=94=80 kmalloc/ + =E2=94=82 =E2=94=82 =E2=94=9C=E2=94=80=E2=94=80 specification # = Human-readable spec + =E2=94=82 =E2=94=82 =E2=94=9C=E2=94=80=E2=94=80 json # J= SON format + =E2=94=82 =E2=94=82 =E2=94=94=E2=94=80=E2=94=80 xml # X= ML format + =E2=94=82 =E2=94=94=E2=94=80=E2=94=80 open/ + =E2=94=82 =E2=94=94=E2=94=80=E2=94=80 ... + =E2=94=9C=E2=94=80=E2=94=80 summary # Overview of all= APIs + =E2=94=9C=E2=94=80=E2=94=80 validation/ # Validation cont= rols + =E2=94=82 =E2=94=9C=E2=94=80=E2=94=80 enabled # Global e= nable/disable + =E2=94=82 =E2=94=9C=E2=94=80=E2=94=80 level # Validati= on level + =E2=94=82 =E2=94=94=E2=94=80=E2=94=80 stats # Validati= on statistics + =E2=94=94=E2=94=80=E2=94=80 export/ # Bulk export opt= ions + =E2=94=9C=E2=94=80=E2=94=80 all.json # All specs in JSON + =E2=94=94=E2=94=80=E2=94=80 all.xml # All specs in XML + +Usage Examples +-------------- + +Query specific API:: + + $ cat /sys/kernel/debug/kapi/apis/kmalloc/specification + API: kmalloc + Version: 3.0 + Description: Allocate kernel memory + + Parameters: + [0] size (size_t, in): Number of bytes to allocate + Range: 0 - 4194304 + [1] flags (flags, in): Allocation flags (GFP_*) + Mask: 0x1ffffff + + Returns: pointer - Pointer to allocated memory or NULL + + Errors: + ENOMEM: Out of memory + + Context: process, softirq, hardirq + + Side Effects: + - Allocates memory from kernel heap + +Export all specifications:: + + $ cat /sys/kernel/debug/kapi/export/all.json > kernel-apis.json + +Enable validation for specific API:: + + $ echo 1 > /sys/kernel/debug/kapi/apis/kmalloc/validate + +Performance Considerations +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D + +Memory Overhead +--------------- + +Each API specification consumes approximately 2-4KB of memory. With thousa= nds +of kernel APIs, this can add up to several megabytes. Consider: + +1. Building with ``CONFIG_KAPI_SPEC=3Dn`` for production kernels +2. Using ``__init`` annotations for APIs only used during boot +3. Implementing lazy loading for rarely used specifications + +Runtime Overhead +---------------- + +When ``CONFIG_KAPI_RUNTIME_CHECKS`` is enabled: + +- Each validated API call adds 50-200ns overhead +- Complex validations (custom validators) may add more +- Use validation only in development/testing kernels + +Optimization Strategies +----------------------- + +1. **Compile-time optimization**: When validation is disabled, all + validation code is optimized away by the compiler. + +2. **Selective validation**: Enable validation only for specific APIs + or subsystems under test. + +3. **Caching**: The framework caches validation results for repeated + calls with identical parameters. + +Documentation Generation +------------------------ + +The framework exports specifications via debugfs that can be used +to generate documentation. Tools for automatic documentation generation +from specifications are planned for future development. + +IDE Integration +--------------- + +Modern IDEs can use the JSON export for: + +- Parameter hints +- Type checking +- Context validation +- Error code documentation + +Testing Framework +----------------- + +The framework includes test helpers:: + + #ifdef CONFIG_KAPI_TESTING + /* Verify API behaves according to specification */ + kapi_test_api("kmalloc", test_cases); + #endif + +Best Practices +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +Writing Specifications +---------------------- + +1. **Be Comprehensive**: Document all parameters, errors, and side effects +2. **Keep Updated**: Update specs when API behavior changes +3. **Use Examples**: Include usage examples in descriptions +4. **Validate Constraints**: Define realistic constraints for parameters +5. **Document Context**: Clearly specify allowed execution contexts + +Maintenance +----------- + +1. **Version Specifications**: Increment version when API changes +2. **Deprecation**: Mark deprecated APIs and suggest replacements +3. **Cross-reference**: Link related APIs in descriptions +4. **Test Specifications**: Verify specs match implementation + +Common Patterns +--------------- + +**Optional Parameters**:: + + KAPI_PARAM(2, optional_arg, KAPI_TYPE_POINTER, KAPI_DIR_IN, + "Optional argument (may be NULL)") + KAPI_PARAM_OPTIONAL(2) + +**Variable Arguments**:: + + KAPI_PARAM(1, fmt, KAPI_TYPE_FORMAT_STRING, KAPI_DIR_IN, + "Printf-style format string") + KAPI_PARAM_VARIADIC(2, "Format arguments") + +**Callback Functions**:: + + KAPI_PARAM(1, callback, KAPI_TYPE_FUNCTION_PTR, KAPI_DIR_IN, + "Callback function") + KAPI_PARAM_CALLBACK(1, "int (*)(void *data)", "data") + +Troubleshooting +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +Common Issues +------------- + +**Specification Not Found**:: + + kernel: KAPI: Specification for 'my_api' not found + + Solution: Ensure KAPI_DEFINE_SPEC is in the same translation unit + as the function implementation. + +**Validation Failures**:: + + kernel: KAPI: Validation failed for kmalloc parameter 'size': + value 5242880 exceeds maximum 4194304 + + Solution: Check parameter constraints or adjust specification if + the constraint is incorrect. + +**Build Errors**:: + + error: 'KAPI_TYPE_UNKNOWN' undeclared + + Solution: Include and ensure + CONFIG_KAPI_SPEC is enabled. + +Debug Options +------------- + +Enable verbose debugging:: + + echo 8 > /proc/sys/kernel/printk + echo 1 > /sys/kernel/debug/kapi/debug/verbose + +Future Directions +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +Planned Features +---------------- + +1. **Automatic Extraction**: Tool to extract specifications from existing + kernel-doc comments + +2. **Contract Verification**: Static analysis to verify implementation + matches specification + +3. **Performance Profiling**: Measure actual API performance against + documented expectations + +4. **Fuzzing Integration**: Use specifications to guide intelligent + fuzzing of kernel APIs + +5. **Version Compatibility**: Track API changes across kernel versions + +Research Areas +-------------- + +1. **Formal Verification**: Use specifications for mathematical proofs + of correctness + +2. **Runtime Monitoring**: Detect specification violations in production + with minimal overhead + +3. **API Evolution**: Analyze how kernel APIs change over time + +4. **Security Applications**: Use specifications for security policy + enforcement + +Contributing +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +Submitting Specifications +------------------------- + +1. Add specifications to the same file as the API implementation +2. Follow existing patterns and naming conventions +3. Test with CONFIG_KAPI_RUNTIME_CHECKS enabled +4. Verify debugfs output is correct +5. Run scripts/checkpatch.pl on your changes + +Review Criteria +--------------- + +Specifications will be reviewed for: + +1. **Completeness**: All parameters and errors documented +2. **Accuracy**: Specification matches implementation +3. **Clarity**: Descriptions are clear and helpful +4. **Consistency**: Follows framework conventions +5. **Performance**: No unnecessary runtime overhead + +Contact +------- + +- Maintainer: Sasha Levin diff --git a/MAINTAINERS b/MAINTAINERS index fed6cd812d79..51c8ff70b8a1 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -13244,6 +13244,15 @@ W: https://linuxtv.org T: git git://linuxtv.org/media.git F: drivers/media/radio/radio-keene* =20 +KERNEL API SPECIFICATION FRAMEWORK (KAPI) +M: Sasha Levin +L: linux-api@vger.kernel.org +S: Maintained +F: Documentation/admin-guide/kernel-api-spec.rst +F: include/linux/kernel_api_spec.h +F: kernel/api/ +F: scripts/extract-kapi-spec.sh + KERNEL AUTOMOUNTER M: Ian Kent L: autofs@vger.kernel.org diff --git a/arch/um/kernel/dyn.lds.S b/arch/um/kernel/dyn.lds.S index a36b7918a011..283ab11788d8 100644 --- a/arch/um/kernel/dyn.lds.S +++ b/arch/um/kernel/dyn.lds.S @@ -102,6 +102,9 @@ SECTIONS init.data : { INIT_DATA } __init_end =3D .; =20 + /* Kernel API specifications in dedicated section */ + KAPI_SPECS_SECTION() + /* Ensure the __preinit_array_start label is properly aligned. We could instead move the label definition inside the section, but the linker would then create the section even if it turns out to diff --git a/arch/um/kernel/uml.lds.S b/arch/um/kernel/uml.lds.S index a409d4b66114..e3850d829343 100644 --- a/arch/um/kernel/uml.lds.S +++ b/arch/um/kernel/uml.lds.S @@ -74,6 +74,9 @@ SECTIONS init.data : { INIT_DATA } __init_end =3D .; =20 + /* Kernel API specifications in dedicated section */ + KAPI_SPECS_SECTION() + .data : { INIT_TASK_DATA(KERNEL_STACK_SIZE) diff --git a/arch/x86/kernel/vmlinux.lds.S b/arch/x86/kernel/vmlinux.lds.S index 4fa0be732af1..8cc508adc9d5 100644 --- a/arch/x86/kernel/vmlinux.lds.S +++ b/arch/x86/kernel/vmlinux.lds.S @@ -173,6 +173,9 @@ SECTIONS RO_DATA(PAGE_SIZE) X86_ALIGN_RODATA_END =20 + /* Kernel API specifications in dedicated section */ + KAPI_SPECS_SECTION() + /* Data */ .data : AT(ADDR(.data) - LOAD_OFFSET) { /* Start of data section */ diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinu= x.lds.h index ae2d2359b79e..93b6293c0259 100644 --- a/include/asm-generic/vmlinux.lds.h +++ b/include/asm-generic/vmlinux.lds.h @@ -279,6 +279,26 @@ defined(CONFIG_AUTOFDO_CLANG) || defined(CONFIG_PROPEL= LER_CLANG) #define TRACE_SYSCALLS() #endif =20 +#ifdef CONFIG_KAPI_SPEC +#define KAPI_SPECS() \ + . =3D ALIGN(8); \ + __start_kapi_specs =3D .; \ + KEEP(*(.kapi_specs)) \ + __stop_kapi_specs =3D .; + +/* For placing KAPI specs in a dedicated section */ +#define KAPI_SPECS_SECTION() \ + .kapi_specs : AT(ADDR(.kapi_specs) - LOAD_OFFSET) { \ + . =3D ALIGN(8); \ + __start_kapi_specs =3D .; \ + KEEP(*(.kapi_specs)) \ + __stop_kapi_specs =3D .; \ + } +#else +#define KAPI_SPECS() +#define KAPI_SPECS_SECTION() +#endif + #ifdef CONFIG_BPF_EVENTS #define BPF_RAW_TP() STRUCT_ALIGN(); \ BOUNDED_SECTION_BY(__bpf_raw_tp_map, __bpf_raw_tp) diff --git a/include/linux/kernel_api_spec.h b/include/linux/kernel_api_spe= c.h new file mode 100644 index 000000000000..163e3af8ca82 --- /dev/null +++ b/include/linux/kernel_api_spec.h @@ -0,0 +1,1559 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * kernel_api_spec.h - Kernel API Formal Specification Framework + * + * This framework provides structures and macros to formally specify kerne= l APIs + * in both human and machine-readable formats. It supports comprehensive d= ocumentation + * of function signatures, parameters, return values, error conditions, an= d constraints. + */ + +#ifndef _LINUX_KERNEL_API_SPEC_H +#define _LINUX_KERNEL_API_SPEC_H + +#include +#include +#include +#include + +struct sigaction; + +#define KAPI_MAX_PARAMS 16 +#define KAPI_MAX_ERRORS 32 +#define KAPI_MAX_CONSTRAINTS 32 +#define KAPI_MAX_SIGNALS 32 +#define KAPI_MAX_NAME_LEN 128 +#define KAPI_MAX_DESC_LEN 512 +#define KAPI_MAX_CAPABILITIES 8 +#define KAPI_MAX_SOCKET_STATES 16 +#define KAPI_MAX_PROTOCOL_BEHAVIORS 8 +#define KAPI_MAX_NET_ERRORS 16 +#define KAPI_MAX_SOCKOPTS 16 +#define KAPI_MAX_ADDR_FAMILIES 8 + +/** + * enum kapi_param_type - Parameter type classification + * @KAPI_TYPE_VOID: void type + * @KAPI_TYPE_INT: Integer types (int, long, etc.) + * @KAPI_TYPE_UINT: Unsigned integer types + * @KAPI_TYPE_PTR: Pointer types + * @KAPI_TYPE_STRUCT: Structure types + * @KAPI_TYPE_UNION: Union types + * @KAPI_TYPE_ENUM: Enumeration types + * @KAPI_TYPE_FUNC_PTR: Function pointer types + * @KAPI_TYPE_ARRAY: Array types + * @KAPI_TYPE_FD: File descriptor - validated in process context + * @KAPI_TYPE_USER_PTR: User space pointer - validated for access and size + * @KAPI_TYPE_PATH: Pathname - validated for access and path limits + * @KAPI_TYPE_CUSTOM: Custom/complex types + */ +enum kapi_param_type { + KAPI_TYPE_VOID =3D 0, + KAPI_TYPE_INT, + KAPI_TYPE_UINT, + KAPI_TYPE_PTR, + KAPI_TYPE_STRUCT, + KAPI_TYPE_UNION, + KAPI_TYPE_ENUM, + KAPI_TYPE_FUNC_PTR, + KAPI_TYPE_ARRAY, + KAPI_TYPE_FD, /* File descriptor - validated in process context */ + KAPI_TYPE_USER_PTR, /* User space pointer - validated for access and size= */ + KAPI_TYPE_PATH, /* Pathname - validated for access and path limits */ + KAPI_TYPE_CUSTOM, +}; + +/** + * enum kapi_param_flags - Parameter attribute flags + * @KAPI_PARAM_IN: Input parameter + * @KAPI_PARAM_OUT: Output parameter + * @KAPI_PARAM_INOUT: Input/output parameter + * @KAPI_PARAM_OPTIONAL: Optional parameter (can be NULL) + * @KAPI_PARAM_CONST: Const qualified parameter + * @KAPI_PARAM_VOLATILE: Volatile qualified parameter + * @KAPI_PARAM_USER: User space pointer + * @KAPI_PARAM_DMA: DMA-capable memory required + * @KAPI_PARAM_ALIGNED: Alignment requirements + */ +enum kapi_param_flags { + KAPI_PARAM_IN =3D (1 << 0), + KAPI_PARAM_OUT =3D (1 << 1), + KAPI_PARAM_INOUT =3D (1 << 2), + KAPI_PARAM_OPTIONAL =3D (1 << 3), + KAPI_PARAM_CONST =3D (1 << 4), + KAPI_PARAM_VOLATILE =3D (1 << 5), + KAPI_PARAM_USER =3D (1 << 6), + KAPI_PARAM_DMA =3D (1 << 7), + KAPI_PARAM_ALIGNED =3D (1 << 8), +}; + +/** + * enum kapi_context_flags - Function execution context flags + * @KAPI_CTX_PROCESS: Can be called from process context + * @KAPI_CTX_SOFTIRQ: Can be called from softirq context + * @KAPI_CTX_HARDIRQ: Can be called from hardirq context + * @KAPI_CTX_NMI: Can be called from NMI context + * @KAPI_CTX_ATOMIC: Must be called in atomic context + * @KAPI_CTX_SLEEPABLE: May sleep + * @KAPI_CTX_PREEMPT_DISABLED: Requires preemption disabled + * @KAPI_CTX_IRQ_DISABLED: Requires interrupts disabled + */ +enum kapi_context_flags { + KAPI_CTX_PROCESS =3D (1 << 0), + KAPI_CTX_SOFTIRQ =3D (1 << 1), + KAPI_CTX_HARDIRQ =3D (1 << 2), + KAPI_CTX_NMI =3D (1 << 3), + KAPI_CTX_ATOMIC =3D (1 << 4), + KAPI_CTX_SLEEPABLE =3D (1 << 5), + KAPI_CTX_PREEMPT_DISABLED =3D (1 << 6), + KAPI_CTX_IRQ_DISABLED =3D (1 << 7), +}; + +/** + * enum kapi_lock_type - Lock types used/required by the function + * @KAPI_LOCK_NONE: No locking requirements + * @KAPI_LOCK_MUTEX: Mutex lock + * @KAPI_LOCK_SPINLOCK: Spinlock + * @KAPI_LOCK_RWLOCK: Read-write lock + * @KAPI_LOCK_SEQLOCK: Sequence lock + * @KAPI_LOCK_RCU: RCU lock + * @KAPI_LOCK_SEMAPHORE: Semaphore + * @KAPI_LOCK_CUSTOM: Custom locking mechanism + */ +enum kapi_lock_type { + KAPI_LOCK_NONE =3D 0, + KAPI_LOCK_MUTEX, + KAPI_LOCK_SPINLOCK, + KAPI_LOCK_RWLOCK, + KAPI_LOCK_SEQLOCK, + KAPI_LOCK_RCU, + KAPI_LOCK_SEMAPHORE, + KAPI_LOCK_CUSTOM, +}; + +/** + * enum kapi_constraint_type - Types of parameter constraints + * @KAPI_CONSTRAINT_NONE: No constraint + * @KAPI_CONSTRAINT_RANGE: Numeric range constraint + * @KAPI_CONSTRAINT_MASK: Bitmask constraint + * @KAPI_CONSTRAINT_ENUM: Enumerated values constraint + * @KAPI_CONSTRAINT_ALIGNMENT: Alignment constraint (must be aligned to sp= ecified boundary) + * @KAPI_CONSTRAINT_POWER_OF_TWO: Value must be a power of two + * @KAPI_CONSTRAINT_PAGE_ALIGNED: Value must be page-aligned + * @KAPI_CONSTRAINT_NONZERO: Value must be non-zero + * @KAPI_CONSTRAINT_CUSTOM: Custom validation function + */ +enum kapi_constraint_type { + KAPI_CONSTRAINT_NONE =3D 0, + KAPI_CONSTRAINT_RANGE, + KAPI_CONSTRAINT_MASK, + KAPI_CONSTRAINT_ENUM, + KAPI_CONSTRAINT_ALIGNMENT, + KAPI_CONSTRAINT_POWER_OF_TWO, + KAPI_CONSTRAINT_PAGE_ALIGNED, + KAPI_CONSTRAINT_NONZERO, + KAPI_CONSTRAINT_CUSTOM, +}; + +/** + * struct kapi_param_spec - Parameter specification + * @name: Parameter name + * @type_name: Type name as string + * @type: Parameter type classification + * @flags: Parameter attribute flags + * @size: Size in bytes (for arrays/buffers) + * @alignment: Required alignment + * @min_value: Minimum valid value (for numeric types) + * @max_value: Maximum valid value (for numeric types) + * @valid_mask: Valid bits mask (for flag parameters) + * @enum_values: Array of valid enumerated values + * @enum_count: Number of valid enumerated values + * @constraint_type: Type of constraint applied + * @validate: Custom validation function + * @description: Human-readable description + * @constraints: Additional constraints description + * @size_param_idx: Index of parameter that determines size (-1 if fixed s= ize) + * @size_multiplier: Multiplier for size calculation (e.g., sizeof(struct)) + */ +struct kapi_param_spec { + char name[KAPI_MAX_NAME_LEN]; + char type_name[KAPI_MAX_NAME_LEN]; + enum kapi_param_type type; + u32 flags; + size_t size; + size_t alignment; + s64 min_value; + s64 max_value; + u64 valid_mask; + const s64 *enum_values; + u32 enum_count; + enum kapi_constraint_type constraint_type; + bool (*validate)(s64 value); + char description[KAPI_MAX_DESC_LEN]; + char constraints[KAPI_MAX_DESC_LEN]; + int size_param_idx; /* Index of param that determines size, -1 if N/A */ + size_t size_multiplier; /* Size per unit (e.g., sizeof(struct epoll_event= )) */ +} __attribute__((packed)); + +/** + * struct kapi_error_spec - Error condition specification + * @error_code: Error code value + * @name: Error code name (e.g., "EINVAL") + * @condition: Condition that triggers this error + * @description: Detailed error description + */ +struct kapi_error_spec { + int error_code; + char name[KAPI_MAX_NAME_LEN]; + char condition[KAPI_MAX_DESC_LEN]; + char description[KAPI_MAX_DESC_LEN]; +} __attribute__((packed)); + +/** + * enum kapi_return_check_type - Return value check types + * @KAPI_RETURN_EXACT: Success is an exact value + * @KAPI_RETURN_RANGE: Success is within a range + * @KAPI_RETURN_ERROR_CHECK: Success is when NOT in error list + * @KAPI_RETURN_FD: Return value is a file descriptor (>=3D 0 is success) + * @KAPI_RETURN_CUSTOM: Custom validation function + * @KAPI_RETURN_NO_RETURN: Function does not return (e.g., exec on success) + */ +enum kapi_return_check_type { + KAPI_RETURN_EXACT, + KAPI_RETURN_RANGE, + KAPI_RETURN_ERROR_CHECK, + KAPI_RETURN_FD, + KAPI_RETURN_CUSTOM, + KAPI_RETURN_NO_RETURN, +}; + +/** + * struct kapi_return_spec - Return value specification + * @type_name: Return type name + * @type: Return type classification + * @check_type: Type of success check to perform + * @success_value: Exact value indicating success (for EXACT) + * @success_min: Minimum success value (for RANGE) + * @success_max: Maximum success value (for RANGE) + * @error_values: Array of error values (for ERROR_CHECK) + * @error_count: Number of error values + * @is_success: Custom function to check success + * @description: Return value description + */ +struct kapi_return_spec { + char type_name[KAPI_MAX_NAME_LEN]; + enum kapi_param_type type; + enum kapi_return_check_type check_type; + s64 success_value; + s64 success_min; + s64 success_max; + const s64 *error_values; + u32 error_count; + bool (*is_success)(s64 retval); + char description[KAPI_MAX_DESC_LEN]; +} __attribute__((packed)); + +/** + * struct kapi_lock_spec - Lock requirement specification + * @lock_name: Name of the lock + * @lock_type: Type of lock + * @acquired: Whether function acquires this lock + * @released: Whether function releases this lock + * @held_on_entry: Whether lock must be held on entry + * @held_on_exit: Whether lock is held on exit + * @description: Additional lock requirements + */ +struct kapi_lock_spec { + char lock_name[KAPI_MAX_NAME_LEN]; + enum kapi_lock_type lock_type; + bool acquired; + bool released; + bool held_on_entry; + bool held_on_exit; + char description[KAPI_MAX_DESC_LEN]; +} __attribute__((packed)); + +/** + * struct kapi_constraint_spec - Additional constraint specification + * @name: Constraint name + * @description: Constraint description + * @expression: Formal expression (if applicable) + */ +struct kapi_constraint_spec { + char name[KAPI_MAX_NAME_LEN]; + char description[KAPI_MAX_DESC_LEN]; + char expression[KAPI_MAX_DESC_LEN]; +} __attribute__((packed)); + +/** + * enum kapi_signal_direction - Signal flow direction + * @KAPI_SIGNAL_RECEIVE: Function may receive this signal + * @KAPI_SIGNAL_SEND: Function may send this signal + * @KAPI_SIGNAL_HANDLE: Function handles this signal specially + * @KAPI_SIGNAL_BLOCK: Function blocks this signal + * @KAPI_SIGNAL_IGNORE: Function ignores this signal + */ +enum kapi_signal_direction { + KAPI_SIGNAL_RECEIVE =3D (1 << 0), + KAPI_SIGNAL_SEND =3D (1 << 1), + KAPI_SIGNAL_HANDLE =3D (1 << 2), + KAPI_SIGNAL_BLOCK =3D (1 << 3), + KAPI_SIGNAL_IGNORE =3D (1 << 4), +}; + +/** + * enum kapi_signal_action - What the function does with the signal + * @KAPI_SIGNAL_ACTION_DEFAULT: Default signal action applies + * @KAPI_SIGNAL_ACTION_TERMINATE: Causes termination + * @KAPI_SIGNAL_ACTION_COREDUMP: Causes termination with core dump + * @KAPI_SIGNAL_ACTION_STOP: Stops the process + * @KAPI_SIGNAL_ACTION_CONTINUE: Continues a stopped process + * @KAPI_SIGNAL_ACTION_CUSTOM: Custom handling described in notes + * @KAPI_SIGNAL_ACTION_RETURN: Returns from syscall with EINTR + * @KAPI_SIGNAL_ACTION_RESTART: Restarts the syscall + * @KAPI_SIGNAL_ACTION_QUEUE: Queues the signal for later delivery + * @KAPI_SIGNAL_ACTION_DISCARD: Discards the signal + * @KAPI_SIGNAL_ACTION_TRANSFORM: Transforms to another signal + */ +enum kapi_signal_action { + KAPI_SIGNAL_ACTION_DEFAULT =3D 0, + KAPI_SIGNAL_ACTION_TERMINATE, + KAPI_SIGNAL_ACTION_COREDUMP, + KAPI_SIGNAL_ACTION_STOP, + KAPI_SIGNAL_ACTION_CONTINUE, + KAPI_SIGNAL_ACTION_CUSTOM, + KAPI_SIGNAL_ACTION_RETURN, + KAPI_SIGNAL_ACTION_RESTART, + KAPI_SIGNAL_ACTION_QUEUE, + KAPI_SIGNAL_ACTION_DISCARD, + KAPI_SIGNAL_ACTION_TRANSFORM, +}; + +/** + * struct kapi_signal_spec - Signal specification + * @signal_num: Signal number (e.g., SIGKILL, SIGTERM) + * @signal_name: Signal name as string + * @direction: Direction flags (OR of kapi_signal_direction) + * @action: What happens when signal is received + * @target: Description of target process/thread for sent signals + * @condition: Condition under which signal is sent/received/handled + * @description: Detailed description of signal handling + * @restartable: Whether syscall is restartable after this signal + * @sa_flags_required: Required signal action flags (SA_*) + * @sa_flags_forbidden: Forbidden signal action flags + * @error_on_signal: Error code returned when signal occurs (-EINTR, etc) + * @transform_to: Signal number to transform to (if action is TRANSFORM) + * @timing: When signal can occur ("entry", "during", "exit", "anytime") + * @priority: Signal handling priority (lower processed first) + * @interruptible: Whether this operation is interruptible by this signal + * @queue_behavior: How signal is queued ("realtime", "standard", "coalesc= e") + * @state_required: Required process state for signal to be delivered + * @state_forbidden: Forbidden process state for signal delivery + */ +struct kapi_signal_spec { + int signal_num; + char signal_name[32]; + u32 direction; + enum kapi_signal_action action; + char target[KAPI_MAX_DESC_LEN]; + char condition[KAPI_MAX_DESC_LEN]; + char description[KAPI_MAX_DESC_LEN]; + bool restartable; + u32 sa_flags_required; + u32 sa_flags_forbidden; + int error_on_signal; + int transform_to; + char timing[32]; + u8 priority; + bool interruptible; + char queue_behavior[128]; + u32 state_required; + u32 state_forbidden; +} __attribute__((packed)); + +/** + * struct kapi_signal_mask_spec - Signal mask specification + * @mask_name: Name of the signal mask + * @signals: Array of signal numbers in the mask + * @signal_count: Number of signals in the mask + * @description: Description of what this mask represents + */ +struct kapi_signal_mask_spec { + char mask_name[KAPI_MAX_NAME_LEN]; + int signals[KAPI_MAX_SIGNALS]; + u32 signal_count; + char description[KAPI_MAX_DESC_LEN]; +} __attribute__((packed)); + +/** + * struct kapi_struct_field - Structure field specification + * @name: Field name + * @type: Field type classification + * @type_name: Type name as string + * @offset: Offset within structure + * @size: Size of field in bytes + * @flags: Field attribute flags + * @constraint_type: Type of constraint applied + * @min_value: Minimum valid value (for numeric types) + * @max_value: Maximum valid value (for numeric types) + * @valid_mask: Valid bits mask (for flag fields) + * @enum_values: Comma-separated list of valid enum values (for enum types) + * @description: Field description + */ +struct kapi_struct_field { + char name[KAPI_MAX_NAME_LEN]; + enum kapi_param_type type; + char type_name[KAPI_MAX_NAME_LEN]; + size_t offset; + size_t size; + u32 flags; + enum kapi_constraint_type constraint_type; + s64 min_value; + s64 max_value; + u64 valid_mask; + char enum_values[KAPI_MAX_DESC_LEN]; /* Comma-separated list of valid enu= m values */ + char description[KAPI_MAX_DESC_LEN]; +} __attribute__((packed)); + +/** + * struct kapi_struct_spec - Structure type specification + * @name: Structure name + * @size: Total size of structure + * @alignment: Required alignment + * @field_count: Number of fields + * @fields: Field specifications + * @description: Structure description + */ +struct kapi_struct_spec { + char name[KAPI_MAX_NAME_LEN]; + size_t size; + size_t alignment; + u32 field_count; + struct kapi_struct_field fields[KAPI_MAX_PARAMS]; + char description[KAPI_MAX_DESC_LEN]; +} __attribute__((packed)); + +/** + * enum kapi_capability_action - What the capability allows + * @KAPI_CAP_BYPASS_CHECK: Bypasses a check entirely + * @KAPI_CAP_INCREASE_LIMIT: Increases or removes a limit + * @KAPI_CAP_OVERRIDE_RESTRICTION: Overrides a restriction + * @KAPI_CAP_GRANT_PERMISSION: Grants permission that would otherwise be d= enied + * @KAPI_CAP_MODIFY_BEHAVIOR: Changes the behavior of the operation + * @KAPI_CAP_ACCESS_RESOURCE: Allows access to restricted resources + * @KAPI_CAP_PERFORM_OPERATION: Allows performing a privileged operation + */ +enum kapi_capability_action { + KAPI_CAP_BYPASS_CHECK =3D 0, + KAPI_CAP_INCREASE_LIMIT, + KAPI_CAP_OVERRIDE_RESTRICTION, + KAPI_CAP_GRANT_PERMISSION, + KAPI_CAP_MODIFY_BEHAVIOR, + KAPI_CAP_ACCESS_RESOURCE, + KAPI_CAP_PERFORM_OPERATION, +}; + +/** + * struct kapi_capability_spec - Capability requirement specification + * @capability: The capability constant (e.g., CAP_IPC_LOCK) + * @cap_name: Capability name as string + * @action: What the capability allows (kapi_capability_action) + * @allows: Description of what the capability allows + * @without_cap: What happens without the capability + * @check_condition: Condition when capability is checked + * @priority: Check priority (lower checked first) + * @alternative: Alternative capabilities that can be used + * @alternative_count: Number of alternative capabilities + */ +struct kapi_capability_spec { + int capability; + char cap_name[KAPI_MAX_NAME_LEN]; + enum kapi_capability_action action; + char allows[KAPI_MAX_DESC_LEN]; + char without_cap[KAPI_MAX_DESC_LEN]; + char check_condition[KAPI_MAX_DESC_LEN]; + u8 priority; + int alternative[KAPI_MAX_CAPABILITIES]; + u32 alternative_count; +} __attribute__((packed)); + +/** + * enum kapi_side_effect_type - Types of side effects + * @KAPI_EFFECT_NONE: No side effects + * @KAPI_EFFECT_ALLOC_MEMORY: Allocates memory + * @KAPI_EFFECT_FREE_MEMORY: Frees memory + * @KAPI_EFFECT_MODIFY_STATE: Modifies global/shared state + * @KAPI_EFFECT_SIGNAL_SEND: Sends signals + * @KAPI_EFFECT_FILE_POSITION: Modifies file position + * @KAPI_EFFECT_LOCK_ACQUIRE: Acquires locks + * @KAPI_EFFECT_LOCK_RELEASE: Releases locks + * @KAPI_EFFECT_RESOURCE_CREATE: Creates system resources (FDs, PIDs, etc) + * @KAPI_EFFECT_RESOURCE_DESTROY: Destroys system resources + * @KAPI_EFFECT_SCHEDULE: May cause scheduling/context switch + * @KAPI_EFFECT_HARDWARE: Interacts with hardware + * @KAPI_EFFECT_NETWORK: Network I/O operation + * @KAPI_EFFECT_FILESYSTEM: Filesystem modification + * @KAPI_EFFECT_PROCESS_STATE: Modifies process state + * @KAPI_EFFECT_IRREVERSIBLE: Effect cannot be undone + */ +enum kapi_side_effect_type { + KAPI_EFFECT_NONE =3D 0, + KAPI_EFFECT_ALLOC_MEMORY =3D (1 << 0), + KAPI_EFFECT_FREE_MEMORY =3D (1 << 1), + KAPI_EFFECT_MODIFY_STATE =3D (1 << 2), + KAPI_EFFECT_SIGNAL_SEND =3D (1 << 3), + KAPI_EFFECT_FILE_POSITION =3D (1 << 4), + KAPI_EFFECT_LOCK_ACQUIRE =3D (1 << 5), + KAPI_EFFECT_LOCK_RELEASE =3D (1 << 6), + KAPI_EFFECT_RESOURCE_CREATE =3D (1 << 7), + KAPI_EFFECT_RESOURCE_DESTROY =3D (1 << 8), + KAPI_EFFECT_SCHEDULE =3D (1 << 9), + KAPI_EFFECT_HARDWARE =3D (1 << 10), + KAPI_EFFECT_NETWORK =3D (1 << 11), + KAPI_EFFECT_FILESYSTEM =3D (1 << 12), + KAPI_EFFECT_PROCESS_STATE =3D (1 << 13), + KAPI_EFFECT_IRREVERSIBLE =3D (1 << 14), +}; + +/** + * struct kapi_side_effect - Side effect specification + * @type: Bitmask of effect types + * @target: What is affected (e.g., "process memory", "file descriptor tab= le") + * @condition: Condition under which effect occurs + * @description: Detailed description of the effect + * @reversible: Whether the effect can be undone + */ +struct kapi_side_effect { + u32 type; + char target[KAPI_MAX_NAME_LEN]; + char condition[KAPI_MAX_DESC_LEN]; + char description[KAPI_MAX_DESC_LEN]; + bool reversible; +} __attribute__((packed)); + +/** + * struct kapi_state_transition - State transition specification + * @from_state: Starting state description + * @to_state: Ending state description + * @condition: Condition for transition + * @object: Object whose state changes + * @description: Detailed description + */ +struct kapi_state_transition { + char from_state[KAPI_MAX_NAME_LEN]; + char to_state[KAPI_MAX_NAME_LEN]; + char condition[KAPI_MAX_DESC_LEN]; + char object[KAPI_MAX_NAME_LEN]; + char description[KAPI_MAX_DESC_LEN]; +} __attribute__((packed)); + +#define KAPI_MAX_STRUCT_SPECS 8 +#define KAPI_MAX_SIDE_EFFECTS 32 +#define KAPI_MAX_STATE_TRANS 8 + +/** + * enum kapi_socket_state - Socket states for state machine + */ +enum kapi_socket_state { + KAPI_SOCK_STATE_UNSPEC =3D 0, + KAPI_SOCK_STATE_CLOSED, + KAPI_SOCK_STATE_OPEN, + KAPI_SOCK_STATE_BOUND, + KAPI_SOCK_STATE_LISTEN, + KAPI_SOCK_STATE_SYN_SENT, + KAPI_SOCK_STATE_SYN_RECV, + KAPI_SOCK_STATE_ESTABLISHED, + KAPI_SOCK_STATE_FIN_WAIT1, + KAPI_SOCK_STATE_FIN_WAIT2, + KAPI_SOCK_STATE_CLOSE_WAIT, + KAPI_SOCK_STATE_CLOSING, + KAPI_SOCK_STATE_LAST_ACK, + KAPI_SOCK_STATE_TIME_WAIT, + KAPI_SOCK_STATE_CONNECTED, + KAPI_SOCK_STATE_DISCONNECTED, +}; + +/** + * enum kapi_socket_protocol - Socket protocol types + */ +enum kapi_socket_protocol { + KAPI_PROTO_TCP =3D (1 << 0), + KAPI_PROTO_UDP =3D (1 << 1), + KAPI_PROTO_UNIX =3D (1 << 2), + KAPI_PROTO_RAW =3D (1 << 3), + KAPI_PROTO_PACKET =3D (1 << 4), + KAPI_PROTO_NETLINK =3D (1 << 5), + KAPI_PROTO_SCTP =3D (1 << 6), + KAPI_PROTO_DCCP =3D (1 << 7), + KAPI_PROTO_ALL =3D 0xFFFFFFFF, +}; + +/** + * enum kapi_buffer_behavior - Network buffer handling behaviors + */ +enum kapi_buffer_behavior { + KAPI_BUF_PEEK =3D (1 << 0), + KAPI_BUF_TRUNCATE =3D (1 << 1), + KAPI_BUF_SCATTER =3D (1 << 2), + KAPI_BUF_ZERO_COPY =3D (1 << 3), + KAPI_BUF_KERNEL_ALLOC =3D (1 << 4), + KAPI_BUF_DMA_CAPABLE =3D (1 << 5), + KAPI_BUF_FRAGMENT =3D (1 << 6), +}; + +/** + * enum kapi_async_behavior - Asynchronous operation behaviors + */ +enum kapi_async_behavior { + KAPI_ASYNC_BLOCK =3D 0, + KAPI_ASYNC_NONBLOCK =3D (1 << 0), + KAPI_ASYNC_POLL_READY =3D (1 << 1), + KAPI_ASYNC_SIGNAL_DRIVEN =3D (1 << 2), + KAPI_ASYNC_AIO =3D (1 << 3), + KAPI_ASYNC_IO_URING =3D (1 << 4), + KAPI_ASYNC_EPOLL =3D (1 << 5), +}; + +/** + * struct kapi_socket_state_spec - Socket state requirement/transition + */ +struct kapi_socket_state_spec { + enum kapi_socket_state required_states[KAPI_MAX_SOCKET_STATES]; + u32 required_state_count; + enum kapi_socket_state forbidden_states[KAPI_MAX_SOCKET_STATES]; + u32 forbidden_state_count; + enum kapi_socket_state resulting_state; + char state_condition[KAPI_MAX_DESC_LEN]; + u32 applicable_protocols; +} __attribute__((packed)); + +/** + * struct kapi_protocol_behavior - Protocol-specific behavior + */ +struct kapi_protocol_behavior { + u32 applicable_protocols; + char behavior[KAPI_MAX_DESC_LEN]; + s64 protocol_flags; + char flag_description[KAPI_MAX_DESC_LEN]; +} __attribute__((packed)); + +/** + * struct kapi_buffer_spec - Network buffer specification + */ +struct kapi_buffer_spec { + u32 buffer_behaviors; + size_t min_buffer_size; + size_t max_buffer_size; + size_t optimal_buffer_size; + char fragmentation_rules[KAPI_MAX_DESC_LEN]; + bool can_partial_transfer; + char partial_transfer_rules[KAPI_MAX_DESC_LEN]; +} __attribute__((packed)); + +/** + * struct kapi_async_spec - Asynchronous behavior specification + */ +struct kapi_async_spec { + enum kapi_async_behavior supported_modes; + int nonblock_errno; + u32 poll_events_in; + u32 poll_events_out; + char completion_condition[KAPI_MAX_DESC_LEN]; + bool supports_timeout; + char timeout_behavior[KAPI_MAX_DESC_LEN]; +} __attribute__((packed)); + +/** + * struct kapi_addr_family_spec - Address family specification + */ +struct kapi_addr_family_spec { + int family; + char family_name[32]; + size_t addr_struct_size; + size_t min_addr_len; + size_t max_addr_len; + char addr_format[KAPI_MAX_DESC_LEN]; + bool supports_wildcard; + bool supports_multicast; + bool supports_broadcast; + char special_addresses[KAPI_MAX_DESC_LEN]; + u32 port_range_min; + u32 port_range_max; +} __attribute__((packed)); + +/** + * struct kernel_api_spec - Complete kernel API specification + * @name: Function name + * @version: API version + * @description: Brief description + * @long_description: Detailed description + * @context_flags: Execution context flags + * @param_count: Number of parameters + * @params: Parameter specifications + * @return_spec: Return value specification + * @error_count: Number of possible errors + * @errors: Error specifications + * @lock_count: Number of lock specifications + * @locks: Lock requirement specifications + * @constraint_count: Number of additional constraints + * @constraints: Additional constraint specifications + * @examples: Usage examples + * @notes: Additional notes + * @since_version: Kernel version when introduced + * @signal_count: Number of signal specifications + * @signals: Signal handling specifications + * @signal_mask_count: Number of signal mask specifications + * @signal_masks: Signal mask specifications + * @struct_spec_count: Number of structure specifications + * @struct_specs: Structure type specifications + * @side_effect_count: Number of side effect specifications + * @side_effects: Side effect specifications + * @state_trans_count: Number of state transition specifications + * @state_transitions: State transition specifications + */ +struct kernel_api_spec { + char name[KAPI_MAX_NAME_LEN]; + u32 version; + char description[KAPI_MAX_DESC_LEN]; + char long_description[KAPI_MAX_DESC_LEN * 4]; + u32 context_flags; + + /* Parameters */ + u32 param_magic; /* 0x4B415031 =3D 'KAP1' */ + u32 param_count; + struct kapi_param_spec params[KAPI_MAX_PARAMS]; + + /* Return value */ + u32 return_magic; /* 0x4B415232 =3D 'KAR2' */ + struct kapi_return_spec return_spec; + + /* Errors */ + u32 error_magic; /* 0x4B414533 =3D 'KAE3' */ + u32 error_count; + struct kapi_error_spec errors[KAPI_MAX_ERRORS]; + + /* Locking */ + u32 lock_magic; /* 0x4B414C34 =3D 'KAL4' */ + u32 lock_count; + struct kapi_lock_spec locks[KAPI_MAX_CONSTRAINTS]; + + /* Constraints */ + u32 constraint_magic; /* 0x4B414335 =3D 'KAC5' */ + u32 constraint_count; + struct kapi_constraint_spec constraints[KAPI_MAX_CONSTRAINTS]; + + /* Additional information */ + u32 info_magic; /* 0x4B414936 =3D 'KAI6' */ + char examples[KAPI_MAX_DESC_LEN * 2]; + char notes[KAPI_MAX_DESC_LEN * 2]; + char since_version[32]; + + /* Signal specifications */ + u32 signal_magic; /* 0x4B415337 =3D 'KAS7' */ + u32 signal_count; + struct kapi_signal_spec signals[KAPI_MAX_SIGNALS]; + + /* Signal mask specifications */ + u32 sigmask_magic; /* 0x4B414D38 =3D 'KAM8' */ + u32 signal_mask_count; + struct kapi_signal_mask_spec signal_masks[KAPI_MAX_SIGNALS]; + + /* Structure specifications */ + u32 struct_magic; /* 0x4B415439 =3D 'KAT9' */ + u32 struct_spec_count; + struct kapi_struct_spec struct_specs[KAPI_MAX_STRUCT_SPECS]; + + /* Side effects */ + u32 effect_magic; /* 0x4B414641 =3D 'KAFA' */ + u32 side_effect_count; + struct kapi_side_effect side_effects[KAPI_MAX_SIDE_EFFECTS]; + + /* State transitions */ + u32 trans_magic; /* 0x4B415442 =3D 'KATB' */ + u32 state_trans_count; + struct kapi_state_transition state_transitions[KAPI_MAX_STATE_TRANS]; + + /* Capability specifications */ + u32 cap_magic; /* 0x4B414343 =3D 'KACC' */ + u32 capability_count; + struct kapi_capability_spec capabilities[KAPI_MAX_CAPABILITIES]; + + /* Extended fields for socket and network operations */ + struct kapi_socket_state_spec socket_state; + struct kapi_protocol_behavior protocol_behaviors[KAPI_MAX_PROTOCOL_BEHAVI= ORS]; + u32 protocol_behavior_count; + struct kapi_buffer_spec buffer_spec; + struct kapi_async_spec async_spec; + struct kapi_addr_family_spec addr_families[KAPI_MAX_ADDR_FAMILIES]; + u32 addr_family_count; + + /* Operation characteristics */ + bool is_connection_oriented; + bool is_message_oriented; + bool supports_oob_data; + bool supports_peek; + bool supports_select_poll; + bool is_reentrant; + + /* Semantic descriptions */ + char connection_establishment[KAPI_MAX_DESC_LEN]; + char connection_termination[KAPI_MAX_DESC_LEN]; + char data_transfer_semantics[KAPI_MAX_DESC_LEN]; +} __attribute__((packed)); + +/* Macros for defining API specifications */ + +/** + * DEFINE_KERNEL_API_SPEC - Define a kernel API specification + * @func_name: Function name to specify + */ +#define DEFINE_KERNEL_API_SPEC(func_name) \ + static struct kernel_api_spec __kapi_spec_##func_name \ + __used __section(".kapi_specs") =3D { \ + .name =3D __stringify(func_name), \ + .version =3D 1, + +#define KAPI_END_SPEC }; + +/** + * KAPI_DESCRIPTION - Set API description + * @desc: Description string + */ +#define KAPI_DESCRIPTION(desc) \ + .description =3D desc, + +/** + * KAPI_LONG_DESC - Set detailed API description + * @desc: Detailed description string + */ +#define KAPI_LONG_DESC(desc) \ + .long_description =3D desc, + +/** + * KAPI_CONTEXT - Set execution context flags + * @flags: Context flags (OR'ed KAPI_CTX_* values) + */ +#define KAPI_CONTEXT(flags) \ + .context_flags =3D flags, + +/** + * KAPI_PARAM - Define a parameter specification + * @idx: Parameter index (0-based) + * @pname: Parameter name + * @ptype: Type name string + * @pdesc: Parameter description + */ +#define KAPI_PARAM(idx, pname, ptype, pdesc) \ + .params[idx] =3D { \ + .name =3D pname, \ + .type_name =3D ptype, \ + .description =3D pdesc, \ + .size_param_idx =3D -1, /* Default: no dynamic sizing */ + +#define KAPI_PARAM_TYPE(ptype) \ + .type =3D ptype, + +#define KAPI_PARAM_FLAGS(pflags) \ + .flags =3D pflags, + +#define KAPI_PARAM_SIZE(psize) \ + .size =3D psize, + +#define KAPI_PARAM_RANGE(pmin, pmax) \ + .min_value =3D pmin, \ + .max_value =3D pmax, + +#define KAPI_PARAM_CONSTRAINT_TYPE(ctype) \ + .constraint_type =3D ctype, + +#define KAPI_PARAM_CONSTRAINT(desc) \ + .constraints =3D desc, + +#define KAPI_PARAM_VALID_MASK(mask) \ + .valid_mask =3D mask, + +#define KAPI_PARAM_ENUM_VALUES(values) \ + .enum_values =3D values, \ + .enum_count =3D ARRAY_SIZE(values), + +#define KAPI_PARAM_ALIGNMENT(align) \ + .alignment =3D align, + +#define KAPI_PARAM_SIZE_PARAM(idx) \ + .size_param_idx =3D idx, + +#define KAPI_PARAM_END }, + +/** + * KAPI_PARAM_COUNT - Set the number of parameters + * @n: Number of parameters + */ +#define KAPI_PARAM_COUNT(n) \ + .param_magic =3D 0x4B415031, /* 'KAP1' */ \ + .param_count =3D n, + +/** + * KAPI_RETURN - Define return value specification + * @rtype: Return type name + * @rdesc: Return value description + */ +#define KAPI_RETURN(rtype, rdesc) \ + .return_spec =3D { \ + .type_name =3D rtype, \ + .description =3D rdesc, + +#define KAPI_RETURN_SUCCESS(val) \ + .success_value =3D val, + +#define KAPI_RETURN_TYPE(rtype) \ + .type =3D rtype, + +#define KAPI_RETURN_CHECK_TYPE(ctype) \ + .check_type =3D ctype, + +#define KAPI_RETURN_ERROR_VALUES(values) \ + .error_values =3D values, + +#define KAPI_RETURN_ERROR_COUNT(count) \ + .error_count =3D count, + +#define KAPI_RETURN_SUCCESS_RANGE(min, max) \ + .success_min =3D min, \ + .success_max =3D max, + +#define KAPI_RETURN_END }, + +/** + * KAPI_ERROR - Define an error condition + * @idx: Error index + * @ecode: Error code value + * @ename: Error name + * @econd: Error condition + * @edesc: Error description + */ +#define KAPI_ERROR(idx, ecode, ename, econd, edesc) \ + .errors[idx] =3D { \ + .error_code =3D ecode, \ + .name =3D ename, \ + .condition =3D econd, \ + .description =3D edesc, \ + }, + +/** + * KAPI_ERROR_COUNT - Set the number of errors + * @n: Number of errors + */ +#define KAPI_ERROR_COUNT(n) \ + .error_magic =3D 0x4B414533, /* 'KAE3' */ \ + .error_count =3D n, + +/** + * KAPI_LOCK - Define a lock requirement + * @idx: Lock index + * @lname: Lock name + * @ltype: Lock type + */ +#define KAPI_LOCK(idx, lname, ltype) \ + .locks[idx] =3D { \ + .lock_name =3D lname, \ + .lock_type =3D ltype, + +#define KAPI_LOCK_ACQUIRED \ + .acquired =3D true, + +#define KAPI_LOCK_RELEASED \ + .released =3D true, + +#define KAPI_LOCK_HELD_ENTRY \ + .held_on_entry =3D true, + +#define KAPI_LOCK_HELD_EXIT \ + .held_on_exit =3D true, + +#define KAPI_LOCK_DESC(ldesc) \ + .description =3D ldesc, + +#define KAPI_LOCK_END }, + +/** + * KAPI_CONSTRAINT - Define an additional constraint + * @idx: Constraint index + * @cname: Constraint name + * @cdesc: Constraint description + */ +#define KAPI_CONSTRAINT(idx, cname, cdesc) \ + .constraints[idx] =3D { \ + .name =3D cname, \ + .description =3D cdesc, + +#define KAPI_CONSTRAINT_EXPR(expr) \ + .expression =3D expr, + +#define KAPI_CONSTRAINT_END }, + +/** + * KAPI_EXAMPLES - Set API usage examples + * @examples: Examples string + */ +#define KAPI_EXAMPLES(ex) \ + .info_magic =3D 0x4B414936, /* 'KAI6' */ \ + .examples =3D ex, + +/** + * KAPI_NOTES - Set API notes + * @notes: Notes string + */ +#define KAPI_NOTES(n) \ + .notes =3D n, + + +/** + * KAPI_SIGNAL - Define a signal specification + * @idx: Signal index + * @signum: Signal number (e.g., SIGKILL) + * @signame: Signal name string + * @dir: Direction flags + * @act: Action taken + */ +#define KAPI_SIGNAL(idx, signum, signame, dir, act) \ + .signals[idx] =3D { \ + .signal_num =3D signum, \ + .signal_name =3D signame, \ + .direction =3D dir, \ + .action =3D act, + +#define KAPI_SIGNAL_TARGET(tgt) \ + .target =3D tgt, + +#define KAPI_SIGNAL_CONDITION(cond) \ + .condition =3D cond, + +#define KAPI_SIGNAL_DESC(desc) \ + .description =3D desc, + +#define KAPI_SIGNAL_RESTARTABLE \ + .restartable =3D true, + +#define KAPI_SIGNAL_SA_FLAGS_REQ(flags) \ + .sa_flags_required =3D flags, + +#define KAPI_SIGNAL_SA_FLAGS_FORBID(flags) \ + .sa_flags_forbidden =3D flags, + +#define KAPI_SIGNAL_ERROR(err) \ + .error_on_signal =3D err, + +#define KAPI_SIGNAL_TRANSFORM(sig) \ + .transform_to =3D sig, + +#define KAPI_SIGNAL_TIMING(when) \ + .timing =3D when, + +#define KAPI_SIGNAL_PRIORITY(prio) \ + .priority =3D prio, + +#define KAPI_SIGNAL_INTERRUPTIBLE \ + .interruptible =3D true, + +#define KAPI_SIGNAL_QUEUE(behavior) \ + .queue_behavior =3D behavior, + +#define KAPI_SIGNAL_STATE_REQ(state) \ + .state_required =3D state, + +#define KAPI_SIGNAL_STATE_FORBID(state) \ + .state_forbidden =3D state, + +#define KAPI_SIGNAL_END }, + +#define KAPI_SIGNAL_COUNT(n) \ + .signal_magic =3D 0x4B415337, /* 'KAS7' */ \ + .signal_count =3D n, + +/** + * KAPI_SIGNAL_MASK - Define a signal mask specification + * @idx: Mask index + * @name: Mask name + * @desc: Mask description + */ +#define KAPI_SIGNAL_MASK(idx, name, desc) \ + .signal_masks[idx] =3D { \ + .mask_name =3D name, \ + .description =3D desc, + +#define KAPI_SIGNAL_MASK_ADD(signum) \ + .signals[.signal_count++] =3D signum, + +#define KAPI_SIGNAL_MASK_END }, + +/** + * KAPI_STRUCT_SPEC - Define a structure specification + * @idx: Structure spec index + * @sname: Structure name + * @sdesc: Structure description + */ +#define KAPI_STRUCT_SPEC(idx, sname, sdesc) \ + .struct_specs[idx] =3D { \ + .name =3D #sname, \ + .description =3D sdesc, + +#define KAPI_STRUCT_SIZE(ssize, salign) \ + .size =3D ssize, \ + .alignment =3D salign, + +#define KAPI_STRUCT_FIELD_COUNT(n) \ + .field_count =3D n, + +/** + * KAPI_STRUCT_FIELD - Define a structure field + * @fidx: Field index + * @fname: Field name + * @ftype: Field type (KAPI_TYPE_*) + * @ftype_name: Type name as string + * @fdesc: Field description + */ +#define KAPI_STRUCT_FIELD(fidx, fname, ftype, ftype_name, fdesc) \ + .fields[fidx] =3D { \ + .name =3D fname, \ + .type =3D ftype, \ + .type_name =3D ftype_name, \ + .description =3D fdesc, + +#define KAPI_FIELD_OFFSET(foffset) \ + .offset =3D foffset, + +#define KAPI_FIELD_SIZE(fsize) \ + .size =3D fsize, + +#define KAPI_FIELD_FLAGS(fflags) \ + .flags =3D fflags, + +#define KAPI_FIELD_CONSTRAINT_RANGE(min, max) \ + .constraint_type =3D KAPI_CONSTRAINT_RANGE, \ + .min_value =3D min, \ + .max_value =3D max, + +#define KAPI_FIELD_CONSTRAINT_MASK(mask) \ + .constraint_type =3D KAPI_CONSTRAINT_MASK, \ + .valid_mask =3D mask, + +#define KAPI_FIELD_CONSTRAINT_ENUM(values) \ + .constraint_type =3D KAPI_CONSTRAINT_ENUM, \ + .enum_values =3D values, + +#define KAPI_STRUCT_FIELD_END }, + +#define KAPI_STRUCT_SPEC_END }, + +/* Counter for structure specifications */ +#define KAPI_STRUCT_SPEC_COUNT(n) \ + .struct_magic =3D 0x4B415439, /* 'KAT9' */ \ + .struct_spec_count =3D n, + +/* Additional lock-related macros */ +#define KAPI_LOCK_COUNT(n) \ + .lock_magic =3D 0x4B414C34, /* 'KAL4' */ \ + .lock_count =3D n, + +/** + * KAPI_SIDE_EFFECT - Define a side effect + * @idx: Side effect index + * @etype: Effect type bitmask (OR'ed KAPI_EFFECT_* values) + * @etarget: What is affected + * @edesc: Effect description + */ +#define KAPI_SIDE_EFFECT(idx, etype, etarget, edesc) \ + .side_effects[idx] =3D { \ + .type =3D etype, \ + .target =3D etarget, \ + .description =3D edesc, \ + .reversible =3D false, /* Default to non-reversible */ + +#define KAPI_EFFECT_CONDITION(cond) \ + .condition =3D cond, + +#define KAPI_EFFECT_REVERSIBLE \ + .reversible =3D true, + +#define KAPI_SIDE_EFFECT_END }, + +/** + * KAPI_STATE_TRANS - Define a state transition + * @idx: State transition index + * @obj: Object whose state changes + * @from: From state + * @to: To state + * @desc: Transition description + */ +#define KAPI_STATE_TRANS(idx, obj, from, to, desc) \ + .state_transitions[idx] =3D { \ + .object =3D obj, \ + .from_state =3D from, \ + .to_state =3D to, \ + .description =3D desc, + +#define KAPI_STATE_TRANS_COND(cond) \ + .condition =3D cond, + +#define KAPI_STATE_TRANS_END }, + +/* Counters for side effects and state transitions */ +#define KAPI_SIDE_EFFECT_COUNT(n) \ + .effect_magic =3D 0x4B414641, /* 'KAFA' */ \ + .side_effect_count =3D n, + +#define KAPI_STATE_TRANS_COUNT(n) \ + .trans_magic =3D 0x4B415442, /* 'KATB' */ \ + .state_trans_count =3D n, + +/* Helper macros for common side effect patterns */ +#define KAPI_EFFECTS_MEMORY (KAPI_EFFECT_ALLOC_MEMORY | KAPI_EFFECT_FREE_M= EMORY) +#define KAPI_EFFECTS_LOCKING (KAPI_EFFECT_LOCK_ACQUIRE | KAPI_EFFECT_LOCK_= RELEASE) +#define KAPI_EFFECTS_RESOURCES (KAPI_EFFECT_RESOURCE_CREATE | KAPI_EFFECT_= RESOURCE_DESTROY) +#define KAPI_EFFECTS_IO (KAPI_EFFECT_NETWORK | KAPI_EFFECT_FILESYSTEM) + +/* Helper macros for common patterns */ + +#define KAPI_PARAM_IN (KAPI_PARAM_IN) +#define KAPI_PARAM_OUT (KAPI_PARAM_OUT) +#define KAPI_PARAM_INOUT (KAPI_PARAM_IN | KAPI_PARAM_OUT) +#define KAPI_PARAM_OPTIONAL (KAPI_PARAM_OPTIONAL) +#define KAPI_PARAM_USER_PTR (KAPI_PARAM_USER | KAPI_PARAM_PTR) + +/* Common signal timing constants */ +#define KAPI_SIGNAL_TIME_ENTRY "entry" +#define KAPI_SIGNAL_TIME_DURING "during" +#define KAPI_SIGNAL_TIME_EXIT "exit" +#define KAPI_SIGNAL_TIME_ANYTIME "anytime" +#define KAPI_SIGNAL_TIME_BLOCKING "while_blocked" +#define KAPI_SIGNAL_TIME_SLEEPING "while_sleeping" +#define KAPI_SIGNAL_TIME_BEFORE "before" +#define KAPI_SIGNAL_TIME_AFTER "after" + +/* Common signal queue behaviors */ +#define KAPI_SIGNAL_QUEUE_STANDARD "standard" +#define KAPI_SIGNAL_QUEUE_REALTIME "realtime" +#define KAPI_SIGNAL_QUEUE_COALESCE "coalesce" +#define KAPI_SIGNAL_QUEUE_REPLACE "replace" +#define KAPI_SIGNAL_QUEUE_DISCARD "discard" + +/* Process state flags for signal delivery */ +#define KAPI_SIGNAL_STATE_RUNNING (1 << 0) +#define KAPI_SIGNAL_STATE_SLEEPING (1 << 1) +#define KAPI_SIGNAL_STATE_STOPPED (1 << 2) +#define KAPI_SIGNAL_STATE_TRACED (1 << 3) +#define KAPI_SIGNAL_STATE_ZOMBIE (1 << 4) +#define KAPI_SIGNAL_STATE_DEAD (1 << 5) + +/* Capability specification macros */ + +/** + * KAPI_CAPABILITY - Define a capability requirement + * @idx: Capability index + * @cap: Capability constant (e.g., CAP_IPC_LOCK) + * @name: Capability name string + * @act: Action type (kapi_capability_action) + */ +#define KAPI_CAPABILITY(idx, cap, name, act) \ + .capabilities[idx] =3D { \ + .capability =3D cap, \ + .cap_name =3D name, \ + .action =3D act, + +#define KAPI_CAP_ALLOWS(desc) \ + .allows =3D desc, + +#define KAPI_CAP_WITHOUT(desc) \ + .without_cap =3D desc, + +#define KAPI_CAP_CONDITION(cond) \ + .check_condition =3D cond, + +#define KAPI_CAP_PRIORITY(prio) \ + .priority =3D prio, + +#define KAPI_CAP_ALTERNATIVE(caps, count) \ + .alternative =3D caps, \ + .alternative_count =3D count, + +#define KAPI_CAPABILITY_END }, + +/* Counter for capability specifications */ +#define KAPI_CAPABILITY_COUNT(n) \ + .cap_magic =3D 0x4B414343, /* 'KACC' */ \ + .capability_count =3D n, + +/* Common signal patterns for syscalls */ +#define KAPI_SIGNAL_INTERRUPTIBLE_SLEEP \ + KAPI_SIGNAL(0, SIGINT, "SIGINT", KAPI_SIGNAL_RECEIVE, KAPI_SIGNAL_ACTION_= RETURN) \ + KAPI_SIGNAL_TIMING(KAPI_SIGNAL_TIME_SLEEPING) \ + KAPI_SIGNAL_ERROR(-EINTR) \ + KAPI_SIGNAL_RESTARTABLE \ + KAPI_SIGNAL_DESC("Interrupts sleep, returns -EINTR") \ + KAPI_SIGNAL_END, \ + KAPI_SIGNAL(1, SIGTERM, "SIGTERM", KAPI_SIGNAL_RECEIVE, KAPI_SIGNAL_ACTIO= N_RETURN) \ + KAPI_SIGNAL_TIMING(KAPI_SIGNAL_TIME_SLEEPING) \ + KAPI_SIGNAL_ERROR(-EINTR) \ + KAPI_SIGNAL_RESTARTABLE \ + KAPI_SIGNAL_DESC("Interrupts sleep, returns -EINTR") \ + KAPI_SIGNAL_END + +#define KAPI_SIGNAL_FATAL_DEFAULT \ + KAPI_SIGNAL(2, SIGKILL, "SIGKILL", KAPI_SIGNAL_RECEIVE, KAPI_SIGNAL_ACTIO= N_TERMINATE) \ + KAPI_SIGNAL_TIMING(KAPI_SIGNAL_TIME_ANYTIME) \ + KAPI_SIGNAL_PRIORITY(0) \ + KAPI_SIGNAL_DESC("Process terminated immediately") \ + KAPI_SIGNAL_END + +#define KAPI_SIGNAL_STOP_CONT \ + KAPI_SIGNAL(3, SIGSTOP, "SIGSTOP", KAPI_SIGNAL_RECEIVE, KAPI_SIGNAL_ACTIO= N_STOP) \ + KAPI_SIGNAL_TIMING(KAPI_SIGNAL_TIME_ANYTIME) \ + KAPI_SIGNAL_DESC("Process stopped") \ + KAPI_SIGNAL_END, \ + KAPI_SIGNAL(4, SIGCONT, "SIGCONT", KAPI_SIGNAL_RECEIVE, KAPI_SIGNAL_ACTIO= N_CONTINUE) \ + KAPI_SIGNAL_TIMING(KAPI_SIGNAL_TIME_ANYTIME) \ + KAPI_SIGNAL_DESC("Process continued") \ + KAPI_SIGNAL_END + +/* Validation and runtime checking */ + +#ifdef CONFIG_KAPI_RUNTIME_CHECKS +bool kapi_validate_params(const struct kernel_api_spec *spec, ...); +bool kapi_validate_param(const struct kapi_param_spec *param_spec, s64 val= ue); +bool kapi_validate_param_with_context(const struct kapi_param_spec *param_= spec, + s64 value, const s64 *all_params, int param_count); +int kapi_validate_syscall_param(const struct kernel_api_spec *spec, + int param_idx, s64 value); +int kapi_validate_syscall_params(const struct kernel_api_spec *spec, + const s64 *params, int param_count); +bool kapi_check_return_success(const struct kapi_return_spec *return_spec,= s64 retval); +bool kapi_validate_return_value(const struct kernel_api_spec *spec, s64 re= tval); +int kapi_validate_syscall_return(const struct kernel_api_spec *spec, s64 r= etval); +void kapi_check_context(const struct kernel_api_spec *spec); +void kapi_check_locks(const struct kernel_api_spec *spec); +bool kapi_check_signal_allowed(const struct kernel_api_spec *spec, int sig= num); +bool kapi_validate_signal_action(const struct kernel_api_spec *spec, int s= ignum, + struct sigaction *act); +int kapi_get_signal_error(const struct kernel_api_spec *spec, int signum); +bool kapi_is_signal_restartable(const struct kernel_api_spec *spec, int si= gnum); +#else +static inline bool kapi_validate_params(const struct kernel_api_spec *spec= , ...) +{ + return true; +} +static inline bool kapi_validate_param(const struct kapi_param_spec *param= _spec, s64 value) +{ + return true; +} +static inline bool kapi_validate_param_with_context(const struct kapi_para= m_spec *param_spec, + s64 value, const s64 *all_params, int param_count) +{ + return true; +} +static inline int kapi_validate_syscall_param(const struct kernel_api_spec= *spec, + int param_idx, s64 value) +{ + return 0; +} +static inline int kapi_validate_syscall_params(const struct kernel_api_spe= c *spec, + const s64 *params, int param_count) +{ + return 0; +} +static inline bool kapi_check_return_success(const struct kapi_return_spec= *return_spec, s64 retval) +{ + return true; +} +static inline bool kapi_validate_return_value(const struct kernel_api_spec= *spec, s64 retval) +{ + return true; +} +static inline int kapi_validate_syscall_return(const struct kernel_api_spe= c *spec, s64 retval) +{ + return 0; +} +static inline void kapi_check_context(const struct kernel_api_spec *spec) = {} +static inline void kapi_check_locks(const struct kernel_api_spec *spec) {} +static inline bool kapi_check_signal_allowed(const struct kernel_api_spec = *spec, int signum) +{ + return true; +} +static inline bool kapi_validate_signal_action(const struct kernel_api_spe= c *spec, int signum, + struct sigaction *act) +{ + return true; +} +static inline int kapi_get_signal_error(const struct kernel_api_spec *spec= , int signum) +{ + return -EINTR; +} +static inline bool kapi_is_signal_restartable(const struct kernel_api_spec= *spec, int signum) +{ + return false; +} +#endif + +/* Export/query functions */ +const struct kernel_api_spec *kapi_get_spec(const char *name); +int kapi_export_json(const struct kernel_api_spec *spec, char *buf, size_t= size); +void kapi_print_spec(const struct kernel_api_spec *spec); + +/* Registration for dynamic APIs */ +int kapi_register_spec(struct kernel_api_spec *spec); +void kapi_unregister_spec(const char *name); + +/* Helper to get parameter constraint info */ +static inline bool kapi_get_param_constraint(const char *api_name, int par= am_idx, + enum kapi_constraint_type *type, + u64 *valid_mask, s64 *min_val, s64 *max_val) +{ + const struct kernel_api_spec *spec =3D kapi_get_spec(api_name); + + if (!spec || param_idx >=3D spec->param_count) + return false; + + if (type) + *type =3D spec->params[param_idx].constraint_type; + if (valid_mask) + *valid_mask =3D spec->params[param_idx].valid_mask; + if (min_val) + *min_val =3D spec->params[param_idx].min_value; + if (max_val) + *max_val =3D spec->params[param_idx].max_value; + + return true; +} + +/* Socket state requirement macros */ +#define KAPI_SOCKET_STATE_REQ(...) \ + .socket_state =3D { \ + .required_states =3D { __VA_ARGS__ }, \ + .required_state_count =3D sizeof((enum kapi_socket_state[]){__VA_ARGS__}= )/sizeof(enum kapi_socket_state), + +#define KAPI_SOCKET_STATE_FORBID(...) \ + .forbidden_states =3D { __VA_ARGS__ }, \ + .forbidden_state_count =3D sizeof((enum kapi_socket_state[]){__VA_ARGS__= })/sizeof(enum kapi_socket_state), + +#define KAPI_SOCKET_STATE_RESULT(state) \ + .resulting_state =3D state, + +#define KAPI_SOCKET_STATE_COND(cond) \ + .state_condition =3D cond, + +#define KAPI_SOCKET_STATE_PROTOS(protos) \ + .applicable_protocols =3D protos, + +#define KAPI_SOCKET_STATE_END }, + +/* Protocol behavior macros */ +#define KAPI_PROTOCOL_BEHAVIOR(idx, protos, desc) \ + .protocol_behaviors[idx] =3D { \ + .applicable_protocols =3D protos, \ + .behavior =3D desc, + +#define KAPI_PROTOCOL_FLAGS(flags, desc) \ + .protocol_flags =3D flags, \ + .flag_description =3D desc, + +#define KAPI_PROTOCOL_BEHAVIOR_END }, + +/* Async behavior macros */ +#define KAPI_ASYNC_SPEC(modes, errno) \ + .async_spec =3D { \ + .supported_modes =3D modes, \ + .nonblock_errno =3D errno, + +#define KAPI_ASYNC_POLL(in, out) \ + .poll_events_in =3D in, \ + .poll_events_out =3D out, + +#define KAPI_ASYNC_COMPLETION(cond) \ + .completion_condition =3D cond, + +#define KAPI_ASYNC_TIMEOUT(supported, desc) \ + .supports_timeout =3D supported, \ + .timeout_behavior =3D desc, + +#define KAPI_ASYNC_END }, + +/* Buffer behavior macros */ +#define KAPI_BUFFER_SPEC(behaviors) \ + .buffer_spec =3D { \ + .buffer_behaviors =3D behaviors, + +#define KAPI_BUFFER_SIZE(min, max, optimal) \ + .min_buffer_size =3D min, \ + .max_buffer_size =3D max, \ + .optimal_buffer_size =3D optimal, + +#define KAPI_BUFFER_PARTIAL(allowed, rules) \ + .can_partial_transfer =3D allowed, \ + .partial_transfer_rules =3D rules, + +#define KAPI_BUFFER_FRAGMENT(rules) \ + .fragmentation_rules =3D rules, + +#define KAPI_BUFFER_END }, + +/* Address family macros */ +#define KAPI_ADDR_FAMILY(idx, fam, name, struct_sz, min_len, max_len) \ + .addr_families[idx] =3D { \ + .family =3D fam, \ + .family_name =3D name, \ + .addr_struct_size =3D struct_sz, \ + .min_addr_len =3D min_len, \ + .max_addr_len =3D max_len, + +#define KAPI_ADDR_FORMAT(fmt) \ + .addr_format =3D fmt, + +#define KAPI_ADDR_FEATURES(wildcard, multicast, broadcast) \ + .supports_wildcard =3D wildcard, \ + .supports_multicast =3D multicast, \ + .supports_broadcast =3D broadcast, + +#define KAPI_ADDR_SPECIAL(addrs) \ + .special_addresses =3D addrs, + +#define KAPI_ADDR_PORTS(min, max) \ + .port_range_min =3D min, \ + .port_range_max =3D max, + +#define KAPI_ADDR_FAMILY_END }, + +#define KAPI_ADDR_FAMILY_COUNT(n) \ + .addr_family_count =3D n, + +#define KAPI_PROTOCOL_BEHAVIOR_COUNT(n) \ + .protocol_behavior_count =3D n, + +#define KAPI_CONSTRAINT_COUNT(n) \ + .constraint_magic =3D 0x4B414335, /* 'KAC5' */ \ + .constraint_count =3D n, + +/* Network operation characteristics macros */ +#define KAPI_NET_CONNECTION_ORIENTED \ + .is_connection_oriented =3D true, + +#define KAPI_NET_MESSAGE_ORIENTED \ + .is_message_oriented =3D true, + +#define KAPI_NET_SUPPORTS_OOB \ + .supports_oob_data =3D true, + +#define KAPI_NET_SUPPORTS_PEEK \ + .supports_peek =3D true, + +#define KAPI_NET_REENTRANT \ + .is_reentrant =3D true, + +/* Semantic description macros */ +#define KAPI_NET_CONN_ESTABLISH(desc) \ + .connection_establishment =3D desc, + +#define KAPI_NET_CONN_TERMINATE(desc) \ + .connection_termination =3D desc, + +#define KAPI_NET_DATA_TRANSFER(desc) \ + .data_transfer_semantics =3D desc, + +#endif /* _LINUX_KERNEL_API_SPEC_H */ diff --git a/include/linux/syscall_api_spec.h b/include/linux/syscall_api_s= pec.h new file mode 100644 index 000000000000..9317aa30e49c --- /dev/null +++ b/include/linux/syscall_api_spec.h @@ -0,0 +1,125 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * syscall_api_spec.h - System Call API Specification Integration + * + * This header extends the SYSCALL_DEFINEX macros to support inline API sp= ecifications, + * allowing syscall documentation to be written alongside the implementati= on in a + * human-readable and machine-parseable format. + */ + +#ifndef _LINUX_SYSCALL_API_SPEC_H +#define _LINUX_SYSCALL_API_SPEC_H + +#include + + + +/* Automatic syscall validation infrastructure */ +/* + * The validation is now integrated directly into the SYSCALL_DEFINEx macr= os + * in syscalls.h when CONFIG_KAPI_RUNTIME_CHECKS is enabled. + * + * The validation happens in the __do_kapi_sys##name wrapper function whic= h: + * 1. Validates all parameters before calling the actual syscall + * 2. Calls the real syscall implementation + * 3. Validates the return value + * 4. Returns the result + */ + + +/* + * Helper macros for common syscall patterns + */ + +/* For syscalls that can sleep */ +#define KAPI_SYSCALL_SLEEPABLE \ + KAPI_CONTEXT(KAPI_CTX_PROCESS | KAPI_CTX_SLEEPABLE) + +/* For syscalls that must be atomic */ +#define KAPI_SYSCALL_ATOMIC \ + KAPI_CONTEXT(KAPI_CTX_PROCESS | KAPI_CTX_ATOMIC) + +/* Common parameter specifications */ +#define KAPI_PARAM_FD(idx, desc) \ + KAPI_PARAM(idx, "fd", "int", desc) \ + KAPI_PARAM_FLAGS(KAPI_PARAM_IN) \ + .type =3D KAPI_TYPE_FD, \ + .constraint_type =3D KAPI_CONSTRAINT_NONE, \ + KAPI_PARAM_END + +#define KAPI_PARAM_USER_BUF(idx, name, desc) \ + KAPI_PARAM(idx, name, "void __user *", desc) \ + KAPI_PARAM_FLAGS(KAPI_PARAM_USER_PTR | KAPI_PARAM_IN) \ + KAPI_PARAM_END + +#define KAPI_PARAM_USER_STRUCT(idx, name, struct_type, desc) \ + KAPI_PARAM(idx, name, #struct_type " __user *", desc) \ + KAPI_PARAM_FLAGS(KAPI_PARAM_USER | KAPI_PARAM_IN) \ + .type =3D KAPI_TYPE_USER_PTR, \ + .size =3D sizeof(struct_type), \ + .constraint_type =3D KAPI_CONSTRAINT_NONE, \ + KAPI_PARAM_END + +#define KAPI_PARAM_SIZE_T(idx, name, desc) \ + KAPI_PARAM(idx, name, "size_t", desc) \ + KAPI_PARAM_FLAGS(KAPI_PARAM_IN) \ + KAPI_PARAM_RANGE(0, SIZE_MAX) \ + KAPI_PARAM_END + +/* Common error specifications */ +#define KAPI_ERROR_EBADF(idx) \ + KAPI_ERROR(idx, -EBADF, "EBADF", "Invalid file descriptor", \ + "The file descriptor is not valid or has been closed") + +#define KAPI_ERROR_EINVAL(idx, condition) \ + KAPI_ERROR(idx, -EINVAL, "EINVAL", condition, \ + "Invalid argument provided") + +#define KAPI_ERROR_ENOMEM(idx) \ + KAPI_ERROR(idx, -ENOMEM, "ENOMEM", "Insufficient memory", \ + "Cannot allocate memory for the operation") + +#define KAPI_ERROR_EPERM(idx) \ + KAPI_ERROR(idx, -EPERM, "EPERM", "Operation not permitted", \ + "The calling process does not have the required permissions") + +#define KAPI_ERROR_EFAULT(idx) \ + KAPI_ERROR(idx, -EFAULT, "EFAULT", "Bad address", \ + "Invalid user space address provided") + +/* Standard return value specifications */ +#define KAPI_RETURN_SUCCESS_ZERO \ + KAPI_RETURN("long", "0 on success, negative error code on failure") \ + KAPI_RETURN_SUCCESS(0, "=3D=3D 0") \ + KAPI_RETURN_END + +#define KAPI_RETURN_FD_SPEC \ + KAPI_RETURN("long", "File descriptor on success, negative error code on f= ailure") \ + .check_type =3D KAPI_RETURN_FD, \ + KAPI_RETURN_END + +#define KAPI_RETURN_COUNT \ + KAPI_RETURN("long", "Number of bytes processed on success, negative error= code on failure") \ + KAPI_RETURN_SUCCESS(0, ">=3D 0") \ + KAPI_RETURN_END + +/* KAPI_ERROR_COUNT and KAPI_PARAM_COUNT are now defined in kernel_api_spe= c.h */ + +/** + * KAPI_SINCE_VERSION - Set the since version + * @version: Version string when the API was introduced + */ +#define KAPI_SINCE_VERSION(version) \ + .since_version =3D version, + + +/** + * KAPI_SIGNAL_MASK_COUNT - Set the signal mask count + * @count: Number of signal masks defined + */ +#define KAPI_SIGNAL_MASK_COUNT(count) \ + .signal_mask_count =3D count, + + + +#endif /* _LINUX_SYSCALL_API_SPEC_H */ \ No newline at end of file diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h index 77f45e5d4413..403d0e09692f 100644 --- a/include/linux/syscalls.h +++ b/include/linux/syscalls.h @@ -88,6 +88,7 @@ struct file_attr; #include #include #include +#include #include #include #include @@ -133,6 +134,7 @@ struct file_attr; #define __SC_TYPE(t, a) t #define __SC_ARGS(t, a) a #define __SC_TEST(t, a) (void)BUILD_BUG_ON_ZERO(!__TYPE_IS_LL(t) && sizeof= (t) > sizeof(long)) +#define __SC_CAST_TO_S64(t, a) (s64)(a) =20 #ifdef CONFIG_FTRACE_SYSCALLS #define __SC_STR_ADECL(t, a) #a @@ -243,6 +245,41 @@ static inline int is_syscall_trace_event(struct trace_= event_call *tp_event) * done within __do_sys_*(). */ #ifndef __SYSCALL_DEFINEx +#ifdef CONFIG_KAPI_RUNTIME_CHECKS +#define __SYSCALL_DEFINEx(x, name, ...) \ + __diag_push(); \ + __diag_ignore(GCC, 8, "-Wattribute-alias", \ + "Type aliasing is used to sanitize syscall arguments");\ + asmlinkage long sys##name(__MAP(x,__SC_DECL,__VA_ARGS__)) \ + __attribute__((alias(__stringify(__se_sys##name)))); \ + ALLOW_ERROR_INJECTION(sys##name, ERRNO); \ + static inline long __do_sys##name(__MAP(x,__SC_DECL,__VA_ARGS__));\ + static inline long __do_kapi_sys##name(__MAP(x,__SC_DECL,__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 =3D __do_kapi_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; \ + } \ + __diag_pop(); \ + static inline long __do_kapi_sys##name(__MAP(x,__SC_DECL,__VA_ARGS__))\ + { \ + const struct kernel_api_spec *__spec =3D kapi_get_spec("sys_" #name); \ + if (__spec) { \ + s64 __params[x] =3D { __MAP(x,__SC_CAST_TO_S64,__VA_ARGS__) }; \ + int __ret =3D kapi_validate_syscall_params(__spec, __params, x); \ + if (__ret) return __ret; \ + } \ + long ret =3D __do_sys##name(__MAP(x,__SC_ARGS,__VA_ARGS__)); \ + if (__spec) { \ + kapi_validate_syscall_return(__spec, (s64)ret); \ + } \ + return ret; \ + } \ + static inline long __do_sys##name(__MAP(x,__SC_DECL,__VA_ARGS__)) +#else /* !CONFIG_KAPI_RUNTIME_CHECKS */ #define __SYSCALL_DEFINEx(x, name, ...) \ __diag_push(); \ __diag_ignore(GCC, 8, "-Wattribute-alias", \ @@ -261,6 +298,7 @@ static inline int is_syscall_trace_event(struct trace_e= vent_call *tp_event) } \ __diag_pop(); \ static inline long __do_sys##name(__MAP(x,__SC_DECL,__VA_ARGS__)) +#endif /* CONFIG_KAPI_RUNTIME_CHECKS */ #endif /* __SYSCALL_DEFINEx */ =20 /* For split 64-bit arguments on 32-bit architectures */ diff --git a/init/Kconfig b/init/Kconfig index 836320251219..481a5a73f1ff 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -2108,6 +2108,8 @@ config TRACEPOINTS =20 source "kernel/Kconfig.kexec" =20 +source "kernel/api/Kconfig" + endmenu # General setup =20 source "arch/Kconfig" diff --git a/kernel/Makefile b/kernel/Makefile index c60623448235..c100baacb1f0 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -56,6 +56,7 @@ obj-y +=3D dma/ obj-y +=3D entry/ obj-y +=3D unwind/ obj-$(CONFIG_MODULES) +=3D module/ +obj-$(CONFIG_KAPI_SPEC) +=3D api/ =20 obj-$(CONFIG_KCMP) +=3D kcmp.o obj-$(CONFIG_FREEZER) +=3D freezer.o diff --git a/kernel/api/Kconfig b/kernel/api/Kconfig new file mode 100644 index 000000000000..fde25ec70e13 --- /dev/null +++ b/kernel/api/Kconfig @@ -0,0 +1,35 @@ +# SPDX-License-Identifier: GPL-2.0-only +# +# Kernel API Specification Framework Configuration +# + +config KAPI_SPEC + bool "Kernel API Specification Framework" + help + This option enables the kernel API specification framework, + which provides formal documentation of kernel APIs in both + human and machine-readable formats. + + The framework allows developers to document APIs inline with + their implementation, including parameter specifications, + return values, error conditions, locking requirements, and + execution context constraints. + + When enabled, API specifications can be queried at runtime + and exported in various formats (JSON, XML) through debugfs. + + If unsure, say N. + +config KAPI_RUNTIME_CHECKS + bool "Runtime API specification checks" + depends on KAPI_SPEC + depends on DEBUG_KERNEL + help + Enable runtime validation of API usage against specifications. + This includes checking execution context requirements, parameter + validation, and lock state verification. + + This adds overhead and should only be used for debugging and + development. The checks use WARN_ONCE to report violations. + + If unsure, say N. diff --git a/kernel/api/Makefile b/kernel/api/Makefile new file mode 100644 index 000000000000..4120ded7e5cf --- /dev/null +++ b/kernel/api/Makefile @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: GPL-2.0 +# +# Makefile for the Kernel API Specification Framework +# + +# Core API specification framework +obj-$(CONFIG_KAPI_SPEC) +=3D kernel_api_spec.o \ No newline at end of file diff --git a/kernel/api/kernel_api_spec.c b/kernel/api/kernel_api_spec.c new file mode 100644 index 000000000000..5500bb98c4f9 --- /dev/null +++ b/kernel/api/kernel_api_spec.c @@ -0,0 +1,1155 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * kernel_api_spec.c - Kernel API Specification Framework Implementation + * + * Provides runtime support for kernel API specifications including valida= tion, + * export to various formats, and querying capabilities. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Section where API specifications are stored */ +extern struct kernel_api_spec __start_kapi_specs[]; +extern struct kernel_api_spec __stop_kapi_specs[]; + +/* Dynamic API registration */ +static LIST_HEAD(dynamic_api_specs); +static DEFINE_MUTEX(api_spec_mutex); + +struct dynamic_api_spec { + struct list_head list; + struct kernel_api_spec *spec; +}; + +/** + * kapi_get_spec - Get API specification by name + * @name: Function name to look up + * + * Return: Pointer to API specification or NULL if not found + */ +const struct kernel_api_spec *kapi_get_spec(const char *name) +{ + struct kernel_api_spec *spec; + struct dynamic_api_spec *dyn_spec; + + /* Search static specifications */ + for (spec =3D __start_kapi_specs; spec < __stop_kapi_specs; spec++) { + if (strcmp(spec->name, name) =3D=3D 0) + return spec; + } + + /* Search dynamic specifications */ + mutex_lock(&api_spec_mutex); + list_for_each_entry(dyn_spec, &dynamic_api_specs, list) { + if (strcmp(dyn_spec->spec->name, name) =3D=3D 0) { + mutex_unlock(&api_spec_mutex); + return dyn_spec->spec; + } + } + mutex_unlock(&api_spec_mutex); + + return NULL; +} +EXPORT_SYMBOL_GPL(kapi_get_spec); + +/** + * kapi_register_spec - Register a dynamic API specification + * @spec: API specification to register + * + * Return: 0 on success, negative error code on failure + */ +int kapi_register_spec(struct kernel_api_spec *spec) +{ + struct dynamic_api_spec *dyn_spec; + + if (!spec || !spec->name[0]) + return -EINVAL; + + /* Check if already exists */ + if (kapi_get_spec(spec->name)) + return -EEXIST; + + dyn_spec =3D kzalloc(sizeof(*dyn_spec), GFP_KERNEL); + if (!dyn_spec) + return -ENOMEM; + + dyn_spec->spec =3D spec; + + mutex_lock(&api_spec_mutex); + list_add_tail(&dyn_spec->list, &dynamic_api_specs); + mutex_unlock(&api_spec_mutex); + + return 0; +} +EXPORT_SYMBOL_GPL(kapi_register_spec); + +/** + * kapi_unregister_spec - Unregister a dynamic API specification + * @name: Name of API to unregister + */ +void kapi_unregister_spec(const char *name) +{ + struct dynamic_api_spec *dyn_spec, *tmp; + + mutex_lock(&api_spec_mutex); + list_for_each_entry_safe(dyn_spec, tmp, &dynamic_api_specs, list) { + if (strcmp(dyn_spec->spec->name, name) =3D=3D 0) { + list_del(&dyn_spec->list); + kfree(dyn_spec); + break; + } + } + mutex_unlock(&api_spec_mutex); +} +EXPORT_SYMBOL_GPL(kapi_unregister_spec); + +/** + * param_type_to_string - Convert parameter type to string + * @type: Parameter type + * + * Return: String representation of type + */ +static const char *param_type_to_string(enum kapi_param_type type) +{ + static const char * const type_names[] =3D { + [KAPI_TYPE_VOID] =3D "void", + [KAPI_TYPE_INT] =3D "int", + [KAPI_TYPE_UINT] =3D "uint", + [KAPI_TYPE_PTR] =3D "pointer", + [KAPI_TYPE_STRUCT] =3D "struct", + [KAPI_TYPE_UNION] =3D "union", + [KAPI_TYPE_ENUM] =3D "enum", + [KAPI_TYPE_FUNC_PTR] =3D "function_pointer", + [KAPI_TYPE_ARRAY] =3D "array", + [KAPI_TYPE_FD] =3D "file_descriptor", + [KAPI_TYPE_USER_PTR] =3D "user_pointer", + [KAPI_TYPE_PATH] =3D "pathname", + [KAPI_TYPE_CUSTOM] =3D "custom", + }; + + if (type >=3D ARRAY_SIZE(type_names)) + return "unknown"; + + return type_names[type]; +} + +/** + * lock_type_to_string - Convert lock type to string + * @type: Lock type + * + * Return: String representation of lock type + */ +static const char *lock_type_to_string(enum kapi_lock_type type) +{ + static const char * const lock_names[] =3D { + [KAPI_LOCK_NONE] =3D "none", + [KAPI_LOCK_MUTEX] =3D "mutex", + [KAPI_LOCK_SPINLOCK] =3D "spinlock", + [KAPI_LOCK_RWLOCK] =3D "rwlock", + [KAPI_LOCK_SEQLOCK] =3D "seqlock", + [KAPI_LOCK_RCU] =3D "rcu", + [KAPI_LOCK_SEMAPHORE] =3D "semaphore", + [KAPI_LOCK_CUSTOM] =3D "custom", + }; + + if (type >=3D ARRAY_SIZE(lock_names)) + return "unknown"; + + return lock_names[type]; +} + +/** + * return_check_type_to_string - Convert return check type to string + * @type: Return check type + * + * Return: String representation of return check type + */ +static const char *return_check_type_to_string(enum kapi_return_check_type= type) +{ + static const char * const check_names[] =3D { + [KAPI_RETURN_EXACT] =3D "exact", + [KAPI_RETURN_RANGE] =3D "range", + [KAPI_RETURN_ERROR_CHECK] =3D "error_check", + [KAPI_RETURN_FD] =3D "file_descriptor", + [KAPI_RETURN_CUSTOM] =3D "custom", + }; + + if (type >=3D ARRAY_SIZE(check_names)) + return "unknown"; + + return check_names[type]; +} + +/** + * capability_action_to_string - Convert capability action to string + * @action: Capability action + * + * Return: String representation of capability action + */ +static const char *capability_action_to_string(enum kapi_capability_action= action) +{ + static const char * const action_names[] =3D { + [KAPI_CAP_BYPASS_CHECK] =3D "bypass_check", + [KAPI_CAP_INCREASE_LIMIT] =3D "increase_limit", + [KAPI_CAP_OVERRIDE_RESTRICTION] =3D "override_restriction", + [KAPI_CAP_GRANT_PERMISSION] =3D "grant_permission", + [KAPI_CAP_MODIFY_BEHAVIOR] =3D "modify_behavior", + [KAPI_CAP_ACCESS_RESOURCE] =3D "access_resource", + [KAPI_CAP_PERFORM_OPERATION] =3D "perform_operation", + }; + + if (action >=3D ARRAY_SIZE(action_names)) + return "unknown"; + + return action_names[action]; +} + +/** + * kapi_export_json - Export API specification to JSON format + * @spec: API specification to export + * @buf: Buffer to write JSON to + * @size: Size of buffer + * + * Return: Number of bytes written or negative error + */ +int kapi_export_json(const struct kernel_api_spec *spec, char *buf, size_t= size) +{ + int ret =3D 0; + int i; + + if (!spec || !buf || size =3D=3D 0) + return -EINVAL; + + ret =3D scnprintf(buf, size, + "{\n" + " \"name\": \"%s\",\n" + " \"version\": %u,\n" + " \"description\": \"%s\",\n" + " \"long_description\": \"%s\",\n" + " \"context_flags\": \"0x%x\",\n", + spec->name, + spec->version, + spec->description, + spec->long_description, + spec->context_flags); + + /* Parameters */ + ret +=3D scnprintf(buf + ret, size - ret, + " \"parameters\": [\n"); + + for (i =3D 0; i < spec->param_count && i < KAPI_MAX_PARAMS; i++) { + const struct kapi_param_spec *param =3D &spec->params[i]; + + ret +=3D scnprintf(buf + ret, size - ret, + " {\n" + " \"name\": \"%s\",\n" + " \"type\": \"%s\",\n" + " \"type_class\": \"%s\",\n" + " \"flags\": \"0x%x\",\n" + " \"description\": \"%s\"\n" + " }%s\n", + param->name, + param->type_name, + param_type_to_string(param->type), + param->flags, + param->description, + (i < spec->param_count - 1) ? "," : ""); + } + + ret +=3D scnprintf(buf + ret, size - ret, " ],\n"); + + /* Return value */ + ret +=3D scnprintf(buf + ret, size - ret, + " \"return\": {\n" + " \"type\": \"%s\",\n" + " \"type_class\": \"%s\",\n" + " \"check_type\": \"%s\",\n", + spec->return_spec.type_name, + param_type_to_string(spec->return_spec.type), + return_check_type_to_string(spec->return_spec.check_type)); + + switch (spec->return_spec.check_type) { + case KAPI_RETURN_EXACT: + ret +=3D scnprintf(buf + ret, size - ret, + " \"success_value\": %lld,\n", + spec->return_spec.success_value); + break; + case KAPI_RETURN_RANGE: + ret +=3D scnprintf(buf + ret, size - ret, + " \"success_min\": %lld,\n" + " \"success_max\": %lld,\n", + spec->return_spec.success_min, + spec->return_spec.success_max); + break; + case KAPI_RETURN_ERROR_CHECK: + ret +=3D scnprintf(buf + ret, size - ret, + " \"error_count\": %u,\n", + spec->return_spec.error_count); + break; + default: + break; + } + + ret +=3D scnprintf(buf + ret, size - ret, + " \"description\": \"%s\"\n" + " },\n", + spec->return_spec.description); + + /* Errors */ + ret +=3D scnprintf(buf + ret, size - ret, + " \"errors\": [\n"); + + for (i =3D 0; i < spec->error_count && i < KAPI_MAX_ERRORS; i++) { + const struct kapi_error_spec *error =3D &spec->errors[i]; + + ret +=3D scnprintf(buf + ret, size - ret, + " {\n" + " \"code\": %d,\n" + " \"name\": \"%s\",\n" + " \"condition\": \"%s\",\n" + " \"description\": \"%s\"\n" + " }%s\n", + error->error_code, + error->name, + error->condition, + error->description, + (i < spec->error_count - 1) ? "," : ""); + } + + ret +=3D scnprintf(buf + ret, size - ret, " ],\n"); + + /* Locks */ + ret +=3D scnprintf(buf + ret, size - ret, + " \"locks\": [\n"); + + for (i =3D 0; i < spec->lock_count && i < KAPI_MAX_CONSTRAINTS; i++) { + const struct kapi_lock_spec *lock =3D &spec->locks[i]; + + ret +=3D scnprintf(buf + ret, size - ret, + " {\n" + " \"name\": \"%s\",\n" + " \"type\": \"%s\",\n" + " \"acquired\": %s,\n" + " \"released\": %s,\n" + " \"held_on_entry\": %s,\n" + " \"held_on_exit\": %s,\n" + " \"description\": \"%s\"\n" + " }%s\n", + lock->lock_name, + lock_type_to_string(lock->lock_type), + lock->acquired ? "true" : "false", + lock->released ? "true" : "false", + lock->held_on_entry ? "true" : "false", + lock->held_on_exit ? "true" : "false", + lock->description, + (i < spec->lock_count - 1) ? "," : ""); + } + + ret +=3D scnprintf(buf + ret, size - ret, " ],\n"); + + /* Capabilities */ + ret +=3D scnprintf(buf + ret, size - ret, + " \"capabilities\": [\n"); + + for (i =3D 0; i < spec->capability_count && i < KAPI_MAX_CAPABILITIES; i+= +) { + const struct kapi_capability_spec *cap =3D &spec->capabilities[i]; + + ret +=3D scnprintf(buf + ret, size - ret, + " {\n" + " \"capability\": %d,\n" + " \"name\": \"%s\",\n" + " \"action\": \"%s\",\n" + " \"allows\": \"%s\",\n" + " \"without_cap\": \"%s\",\n" + " \"check_condition\": \"%s\",\n" + " \"priority\": %u", + cap->capability, + cap->cap_name, + capability_action_to_string(cap->action), + cap->allows, + cap->without_cap, + cap->check_condition, + cap->priority); + + if (cap->alternative_count > 0) { + int j; + ret +=3D scnprintf(buf + ret, size - ret, + ",\n \"alternatives\": ["); + for (j =3D 0; j < cap->alternative_count; j++) { + ret +=3D scnprintf(buf + ret, size - ret, + "%d%s", cap->alternative[j], + (j < cap->alternative_count - 1) ? ", " : ""); + } + ret +=3D scnprintf(buf + ret, size - ret, "]"); + } + + ret +=3D scnprintf(buf + ret, size - ret, + "\n }%s\n", + (i < spec->capability_count - 1) ? "," : ""); + } + + ret +=3D scnprintf(buf + ret, size - ret, " ],\n"); + + /* Additional info */ + ret +=3D scnprintf(buf + ret, size - ret, + " \"since_version\": \"%s\",\n" + " \"examples\": \"%s\",\n" + " \"notes\": \"%s\"\n" + "}\n", + spec->since_version, + spec->examples, + spec->notes); + + return ret; +} +EXPORT_SYMBOL_GPL(kapi_export_json); + + +/** + * kapi_print_spec - Print API specification to kernel log + * @spec: API specification to print + */ +void kapi_print_spec(const struct kernel_api_spec *spec) +{ + int i; + + if (!spec) + return; + + pr_info("=3D=3D=3D Kernel API Specification =3D=3D=3D\n"); + pr_info("Name: %s\n", spec->name); + pr_info("Version: %u\n", spec->version); + pr_info("Description: %s\n", spec->description); + + if (spec->long_description[0]) + pr_info("Long Description: %s\n", spec->long_description); + + pr_info("Context Flags: 0x%x\n", spec->context_flags); + + /* Parameters */ + if (spec->param_count > 0) { + pr_info("Parameters:\n"); + for (i =3D 0; i < spec->param_count && i < KAPI_MAX_PARAMS; i++) { + const struct kapi_param_spec *param =3D &spec->params[i]; + pr_info(" [%d] %s: %s (flags: 0x%x)\n", + i, param->name, param->type_name, param->flags); + if (param->description[0]) + pr_info(" Description: %s\n", param->description); + } + } + + /* Return value */ + pr_info("Return: %s\n", spec->return_spec.type_name); + if (spec->return_spec.description[0]) + pr_info(" Description: %s\n", spec->return_spec.description); + + /* Errors */ + if (spec->error_count > 0) { + pr_info("Possible Errors:\n"); + for (i =3D 0; i < spec->error_count && i < KAPI_MAX_ERRORS; i++) { + const struct kapi_error_spec *error =3D &spec->errors[i]; + pr_info(" %s (%d): %s\n", + error->name, error->error_code, error->condition); + } + } + + /* Capabilities */ + if (spec->capability_count > 0) { + pr_info("Capabilities:\n"); + for (i =3D 0; i < spec->capability_count && i < KAPI_MAX_CAPABILITIES; i= ++) { + const struct kapi_capability_spec *cap =3D &spec->capabilities[i]; + pr_info(" %s (%d):\n", cap->cap_name, cap->capability); + pr_info(" Action: %s\n", capability_action_to_string(cap->action)); + pr_info(" Allows: %s\n", cap->allows); + pr_info(" Without: %s\n", cap->without_cap); + if (cap->check_condition[0]) + pr_info(" Condition: %s\n", cap->check_condition); + } + } + + pr_info("=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D\n"); +} +EXPORT_SYMBOL_GPL(kapi_print_spec); + +#ifdef CONFIG_KAPI_RUNTIME_CHECKS + +/** + * kapi_validate_fd - Validate that a file descriptor is valid in current = context + * @fd: File descriptor to validate + * + * Return: true if fd is valid in current process context, false otherwise + */ +static bool kapi_validate_fd(int fd) +{ + struct fd f; + + /* Special case: AT_FDCWD is always valid */ + if (fd =3D=3D AT_FDCWD) + return true; + + /* Check basic range */ + if (fd < 0) + return false; + + /* Check if fd is valid in current process context */ + f =3D fdget(fd); + if (fd_empty(f)) { + return false; + } + + /* fd is valid, release reference */ + fdput(f); + return true; +} + +/** + * kapi_validate_user_ptr - Validate that a user pointer is accessible + * @ptr: User pointer to validate + * @size: Size in bytes to validate + * @write: Whether write access is required + * + * Return: true if user memory is accessible, false otherwise + */ +static bool kapi_validate_user_ptr(const void __user *ptr, size_t size, bo= ol write) +{ + /* NULL is valid if parameter is marked optional */ + if (!ptr) + return false; + + /* Check if the user memory region is accessible */ + if (write) { + return access_ok(ptr, size); + } else { + return access_ok(ptr, size); + } +} + +/** + * kapi_validate_user_ptr_with_params - Validate user pointer with dynamic= size + * @param_spec: Parameter specification + * @ptr: User pointer to validate + * @all_params: Array of all parameter values + * @param_count: Number of parameters + * + * Return: true if user memory is accessible, false otherwise + */ +static bool kapi_validate_user_ptr_with_params(const struct kapi_param_spe= c *param_spec, + const void __user *ptr, + const s64 *all_params, + int param_count) +{ + size_t actual_size; + bool write; + + /* NULL is allowed for optional parameters */ + if (!ptr && (param_spec->flags & KAPI_PARAM_OPTIONAL)) + return true; + + /* Calculate actual size based on related parameter */ + if (param_spec->size_param_idx >=3D 0 && + param_spec->size_param_idx < param_count) { + s64 count =3D all_params[param_spec->size_param_idx]; + + /* Validate count is positive */ + if (count <=3D 0) { + pr_warn("Parameter %s: size determinant is non-positive (%lld)\n", + param_spec->name, count); + return false; + } + + /* Check for multiplication overflow */ + if (param_spec->size_multiplier > 0 && + count > SIZE_MAX / param_spec->size_multiplier) { + pr_warn("Parameter %s: size calculation overflow\n", + param_spec->name); + return false; + } + + actual_size =3D count * param_spec->size_multiplier; + } else { + /* Use fixed size */ + actual_size =3D param_spec->size; + } + + write =3D (param_spec->flags & KAPI_PARAM_OUT) || + (param_spec->flags & KAPI_PARAM_INOUT); + + return kapi_validate_user_ptr(ptr, actual_size, write); +} + +/** + * kapi_validate_path - Validate that a pathname is accessible and within = limits + * @path: User pointer to pathname + * @param_spec: Parameter specification + * + * Return: true if path is valid, false otherwise + */ +static bool kapi_validate_path(const char __user *path, + const struct kapi_param_spec *param_spec) +{ + size_t len; + + /* NULL is allowed for optional parameters */ + if (!path && (param_spec->flags & KAPI_PARAM_OPTIONAL)) + return true; + + if (!path) { + pr_warn("Parameter %s: NULL path not allowed\n", param_spec->name); + return false; + } + + /* Check if the path is accessible */ + if (!access_ok(path, 1)) { + pr_warn("Parameter %s: path pointer %p not accessible\n", + param_spec->name, path); + return false; + } + + /* Use strnlen_user to get the length and validate accessibility */ + len =3D strnlen_user(path, PATH_MAX + 1); + if (len =3D=3D 0) { + pr_warn("Parameter %s: invalid path pointer %p\n", + param_spec->name, path); + return false; + } + + /* Check path length limit */ + if (len > PATH_MAX) { + pr_warn("Parameter %s: path too long (exceeds PATH_MAX)\n", + param_spec->name); + return false; + } + + return true; +} + +/** + * kapi_validate_param - Validate a parameter against its specification + * @param_spec: Parameter specification + * @value: Parameter value to validate + * + * Return: true if valid, false otherwise + */ +bool kapi_validate_param(const struct kapi_param_spec *param_spec, s64 val= ue) +{ + int i; + + /* Special handling for file descriptor type */ + if (param_spec->type =3D=3D KAPI_TYPE_FD) { + if (!kapi_validate_fd((int)value)) { + pr_warn("Parameter %s: invalid file descriptor %lld\n", + param_spec->name, value); + return false; + } + /* Continue with additional constraint checks if needed */ + } + + /* Special handling for user pointer type */ + if (param_spec->type =3D=3D KAPI_TYPE_USER_PTR) { + const void __user *ptr =3D (const void __user *)value; + bool write =3D (param_spec->flags & KAPI_PARAM_OUT) || + (param_spec->flags & KAPI_PARAM_INOUT); + + /* NULL is allowed for optional parameters */ + if (!ptr && (param_spec->flags & KAPI_PARAM_OPTIONAL)) + return true; + + if (!kapi_validate_user_ptr(ptr, param_spec->size, write)) { + pr_warn("Parameter %s: invalid user pointer %p (size: %zu, %s)\n", + param_spec->name, ptr, param_spec->size, + write ? "write" : "read"); + return false; + } + /* Continue with additional constraint checks if needed */ + } + + /* Special handling for path type */ + if (param_spec->type =3D=3D KAPI_TYPE_PATH) { + const char __user *path =3D (const char __user *)value; + + if (!kapi_validate_path(path, param_spec)) { + return false; + } + /* Continue with additional constraint checks if needed */ + } + + switch (param_spec->constraint_type) { + case KAPI_CONSTRAINT_NONE: + return true; + + case KAPI_CONSTRAINT_RANGE: + if (value < param_spec->min_value || value > param_spec->max_value) { + pr_warn("Parameter %s value %lld out of range [%lld, %lld]\n", + param_spec->name, value, + param_spec->min_value, param_spec->max_value); + return false; + } + return true; + + case KAPI_CONSTRAINT_MASK: + if (value & ~param_spec->valid_mask) { + pr_warn("Parameter %s value 0x%llx contains invalid bits (valid mask: 0= x%llx)\n", + param_spec->name, value, param_spec->valid_mask); + return false; + } + return true; + + case KAPI_CONSTRAINT_ENUM: + if (!param_spec->enum_values || param_spec->enum_count =3D=3D 0) + return true; + + for (i =3D 0; i < param_spec->enum_count; i++) { + if (value =3D=3D param_spec->enum_values[i]) + return true; + } + pr_warn("Parameter %s value %lld not in valid enumeration\n", + param_spec->name, value); + return false; + + case KAPI_CONSTRAINT_ALIGNMENT: + if (param_spec->alignment =3D=3D 0) { + pr_warn("Parameter %s: alignment constraint specified but alignment is = 0\n", + param_spec->name); + return false; + } + if (value & (param_spec->alignment - 1)) { + pr_warn("Parameter %s value 0x%llx not aligned to %zu boundary\n", + param_spec->name, value, param_spec->alignment); + return false; + } + return true; + + case KAPI_CONSTRAINT_POWER_OF_TWO: + if (value =3D=3D 0 || (value & (value - 1))) { + pr_warn("Parameter %s value %lld is not a power of two\n", + param_spec->name, value); + return false; + } + return true; + + case KAPI_CONSTRAINT_PAGE_ALIGNED: + if (value & (PAGE_SIZE - 1)) { + pr_warn("Parameter %s value 0x%llx not page-aligned (PAGE_SIZE=3D%ld)\n= ", + param_spec->name, value, PAGE_SIZE); + return false; + } + return true; + + case KAPI_CONSTRAINT_NONZERO: + if (value =3D=3D 0) { + pr_warn("Parameter %s must be non-zero\n", param_spec->name); + return false; + } + return true; + + case KAPI_CONSTRAINT_CUSTOM: + if (param_spec->validate) + return param_spec->validate(value); + return true; + + default: + return true; + } +} +EXPORT_SYMBOL_GPL(kapi_validate_param); + +/** + * kapi_validate_param_with_context - Validate parameter with access to al= l params + * @param_spec: Parameter specification + * @value: Parameter value to validate + * @all_params: Array of all parameter values + * @param_count: Number of parameters + * + * Return: true if valid, false otherwise + */ +bool kapi_validate_param_with_context(const struct kapi_param_spec *param_= spec, + s64 value, const s64 *all_params, int param_count) +{ + /* Special handling for user pointer type with dynamic sizing */ + if (param_spec->type =3D=3D KAPI_TYPE_USER_PTR) { + const void __user *ptr =3D (const void __user *)value; + + /* NULL is allowed for optional parameters */ + if (!ptr && (param_spec->flags & KAPI_PARAM_OPTIONAL)) + return true; + + if (!kapi_validate_user_ptr_with_params(param_spec, ptr, all_params, par= am_count)) { + pr_warn("Parameter %s: invalid user pointer %p\n", + param_spec->name, ptr); + return false; + } + /* Continue with additional constraint checks if needed */ + } + + /* For other types, fall back to regular validation */ + return kapi_validate_param(param_spec, value); +} +EXPORT_SYMBOL_GPL(kapi_validate_param_with_context); + +/** + * kapi_validate_syscall_param - Validate syscall parameter with enforceme= nt + * @spec: API specification + * @param_idx: Parameter index + * @value: Parameter value + * + * Return: -EINVAL if invalid, 0 if valid + */ +int kapi_validate_syscall_param(const struct kernel_api_spec *spec, + int param_idx, s64 value) +{ + const struct kapi_param_spec *param_spec; + + if (!spec || param_idx >=3D spec->param_count) + return 0; + + param_spec =3D &spec->params[param_idx]; + + if (!kapi_validate_param(param_spec, value)) { + if (strncmp(spec->name, "sys_", 4) =3D=3D 0) { + /* For syscalls, we can return EINVAL to userspace */ + return -EINVAL; + } + } + + return 0; +} +EXPORT_SYMBOL_GPL(kapi_validate_syscall_param); + +/** + * kapi_validate_syscall_params - Validate all syscall parameters together + * @spec: API specification + * @params: Array of parameter values + * @param_count: Number of parameters + * + * Return: -EINVAL if any parameter is invalid, 0 if all valid + */ +int kapi_validate_syscall_params(const struct kernel_api_spec *spec, + const s64 *params, int param_count) +{ + int i; + + if (!spec || !params) + return 0; + + /* Validate that we have the expected number of parameters */ + if (param_count !=3D spec->param_count) { + pr_warn("API %s: parameter count mismatch (expected %u, got %d)\n", + spec->name, spec->param_count, param_count); + return -EINVAL; + } + + /* Validate each parameter with context */ + for (i =3D 0; i < spec->param_count && i < KAPI_MAX_PARAMS; i++) { + const struct kapi_param_spec *param_spec =3D &spec->params[i]; + + if (!kapi_validate_param_with_context(param_spec, params[i], params, par= am_count)) { + if (strncmp(spec->name, "sys_", 4) =3D=3D 0) { + /* For syscalls, we can return EINVAL to userspace */ + return -EINVAL; + } + } + } + + return 0; +} +EXPORT_SYMBOL_GPL(kapi_validate_syscall_params); + +/** + * kapi_check_return_success - Check if return value indicates success + * @return_spec: Return specification + * @retval: Return value to check + * + * Returns true if the return value indicates success according to the spe= c. + */ +bool kapi_check_return_success(const struct kapi_return_spec *return_spec,= s64 retval) +{ + u32 i; + + if (!return_spec) + return true; /* No spec means we can't validate */ + + switch (return_spec->check_type) { + case KAPI_RETURN_EXACT: + return retval =3D=3D return_spec->success_value; + + case KAPI_RETURN_RANGE: + return retval >=3D return_spec->success_min && + retval <=3D return_spec->success_max; + + case KAPI_RETURN_ERROR_CHECK: + /* Success if NOT in error list */ + if (return_spec->error_values) { + for (i =3D 0; i < return_spec->error_count; i++) { + if (retval =3D=3D return_spec->error_values[i]) + return false; /* Found in error list */ + } + } + return true; /* Not in error list =3D success */ + + case KAPI_RETURN_FD: + /* File descriptors: >=3D 0 is success, < 0 is error */ + return retval >=3D 0; + + case KAPI_RETURN_CUSTOM: + if (return_spec->is_success) + return return_spec->is_success(retval); + fallthrough; + + default: + return true; /* Unknown check type, assume success */ + } +} +EXPORT_SYMBOL_GPL(kapi_check_return_success); + +/** + * kapi_validate_return_value - Validate that return value matches spec + * @spec: API specification + * @retval: Return value to validate + * + * Return: true if return value is valid according to spec, false otherwis= e. + * + * This function checks: + * 1. If the value indicates success, it must match the success criteria + * 2. If the value indicates error, it must be one of the specified error = codes + */ +bool kapi_validate_return_value(const struct kernel_api_spec *spec, s64 re= tval) +{ + int i; + bool is_success; + + if (!spec) + return true; /* No spec means we can't validate */ + + /* First check if this is a success return */ + is_success =3D kapi_check_return_success(&spec->return_spec, retval); + + if (is_success) { + /* Success case - already validated by kapi_check_return_success */ + return true; + } + + /* Special validation for file descriptor returns */ + if (spec->return_spec.check_type =3D=3D KAPI_RETURN_FD && is_success) { + /* For successful FD returns, validate it's a valid FD */ + if (!kapi_validate_fd((int)retval)) { + pr_warn("API %s returned invalid file descriptor %lld\n", + spec->name, retval); + return false; + } + return true; + } + + /* Error case - check if it's one of the specified errors */ + if (spec->error_count =3D=3D 0) { + /* No errors specified, so any error is potentially valid */ + pr_debug("API %s returned unspecified error %lld\n", + spec->name, retval); + return true; + } + + /* Check if the error is in our list of specified errors */ + for (i =3D 0; i < spec->error_count && i < KAPI_MAX_ERRORS; i++) { + if (retval =3D=3D spec->errors[i].error_code) + return true; + } + + /* Error not in spec */ + pr_warn("API %s returned unspecified error code %lld. Valid errors are:\n= ", + spec->name, retval); + for (i =3D 0; i < spec->error_count && i < KAPI_MAX_ERRORS; i++) { + pr_warn(" %s (%d): %s\n", + spec->errors[i].name, + spec->errors[i].error_code, + spec->errors[i].condition); + } + + return false; +} +EXPORT_SYMBOL_GPL(kapi_validate_return_value); + +/** + * kapi_validate_syscall_return - Validate syscall return value with enfor= cement + * @spec: API specification + * @retval: Return value + * + * Return: 0 if valid, -EINVAL if the return value doesn't match spec + * + * For syscalls, this can help detect kernel bugs where unspecified error + * codes are returned to userspace. + */ +int kapi_validate_syscall_return(const struct kernel_api_spec *spec, s64 r= etval) +{ + if (!spec) + return 0; + + if (!kapi_validate_return_value(spec, retval)) { + /* Log the violation but don't change the return value */ + WARN_ONCE(1, "Syscall %s returned unspecified value %lld\n", + spec->name, retval); + /* Could return -EINVAL here to enforce, but that might break userspace = */ + } + + return 0; +} +EXPORT_SYMBOL_GPL(kapi_validate_syscall_return); + +/** + * kapi_check_context - Check if current context matches API requirements + * @spec: API specification to check against + */ +void kapi_check_context(const struct kernel_api_spec *spec) +{ + u32 ctx =3D spec->context_flags; + bool valid =3D false; + + if (!ctx) + return; + + /* Check if we're in an allowed context */ + if ((ctx & KAPI_CTX_PROCESS) && !in_interrupt()) + valid =3D true; + + if ((ctx & KAPI_CTX_SOFTIRQ) && in_softirq()) + valid =3D true; + + if ((ctx & KAPI_CTX_HARDIRQ) && in_hardirq()) + valid =3D true; + + if ((ctx & KAPI_CTX_NMI) && in_nmi()) + valid =3D true; + + if (!valid) { + WARN_ONCE(1, "API %s called from invalid context\n", spec->name); + } + + /* Check specific requirements */ + if ((ctx & KAPI_CTX_ATOMIC) && preemptible()) { + WARN_ONCE(1, "API %s requires atomic context\n", spec->name); + } + + if ((ctx & KAPI_CTX_SLEEPABLE) && !preemptible()) { + WARN_ONCE(1, "API %s requires sleepable context\n", spec->name); + } +} +EXPORT_SYMBOL_GPL(kapi_check_context); + +#endif /* CONFIG_KAPI_RUNTIME_CHECKS */ + +/* DebugFS interface */ +#ifdef CONFIG_DEBUG_FS + +static struct dentry *kapi_debugfs_root; + +static int kapi_spec_show(struct seq_file *s, void *v) +{ + struct kernel_api_spec *spec =3D s->private; + char *buf; + int ret; + + buf =3D kmalloc(PAGE_SIZE * 4, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + ret =3D kapi_export_json(spec, buf, PAGE_SIZE * 4); + if (ret > 0) + seq_printf(s, "%s", buf); + + kfree(buf); + return 0; +} + +static int kapi_spec_open(struct inode *inode, struct file *file) +{ + return single_open(file, kapi_spec_show, inode->i_private); +} + +static const struct file_operations kapi_spec_fops =3D { + .open =3D kapi_spec_open, + .read =3D seq_read, + .llseek =3D seq_lseek, + .release =3D single_release, +}; + +static int kapi_list_show(struct seq_file *s, void *v) +{ + struct kernel_api_spec *spec; + struct dynamic_api_spec *dyn_spec; + + seq_printf(s, "Kernel API Specifications:\n\n"); + + /* List static specifications */ + seq_printf(s, "Static APIs:\n"); + for (spec =3D __start_kapi_specs; spec < __stop_kapi_specs; spec++) { + seq_printf(s, " %s (v%u): %s\n", + spec->name, spec->version, spec->description); + } + + /* List dynamic specifications */ + seq_printf(s, "\nDynamic APIs:\n"); + mutex_lock(&api_spec_mutex); + list_for_each_entry(dyn_spec, &dynamic_api_specs, list) { + spec =3D dyn_spec->spec; + seq_printf(s, " %s (v%u): %s\n", + spec->name, spec->version, spec->description); + } + mutex_unlock(&api_spec_mutex); + + return 0; +} + +static int kapi_list_open(struct inode *inode, struct file *file) +{ + return single_open(file, kapi_list_show, NULL); +} + +static const struct file_operations kapi_list_fops =3D { + .open =3D kapi_list_open, + .read =3D seq_read, + .llseek =3D seq_lseek, + .release =3D single_release, +}; + +static int __init kapi_debugfs_init(void) +{ + struct kernel_api_spec *spec; + struct dentry *spec_dir; + + kapi_debugfs_root =3D debugfs_create_dir("kapi", NULL); + if (!kapi_debugfs_root) + return -ENOMEM; + + /* Create list file */ + debugfs_create_file("list", 0444, kapi_debugfs_root, NULL, + &kapi_list_fops); + + /* Create directory for specifications */ + spec_dir =3D debugfs_create_dir("specs", kapi_debugfs_root); + + /* Create files for each static specification */ + for (spec =3D __start_kapi_specs; spec < __stop_kapi_specs; spec++) { + debugfs_create_file(spec->name, 0444, spec_dir, spec, + &kapi_spec_fops); + } + + return 0; +} + +late_initcall(kapi_debugfs_init); + +#endif /* CONFIG_DEBUG_FS */ \ No newline at end of file --=20 2.50.1