[PATCH 07/11] moduleparam: Route DEFINE_KERNEL_PARAM_OPS get pointer via _Generic
Petr Pavlu
petr.pavlu at suse.com
Mon May 25 16:24:07 UTC 2026
On 5/21/26 3:33 PM, Kees Cook wrote:
> Make the DEFINE_KERNEL_PARAM_OPS family route their _get argument to
> either .get (struct seq_buf *) or .get_str (char *) at compile time
> based on the pointer's actual function signature. Two helper macros
> do the routing:
>
> _KERNEL_PARAM_OPS_GET - return the pointer if it has the seq_buf
> signature, otherwise NULL of that type
> _KERNEL_PARAM_OPS_GET_STR - mirror image for the char * signature
>
> Both use _Generic; only the two valid function-pointer types are
> listed, so any third-party type is a compile error rather than
> silently falling through.
>
> Now a callback whose body has been migrated from char * to struct
> seq_buf * needs no change at its kernel_param_ops initialization site,
> because the macro picks up the new type automatically and assigns to
> the correct field.
>
> Signed-off-by: Kees Cook <kees at kernel.org>
> ---
> include/linux/moduleparam.h | 33 ++++++++++++++++++++++++++-------
> 1 file changed, 26 insertions(+), 7 deletions(-)
>
> diff --git a/include/linux/moduleparam.h b/include/linux/moduleparam.h
> index c52120f6ac28..795bc7c654ef 100644
> --- a/include/linux/moduleparam.h
> +++ b/include/linux/moduleparam.h
> @@ -85,15 +85,32 @@ struct kernel_param_ops {
> *
> * static DEFINE_KERNEL_PARAM_OPS(my_ops, my_set, my_get);
> *
> - * Routing the @_set and @_get function pointers through the macro
> - * (rather than naming the struct fields at every call site) lets the
> - * field layout change in one place when callbacks are migrated to a
> - * new signature.
> + * @_get may be either of:
> + * int (*)(struct seq_buf *, const struct kernel_param *) (seq_buf)
> + * int (*)(char *, const struct kernel_param *) (legacy)
> + *
> + * The macro uses _Generic to route the function pointer to the
> + * matching field (.get or .get_str) at compile time, leaving the
> + * other field NULL. Each helper matches the wrong prototype signature
> + * and returns NULL, falling through to the default branch otherwise;
> + * if @_get has neither expected signature the assignment to the
> + * fields gets a normal compile-time type-mismatch error.
> */
> +#define _KERNEL_PARAM_OPS_GET(_get) \
> + _Generic((_get), \
> + int (*)(char *, const struct kernel_param *): NULL, \
> + default: (_get))
> +
> +#define _KERNEL_PARAM_OPS_GET_STR(_get) \
> + _Generic((_get), \
> + int (*)(struct seq_buf *, const struct kernel_param *): NULL, \
> + default: (_get))
> +
> #define DEFINE_KERNEL_PARAM_OPS(_name, _set, _get) \
> const struct kernel_param_ops _name = { \
> .set = (_set), \
> - .get_str = (_get), \
> + .get = _KERNEL_PARAM_OPS_GET(_get), \
> + .get_str = _KERNEL_PARAM_OPS_GET_STR(_get), \
> }
>
> /* As DEFINE_KERNEL_PARAM_OPS, with KERNEL_PARAM_OPS_FL_NOARG set. */
> @@ -101,14 +118,16 @@ struct kernel_param_ops {
> const struct kernel_param_ops _name = { \
> .flags = KERNEL_PARAM_OPS_FL_NOARG, \
> .set = (_set), \
> - .get_str = (_get), \
> + .get = _KERNEL_PARAM_OPS_GET(_get), \
> + .get_str = _KERNEL_PARAM_OPS_GET_STR(_get), \
> }
>
> /* As DEFINE_KERNEL_PARAM_OPS, with an additional .free callback. */
> #define DEFINE_KERNEL_PARAM_OPS_FREE(_name, _set, _get, _free) \
> const struct kernel_param_ops _name = { \
> .set = (_set), \
> - .get_str = (_get), \
> + .get = _KERNEL_PARAM_OPS_GET(_get), \
> + .get_str = _KERNEL_PARAM_OPS_GET_STR(_get), \
> .free = (_free), \
> }
>
Reviewed-by: Petr Pavlu <petr.pavlu at suse.com>
-- Petr
More information about the Linux-security-module-archive
mailing list