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
next prev parent 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®