Linux Serial subsystem development
 help / color / mirror / Atom feed
From: Kees Cook <kees@kernel.org>
To: Luis Chamberlain <mcgrof@kernel.org>
Cc: "Kees Cook" <kees@kernel.org>,
	"Pengpeng Hou" <pengpeng@iscas.ac.cn>,
	"Petr Pavlu" <petr.pavlu@suse.com>,
	"Richard Weinberger" <richard@nod.at>,
	"Anton Ivanov" <anton.ivanov@cambridgegreys.com>,
	"Johannes Berg" <johannes@sipsolutions.net>,
	"Rafael J. Wysocki" <rafael@kernel.org>,
	"Len Brown" <lenb@kernel.org>,
	"Corey Minyard" <corey@minyard.net>,
	"Gabriel Somlo" <somlo@cmu.edu>,
	"Michael S. Tsirkin" <mst@redhat.com>,
	"Jani Nikula" <jani.nikula@linux.intel.com>,
	"Joonas Lahtinen" <joonas.lahtinen@linux.intel.com>,
	"Rodrigo Vivi" <rodrigo.vivi@intel.com>,
	"Tvrtko Ursulin" <tursulin@ursulin.net>,
	"David Airlie" <airlied@gmail.com>,
	"Simona Vetter" <simona@ffwll.ch>,
	"Bart Van Assche" <bvanassche@acm.org>,
	"Jason Gunthorpe" <jgg@ziepe.ca>,
	"Leon Romanovsky" <leon@kernel.org>,
	"Laurent Pinchart" <laurent.pinchart@ideasonboard.com>,
	"Hans de Goede" <hansg@kernel.org>,
	"Mauro Carvalho Chehab" <mchehab@kernel.org>,
	"Bjorn Helgaas" <bhelgaas@google.com>,
	"Hannes Reinecke" <hare@suse.de>,
	"James E.J. Bottomley" <James.Bottomley@HansenPartnership.com>,
	"Martin K. Petersen" <martin.petersen@oracle.com>,
	"Daniel Lezcano" <daniel.lezcano@kernel.org>,
	"Zhang Rui" <rui.zhang@intel.com>,
	"Lukasz Luba" <lukasz.luba@arm.com>,
	"Greg Kroah-Hartman" <gregkh@linuxfoundation.org>,
	"Jiri Slaby" <jirislaby@kernel.org>,
	"Alan Stern" <stern@rowland.harvard.edu>,
	"Jason Wang" <jasowang@redhat.com>,
	"Xuan Zhuo" <xuanzhuo@linux.alibaba.com>,
	"Eugenio Pérez" <eperezma@redhat.com>,
	"Jason Baron" <jbaron@akamai.com>,
	"Jim Cromie" <jim.cromie@gmail.com>,
	"Tiwei Bie" <tiwei.btw@antgroup.com>,
	"Benjamin Berg" <benjamin.berg@intel.com>,
	"Ilpo Järvinen" <ilpo.jarvinen@linux.intel.com>,
	"David E. Box" <david.e.box@linux.intel.com>,
	"Maciej W. Rozycki" <macro@orcam.me.uk>,
	"Srinivas Pandruvada" <srinivas.pandruvada@linux.intel.com>,
	"Peter Zijlstra" <peterz@infradead.org>,
	"Heiko Carstens" <hca@linux.ibm.com>,
	"Vasily Gorbik" <gor@linux.ibm.com>,
	"Sean Christopherson" <seanjc@google.com>,
	"Paolo Bonzini" <pbonzini@redhat.com>,
	"Thomas Gleixner" <tglx@kernel.org>,
	"Ingo Molnar" <mingo@redhat.com>,
	"Borislav Petkov" <bp@alien8.de>,
	"Dave Hansen" <dave.hansen@linux.intel.com>,
	x86@kernel.org, "H. Peter Anvin" <hpa@zytor.com>,
	"Vinod Koul" <vkoul@kernel.org>, "Frank Li" <Frank.Li@kernel.org>,
	"Daniel Gomez" <da.gomez@kernel.org>,
	"Sami Tolvanen" <samitolvanen@google.com>,
	"Aaron Tomlin" <atomlin@atomlin.com>,
	"Alexander Potapenko" <glider@google.com>,
	"Marco Elver" <elver@google.com>,
	"Dmitry Vyukov" <dvyukov@google.com>,
	"Andrew Morton" <akpm@linux-foundation.org>,
	"John Johansen" <john.johansen@canonical.com>,
	"Paul Moore" <paul@paul-moore.com>,
	"James Morris" <jmorris@namei.org>,
	"Serge E. Hallyn" <serge@hallyn.com>,
	"Andy Shevchenko" <andriy.shevchenko@linux.intel.com>,
	"Georgia Garcia" <georgia.garcia@canonical.com>,
	kvm@vger.kernel.org, dmaengine@vger.kernel.org,
	linux-modules@vger.kernel.org, kasan-dev@googlegroups.com,
	linux-mm@kvack.org, apparmor@lists.ubuntu.com,
	linux-security-module@vger.kernel.org,
	linux-um@lists.infradead.org, linux-acpi@vger.kernel.org,
	openipmi-developer@lists.sourceforge.net, qemu-devel@nongnu.org,
	intel-gfx@lists.freedesktop.org, dri-devel@lists.freedesktop.org,
	linux-rdma@vger.kernel.org, linux-media@vger.kernel.org,
	linux-pci@vger.kernel.org, linux-scsi@vger.kernel.org,
	linux-pm@vger.kernel.org, linuxppc-dev@lists.ozlabs.org,
	linux-serial@vger.kernel.org, linux-usb@vger.kernel.org,
	usb-storage@lists.one-eyed-alien.net,
	virtualization@lists.linux.dev, linux-kernel@vger.kernel.org,
	linux-arch@vger.kernel.org, netdev@vger.kernel.org,
	linux-fsdevel@vger.kernel.org, linux-hardening@vger.kernel.org
