lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <139638bcf35a5306019d9399a0127f946d037f4c.1770496163.git.wen.yang@linux.dev>
Date: Sun,  8 Feb 2026 04:35:16 +0800
From: wen.yang@...ux.dev
To: Joel Granados <joel.granados@...nel.org>
Cc: linux-kernel@...r.kernel.org,
	Wen Yang <wen.yang@...ux.dev>
Subject: [RFC PATCH v2 1/2] sysctl: introduce SYSCTL_ENTRY() helper macro

From: Wen Yang <wen.yang@...ux.dev>

Add SYSCTL_ENTRY() macro to simplify struct ctl_table initialization.
This macro provides automatic type detection, handler selection, and
sensible defaults, reducing boilerplate and potential errors.

Based on discussion and suggestions from:
https://sysctl-dev-rtd.readthedocs.io/en/latest/notes/ctltable_entry_macro.html#table-entry-macro
https://lore.kernel.org/all/psot4oeauxi3yyj2w4ajm3tfgtcsvao4rhv5sgd5s6ymmjgojk@p3vrj3qluban/

Features:
- Automatic type detection and handler selection via _Generic()
   - Supports int, unsigned int, long, unsigned long
   - Auto-selects range-checking handlers when min/max provided

- Flexible calling conventions (1-7 arguments):
   - SYSCTL_TBL_ENTRY(var) -> readonly, auto-handler
   - SYSCTL_TBL_ENTRY(name, var) -> custom name
   - SYSCTL_TBL_ENTRY(name, var, mode) -> custom mode
   - SYSCTL_TBL_ENTRY(name, var, mode, handler) -> custom handler
   - SYSCTL_TBL_ENTRY(name, var, mode, min, max) -> with range
   - SYSCTL_TBL_ENTRY(name, var, mode, handler, min, max) -> full control
   - SYSCTL_TBL_ENTRY(name, var, mode, handler, min, max, maxlen) -> explicit maxlen

- Smart defaults:
   - Auto address-of: SYSCTL_ENTRY(my_var) -> .data = &my_var
   - Auto maxlen: uses sizeof(var) when not specified
   - SYSCTL_NULL marker for entries without data

- Compile-time validation:
   - NAME must be string literal
   - MODE, HANDLER validated via type compatibility checks
   - VAR must be lvalue

Example usage:

  static int my_int = 256;

  /* Before */
  {
      .procname     = "my_int",
      .data         = &my_int,
      .maxlen       = sizeof(int),
      .mode         = 0644,
      .proc_handler = proc_dointvec,
  }

  /* After */
  SYSCTL_TBL_ENTRY("my_int", my_int, 0644)

No functional change intended.

Suggested-by: Joel Granados <joel.granados@...nel.org>
Signed-off-by: Wen Yang <wen.yang@...ux.dev>
---
 include/linux/sysctl.h | 131 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 131 insertions(+)

diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h
index 2886fbceb5d6..3d10e2e9d6dc 100644
--- a/include/linux/sysctl.h
+++ b/include/linux/sysctl.h
@@ -175,6 +175,137 @@ struct ctl_table {
 	void *extra2;
 } __randomize_layout;
 
