[PATCH 06/11] moduleparam: Add seq_buf-based .get callback alongside .get_str
Kees Cook
kees at kernel.org
Thu May 21 06:33:19 PDT 2026
Add a new struct kernel_param_ops::get callback whose signature
takes a struct seq_buf instead of a raw char buffer:
int (*get)(struct seq_buf *sb, const struct kernel_param *kp);
The previously-legacy .get field is now .get_str (char *buffer);
.get is the new seq_buf-aware form. param_attr_show() prefers .get
when set, otherwise falls back to .get_str. WARN_ON_ONCE() if both
are set. Return contract for .get:
< 0 : errno propagated to userspace; seq_buf contents discarded
= 0 : success; length derived from seq_buf_used()
> 0 : forbidden; the dispatcher WARN_ON_ONCE()s and treats as 0
The default policy on seq_buf_has_overflowed() is silent truncation,
matching scnprintf()/sysfs_emit() behaviour. Callbacks that want a
specific overflow errno can check seq_buf_has_overflowed() and
return their preferred error.
No callbacks use .get yet; the legacy path is still the only one in use
after this commit. A subsequent commit teaches DEFINE_KERNEL_PARAM_OPS
to route initializers by type.
Signed-off-by: Kees Cook <kees at kernel.org>
---
include/linux/moduleparam.h | 13 ++++++++++++-
kernel/params.c | 26 ++++++++++++++++++++++++--
2 files changed, 36 insertions(+), 3 deletions(-)
diff --git a/include/linux/moduleparam.h b/include/linux/moduleparam.h
index f5f4148e2504..c52120f6ac28 100644
--- a/include/linux/moduleparam.h
+++ b/include/linux/moduleparam.h
@@ -7,6 +7,7 @@
#include <linux/build_bug.h>
#include <linux/compiler.h>
#include <linux/init.h>
+#include <linux/seq_buf.h>
#include <linux/stringify.h>
#include <linux/sysfs.h>
#include <linux/types.h>
@@ -62,7 +63,17 @@ struct kernel_param_ops {
unsigned int flags;
/* Returns 0, or -errno. arg is in kp->arg. */
int (*set)(const char *val, const struct kernel_param *kp);
- /* Returns length written or -errno. Buffer is 4k (ie. be short!) */
+ /*
+ * Format the parameter's value into @s. Return 0 on success
+ * (length derived from seq_buf_used()) or -errno on error.
+ * Exactly one of .get and .get_str should be set; the dispatcher
+ * WARNs and prefers .get if both are.
+ */
+ int (*get)(struct seq_buf *s, const struct kernel_param *kp);
+ /*
+ * Returns length written or -errno. Buffer is 4k (ie. be short!).
+ * Deprecated: callbacks should implement .get instead.
+ */
int (*get_str)(char *buffer, const struct kernel_param *kp);
/* Optional function to free kp->arg when module unloaded. */
void (*free)(void *arg);
diff --git a/kernel/params.c b/kernel/params.c
index 6852caea1785..4eda2d23ddf2 100644
--- a/kernel/params.c
+++ b/kernel/params.c
@@ -553,12 +553,34 @@ static ssize_t param_attr_show(const struct module_attribute *mattr,
{
int count;
const struct param_attribute *attribute = to_param_attr(mattr);
+ const struct kernel_param_ops *ops = attribute->param->ops;
- if (!attribute->param->ops->get_str)
+ if (!ops->get && !ops->get_str)
return -EPERM;
+ WARN_ON_ONCE(ops->get && ops->get_str);
+
kernel_param_lock(mk->mod);
- count = attribute->param->ops->get_str(buf, attribute->param);
+ if (ops->get) {
+ struct seq_buf s;
+
+ seq_buf_init(&s, buf, PAGE_SIZE);
+ count = ops->get(&s, attribute->param);
+ if (count >= 0) {
+ WARN_ON_ONCE(count > 0);
+ count = seq_buf_used(&s);
+ /* Make sure string is terminated. */
+ seq_buf_str(&s);
+ /*
+ * If overflowed, reduce count by 1 for trailing
+ * NUL byte.
+ */
+ if (seq_buf_has_overflowed(&s))
+ count--;
+ }
+ } else {
+ count = ops->get_str(buf, attribute->param);
+ }
kernel_param_unlock(mk->mod);
return count;
}
--
2.34.1
More information about the linux-um
mailing list