Subject: [PATCH 08/11] params: Convert generic kernel_param_ops .get helpers to seq_buf
Date: Thu, 21 May 2026 06:33:21 -0700	[thread overview]
Message-ID: <20260521133326.2465264-8-kees@kernel.org> (raw)
In-Reply-To: <20260521133315.work.845-kees@kernel.org>

Convert the generic struct kernel_param_ops .get helpers in
kernel/params.c directly to the seq_buf signature, drop their legacy
"char *" form, and refresh prototypes in <linux/moduleparam.h>:

  param_get_byte/short/ushort/int/uint/long/ulong/ullong/hexint
  param_get_charp/bool/invbool/string
  param_array_get

The STANDARD_PARAM_DEF() macro expands to a seq_buf body for every
numeric helper. param_array_get() now writes element output directly
into the parent seq_buf when the element ops provide .get; it only
allocates the per-call PAGE_SIZE bounce buffer when the element ops
still use the legacy .get_str path. The common "rewrite the prior
element's trailing newline as a comma" step lives outside both
branches so the two paths share it.

The non-core changes in this commit (arch/x86/kvm, mm/kfence,
drivers/dma/dmatest, security/apparmor) are the small set of callers that
directly invoke one of the converted generic helpers from their own .get
callback (e.g. an apparmor wrapper that adds a capability check and then
delegates to param_get_bool()). Because the helpers' signature changes
here, these wrappers must move in lockstep. Each of them is updated
to take "struct seq_buf *" and pass it through; param_get_debug() in
apparmor also pulls aa_print_debug_params() (and its val_mask_to_str()
helper, in security/apparmor/lib.c) over to seq_buf, since that is the
only consumer. No other behavioural change is intended.

Custom .get callbacks that do not delegate to a generic helper (and
therefore still match the .get_str signature) are routed automatically
to the .get_str field by the DEFINE_KERNEL_PARAM_OPS _Generic dispatcher
and are deliberately left alone here, to be changed separately within
their respective subsystems.

Signed-off-by: Kees Cook <kees@kernel.org>
---
 include/linux/moduleparam.h     | 26 +++++------
 security/apparmor/include/lib.h |  3 +-
 mm/kfence/core.c                |  8 ++--
 arch/x86/kvm/mmu/mmu.c          | 16 ++++---
 arch/x86/kvm/svm/avic.c         |  8 ++--
 drivers/dma/dmatest.c           | 14 +++---
 kernel/params.c                 | 80 ++++++++++++++++++++-------------
 security/apparmor/lib.c         | 27 +++++------
 security/apparmor/lsm.c         | 25 ++++++-----
 9 files changed, 114 insertions(+), 93 deletions(-)

diff --git a/include/linux/moduleparam.h b/include/linux/moduleparam.h
index 795bc7c654ef..38acb5aef56b 100644
--- a/include/linux/moduleparam.h
+++ b/include/linux/moduleparam.h
@@ -500,61 +500,61 @@ void module_destroy_params(const struct kernel_param *params, unsigned int num);
 
 extern const struct kernel_param_ops param_ops_byte;
 int param_set_byte(const char *val, const struct kernel_param *kp);
-int param_get_byte(char *buffer, const struct kernel_param *kp);
+int param_get_byte(struct seq_buf *s, const struct kernel_param *kp);
 #define param_check_byte(name, p) __param_check(name, p, unsigned char)
 
 extern const struct kernel_param_ops param_ops_short;
 int param_set_short(const char *val, const struct kernel_param *kp);
-int param_get_short(char *buffer, const struct kernel_param *kp);
+int param_get_short(struct seq_buf *s, const struct kernel_param *kp);
 #define param_check_short(name, p) __param_check(name, p, short)
 
 extern const struct kernel_param_ops param_ops_ushort;
 int param_set_ushort(const char *val, const struct kernel_param *kp);
-int param_get_ushort(char *buffer, const struct kernel_param *kp);
+int param_get_ushort(struct seq_buf *s, const struct kernel_param *kp);
 #define param_check_ushort(name, p) __param_check(name, p, unsigned short)
 
 extern const struct kernel_param_ops param_ops_int;
 int param_set_int(const char *val, const struct kernel_param *kp);
-int param_get_int(char *buffer, const struct kernel_param *kp);
+int param_get_int(struct seq_buf *s, const struct kernel_param *kp);
 #define param_check_int(name, p) __param_check(name, p, int)
 
 extern const struct kernel_param_ops param_ops_uint;
 int param_set_uint(const char *val, const struct kernel_param *kp);