+/* Special marker type to represent NULL data in sysctl entries */
+struct __sysctl_null_type { char __dummy; };
+extern const struct __sysctl_null_type __sysctl_null_marker;
+
+/* Use SYSCTL_NULL to indicate a sysctl entry without associated data */
+#define SYSCTL_NULL (__sysctl_null_marker)
+
+/* Validate NAME is a string literal and return it (fails on non-literals) */
+#define __SYSCTL_PROCNAME(NAME) \
+	("" NAME "")
+
+/* Generate data pointer: NULL for SYSCTL_NULL, &VAR for actual variables */
+#define __SYSCTL_DATA(VAR) \
+	_Generic((VAR), \
+		struct __sysctl_null_type : ((void *)NULL), \
+		default : \
+			((void *)&(VAR)) \
+		)
+
+/* Compute maxlen for NULL entries: use explicit MAXLEN if >0, else 0 */
+#define __SYSCTL_MAXLEN_NULL(MAXLEN) \
+	((MAXLEN) > 0 ? (size_t)(MAXLEN) : (size_t)0)
+
+/* Compute maxlen: use explicit MAXLEN if >0, else sizeof(VAR) */
+#define __SYSCTL_MAXLEN_VAR(VAR, MAXLEN) \
+	((MAXLEN) >= 0 ? (size_t)(MAXLEN) : (size_t)sizeof(VAR))
+
+/* Compute maxlen: auto-detect based on entry type (NULL vs variable) */
+#define __SYSCTL_MAXLEN(VAR, MAXLEN) \
+	_Generic((VAR), \
+		struct __sysctl_null_type : __SYSCTL_MAXLEN_NULL(MAXLEN), \
+		default : \
+			  __SYSCTL_MAXLEN_VAR(VAR, MAXLEN) \
+		)
+
+/* Validate MODE is compatible with umode_t and return it */
+#define __SYSCTL_MODE(MODE) \
+	(0 ? (umode_t)0 : (MODE))
+
+/* Validate HANDLER matches proc_handler signature and return it */
+#define __SYSCTL_PROC_HANDLER(HANDLER) \
+	(0 ? (proc_handler *)0 : (HANDLER))
+
+/* Auto-select appropriate proc_handler based on VAR's type */
+#define __SYSCTL_AUTO_HANDLER(VAR) \
+	_Generic((VAR), \
+		int : (proc_handler *)proc_dointvec, \
+		unsigned int : (proc_handler *)proc_douintvec, \
+		long : (proc_handler *)proc_dointvec, \
+		unsigned long : (proc_handler *)proc_douintvec, \
+		default : \
+			(proc_handler *)NULL \
+		)
+
+/* Auto-select range-checking proc_handler based on VAR's type */
+#define __SYSCTL_AUTO_HANDLER_MINMAX(VAR) \
+	_Generic((VAR), \
+		int : (proc_handler *)proc_dointvec_minmax, \
+		unsigned int : (proc_handler *)proc_douintvec_minmax, \
+		long : (proc_handler *)proc_doulongvec_minmax, \
+		unsigned long : (proc_handler *)proc_doulongvec_minmax, \
+		default : \
+			  (proc_handler *)NULL \
+		)
+
+/* Validate PTR is pointer-compatible and return it as void* */
+#define __SYSCTL_EXTRA(PTR) \
+	(0 ? (void *)0 : (PTR))
+
+/* Initialize a ctl_table entry with all parameters */
+#define __SYSCTL_TBL_ENTRY(NAME, VAR, MODE, HANDLER, MIN, MAX, MAXLEN) \
+	{ \
+		.procname     = __SYSCTL_PROCNAME(NAME), \
+		.data         = __SYSCTL_DATA(VAR), \
+		.maxlen       = __SYSCTL_MAXLEN(VAR, MAXLEN), \
+		.mode         = __SYSCTL_MODE(MODE), \
+		.proc_handler = __SYSCTL_PROC_HANDLER(HANDLER), \
+		.poll         = NULL, \
+		.extra1       = __SYSCTL_EXTRA(MIN), \
+		.extra2       = __SYSCTL_EXTRA(MAX), \
+	}
+
+/* Count the number of variadic arguments (supports 1-7 arguments) */
+#define __SYSCTL_NARG(...) \
+	__SYSCTL_NARG_(__VA_ARGS__, 7, 6, 5, 4, 3, 2, 1, 0)
+
+/* Helper for __SYSCTL_NARG - maps arguments to their count */
+#define __SYSCTL_NARG_(_1, _2, _3, _4, _5, _6, _7, N, ...) N
+
+/* Concatenate two tokens */
+#define __SYSCTL_CONCAT(A, B) A##B
+
+/* Select macro variant based on argument count */
+#define __SYSCTL_SELECT(NAME, N) __SYSCTL_CONCAT(NAME, N)
+
+/* SYSCTL_TBL_ENTRY(var) - use variable name as procname, readonly, auto handler */
+#define __SYSCTL_TBL_ENTRY_1(VAR) \
+	__SYSCTL_TBL_ENTRY(#VAR, VAR, 0444, \
+			   __SYSCTL_AUTO_HANDLER(VAR), NULL, NULL, -1)
+
+/* SYSCTL_TBL_ENTRY(name, var) - custom name, readonly, auto handler */
+#define __SYSCTL_TBL_ENTRY_2(NAME, VAR) \
+	__SYSCTL_TBL_ENTRY(NAME, VAR, 0444, \
+			   __SYSCTL_AUTO_HANDLER(VAR), NULL, NULL, -1)
+
+/* SYSCTL_TBL_ENTRY(name, var, mode) - custom name and mode, auto handler */
+#define __SYSCTL_TBL_ENTRY_3(NAME, VAR, MODE) \
+	__SYSCTL_TBL_ENTRY(NAME, VAR, MODE, \
+			   __SYSCTL_AUTO_HANDLER(VAR), NULL, NULL, -1)
+
+/* SYSCTL_TBL_ENTRY(name, var, mode, handler) - custom handler */
+#define __SYSCTL_TBL_ENTRY_4(NAME, VAR, MODE, HANDLER) \
+	__SYSCTL_TBL_ENTRY(NAME, VAR, MODE, HANDLER, NULL, NULL, -1)
+
+/* SYSCTL_TBL_ENTRY(name, var, mode, min, max) - auto range-checking handler */
+#define __SYSCTL_TBL_ENTRY_5(NAME, VAR, MODE, MIN, MAX) \
+	__SYSCTL_TBL_ENTRY(NAME, VAR, MODE, \
+			   __SYSCTL_AUTO_HANDLER_MINMAX(VAR), MIN, MAX, -1)
+
+/* SYSCTL_TBL_ENTRY(name, var, mode, handler, min, max) - custom handler with range */
+#define __SYSCTL_TBL_ENTRY_6(NAME, VAR, MODE, HANDLER, MIN, MAX) \
+	__SYSCTL_TBL_ENTRY(NAME, VAR, MODE, HANDLER, MIN, MAX, -1)
+
+/* SYSCTL_TBL_ENTRY(name, var, mode, handler, min, max, maxlen) - full control */
+#define __SYSCTL_TBL_ENTRY_7(NAME, VAR, MODE, HANDLER, MIN, MAX, MAXLEN) \
+	__SYSCTL_TBL_ENTRY(NAME, VAR, MODE, HANDLER, MIN, MAX, MAXLEN)
+
+/* Define a sysctl table entry with automatic type detection and parameter handling */
+#define SYSCTL_TBL_ENTRY(...) \
+	__SYSCTL_SELECT(__SYSCTL_TBL_ENTRY_, __SYSCTL_NARG(__VA_ARGS__))(__VA_ARGS__)
+
 struct ctl_node {
 	struct rb_node node;
 	struct ctl_table_header *header;
-- 
2.25.1


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