mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Joel Granados <joel.granados@kernel.org>
To: Kees Cook <kees@kernel.org>
Cc: linux-kernel@vger.kernel.org, linux-fsdevel@vger.kernel.org,
	"Ondrej Mosnáček" <omosnacek@gmail.com>,
	"Andrew Morton" <akpm@linux-foundation.org>,
	"Ryan Roberts" <ryan.roberts@arm.com>,
	"Serge Hallyn" <serge@hallyn.com>,
	"Eric W . Biederman" <ebiederm@xmission.com>,
	"Alexey Gladkov" <legion@kernel.org>,
	"Joel Granados" <joel.granados@kernel.org>
Subject: [PATCH RFC 1/4] sysctl: add a registration context to ctl_table_header
Date: Thu, 24 Sep 2026 16:34:09 +0200	[thread overview]
Message-ID: <20260924-lklm-sysctl-headerctx-template-v1-1-b25e51c66ba7@kernel.org> (raw)
In-Reply-To: <20260924-lklm-sysctl-headerctx-template-v1-0-b25e51c66ba7@kernel.org>

The sysctl context holds a pointer where the actual data (per-namespace
or per-device) is located. When an entry is marked CTL_TABLE_F_CTX_DATA
it is replaced just before calling proc_handler. Add flags to
each ctl_table entry to pass along CTL_TABLE_F_CTX_DATA.

SYSCTL_CTX() builds the context and fails the build unless the instance
and the template point at the same type.

This is a prep commit, no functional changes intended.

Signed-off-by: Joel Granados <joel.granados@kernel.org>
---
 fs/proc/proc_sysctl.c  | 29 ++++++++++++++++++++++----
 include/linux/sysctl.h | 55 ++++++++++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 78 insertions(+), 6 deletions(-)

diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c
index 04a382178c657b5af201a838fa15703d9eea9c7b..fe32337892f9badc897a29e9176e66790003fb05 100644
--- a/fs/proc/proc_sysctl.c
+++ b/fs/proc/proc_sysctl.c
@@ -1143,10 +1143,18 @@ static int sysctl_check_table_array(const char *path, const struct ctl_table *ta
 static int sysctl_check_table(const char *path, struct ctl_table_header *header)
 {
 	const struct ctl_table *entry;
+	u8 flagged = 0;
 	int err = 0;
 	list_for_each_table_entry(entry, header) {
 		if (!entry->procname)
 			err |= sysctl_err(path, entry, "procname is null");
+		if (entry->flags & CTL_TABLE_F_CTX_DATA) {
+			if (!entry->data)
+				err |= sysctl_err(path, entry, "No data to resolve");
+			if (!header->ctx.inst || !header->ctx.tmpl)
+				err |= sysctl_err(path, entry, "No context to resolve against");
+		}
+		flagged |= entry->flags & CTL_TABLE_F_CTX;
 		if ((entry->proc_handler == proc_dostring) ||
 		    (entry->proc_handler == proc_dobool) ||
 		    (entry->proc_handler == proc_dointvec) ||
@@ -1173,6 +1181,12 @@ static int sysctl_check_table(const char *path, struct ctl_table_header *header)
 			err |= sysctl_err(path, entry, "bogus .mode 0%o",
 				entry->mode);
 	}
+	/* A context nobody resolves against is a forgotten flag. */
+	if (!flagged && (header->ctx.inst || header->ctx.tmpl)) {
+		pr_err("sysctl table check failed: %s context given but no entry is flagged\n",
+		       path);
+		err = -EINVAL;
+	}
 	return err;
 }
 
@@ -1324,7 +1338,7 @@ static struct ctl_dir *sysctl_mkdir_p(struct ctl_dir *dir, const char *path)
 }
 
 /**
- * __register_sysctl_table - register a leaf sysctl table
+ * __register_sysctl_table_ctx - register a leaf sysctl table
  * @set: Sysctl tree to register on
  * @path: The path to the directory the sysctl table is in.
  *
@@ -1333,6 +1347,9 @@ static struct ctl_dir *sysctl_mkdir_p(struct ctl_dir *dir, const char *path)
  *         be a global or dynamically allocated by the caller and free'd later
  *         after sysctl unregistration.
  * @table_size : The number of elements in table
+ * @ctx: instances that entries flagged CTL_TABLE_F_CTX_* resolve against, see
+ *       struct sysctl_context.  Copied, so it may be on stack.  %NULL when no
+ *       entry is flagged.
  *
  * Register a sysctl table hierarchy. @table should be a filled in ctl_table
  * array.
@@ -1343,6 +1360,7 @@ static struct ctl_dir *sysctl_mkdir_p(struct ctl_dir *dir, const char *path)
  * data     - a pointer to data for use by proc_handler
  * maxlen   - the maximum size in bytes of the data
  * mode     - the file permissions for the /proc/sys file
+ * flags    - CTL_TABLE_F_* bits naming members to resolve against @ctx
  * type     - Defines the target type (described in struct definition)
  * proc_handler - the text handler routine (described below)
  *
@@ -1366,9 +1384,10 @@ static struct ctl_dir *sysctl_mkdir_p(struct ctl_dir *dir, const char *path)
  * This routine returns %NULL on a failure to register, and a pointer
  * to the table header on success.
  */
-struct ctl_table_header *__register_sysctl_table(
+struct ctl_table_header *__register_sysctl_table_ctx(
 	struct ctl_table_set *set,
-	const char *path, const struct ctl_table *table, size_t table_size)
+	const char *path, const struct ctl_table *table, size_t table_size,
+	const struct sysctl_context *ctx)
 {
 	struct ctl_table_root *root = set->dir.header.root;
 	struct ctl_table_header *header;
@@ -1382,6 +1401,8 @@ struct ctl_table_header *__register_sysctl_table(
 
 	node = (struct ctl_node *)(header + 1);
 	init_header(header, root, set, node, table, table_size);
+	if (ctx)
+		header->ctx = *ctx;
 	if (sysctl_check_table(path, header))
 		goto fail;
 
@@ -1427,7 +1448,7 @@ struct ctl_table_header *__register_sysctl_table(
  * Register a sysctl table. @table should be a filled in ctl_table
  * array. A completely 0 filled entry terminates the table.
  *
- * See __register_sysctl_table for more details.
+ * See __register_sysctl_table_ctx for more details.
  */
 struct ctl_table_header *register_sysctl_sz(const char *path, const struct ctl_table *table,
 					    size_t table_size)
diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h
index e5d7226ab6f5af34a33829883ad5d1b405e19c86..b2c57c530bdc9b3542375b761fec3e02ab38bc7f 100644
--- a/include/linux/sysctl.h
+++ b/include/linux/sysctl.h
@@ -22,6 +22,8 @@
 #ifndef _LINUX_SYSCTL_H
 #define _LINUX_SYSCTL_H
 
+#include <linux/bits.h>
+#include <linux/build_bug.h>
 #include <linux/list.h>
 #include <linux/rcupdate.h>
 #include <linux/wait.h>
@@ -224,12 +226,50 @@ struct ctl_table {
 	void *data;
 	int maxlen;
 	umode_t mode;
+	u8 flags;			/* CTL_TABLE_F_* */
 	proc_handler *proc_handler;	/* Callback for text formatting */
 	struct ctl_table_poll *poll;
 	void *extra1;
 	void *extra2;
 } __randomize_layout;
 
+/*
+ * ctl_table::flags.  Resolve the corresponding member against the
+ * registration context instead of using it as it stands.
+ */
+#define CTL_TABLE_F_CTX_DATA	BIT(0)
+#define CTL_TABLE_F_CTX		CTL_TABLE_F_CTX_DATA
+
+/**
+ * struct sysctl_context - ctl_table specific context
+ * @inst: entry location
+ * @tmpl: struct template (used to calculate offset into @inst)
+ *
+ * @inst/@tmpl pair is used to overlay the ctl_table entry before calling
+ * proc_handler. This is relevant when struct members (like ->data) are
+ * somewhere different than the const static ctl_table array (think
+ * namespaces).  Build it with SYSCTL_CTX() so the compiler checks that
+ * both point at the same type.
+ */
+struct sysctl_context {
+	void *inst;
+	const void *tmpl;
+};
+
+/**
+ * SYSCTL_CTX - build a struct sysctl_context
+ * @_inst: the instance this registration describes
+ * @_tmpl: the instance the table's data members name
+ *
+ * Fails to build unless @_inst and @_tmpl point at the same type.
+ */
+#define SYSCTL_CTX(_inst, _tmpl)					\
+	((struct sysctl_context){					\
+		.inst = (_inst) +					\
+			BUILD_BUG_ON_ZERO(!__same_type(*(_inst), *(_tmpl))), \
+		.tmpl = (_tmpl),					\
+	})
+
 struct ctl_node {
 	struct rb_node node;
 	struct ctl_table_header *header;
@@ -244,6 +284,7 @@ struct ctl_node {
  *         something is removed from inodes
  * @nreg: When nreg drops to 0 the ctl_table_header will be unregistered.
  * @rcu: Delays the freeing of the inode. Introduced with "unfuck proc_sysctl ->d_compare()"
+ * @ctx: instances given to __register_sysctl_table_ctx(), see struct sysctl_context
  *
  * @type: Enumeration to differentiate between ctl target types:
  * type.SYSCTL_TABLE_TYPE_DEFAULT: ctl target with no special considerations
@@ -268,6 +309,7 @@ struct ctl_table_header {
 	struct ctl_dir *parent;
 	struct ctl_node *node;
 	struct hlist_head inodes; /* head for proc_inode->sysctl_inodes */
+	struct sysctl_context ctx;
 	enum {
 		SYSCTL_TABLE_TYPE_DEFAULT,
 		SYSCTL_TABLE_TYPE_PERMANENTLY_EMPTY,
@@ -305,9 +347,18 @@ extern void setup_sysctl_set(struct ctl_table_set *p,
 	int (*is_seen)(struct ctl_table_set *));
 extern void retire_sysctl_set(struct ctl_table_set *set);
 
-struct ctl_table_header *__register_sysctl_table(
+struct ctl_table_header *__register_sysctl_table_ctx(
 	struct ctl_table_set *set,
-	const char *path, const struct ctl_table *table, size_t table_size);
+	const char *path, const struct ctl_table *table, size_t table_size,
+	const struct sysctl_context *ctx);
+
+static inline struct ctl_table_header *__register_sysctl_table(
+	struct ctl_table_set *set,
+	const char *path, const struct ctl_table *table, size_t table_size)
+{
+	return __register_sysctl_table_ctx(set, path, table, table_size, NULL);
+}
+
 struct ctl_table_header *register_sysctl_sz(const char *path, const struct ctl_table *table,
 					    size_t table_size);
 void unregister_sysctl_table(struct ctl_table_header * table);

-- 
2.50.1



  reply	other threads:[~2026-09-24 14:34 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-24 14:34 [PATCH RFC 0/4] sysctl: add a registration context to share ctl_table arrays Joel Granados
2026-09-24 14:34 ` Joel Granados [this message]
2026-09-24 14:34 ` [PATCH RFC 2/4] sysctl: Apply sysctl context when flag is active Joel Granados
2026-09-24 18:41   ` Alexey Gladkov
2026-09-24 14:34 ` [PATCH RFC 3/4] ipc: Use sysctl context to register ipc namespaces Joel Granados
2026-09-24 14:34 ` [PATCH RFC 4/4] mqueue: Use sysctl context to register mq_sysctls Joel Granados

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260924-lklm-sysctl-headerctx-template-v1-1-b25e51c66ba7@kernel.org \
    --to=joel.granados@kernel.org \
    --cc=akpm@linux-foundation.org \
    --cc=ebiederm@xmission.com \
    --cc=kees@kernel.org \
    --cc=legion@kernel.org \
    --cc=linux-fsdevel@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=omosnacek@gmail.com \
    --cc=ryan.roberts@arm.com \
    --cc=serge@hallyn.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®