-int param_get_uint(char *buffer, const struct kernel_param *kp);
+int param_get_uint(struct seq_buf *s, const struct kernel_param *kp);
 int param_set_uint_minmax(const char *val, const struct kernel_param *kp,
 		unsigned int min, unsigned int max);
 #define param_check_uint(name, p) __param_check(name, p, unsigned int)
 
 extern const struct kernel_param_ops param_ops_long;
 int param_set_long(const char *val, const struct kernel_param *kp);
-int param_get_long(char *buffer, const struct kernel_param *kp);
+int param_get_long(struct seq_buf *s, const struct kernel_param *kp);
 #define param_check_long(name, p) __param_check(name, p, long)
 
 extern const struct kernel_param_ops param_ops_ulong;
 int param_set_ulong(const char *val, const struct kernel_param *kp);
-int param_get_ulong(char *buffer, const struct kernel_param *kp);
+int param_get_ulong(struct seq_buf *s, const struct kernel_param *kp);
 #define param_check_ulong(name, p) __param_check(name, p, unsigned long)
 
 extern const struct kernel_param_ops param_ops_ullong;
 int param_set_ullong(const char *val, const struct kernel_param *kp);
-int param_get_ullong(char *buffer, const struct kernel_param *kp);
+int param_get_ullong(struct seq_buf *s, const struct kernel_param *kp);
 #define param_check_ullong(name, p) __param_check(name, p, unsigned long long)
 
 extern const struct kernel_param_ops param_ops_hexint;
 int param_set_hexint(const char *val, const struct kernel_param *kp);
-int param_get_hexint(char *buffer, const struct kernel_param *kp);
+int param_get_hexint(struct seq_buf *s, const struct kernel_param *kp);
 #define param_check_hexint(name, p) param_check_uint(name, p)
 
 extern const struct kernel_param_ops param_ops_charp;
 int param_set_charp(const char *val, const struct kernel_param *kp);
-int param_get_charp(char *buffer, const struct kernel_param *kp);
+int param_get_charp(struct seq_buf *s, const struct kernel_param *kp);
 void param_free_charp(void *arg);
 #define param_check_charp(name, p) __param_check(name, p, char *)
 
 /* We used to allow int as well as bool.  We're taking that away! */
 extern const struct kernel_param_ops param_ops_bool;
 int param_set_bool(const char *val, const struct kernel_param *kp);
-int param_get_bool(char *buffer, const struct kernel_param *kp);
+int param_get_bool(struct seq_buf *s, const struct kernel_param *kp);
 #define param_check_bool(name, p) __param_check(name, p, bool)
 
 extern const struct kernel_param_ops param_ops_bool_enable_only;
@@ -564,7 +564,7 @@ int param_set_bool_enable_only(const char *val, const struct kernel_param *kp);
 
 extern const struct kernel_param_ops param_ops_invbool;
 int param_set_invbool(const char *val, const struct kernel_param *kp);
-int param_get_invbool(char *buffer, const struct kernel_param *kp);
+int param_get_invbool(struct seq_buf *s, const struct kernel_param *kp);
 #define param_check_invbool(name, p) __param_check(name, p, bool)
 
 /* An int, which can only be set like a bool (though it shows as an int). */
@@ -677,7 +677,7 @@ extern const struct kernel_param_ops param_array_ops;
 
 extern const struct kernel_param_ops param_ops_string;
 int param_set_copystring(const char *val, const struct kernel_param *kp);
-int param_get_string(char *buffer, const struct kernel_param *kp);
+int param_get_string(struct seq_buf *s, const struct kernel_param *kp);
 
 /* for exporting parameters in /sys/module/.../parameters */
 
diff --git a/security/apparmor/include/lib.h b/security/apparmor/include/lib.h
index 8c6ce8484552..966082075e61 100644
--- a/security/apparmor/include/lib.h
+++ b/security/apparmor/include/lib.h
@@ -13,6 +13,7 @@
 #include <linux/slab.h>
 #include <linux/fs.h>
 #include <linux/lsm_hooks.h>
+#include <linux/seq_buf.h>
 
 #include "match.h"
 
@@ -72,7 +73,7 @@ do {									\
 #endif
 
 int aa_parse_debug_params(const char *str);
-int aa_print_debug_params(char *buffer);
+int aa_print_debug_params(struct seq_buf *s);
 
 #define AA_ERROR(fmt, args...)						\
 	pr_err_ratelimited("AppArmor: " fmt, ##args)
diff --git a/mm/kfence/core.c b/mm/kfence/core.c
index e14102c01520..bfa936f09978 100644
--- a/mm/kfence/core.c
+++ b/mm/kfence/core.c
@@ -84,10 +84,12 @@ static int param_set_sample_interval(const char *val, const struct kernel_param
 	return 0;
 }
 
-static int param_get_sample_interval(char *buffer, const struct kernel_param *kp)
+static int param_get_sample_interval(struct seq_buf *buffer, const struct kernel_param *kp)
 {
-	if (!READ_ONCE(kfence_enabled))
-		return sprintf(buffer, "0\n");
+	if (!READ_ONCE(kfence_enabled)) {
+		seq_buf_puts(buffer, "0\n");
+		return 0;
+	}
 
 	return param_get_ulong(buffer, kp);
 }
diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c
index 996818ee9b09..5e9a2690d335 100644
--- a/arch/x86/kvm/mmu/mmu.c
+++ b/arch/x86/kvm/mmu/mmu.c
@@ -70,7 +70,7 @@ static uint __read_mostly nx_huge_pages_recovery_ratio = 0;
 static uint __read_mostly nx_huge_pages_recovery_ratio = 60;
 #endif
 
-static int get_nx_huge_pages(char *buffer, const struct kernel_param *kp);
+static int get_nx_huge_pages(struct seq_buf *buffer, const struct kernel_param *kp);
 static int set_nx_huge_pages(const char *val, const struct kernel_param *kp);
 static int set_nx_huge_pages_recovery_param(const char *val, const struct kernel_param *kp);
 
@@ -7493,15 +7493,19 @@ static void kvm_wake_nx_recovery_thread(struct kvm *kvm)
 		vhost_task_wake(nx_thread);
 }
 
-static int get_nx_huge_pages(char *buffer, const struct kernel_param *kp)
+static int get_nx_huge_pages(struct seq_buf *buffer, const struct kernel_param *kp)
 {
 	int val = *(int *)kp->arg;
 
-	if (nx_hugepage_mitigation_hard_disabled)
-		return sysfs_emit(buffer, "never\n");
+	if (nx_hugepage_mitigation_hard_disabled) {
+		seq_buf_puts(buffer, "never\n");
+		return 0;
+	}
 
-	if (val == -1)
-		return sysfs_emit(buffer, "auto\n");
+	if (val == -1) {
+		seq_buf_puts(buffer, "auto\n");
+		return 0;
+	}
 
 	return param_get_bool(buffer, kp);
 }
diff --git a/arch/x86/kvm/svm/avic.c b/arch/x86/kvm/svm/avic.c
index 7907f9addff9..6c3b4626c5c1 100644
--- a/arch/x86/kvm/svm/avic.c
+++ b/arch/x86/kvm/svm/avic.c
@@ -77,12 +77,14 @@ static int avic_param_set(const char *val, const struct kernel_param *kp)
 	return param_set_bint(val, kp);
 }
 
-static int avic_param_get(char *buffer, const struct kernel_param *kp)
+static int avic_param_get(struct seq_buf *buffer, const struct kernel_param *kp)
 {
 	int val = *(int *)kp->arg;
 
-	if (val == AVIC_AUTO_MODE)
-		return sysfs_emit(buffer, "N\n");
+	if (val == AVIC_AUTO_MODE) {
+		seq_buf_puts(buffer, "N\n");
+		return 0;
+	}
 
 	return param_get_bool(buffer, kp);
 }
diff --git a/drivers/dma/dmatest.c b/drivers/dma/dmatest.c
index a7bddadcc52d..828298faca16 100644
--- a/drivers/dma/dmatest.c
+++ b/drivers/dma/dmatest.c
@@ -153,14 +153,14 @@ static struct dmatest_info {
 };
 
 static int dmatest_run_set(const char *val, const struct kernel_param *kp);
-static int dmatest_run_get(char *val, const struct kernel_param *kp);
+static int dmatest_run_get(struct seq_buf *val, const struct kernel_param *kp);
 static DEFINE_KERNEL_PARAM_OPS(run_ops, dmatest_run_set, dmatest_run_get);
 static bool dmatest_run;
 module_param_cb(run, &run_ops, &dmatest_run, 0644);
 MODULE_PARM_DESC(run, "Run the test (default: false)");
 
 static int dmatest_chan_set(const char *val, const struct kernel_param *kp);
-static int dmatest_chan_get(char *val, const struct kernel_param *kp);
+static int dmatest_chan_get(struct seq_buf *val, const struct kernel_param *kp);
 static DEFINE_KERNEL_PARAM_OPS(multi_chan_ops, dmatest_chan_set,
 			       dmatest_chan_get);
 
@@ -172,7 +172,7 @@ static struct kparam_string newchan_kps = {
 module_param_cb(channel, &multi_chan_ops, &newchan_kps, 0644);
 MODULE_PARM_DESC(channel, "Bus ID of the channel to test (default: any)");
 
-static int dmatest_test_list_get(char *val, const struct kernel_param *kp);
+static int dmatest_test_list_get(struct seq_buf *val, const struct kernel_param *kp);
 static DEFINE_KERNEL_PARAM_OPS(test_list_ops, NULL, dmatest_test_list_get);
 module_param_cb(test_list, &test_list_ops, NULL, 0444);
 MODULE_PARM_DESC(test_list, "Print current test list");
@@ -274,7 +274,7 @@ static bool is_threaded_test_pending(struct dmatest_info *info)
 	return false;
 }
 
-static int dmatest_wait_get(char *val, const struct kernel_param *kp)
+static int dmatest_wait_get(struct seq_buf *val, const struct kernel_param *kp)
 {
 	struct dmatest_info *info = &test_info;
 	struct dmatest_params *params = &info->params;
@@ -1164,7 +1164,7 @@ static void start_threaded_tests(struct dmatest_info *info)
 	run_pending_tests(info);
 }
 
-static int dmatest_run_get(char *val, const struct kernel_param *kp)
+static int dmatest_run_get(struct seq_buf *val, const struct kernel_param *kp)
 {
 	struct dmatest_info *info = &test_info;
 
@@ -1292,7 +1292,7 @@ static int dmatest_chan_set(const char *val, const struct kernel_param *kp)
 	return ret;
 }
 
-static int dmatest_chan_get(char *val, const struct kernel_param *kp)
+static int dmatest_chan_get(struct seq_buf *val, const struct kernel_param *kp)
 {
 	struct dmatest_info *info = &test_info;
 
@@ -1306,7 +1306,7 @@ static int dmatest_chan_get(char *val, const struct kernel_param *kp)
 	return param_get_string(val, kp);
 }
 
-static int dmatest_test_list_get(char *val, const struct kernel_param *kp)
+static int dmatest_test_list_get(struct seq_buf *val, const struct kernel_param *kp)
 {
 	struct dmatest_info *info = &test_info;
 	struct dmatest_chan *dtc;
diff --git a/kernel/params.c b/kernel/params.c
index 4eda2d23ddf2..25f0c8d5d19f 100644
--- a/kernel/params.c
+++ b/kernel/params.c
@@ -212,15 +212,16 @@ char *parse_args(const char *doing,
 }
 
 /* Lazy bastard, eh? */
-#define STANDARD_PARAM_DEF(name, type, format, strtolfn)      		\
+#define STANDARD_PARAM_DEF(name, type, format, strtolfn)		\
 	int param_set_##name(const char *val, const struct kernel_param *kp) \
 	{								\
 		return strtolfn(val, 0, (type *)kp->arg);		\
 	}								\
-	int param_get_##name(char *buffer, const struct kernel_param *kp) \
+	int param_get_##name(struct seq_buf *s,				\
+			     const struct kernel_param *kp)		\
 	{								\
-		return scnprintf(buffer, PAGE_SIZE, format "\n",	\
-				*((type *)kp->arg));			\
+		seq_buf_printf(s, format "\n", *((type *)kp->arg));	\
+		return 0;						\
 	}								\
 	DEFINE_KERNEL_PARAM_OPS(param_ops_##name,			\
 				param_set_##name, param_get_##name);	\
@@ -285,9 +286,10 @@ int param_set_charp(const char *val, const struct kernel_param *kp)
 }
 EXPORT_SYMBOL(param_set_charp);
 
-int param_get_charp(char *buffer, const struct kernel_param *kp)
+int param_get_charp(struct seq_buf *s, const struct kernel_param *kp)
 {
-	return scnprintf(buffer, PAGE_SIZE, "%s\n", *((char **)kp->arg));
+	seq_buf_printf(s, "%s\n", *((char **)kp->arg));
+	return 0;
 }
 EXPORT_SYMBOL(param_get_charp);
 
@@ -312,10 +314,11 @@ int param_set_bool(const char *val, const struct kernel_param *kp)
 }
 EXPORT_SYMBOL(param_set_bool);
 
-int param_get_bool(char *buffer, const struct kernel_param *kp)
+int param_get_bool(struct seq_buf *s, const struct kernel_param *kp)
 {
 	/* Y and N chosen as being relatively non-coder friendly */
-	return sprintf(buffer, "%c\n", *(bool *)kp->arg ? 'Y' : 'N');
+	seq_buf_printf(s, "%c\n", *(bool *)kp->arg ? 'Y' : 'N');
+	return 0;
 }
 EXPORT_SYMBOL(param_get_bool);
 
@@ -365,9 +368,10 @@ int param_set_invbool(const char *val, const struct kernel_param *kp)
 }
 EXPORT_SYMBOL(param_set_invbool);
 
-int param_get_invbool(char *buffer, const struct kernel_param *kp)
+int param_get_invbool(struct seq_buf *s, const struct kernel_param *kp)
 {
-	return sprintf(buffer, "%c\n", (*(bool *)kp->arg) ? 'N' : 'Y');
+	seq_buf_printf(s, "%c\n", (*(bool *)kp->arg) ? 'N' : 'Y');
+	return 0;
 }
 EXPORT_SYMBOL(param_get_invbool);
 
@@ -453,36 +457,46 @@ static int param_array_set(const char *val, const struct kernel_param *kp)
 			   arr->num ?: &temp_num);
 }
 
-static int param_array_get(char *buffer, const struct kernel_param *kp)
+static int param_array_get(struct seq_buf *s, const struct kernel_param *kp)
 {
-	int i, off, ret;
-	char *elem_buf;
 	const struct kparam_array *arr = kp->arr;
 	struct kernel_param p = *kp;
+	char *elem_buf = NULL;
+	int i, ret = 0;
 
-	elem_buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
-	if (!elem_buf)
-		return -ENOMEM;
+	for (i = 0; i < (arr->num ? *arr->num : arr->max); i++) {
+		size_t before = s->len;
 
-	for (i = off = 0; i < (arr->num ? *arr->num : arr->max); i++) {
 		p.arg = arr->elem + arr->elemsize * i;
 		check_kparam_locked(p.mod);
-		ret = arr->ops->get_str(elem_buf, &p);
-		if (ret < 0)
-			goto out;
-		ret = min(ret, (int)(PAGE_SIZE - 1 - off));
-		if (!ret)
+
+		if (arr->ops->get) {
+			ret = arr->ops->get(s, &p);
+			if (ret < 0)
+				goto out;
+		} else {
+			if (!elem_buf) {
+				elem_buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
+				if (!elem_buf) {
+					ret = -ENOMEM;
+					goto out;
+				}
+			}
+			ret = arr->ops->get_str(elem_buf, &p);
+			if (ret < 0)
+				goto out;
+			seq_buf_putmem(s, elem_buf, ret);
+		}
+
+		/* Nothing got written (e.g. overflow) — stop. */
+		if (s->len == before)
 			break;
+
 		/* Replace the previous element's trailing newline with a comma. */
-		if (i)
-			buffer[off - 1] = ',';
-		memcpy(buffer + off, elem_buf, ret);
-		off += ret;
-		if (off == PAGE_SIZE - 1)
-			break;
+		if (i && s->buffer[before - 1] == '\n')
+			s->buffer[before - 1] = ',';
 	}
-	buffer[off] = '\0';
-	ret = off;
+	ret = 0;
 out:
 	kfree(elem_buf);
 	return ret;
@@ -517,10 +531,12 @@ int param_set_copystring(const char *val, const struct kernel_param *kp)
 }
 EXPORT_SYMBOL(param_set_copystring);
 
-int param_get_string(char *buffer, const struct kernel_param *kp)
+int param_get_string(struct seq_buf *s, const struct kernel_param *kp)
 {
 	const struct kparam_string *kps = kp->str;
-	return scnprintf(buffer, PAGE_SIZE, "%s\n", kps->string);
+
+	seq_buf_printf(s, "%s\n", kps->string);
+	return 0;
 }
 EXPORT_SYMBOL(param_get_string);
 
diff --git a/security/apparmor/lib.c b/security/apparmor/lib.c
index e41ff57798b2..eef136add5b4 100644
--- a/security/apparmor/lib.c
+++ b/security/apparmor/lib.c
@@ -85,37 +85,32 @@ int aa_parse_debug_params(const char *str)
 
 /**
  * val_mask_to_str - convert a perm mask to its short string
- * @str: character buffer to store string in (at least 10 characters)
- * @size: size of the @str buffer
+ * @s: seq_buf to store string in
  * @table: NUL-terminated character buffer of permission characters (NOT NULL)
  * @mask: permission mask to convert
  */
-static int val_mask_to_str(char *str, size_t size,
-			   const struct val_table_ent *table, u32 mask)
+static void val_mask_to_str(struct seq_buf *s,
+			    const struct val_table_ent *table, u32 mask)
 {
 	const struct val_table_ent *ent;
-	int total = 0;
+	bool first = true;
 
 	for (ent = table; ent->str; ent++) {
 		if (ent->value && (ent->value & mask) == ent->value) {
-			int len = scnprintf(str, size, "%s%s", total ? "," : "",
-					    ent->str);
-			size -= len;
-			str += len;
-			total += len;
+			seq_buf_printf(s, "%s%s", first ? "" : ",", ent->str);
+			first = false;
 			mask &= ~ent->value;
 		}
 	}
-
-	return total;
 }
 
-int aa_print_debug_params(char *buffer)
+int aa_print_debug_params(struct seq_buf *s)
 {
 	if (!aa_g_debug)
-		return sprintf(buffer, "N");
-	return val_mask_to_str(buffer, PAGE_SIZE, debug_values_table,
-			       aa_g_debug);
+		seq_buf_puts(s, "N");
+	else
+		val_mask_to_str(s, debug_values_table, aa_g_debug);
+	return 0;
 }
 
 bool aa_resize_str_table(struct aa_str_table *t, int newsize, gfp_t gfp)
diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
index 8a253c743363..a6815b4bd0da 100644
--- a/security/apparmor/lsm.c
+++ b/security/apparmor/lsm.c
@@ -16,6 +16,7 @@
 #include <linux/namei.h>
 #include <linux/ptrace.h>
 #include <linux/ctype.h>
+#include <linux/seq_buf.h>
 #include <linux/sysctl.h>
 #include <linux/sysfs.h>
 #include <linux/audit.h>
@@ -1765,20 +1766,20 @@ static struct security_hook_list apparmor_hooks[] __ro_after_init = {
  */
 
 static int param_set_aabool(const char *val, const struct kernel_param *kp);
-static int param_get_aabool(char *buffer, const struct kernel_param *kp);
+static int param_get_aabool(struct seq_buf *buffer, const struct kernel_param *kp);
 #define param_check_aabool param_check_bool
 static DEFINE_KERNEL_PARAM_OPS_NOARG(param_ops_aabool, param_set_aabool,
 				     param_get_aabool);
 
 static int param_set_aauint(const char *val, const struct kernel_param *kp);
-static int param_get_aauint(char *buffer, const struct kernel_param *kp);
+static int param_get_aauint(struct seq_buf *buffer, const struct kernel_param *kp);
 #define param_check_aauint param_check_uint
 static DEFINE_KERNEL_PARAM_OPS(param_ops_aauint, param_set_aauint,
 			       param_get_aauint);
 
 static int param_set_aacompressionlevel(const char *val,
 					const struct kernel_param *kp);
-static int param_get_aacompressionlevel(char *buffer,
+static int param_get_aacompressionlevel(struct seq_buf *buffer,
 					const struct kernel_param *kp);
 #define param_check_aacompressionlevel param_check_int
 static DEFINE_KERNEL_PARAM_OPS(param_ops_aacompressionlevel,
@@ -1786,14 +1787,14 @@ static DEFINE_KERNEL_PARAM_OPS(param_ops_aacompressionlevel,
 			       param_get_aacompressionlevel);
 
 static int param_set_aalockpolicy(const char *val, const struct kernel_param *kp);
-static int param_get_aalockpolicy(char *buffer, const struct kernel_param *kp);
+static int param_get_aalockpolicy(struct seq_buf *buffer, const struct kernel_param *kp);
 #define param_check_aalockpolicy param_check_bool
 static DEFINE_KERNEL_PARAM_OPS_NOARG(param_ops_aalockpolicy,
 				     param_set_aalockpolicy,
 				     param_get_aalockpolicy);
 
 static int param_set_debug(const char *val, const struct kernel_param *kp);
-static int param_get_debug(char *buffer, const struct kernel_param *kp);
+static int param_get_debug(struct seq_buf *buffer, const struct kernel_param *kp);
 
 static int param_set_audit(const char *val, const struct kernel_param *kp);
 static int param_get_audit(char *buffer, const struct kernel_param *kp);
@@ -1868,7 +1869,7 @@ module_param_named(path_max, aa_g_path_max, aauint, S_IRUSR);
 bool aa_g_paranoid_load = IS_ENABLED(CONFIG_SECURITY_APPARMOR_PARANOID_LOAD);
 module_param_named(paranoid_load, aa_g_paranoid_load, aabool, S_IRUGO);
 
-static int param_get_aaintbool(char *buffer, const struct kernel_param *kp);
+static int param_get_aaintbool(struct seq_buf *buffer, const struct kernel_param *kp);
 static int param_set_aaintbool(const char *val, const struct kernel_param *kp);
 #define param_check_aaintbool param_check_int
 static DEFINE_KERNEL_PARAM_OPS(param_ops_aaintbool, param_set_aaintbool,
@@ -1898,7 +1899,7 @@ static int param_set_aalockpolicy(const char *val, const struct kernel_param *kp
 	return param_set_bool(val, kp);
 }
 
-static int param_get_aalockpolicy(char *buffer, const struct kernel_param *kp)
+static int param_get_aalockpolicy(struct seq_buf *buffer, const struct kernel_param *kp)
 {
 	if (!apparmor_enabled)
 		return -EINVAL;
@@ -1916,7 +1917,7 @@ static int param_set_aabool(const char *val, const struct kernel_param *kp)
 	return param_set_bool(val, kp);
 }
 
-static int param_get_aabool(char *buffer, const struct kernel_param *kp)
+static int param_get_aabool(struct seq_buf *buffer, const struct kernel_param *kp)
 {
 	if (!apparmor_enabled)
 		return -EINVAL;
@@ -1942,7 +1943,7 @@ static int param_set_aauint(const char *val, const struct kernel_param *kp)
 	return error;
 }
 
-static int param_get_aauint(char *buffer, const struct kernel_param *kp)
+static int param_get_aauint(struct seq_buf *buffer, const struct kernel_param *kp)
 {
 	if (!apparmor_enabled)
 		return -EINVAL;
@@ -1978,7 +1979,7 @@ static int param_set_aaintbool(const char *val, const struct kernel_param *kp)
  * display in the /sys filesystem, while keeping it "int" for the LSM
  * infrastructure.
  */
-static int param_get_aaintbool(char *buffer, const struct kernel_param *kp)
+static int param_get_aaintbool(struct seq_buf *buffer, const struct kernel_param *kp)
 {
 	struct kernel_param kp_local;
 	bool value;
@@ -2011,7 +2012,7 @@ static int param_set_aacompressionlevel(const char *val,
 	return error;
 }
 
-static int param_get_aacompressionlevel(char *buffer,
+static int param_get_aacompressionlevel(struct seq_buf *buffer,
 					const struct kernel_param *kp)
 {
 	if (!apparmor_enabled)
@@ -2021,7 +2022,7 @@ static int param_get_aacompressionlevel(char *buffer,
 	return param_get_int(buffer, kp);
 }
 
-static int param_get_debug(char *buffer, const struct kernel_param *kp)
+static int param_get_debug(struct seq_buf *buffer, const struct kernel_param *kp)
 {
 	if (!apparmor_enabled)
 		return -EINVAL;
-- 
2.34.1


  parent reply	other threads:[~2026-05-21 13:33 UTC|newest]

Thread overview: 16+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-05-21 13:33 [PATCH 00/11] Convert moduleparams to seq_buf Kees Cook
2026-05-21 13:33 ` [PATCH 01/11] params: bound array element output to the caller's page buffer Kees Cook
2026-05-21 16:46   ` David Laight
2026-05-21 13:33 ` [PATCH 02/11] panic: Replace panic_print_get() with generic helper Kees Cook
2026-05-21 13:33 ` [PATCH 03/11] moduleparam: Add DEFINE_KERNEL_PARAM_OPS macro family Kees Cook
2026-05-21 13:33 ` [PATCH 04/11] treewide: Convert struct kernel_param_ops initializers to DEFINE_KERNEL_PARAM_OPS Kees Cook
2026-05-21 13:59   ` Sean Christopherson
2026-05-21 13:33 ` [PATCH 05/11] moduleparam: Rename .get field to .get_str Kees Cook
2026-05-21 13:33 ` [PATCH 06/11] moduleparam: Add seq_buf-based .get callback alongside .get_str Kees Cook
2026-05-21 13:33 ` [PATCH 07/11] moduleparam: Route DEFINE_KERNEL_PARAM_OPS get pointer via _Generic Kees Cook
2026-05-21 13:33 ` Kees Cook [this message]
2026-05-21 13:33 ` [PATCH 09/11] treewide: Convert custom kernel_param_ops .get callbacks to seq_buf via cocci Kees Cook
2026-05-21 13:45   ` Sean Christopherson
2026-05-21 13:33 ` [PATCH 10/11] treewide: Manually convert custom kernel_param_ops .get callbacks Kees Cook
2026-05-21 17:44   ` Jani Nikula
2026-05-21 13:33 ` [PATCH 11/11] moduleparam: Drop legacy kernel_param_ops .get_str field and dispatch logic Kees Cook

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=20260521133326.2465264-8-kees@kernel.org \
    --to=kees@kernel.org \
    --cc=Frank.Li@kernel.org \
    --cc=James.Bottomley@HansenPartnership.com \
    --cc=airlied@gmail.com \
    --cc=akpm@linux-foundation.org \
    --cc=andriy.shevchenko@linux.intel.com \
    --cc=anton.ivanov@cambridgegreys.com \
    --cc=apparmor@lists.ubuntu.com \
    --cc=atomlin@atomlin.com \
    --cc=benjamin.berg@intel.com \
    --cc=bhelgaas@google.com \
    --cc=bp@alien8.de \
    --cc=bvanassche@acm.org \
    --cc=corey@minyard.net \
    --cc=da.gomez@kernel.org \
    --cc=daniel.lezcano@kernel.org \
    --cc=dave.hansen@linux.intel.com \
    --cc=david.e.box@linux.intel.com \
    --cc=dmaengine@vger.kernel.org \
    --cc=dri-devel@lists.freedesktop.org \
    --cc=dvyukov@google.com \
    --cc=elver@google.com \
    --cc=eperezma@redhat.com \
    --cc=georgia.garcia@canonical.com \
    --cc=glider@google.com \
    --cc=gor@linux.ibm.com \
    --cc=gregkh@linuxfoundation.org \
    --cc=hansg@kernel.org \
    --cc=hare@suse.de \
    --cc=hca@linux.ibm.com \
    --cc=hpa@zytor.com \
    --cc=ilpo.jarvinen@linux.intel.com \
    --cc=intel-gfx@lists.freedesktop.org \
    --cc=jani.nikula@linux.intel.com \
    --cc=jasowang@redhat.com \
    --cc=jbaron@akamai.com \
    --cc=jgg@ziepe.ca \
    --cc=jim.cromie@gmail.com \
    --cc=jirislaby@kernel.org \
    --cc=jmorris@namei.org \
    --cc=johannes@sipsolutions.net \
    --cc=john.johansen@canonical.com \
    --cc=joonas.lahtinen@linux.intel.com \
    --cc=kasan-dev@googlegroups.com \
    --cc=kvm@vger.kernel.org \
    --cc=laurent.pinchart@ideasonboard.com \
    --cc=lenb@kernel.org \
    --cc=leon@kernel.org \
    --cc=linux-acpi@vger.kernel.org \
    --cc=linux-arch@vger.kernel.org \
    --cc=linux-fsdevel@vger.kernel.org \
    --cc=linux-hardening@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-media@vger.kernel.org \
    --cc=linux-mm@kvack.org \
    --cc=linux-modules@vger.kernel.org \
    --cc=linux-pci@vger.kernel.org \
    --cc=linux-pm@vger.kernel.org \
    --cc=linux-rdma@vger.kernel.org \
    --cc=linux-scsi@vger.kernel.org \
    --cc=linux-security-module@vger.kernel.org \
    --cc=linux-serial@vger.kernel.org \
    --cc=linux-um@lists.infradead.org \
    --cc=linux-usb@vger.kernel.org \
    --cc=linuxppc-dev@lists.ozlabs.org \
    --cc=lukasz.luba@arm.com \
    --cc=macro@orcam.me.uk \
    --cc=martin.petersen@oracle.com \
    --cc=mcgrof@kernel.org \
    --cc=mchehab@kernel.org \
    --cc=mingo@redhat.com \
    --cc=mst@redhat.com \
    --cc=netdev@vger.kernel.org \
    --cc=openipmi-developer@lists.sourceforge.net \
    --cc=paul@paul-moore.com \
    --cc=pbonzini@redhat.com \
    --cc=pengpeng@iscas.ac.cn \
    --cc=peterz@infradead.org \
    --cc=petr.pavlu@suse.com \
    --cc=qemu-devel@nongnu.org \
    --cc=rafael@kernel.org \
    --cc=richard@nod.at \
    --cc=rodrigo.vivi@intel.com \
    --cc=rui.zhang@intel.com \
    --cc=samitolvanen@google.com \
    --cc=seanjc@google.com \
    --cc=serge@hallyn.com \
    --cc=simona@ffwll.ch \
    --cc=somlo@cmu.edu \
    --cc=srinivas.pandruvada@linux.intel.com \
    --cc=stern@rowland.harvard.edu \
    --cc=tglx@kernel.org \
    --cc=tiwei.btw@antgroup.com \
    --cc=tursulin@ursulin.net \
    --cc=usb-storage@lists.one-eyed-alien.net \
    --cc=virtualization@lists.linux.dev \
    --cc=vkoul@kernel.org \
    --cc=x86@kernel.org \
    --cc=xuanzhuo@linux.alibaba.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