* [PATCH v3 2/2] livepatch: Free klp_{object,func}_ext data after initialization
From: Petr Pavlu @ 2026-01-23 10:26 UTC (permalink / raw)
To: Josh Poimboeuf, Jiri Kosina, Miroslav Benes, Petr Mladek,
Joe Lawrence
Cc: Luis Chamberlain, Petr Pavlu, Daniel Gomez, Sami Tolvanen,
Aaron Tomlin, Peter Zijlstra, live-patching, linux-modules,
linux-kernel
In-Reply-To: <20260123102825.3521961-1-petr.pavlu@suse.com>
The klp_object_ext and klp_func_ext data, which are stored in the
__klp_objects and __klp_funcs sections, respectively, are not needed
after they are used to create the actual klp_object and klp_func
instances. This operation is implemented by the init function in
scripts/livepatch/init.c.
Prefix the two sections with ".init" so they are freed after the module
is initializated.
Signed-off-by: Petr Pavlu <petr.pavlu@suse.com>
Acked-by: Joe Lawrence <joe.lawrence@redhat.com>
---
scripts/livepatch/init.c | 2 +-
scripts/module.lds.S | 4 ++--
tools/objtool/check.c | 2 +-
tools/objtool/include/objtool/klp.h | 10 +++++-----
tools/objtool/klp-diff.c | 2 +-
5 files changed, 10 insertions(+), 10 deletions(-)
diff --git a/scripts/livepatch/init.c b/scripts/livepatch/init.c
index 9e315fc857bd..638c95cffe76 100644
--- a/scripts/livepatch/init.c
+++ b/scripts/livepatch/init.c
@@ -19,7 +19,7 @@ static int __init livepatch_mod_init(void)
unsigned int nr_objs;
int ret;
- obj_exts = klp_find_section_by_name(THIS_MODULE, "__klp_objects",
+ obj_exts = klp_find_section_by_name(THIS_MODULE, ".init.klp_objects",
&obj_exts_sec_size);
nr_objs = obj_exts_sec_size / sizeof(*obj_exts);
if (!nr_objs) {
diff --git a/scripts/module.lds.S b/scripts/module.lds.S
index 383d19beffb4..054ef99e8288 100644
--- a/scripts/module.lds.S
+++ b/scripts/module.lds.S
@@ -34,8 +34,8 @@ SECTIONS {
__patchable_function_entries : { *(__patchable_function_entries) }
- __klp_funcs 0: ALIGN(8) { KEEP(*(__klp_funcs)) }
- __klp_objects 0: ALIGN(8) { KEEP(*(__klp_objects)) }
+ .init.klp_funcs 0 : ALIGN(8) { KEEP(*(.init.klp_funcs)) }
+ .init.klp_objects 0 : ALIGN(8) { KEEP(*(.init.klp_objects)) }
#ifdef CONFIG_ARCH_USES_CFI_TRAPS
__kcfi_traps : { KEEP(*(.kcfi_traps)) }
diff --git a/tools/objtool/check.c b/tools/objtool/check.c
index 3f7999317f4d..933868ee3beb 100644
--- a/tools/objtool/check.c
+++ b/tools/objtool/check.c
@@ -4761,7 +4761,7 @@ static int validate_ibt(struct objtool_file *file)
!strcmp(sec->name, "__bug_table") ||
!strcmp(sec->name, "__ex_table") ||
!strcmp(sec->name, "__jump_table") ||
- !strcmp(sec->name, "__klp_funcs") ||
+ !strcmp(sec->name, ".init.klp_funcs") ||
!strcmp(sec->name, "__mcount_loc") ||
!strcmp(sec->name, ".llvm.call-graph-profile") ||
!strcmp(sec->name, ".llvm_bb_addr_map") ||
diff --git a/tools/objtool/include/objtool/klp.h b/tools/objtool/include/objtool/klp.h
index ad830a7ce55b..e32e5e8bc631 100644
--- a/tools/objtool/include/objtool/klp.h
+++ b/tools/objtool/include/objtool/klp.h
@@ -6,12 +6,12 @@
#define SHN_LIVEPATCH 0xff20
/*
- * __klp_objects and __klp_funcs are created by klp diff and used by the patch
- * module init code to build the klp_patch, klp_object and klp_func structs
- * needed by the livepatch API.
+ * .init.klp_objects and .init.klp_funcs are created by klp diff and used by the
+ * patch module init code to build the klp_patch, klp_object and klp_func
+ * structs needed by the livepatch API.
*/
-#define KLP_OBJECTS_SEC "__klp_objects"
-#define KLP_FUNCS_SEC "__klp_funcs"
+#define KLP_OBJECTS_SEC ".init.klp_objects"
+#define KLP_FUNCS_SEC ".init.klp_funcs"
/*
* __klp_relocs is an intermediate section which are created by klp diff and
diff --git a/tools/objtool/klp-diff.c b/tools/objtool/klp-diff.c
index 4d1f9e9977eb..fd64d5e3c3b6 100644
--- a/tools/objtool/klp-diff.c
+++ b/tools/objtool/klp-diff.c
@@ -1439,7 +1439,7 @@ static int clone_special_sections(struct elfs *e)
}
/*
- * Create __klp_objects and __klp_funcs sections which are intermediate
+ * Create .init.klp_objects and .init.klp_funcs sections which are intermediate
* sections provided as input to the patch module's init code for building the
* klp_patch, klp_object and klp_func structs for the livepatch API.
*/
--
2.52.0
^ permalink raw reply related
* [PATCH v3 1/2] livepatch: Fix having __klp_objects relics in non-livepatch modules
From: Petr Pavlu @ 2026-01-23 10:26 UTC (permalink / raw)
To: Josh Poimboeuf, Jiri Kosina, Miroslav Benes, Petr Mladek,
Joe Lawrence
Cc: Luis Chamberlain, Petr Pavlu, Daniel Gomez, Sami Tolvanen,
Aaron Tomlin, Peter Zijlstra, live-patching, linux-modules,
linux-kernel
In-Reply-To: <20260123102825.3521961-1-petr.pavlu@suse.com>
The linker script scripts/module.lds.S specifies that all input
__klp_objects sections should be consolidated into an output section of
the same name, and start/stop symbols should be created to enable
scripts/livepatch/init.c to locate this data.
This start/stop pattern is not ideal for modules because the symbols are
created even if no __klp_objects input sections are present.
Consequently, a dummy __klp_objects section also appears in the
resulting module. This unnecessarily pollutes non-livepatch modules.
Instead, since modules are relocatable files, the usual method for
locating consolidated data in a module is to read its section table.
This approach avoids the aforementioned problem.
The klp_modinfo already stores a copy of the entire section table with
the final addresses. Introduce a helper function that
scripts/livepatch/init.c can call to obtain the location of the
__klp_objects section from this data.
Signed-off-by: Petr Pavlu <petr.pavlu@suse.com>
Acked-by: Joe Lawrence <joe.lawrence@redhat.com>
---
include/linux/livepatch.h | 3 +++
kernel/livepatch/core.c | 19 +++++++++++++++++++
scripts/livepatch/init.c | 20 +++++++++-----------
scripts/module.lds.S | 7 +------
4 files changed, 32 insertions(+), 17 deletions(-)
diff --git a/include/linux/livepatch.h b/include/linux/livepatch.h
index 772919e8096a..ba9e3988c07c 100644
--- a/include/linux/livepatch.h
+++ b/include/linux/livepatch.h
@@ -175,6 +175,9 @@ int klp_enable_patch(struct klp_patch *);
int klp_module_coming(struct module *mod);
void klp_module_going(struct module *mod);
+void *klp_find_section_by_name(const struct module *mod, const char *name,
+ size_t *sec_size);
+
void klp_copy_process(struct task_struct *child);
void klp_update_patch_state(struct task_struct *task);
diff --git a/kernel/livepatch/core.c b/kernel/livepatch/core.c
index 9917756dae46..1acbad2dbfdf 100644
--- a/kernel/livepatch/core.c
+++ b/kernel/livepatch/core.c
@@ -1356,6 +1356,25 @@ void klp_module_going(struct module *mod)
mutex_unlock(&klp_mutex);
}
+void *klp_find_section_by_name(const struct module *mod, const char *name,
+ size_t *sec_size)
+{
+ struct klp_modinfo *info = mod->klp_info;
+
+ for (int i = 1; i < info->hdr.e_shnum; i++) {
+ Elf_Shdr *shdr = &info->sechdrs[i];
+
+ if (!strcmp(info->secstrings + shdr->sh_name, name)) {
+ *sec_size = shdr->sh_size;
+ return (void *)shdr->sh_addr;
+ }
+ }
+
+ *sec_size = 0;
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(klp_find_section_by_name);
+
static int __init klp_init(void)
{
klp_root_kobj = kobject_create_and_add("livepatch", kernel_kobj);
diff --git a/scripts/livepatch/init.c b/scripts/livepatch/init.c
index 2274d8f5a482..9e315fc857bd 100644
--- a/scripts/livepatch/init.c
+++ b/scripts/livepatch/init.c
@@ -9,19 +9,19 @@
#include <linux/slab.h>
#include <linux/livepatch.h>
-extern struct klp_object_ext __start_klp_objects[];
-extern struct klp_object_ext __stop_klp_objects[];
-
static struct klp_patch *patch;
static int __init livepatch_mod_init(void)
{
+ struct klp_object_ext *obj_exts;
+ size_t obj_exts_sec_size;
struct klp_object *objs;
unsigned int nr_objs;
int ret;
- nr_objs = __stop_klp_objects - __start_klp_objects;
-
+ obj_exts = klp_find_section_by_name(THIS_MODULE, "__klp_objects",
+ &obj_exts_sec_size);
+ nr_objs = obj_exts_sec_size / sizeof(*obj_exts);
if (!nr_objs) {
pr_err("nothing to patch!\n");
ret = -EINVAL;
@@ -41,7 +41,7 @@ static int __init livepatch_mod_init(void)
}
for (int i = 0; i < nr_objs; i++) {
- struct klp_object_ext *obj_ext = __start_klp_objects + i;
+ struct klp_object_ext *obj_ext = obj_exts + i;
struct klp_func_ext *funcs_ext = obj_ext->funcs;
unsigned int nr_funcs = obj_ext->nr_funcs;
struct klp_func *funcs = objs[i].funcs;
@@ -90,12 +90,10 @@ static int __init livepatch_mod_init(void)
static void __exit livepatch_mod_exit(void)
{
- unsigned int nr_objs;
-
- nr_objs = __stop_klp_objects - __start_klp_objects;
+ struct klp_object *obj;
- for (int i = 0; i < nr_objs; i++)
- kfree(patch->objs[i].funcs);
+ klp_for_each_object_static(patch, obj)
+ kfree(obj->funcs);
kfree(patch->objs);
kfree(patch);
diff --git a/scripts/module.lds.S b/scripts/module.lds.S
index 3037d5e5527c..383d19beffb4 100644
--- a/scripts/module.lds.S
+++ b/scripts/module.lds.S
@@ -35,12 +35,7 @@ SECTIONS {
__patchable_function_entries : { *(__patchable_function_entries) }
__klp_funcs 0: ALIGN(8) { KEEP(*(__klp_funcs)) }
-
- __klp_objects 0: ALIGN(8) {
- __start_klp_objects = .;
- KEEP(*(__klp_objects))
- __stop_klp_objects = .;
- }
+ __klp_objects 0: ALIGN(8) { KEEP(*(__klp_objects)) }
#ifdef CONFIG_ARCH_USES_CFI_TRAPS
__kcfi_traps : { KEEP(*(.kcfi_traps)) }
--
2.52.0
^ permalink raw reply related
* [PATCH v3 0/2] Improve handling of the __klp_{objects,funcs} sections in modules
From: Petr Pavlu @ 2026-01-23 10:26 UTC (permalink / raw)
To: Josh Poimboeuf, Jiri Kosina, Miroslav Benes, Petr Mladek,
Joe Lawrence
Cc: Luis Chamberlain, Petr Pavlu, Daniel Gomez, Sami Tolvanen,
Aaron Tomlin, Peter Zijlstra, live-patching, linux-modules,
linux-kernel
Changes since v2 [1]:
- Generalize the helper function that locates __klp_objects in a module
to allow it to find any data in other sections as well.
Changes since v1 [2]:
- Generalize the helper function that locates __klp_objects in a module
to allow it to find objects in other sections as well.
[1] https://lore.kernel.org/linux-modules/20260121082842.3050453-1-petr.pavlu@suse.com/
[2] https://lore.kernel.org/linux-modules/20260114123056.2045816-1-petr.pavlu@suse.com/
Petr Pavlu (2):
livepatch: Fix having __klp_objects relics in non-livepatch modules
livepatch: Free klp_{object,func}_ext data after initialization
include/linux/livepatch.h | 3 +++
kernel/livepatch/core.c | 19 +++++++++++++++++++
scripts/livepatch/init.c | 20 +++++++++-----------
scripts/module.lds.S | 9 ++-------
tools/objtool/check.c | 2 +-
tools/objtool/include/objtool/klp.h | 10 +++++-----
tools/objtool/klp-diff.c | 2 +-
7 files changed, 40 insertions(+), 25 deletions(-)
base-commit: 0f61b1860cc3f52aef9036d7235ed1f017632193
--
2.52.0
^ permalink raw reply
* Re: [RFC PATCH 1/1] module: speed modprobe by adding name_crc to struct module
From: Petr Pavlu @ 2026-01-23 9:36 UTC (permalink / raw)
To: Jim Cromie
Cc: Luis Chamberlain, Daniel Gomez, Sami Tolvanen, Aaron Tomlin,
linux-modules, linux-kernel
In-Reply-To: <20260122234621.3403276-1-jim.cromie@gmail.com>
On 1/23/26 12:46 AM, Jim Cromie wrote:
> "modprobe foo" currently does strcmp on the name, this can be improved.
>
> So this commit:
>
> 1. adds name_crc to struct module
> 2. modpost.c computes the value and
> 3. outputs it for "modinfo foo" to see/use.
>
> 4. adds hotpath to find_module_all()
> this uses name_crc to do quick "name-check"
> falls back to strcmp only to guard against collisions.
>
> This should significantly reduce modprobe workload, and shorten module
> load-time.
>
> Since it alters struct module, its binary incompatible. This means:
>
> 1. RFC for its wide "blast radius".
> 2. suitable for major version bump *only*
>
> 3. it opens door for further struct module reorg, to:
> a. segregate fields by "temperature"
> b. pack out paholes.
> c. improve cache locality (by reordering coldest on bottom)
> name should be cold now.
> bikeshedding is appropriate here.
>
> NB: this isn't a substitute for CONFIG_MODULE_SIG.
> It reimplements crc_le(), doesn't reuse kernel's version.
>
> CC: Luis Chamberlain <mcgrof@kernel.org>
> CC: Petr Pavlu <petr.pavlu@suse.com>
> CC: Daniel Gomez <da.gomez@kernel.org>
> CC: Sami Tolvanen <samitolvanen@google.com>
> CC: Aaron Tomlin <atomlin@atomlin.com>
> CC: linux-modules@vger.kernel.org
>
> Signed-off-by: Jim Cromie <jim.cromie@gmail.com>
>
> '#' will be ignored, and an empty message aborts the commit.
This patch looks as if it were generated by AI. If so, please avoid
sending such changes. Otherwise, the commit description should explain
the affected workload. This should be backed up by actual measurements,
showing how the change improves the situation.
Implementation-wise, I don't think this is the right approach. If
searching by a module name is a hot operation, a hash table can be added
to speed it up.
--
Cheers,
Petr
^ permalink raw reply
* [RFC PATCH 1/1] module: speed modprobe by adding name_crc to struct module
From: Jim Cromie @ 2026-01-22 23:46 UTC (permalink / raw)
To: linux-kernel
Cc: Jim Cromie, Luis Chamberlain, Petr Pavlu, Daniel Gomez,
Sami Tolvanen, Aaron Tomlin, linux-modules
"modprobe foo" currently does strcmp on the name, this can be improved.
So this commit:
1. adds name_crc to struct module
2. modpost.c computes the value and
3. outputs it for "modinfo foo" to see/use.
4. adds hotpath to find_module_all()
this uses name_crc to do quick "name-check"
falls back to strcmp only to guard against collisions.
This should significantly reduce modprobe workload, and shorten module
load-time.
Since it alters struct module, its binary incompatible. This means:
1. RFC for its wide "blast radius".
2. suitable for major version bump *only*
3. it opens door for further struct module reorg, to:
a. segregate fields by "temperature"
b. pack out paholes.
c. improve cache locality (by reordering coldest on bottom)
name should be cold now.
bikeshedding is appropriate here.
NB: this isn't a substitute for CONFIG_MODULE_SIG.
It reimplements crc_le(), doesn't reuse kernel's version.
CC: Luis Chamberlain <mcgrof@kernel.org>
CC: Petr Pavlu <petr.pavlu@suse.com>
CC: Daniel Gomez <da.gomez@kernel.org>
CC: Sami Tolvanen <samitolvanen@google.com>
CC: Aaron Tomlin <atomlin@atomlin.com>
CC: linux-modules@vger.kernel.org
Signed-off-by: Jim Cromie <jim.cromie@gmail.com>
'#' will be ignored, and an empty message aborts the commit.
---
include/linux/module.h | 15 ++++++++-------
kernel/module/main.c | 8 ++++++--
scripts/mod/modpost.c | 18 ++++++++++++++++++
scripts/mod/modpost.h | 6 +++++-
4 files changed, 37 insertions(+), 10 deletions(-)
diff --git a/include/linux/module.h b/include/linux/module.h
index d80c3ea57472..4ea6c5ae3374 100644
--- a/include/linux/module.h
+++ b/include/linux/module.h
@@ -402,10 +402,18 @@ struct klp_modinfo {
struct module {
enum module_state state;
+ u32 name_hash;
/* Member of list of modules */
struct list_head list;
+ /* Sysfs stuff. */
+ struct module_kobject mkobj;
+ struct module_attribute *modinfo_attrs;
+ const char *version;
+ const char *srcversion;
+ struct kobject *holders_dir;
+
/* Unique handle for this module */
char name[MODULE_NAME_LEN];
@@ -414,13 +422,6 @@ struct module {
unsigned char build_id[BUILD_ID_SIZE_MAX];
#endif
- /* Sysfs stuff. */
- struct module_kobject mkobj;
- struct module_attribute *modinfo_attrs;
- const char *version;
- const char *srcversion;
- struct kobject *holders_dir;
-
/* Exported symbols */
const struct kernel_symbol *syms;
const u32 *crcs;
diff --git a/kernel/module/main.c b/kernel/module/main.c
index d855f43a2be3..685218b2c5ef 100644
--- a/kernel/module/main.c
+++ b/kernel/module/main.c
@@ -39,6 +39,7 @@
#include <linux/mutex.h>
#include <linux/rculist.h>
#include <linux/uaccess.h>
+#include <linux/crc32.h>
#include <asm/cacheflush.h>
#include <linux/set_memory.h>
#include <asm/mmu_context.h>
@@ -431,13 +432,16 @@ struct module *find_module_all(const char *name, size_t len,
bool even_unformed)
{
struct module *mod;
+ u32 incoming_name_hash = crc32_le(0, name, len);
list_for_each_entry_rcu(mod, &modules, list,
lockdep_is_held(&module_mutex)) {
if (!even_unformed && mod->state == MODULE_STATE_UNFORMED)
continue;
- if (strlen(mod->name) == len && !memcmp(mod->name, name, len))
- return mod;
+ if (mod->name_hash == incoming_name_hash) {
+ if (strlen(mod->name) == len && !memcmp(mod->name, name, len))
+ return mod;
+ }
}
return NULL;
}
diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c
index 755b842f1f9b..ae90e0bf9330 100644
--- a/scripts/mod/modpost.c
+++ b/scripts/mod/modpost.c
@@ -21,6 +21,22 @@
#include <stdbool.h>
#include <errno.h>
+/* Local CRC32 implementation for modpost.c */
+#define CRCPOLY_LE 0xEDB88320
+
+typedef uint32_t u32;
+
+static u32 crc32_le(u32 crc, char *p, size_t len)
+{
+ int i;
+ while (len--) {
+ crc ^= *p++;
+ for (i = 0; i < 8; i++)
+ crc = (crc >> 1) ^ ((crc & 1) ? CRCPOLY_LE : 0);
+ }
+ return crc;
+}
+
#include <hash.h>
#include <hashtable.h>
#include <list.h>
@@ -1581,6 +1597,7 @@ static void read_symbols(const char *modname)
/* strip trailing .o */
mod = new_module(modname, strlen(modname) - strlen(".o"));
+ mod->name_hash = crc32_le(0, mod->name, strlen(mod->name));
/* save .no_trim_symbol section for later use */
if (info.no_trim_symbol_len) {
@@ -1834,6 +1851,7 @@ static void add_header(struct buffer *b, struct module *mod)
buf_printf(b, "#include <linux/compiler.h>\n");
buf_printf(b, "\n");
buf_printf(b, "MODULE_INFO(name, KBUILD_MODNAME);\n");
+ buf_printf(b, "MODULE_INFO(name_crc, \"0x%08x\");\n", mod->name_hash);
buf_printf(b, "\n");
buf_printf(b, "__visible struct module __this_module\n");
buf_printf(b, "__section(\".gnu.linkonce.this_module\") = {\n");
diff --git a/scripts/mod/modpost.h b/scripts/mod/modpost.h
index 2aecb8f25c87..3fc3cfd0a039 100644
--- a/scripts/mod/modpost.h
+++ b/scripts/mod/modpost.h
@@ -11,11 +11,14 @@
#include <fcntl.h>
#include <unistd.h>
#include <elf.h>
+#include <stdint.h>
#include "../../include/linux/module_symbol.h"
#include <list_types.h>
#include "elfconfig.h"
+typedef uint32_t u32;
+
/* On BSD-alike OSes elf.h defines these according to host's word size */
#undef ELF_ST_BIND
#undef ELF_ST_TYPE
@@ -126,7 +129,8 @@ struct module {
bool seen;
bool has_init;
bool has_cleanup;
- char srcversion[25];
+ char srcversion[25];
+ u32 name_hash;
// Missing namespace dependencies
struct list_head missing_namespaces;
// Actual imported namespaces
--
2.52.0
^ permalink raw reply related
* Re: [PATCH v2 1/2] livepatch: Fix having __klp_objects relics in non-livepatch modules
From: Petr Pavlu @ 2026-01-22 8:34 UTC (permalink / raw)
To: Josh Poimboeuf
Cc: Jiri Kosina, Miroslav Benes, Petr Mladek, Joe Lawrence,
Luis Chamberlain, Daniel Gomez, Sami Tolvanen, Aaron Tomlin,
Peter Zijlstra, live-patching, linux-modules, linux-kernel
In-Reply-To: <okmrns5zlxqkwrou5rspq3zyakuv4gwwe4do7yovjbeaa5eajh@fud5amphpycu>
On 1/21/26 10:04 PM, Josh Poimboeuf wrote:
> On Wed, Jan 21, 2026 at 09:28:16AM +0100, Petr Pavlu wrote:
>> +void *klp_locate_section_objs(const struct module *mod, const char *name,
>> + size_t object_size, unsigned int *nr_objs)
>> +{
>> + struct klp_modinfo *info = mod->klp_info;
>> +
>> + for (int i = 1; i < info->hdr.e_shnum; i++) {
>> + Elf_Shdr *shdr = &info->sechdrs[i];
>> +
>> + if (strcmp(info->secstrings + shdr->sh_name, name))
>> + continue;
>> +
>> + *nr_objs = shdr->sh_size / object_size;
>> + return (void *)shdr->sh_addr;
>> + }
>> +
>> + *nr_objs = 0;
>> + return NULL;
>> +}
>> +EXPORT_SYMBOL_GPL(klp_locate_section_objs);
>
> How about we make it even more generic with something like
>
> void *klp_find_section_by_name(const struct module *mod, const char *name,
> size_t *sec_size);
>
> ?
>
> I think that would help the code read more clearly.
Ok, I'll update it.
--
Thanks,
Petr
^ permalink raw reply
* Re: [PATCH v2 0/2] gendwarfksyms: Document build dependencies
From: Nathan Chancellor @ 2026-01-22 0:00 UTC (permalink / raw)
To: Nathan Chancellor, Nicolas Schier, Jonathan Corbet, Miguel Ojeda,
Boqun Feng, Sami Tolvanen, Masahiro Yamada, Petr Pavlu, Jihan LIN
Cc: linux-modules, linux-kbuild, linux-doc, linux-kernel
In-Reply-To: <20260114-documents_gendwarfksyms-v2-0-297c98bd62c6@gmail.com>
On Wed, 14 Jan 2026 19:47:43 +0800, Jihan LIN wrote:
> I found there is no documentation for build dependencies in gendwarfksyms
> while digging into Rust drivers. Though Yuli added libdw-dev to the build
> dependencies for packaging [1], it seems that there is no documentation
> about it.
>
> This series documents the build dependencies of gendwarfksyms, adds a few
> examples for installing these dependencies on some distributions and
> introduces indentation style cleanup as suggested.
>
> [...]
Applied to
https://git.kernel.org/pub/scm/linux/kernel/git/kbuild/linux.git kbuild-next
Thanks!
[1/2] Documentation/kbuild: Document gendwarfksyms build dependencies
https://git.kernel.org/kbuild/c/983233ac2ef1b
[2/2] Documentation/kbuild: gendwarfksyms: Style cleanup
https://git.kernel.org/kbuild/c/301a02d405a3a
Please look out for regression or issue reports or other follow up
comments, as they may result in the patch/series getting dropped or
reverted. Patches applied to an "unstable" branch are accepted pending
wider testing in -next and any post-commit review; they will generally
be moved to the main branch in a week if no issues are found.
Best regards,
--
Nathan Chancellor <nathan@kernel.org>
^ permalink raw reply
* Re: [PATCH v2 1/2] Documentation/kbuild: Document gendwarfksyms build dependencies
From: Nathan Chancellor @ 2026-01-21 23:56 UTC (permalink / raw)
To: Petr Pavlu
Cc: linjh22s, Nicolas Schier, Jonathan Corbet, Miguel Ojeda,
Boqun Feng, Sami Tolvanen, Masahiro Yamada, linux-modules,
linux-kbuild, linux-doc, linux-kernel
In-Reply-To: <4d379736-9b6a-4e40-ad67-53ee7498759c@suse.com>
On Tue, Jan 20, 2026 at 01:17:48PM +0100, Petr Pavlu wrote:
> Nit: I suggest slightly adjusting the text to something like:
>
> """
> Gendwarfksyms depends on the libelf, libdw, and zlib libraries.
>
> Here are a few examples of how to install these dependencies:
> """
>
> .. and swap the items on the pacman line to 'libelf zlib' so the order
> is always libelf, libdw, zlib.
I applied the following diff to this change and applied these to
kbuild-next.
diff --git a/Documentation/kbuild/gendwarfksyms.rst b/Documentation/kbuild/gendwarfksyms.rst
index 0e153d13b052..c5e4617b4b41 100644
--- a/Documentation/kbuild/gendwarfksyms.rst
+++ b/Documentation/kbuild/gendwarfksyms.rst
@@ -17,13 +17,13 @@ details about the final module ABI.
Dependencies
------------
-libelf, libdw and zlib are dependencies of gendwarfksyms.
+gendwarfksyms depends on the libelf, libdw, and zlib libraries.
-Here are a few examples for installing these dependencies:
+Here are a few examples of how to install these dependencies:
* Arch Linux and derivatives::
- sudo pacman --needed -S zlib libelf
+ sudo pacman --needed -S libelf zlib
* Debian, Ubuntu, and derivatives::
^ permalink raw reply related
* [PATCH v14 5/5] modsign: Enable ML-DSA module signing
From: David Howells @ 2026-01-21 22:36 UTC (permalink / raw)
To: Lukas Wunner, Ignat Korchagin
Cc: David Howells, Jarkko Sakkinen, Herbert Xu, Eric Biggers,
Luis Chamberlain, Petr Pavlu, Daniel Gomez, Sami Tolvanen,
Jason A . Donenfeld, Ard Biesheuvel, Stephan Mueller,
linux-crypto, keyrings, linux-modules, linux-kernel
In-Reply-To: <20260121223609.1650735-1-dhowells@redhat.com>
Allow ML-DSA module signing to be enabled.
Note that OpenSSL's CMS_*() function suite does not, as of OpenSSL-3.6,
support the use of CMS_NOATTR with ML-DSA, so the prohibition against using
signedAttrs with module signing has to be removed. The selected digest
then applies only to the algorithm used to calculate the digest stored in
the messageDigest attribute. The OpenSSL development branch has patches
applied that fix this[1], but it appears that that will only be available
in OpenSSL-4.
[1] https://github.com/openssl/openssl/pull/28923
sign-file won't set CMS_NOATTR if openssl is earlier than v4, resulting in
the use of signed attributes.
The ML-DSA algorithm takes the raw data to be signed without regard to what
digest algorithm is specified in the CMS message. The CMS specified digest
algorithm is ignored unless signedAttrs are used; in such a case, only
SHA512 is permitted.
Signed-off-by: David Howells <dhowells@redhat.com>
cc: Eric Biggers <ebiggers@kernel.org>
cc: Lukas Wunner <lukas@wunner.de>
cc: Ignat Korchagin <ignat@cloudflare.com>
cc: Stephan Mueller <smueller@chronox.de>
cc: Herbert Xu <herbert@gondor.apana.org.au>
cc: keyrings@vger.kernel.org
cc: linux-crypto@vger.kernel.org
---
Documentation/admin-guide/module-signing.rst | 16 +++++----
certs/Kconfig | 30 +++++++++++++++++
certs/Makefile | 3 ++
crypto/asymmetric_keys/pkcs7_verify.c | 4 ---
scripts/sign-file.c | 34 +++++++++++++++-----
5 files changed, 68 insertions(+), 19 deletions(-)
diff --git a/Documentation/admin-guide/module-signing.rst b/Documentation/admin-guide/module-signing.rst
index a8667a777490..7f2f127dc76f 100644
--- a/Documentation/admin-guide/module-signing.rst
+++ b/Documentation/admin-guide/module-signing.rst
@@ -28,10 +28,12 @@ trusted userspace bits.
This facility uses X.509 ITU-T standard certificates to encode the public keys
involved. The signatures are not themselves encoded in any industrial standard
-type. The built-in facility currently only supports the RSA & NIST P-384 ECDSA
-public key signing standard (though it is pluggable and permits others to be
-used). The possible hash algorithms that can be used are SHA-2 and SHA-3 of
-sizes 256, 384, and 512 (the algorithm is selected by data in the signature).
+type. The built-in facility currently only supports the RSA, NIST P-384 ECDSA
+and NIST FIPS-204 ML-DSA public key signing standards (though it is pluggable
+and permits others to be used). For RSA and ECDSA, the possible hash
+algorithms that can be used are SHA-2 and SHA-3 of sizes 256, 384, and 512 (the
+algorithm is selected by data in the signature); ML-DSA does its own hashing,
+but is allowed to be used with a SHA512 hash for signed attributes.
==========================
@@ -146,9 +148,9 @@ into vmlinux) using parameters in the::
file (which is also generated if it does not already exist).
-One can select between RSA (``MODULE_SIG_KEY_TYPE_RSA``) and ECDSA
-(``MODULE_SIG_KEY_TYPE_ECDSA``) to generate either RSA 4k or NIST
-P-384 keypair.
+One can select between RSA (``MODULE_SIG_KEY_TYPE_RSA``), ECDSA
+(``MODULE_SIG_KEY_TYPE_ECDSA``) and ML-DSA (``MODULE_SIG_KEY_TYPE_MLDSA_*``) to
+generate an RSA 4k, a NIST P-384 keypair or an ML-DSA 44, 65 or 87 keypair.
It is strongly recommended that you provide your own x509.genkey file.
diff --git a/certs/Kconfig b/certs/Kconfig
index 78307dc25559..2b088ef58373 100644
--- a/certs/Kconfig
+++ b/certs/Kconfig
@@ -39,6 +39,36 @@ config MODULE_SIG_KEY_TYPE_ECDSA
Note: Remove all ECDSA signing keys, e.g. certs/signing_key.pem,
when falling back to building Linux 5.14 and older kernels.
+config MODULE_SIG_KEY_TYPE_MLDSA_44
+ bool "ML-DSA-44"
+ select CRYPTO_MLDSA
+ help
+ Use an ML-DSA-44 key (NIST FIPS 204) for module signing. ML-DSA
+ support requires OpenSSL-3.5 minimum; preferably OpenSSL-4+. With
+ the latter, the entire module body will be signed; with the former,
+ signedAttrs will be used as it lacks support for CMS_NOATTR with
+ ML-DSA.
+
+config MODULE_SIG_KEY_TYPE_MLDSA_65
+ bool "ML-DSA-65"
+ select CRYPTO_MLDSA
+ help
+ Use an ML-DSA-65 key (NIST FIPS 204) for module signing. ML-DSA
+ support requires OpenSSL-3.5 minimum; preferably OpenSSL-4+. With
+ the latter, the entire module body will be signed; with the former,
+ signedAttrs will be used as it lacks support for CMS_NOATTR with
+ ML-DSA.
+
+config MODULE_SIG_KEY_TYPE_MLDSA_87
+ bool "ML-DSA-87"
+ select CRYPTO_MLDSA
+ help
+ Use an ML-DSA-87 key (NIST FIPS 204) for module signing. ML-DSA
+ support requires OpenSSL-3.5 minimum; preferably OpenSSL-4+. With
+ the latter, the entire module body will be signed; with the former,
+ signedAttrs will be used as it lacks support for CMS_NOATTR with
+ ML-DSA.
+
endchoice
config SYSTEM_TRUSTED_KEYRING
diff --git a/certs/Makefile b/certs/Makefile
index f6fa4d8d75e0..3ee1960f9f4a 100644
--- a/certs/Makefile
+++ b/certs/Makefile
@@ -43,6 +43,9 @@ targets += x509_certificate_list
ifeq ($(CONFIG_MODULE_SIG_KEY),certs/signing_key.pem)
keytype-$(CONFIG_MODULE_SIG_KEY_TYPE_ECDSA) := -newkey ec -pkeyopt ec_paramgen_curve:secp384r1
+keytype-$(CONFIG_MODULE_SIG_KEY_TYPE_MLDSA_44) := -newkey ml-dsa-44
+keytype-$(CONFIG_MODULE_SIG_KEY_TYPE_MLDSA_65) := -newkey ml-dsa-65
+keytype-$(CONFIG_MODULE_SIG_KEY_TYPE_MLDSA_87) := -newkey ml-dsa-87
quiet_cmd_gen_key = GENKEY $@
cmd_gen_key = openssl req -new -nodes -utf8 -$(CONFIG_MODULE_SIG_HASH) -days 36500 \
diff --git a/crypto/asymmetric_keys/pkcs7_verify.c b/crypto/asymmetric_keys/pkcs7_verify.c
index a5b2ed4d53fd..75d1d694dc7b 100644
--- a/crypto/asymmetric_keys/pkcs7_verify.c
+++ b/crypto/asymmetric_keys/pkcs7_verify.c
@@ -431,10 +431,6 @@ int pkcs7_verify(struct pkcs7_message *pkcs7,
pr_warn("Invalid module sig (not pkcs7-data)\n");
return -EKEYREJECTED;
}
- if (pkcs7->have_authattrs) {
- pr_warn("Invalid module sig (has authattrs)\n");
- return -EKEYREJECTED;
- }
break;
case VERIFYING_FIRMWARE_SIGNATURE:
if (pkcs7->data_type != OID_data) {
diff --git a/scripts/sign-file.c b/scripts/sign-file.c
index 7070245edfc1..547b97097230 100644
--- a/scripts/sign-file.c
+++ b/scripts/sign-file.c
@@ -315,18 +315,36 @@ int main(int argc, char **argv)
ERR(!digest_algo, "EVP_get_digestbyname");
#ifndef USE_PKCS7
+
+ unsigned int flags =
+ CMS_NOCERTS |
+ CMS_PARTIAL |
+ CMS_BINARY |
+ CMS_DETACHED |
+ CMS_STREAM |
+ CMS_NOSMIMECAP |
+ CMS_NO_SIGNING_TIME |
+ use_keyid;
+
+ if ((EVP_PKEY_is_a(private_key, "ML-DSA-44") ||
+ EVP_PKEY_is_a(private_key, "ML-DSA-65") ||
+ EVP_PKEY_is_a(private_key, "ML-DSA-87")) &&
+ OPENSSL_VERSION_MAJOR < 4) {
+ /* ML-DSA + CMS_NOATTR is not supported in openssl-3.5
+ * and before.
+ */
+ use_signed_attrs = 0;
+ }
+
+ flags |= use_signed_attrs;
+
/* Load the signature message from the digest buffer. */
- cms = CMS_sign(NULL, NULL, NULL, NULL,
- CMS_NOCERTS | CMS_PARTIAL | CMS_BINARY |
- CMS_DETACHED | CMS_STREAM);
+ cms = CMS_sign(NULL, NULL, NULL, NULL, flags);
ERR(!cms, "CMS_sign");
- ERR(!CMS_add1_signer(cms, x509, private_key, digest_algo,
- CMS_NOCERTS | CMS_BINARY |
- CMS_NOSMIMECAP | use_keyid |
- use_signed_attrs),
+ ERR(!CMS_add1_signer(cms, x509, private_key, digest_algo, flags),
"CMS_add1_signer");
- ERR(CMS_final(cms, bm, NULL, CMS_NOCERTS | CMS_BINARY) != 1,
+ ERR(CMS_final(cms, bm, NULL, flags) != 1,
"CMS_final");
#else
^ permalink raw reply related
* [PATCH v14 4/5] pkcs7, x509: Add ML-DSA support
From: David Howells @ 2026-01-21 22:36 UTC (permalink / raw)
To: Lukas Wunner, Ignat Korchagin
Cc: David Howells, Jarkko Sakkinen, Herbert Xu, Eric Biggers,
Luis Chamberlain, Petr Pavlu, Daniel Gomez, Sami Tolvanen,
Jason A . Donenfeld, Ard Biesheuvel, Stephan Mueller,
linux-crypto, keyrings, linux-modules, linux-kernel
In-Reply-To: <20260121223609.1650735-1-dhowells@redhat.com>
Add support for ML-DSA keys and signatures to the CMS/PKCS#7 and X.509
implementations. ML-DSA-44, -65 and -87 are all supported. For X.509
certificates, the TBSCertificate is required to be signed directly; for CMS,
direct signing of the data is preferred, though use of SHA512 (and only that)
as an intermediate hash of the content is permitted with signedAttrs.
Signed-off-by: David Howells <dhowells@redhat.com>
cc: Lukas Wunner <lukas@wunner.de>
cc: Ignat Korchagin <ignat@cloudflare.com>
cc: Stephan Mueller <smueller@chronox.de>
cc: Eric Biggers <ebiggers@kernel.org>
cc: Herbert Xu <herbert@gondor.apana.org.au>
cc: keyrings@vger.kernel.org
cc: linux-crypto@vger.kernel.org
---
crypto/asymmetric_keys/pkcs7_parser.c | 24 +++++++++++++++++++-
crypto/asymmetric_keys/public_key.c | 10 +++++++++
crypto/asymmetric_keys/x509_cert_parser.c | 27 ++++++++++++++++++++++-
include/linux/oid_registry.h | 5 +++++
4 files changed, 64 insertions(+), 2 deletions(-)
diff --git a/crypto/asymmetric_keys/pkcs7_parser.c b/crypto/asymmetric_keys/pkcs7_parser.c
index 3cdbab3b9f50..594a8f1d9dfb 100644
--- a/crypto/asymmetric_keys/pkcs7_parser.c
+++ b/crypto/asymmetric_keys/pkcs7_parser.c
@@ -95,11 +95,18 @@ static int pkcs7_check_authattrs(struct pkcs7_message *msg)
if (sinfo->authattrs) {
want = true;
msg->have_authattrs = true;
+ } else if (sinfo->sig->algo_takes_data) {
+ sinfo->sig->hash_algo = "none";
}
- for (sinfo = sinfo->next; sinfo; sinfo = sinfo->next)
+ for (sinfo = sinfo->next; sinfo; sinfo = sinfo->next) {
if (!!sinfo->authattrs != want)
goto inconsistent;
+
+ if (!sinfo->authattrs &&
+ sinfo->sig->algo_takes_data)
+ sinfo->sig->hash_algo = "none";
+ }
return 0;
inconsistent:
@@ -297,6 +304,21 @@ int pkcs7_sig_note_pkey_algo(void *context, size_t hdrlen,
ctx->sinfo->sig->pkey_algo = "ecrdsa";
ctx->sinfo->sig->encoding = "raw";
break;
+ case OID_id_ml_dsa_44:
+ ctx->sinfo->sig->pkey_algo = "mldsa44";
+ ctx->sinfo->sig->encoding = "raw";
+ ctx->sinfo->sig->algo_takes_data = true;
+ break;
+ case OID_id_ml_dsa_65:
+ ctx->sinfo->sig->pkey_algo = "mldsa65";
+ ctx->sinfo->sig->encoding = "raw";
+ ctx->sinfo->sig->algo_takes_data = true;
+ break;
+ case OID_id_ml_dsa_87:
+ ctx->sinfo->sig->pkey_algo = "mldsa87";
+ ctx->sinfo->sig->encoding = "raw";
+ ctx->sinfo->sig->algo_takes_data = true;
+ break;
default:
printk("Unsupported pkey algo: %u\n", ctx->last_oid);
return -ENOPKG;
diff --git a/crypto/asymmetric_keys/public_key.c b/crypto/asymmetric_keys/public_key.c
index a46356e0c08b..09a0b83d5d77 100644
--- a/crypto/asymmetric_keys/public_key.c
+++ b/crypto/asymmetric_keys/public_key.c
@@ -142,6 +142,16 @@ software_key_determine_akcipher(const struct public_key *pkey,
if (strcmp(hash_algo, "streebog256") != 0 &&
strcmp(hash_algo, "streebog512") != 0)
return -EINVAL;
+ } else if (strcmp(pkey->pkey_algo, "mldsa44") == 0 ||
+ strcmp(pkey->pkey_algo, "mldsa65") == 0 ||
+ strcmp(pkey->pkey_algo, "mldsa87") == 0) {
+ if (strcmp(encoding, "raw") != 0)
+ return -EINVAL;
+ if (!hash_algo)
+ return -EINVAL;
+ if (strcmp(hash_algo, "none") != 0 &&
+ strcmp(hash_algo, "sha512") != 0)
+ return -EINVAL;
} else {
/* Unknown public key algorithm */
return -ENOPKG;
diff --git a/crypto/asymmetric_keys/x509_cert_parser.c b/crypto/asymmetric_keys/x509_cert_parser.c
index b37cae914987..2fe094f5caf3 100644
--- a/crypto/asymmetric_keys/x509_cert_parser.c
+++ b/crypto/asymmetric_keys/x509_cert_parser.c
@@ -257,6 +257,15 @@ int x509_note_sig_algo(void *context, size_t hdrlen, unsigned char tag,
case OID_gost2012Signature512:
ctx->cert->sig->hash_algo = "streebog512";
goto ecrdsa;
+ case OID_id_ml_dsa_44:
+ ctx->cert->sig->pkey_algo = "mldsa44";
+ goto ml_dsa;
+ case OID_id_ml_dsa_65:
+ ctx->cert->sig->pkey_algo = "mldsa65";
+ goto ml_dsa;
+ case OID_id_ml_dsa_87:
+ ctx->cert->sig->pkey_algo = "mldsa87";
+ goto ml_dsa;
}
rsa_pkcs1:
@@ -274,6 +283,12 @@ int x509_note_sig_algo(void *context, size_t hdrlen, unsigned char tag,
ctx->cert->sig->encoding = "x962";
ctx->sig_algo = ctx->last_oid;
return 0;
+ml_dsa:
+ ctx->cert->sig->algo_takes_data = true;
+ ctx->cert->sig->hash_algo = "none";
+ ctx->cert->sig->encoding = "raw";
+ ctx->sig_algo = ctx->last_oid;
+ return 0;
}
/*
@@ -300,7 +315,8 @@ int x509_note_signature(void *context, size_t hdrlen,
if (strcmp(ctx->cert->sig->pkey_algo, "rsa") == 0 ||
strcmp(ctx->cert->sig->pkey_algo, "ecrdsa") == 0 ||
- strcmp(ctx->cert->sig->pkey_algo, "ecdsa") == 0) {
+ strcmp(ctx->cert->sig->pkey_algo, "ecdsa") == 0 ||
+ strncmp(ctx->cert->sig->pkey_algo, "mldsa", 5) == 0) {
/* Discard the BIT STRING metadata */
if (vlen < 1 || *(const u8 *)value != 0)
return -EBADMSG;
@@ -524,6 +540,15 @@ int x509_extract_key_data(void *context, size_t hdrlen,
return -ENOPKG;
}
break;
+ case OID_id_ml_dsa_44:
+ ctx->cert->pub->pkey_algo = "mldsa44";
+ break;
+ case OID_id_ml_dsa_65:
+ ctx->cert->pub->pkey_algo = "mldsa65";
+ break;
+ case OID_id_ml_dsa_87:
+ ctx->cert->pub->pkey_algo = "mldsa87";
+ break;
default:
return -ENOPKG;
}
diff --git a/include/linux/oid_registry.h b/include/linux/oid_registry.h
index 6de479ebbe5d..ebce402854de 100644
--- a/include/linux/oid_registry.h
+++ b/include/linux/oid_registry.h
@@ -145,6 +145,11 @@ enum OID {
OID_id_rsassa_pkcs1_v1_5_with_sha3_384, /* 2.16.840.1.101.3.4.3.15 */
OID_id_rsassa_pkcs1_v1_5_with_sha3_512, /* 2.16.840.1.101.3.4.3.16 */
+ /* NIST FIPS-204 ML-DSA */
+ OID_id_ml_dsa_44, /* 2.16.840.1.101.3.4.3.17 */
+ OID_id_ml_dsa_65, /* 2.16.840.1.101.3.4.3.18 */
+ OID_id_ml_dsa_87, /* 2.16.840.1.101.3.4.3.19 */
+
OID__NR
};
^ permalink raw reply related
* [PATCH v14 3/5] pkcs7: Allow the signing algo to do whatever digestion it wants itself
From: David Howells @ 2026-01-21 22:36 UTC (permalink / raw)
To: Lukas Wunner, Ignat Korchagin
Cc: David Howells, Jarkko Sakkinen, Herbert Xu, Eric Biggers,
Luis Chamberlain, Petr Pavlu, Daniel Gomez, Sami Tolvanen,
Jason A . Donenfeld, Ard Biesheuvel, Stephan Mueller,
linux-crypto, keyrings, linux-modules, linux-kernel
In-Reply-To: <20260121223609.1650735-1-dhowells@redhat.com>
Allow the data to be verified in a PKCS#7 or CMS message to be passed
directly to an asymmetric cipher algorithm (e.g. ML-DSA) if it wants to do
whatever passes for hashing/digestion itself. The normal digestion of the
data is then skipped as that would be ignored unless another signed info in
the message has some other algorithm that needs it.
The 'data to be verified' may be the content of the PKCS#7 message or it
will be the authenticatedAttributes (signedAttrs if CMS), modified, if
those are present.
This is done by:
(1) Rename ->digest and ->digest_len to ->m and ->m_size to represent the
input to the signature verification algorithm, reflecting that
->digest may no longer actually *be* a digest.
(2) Make ->m and ->m_size point to the data to be verified rather than
making public_key_verify_signature() access the data directly. This
is so that keyctl(KEYCTL_PKEY_VERIFY) will still work.
(3) Add a flag, ->algo_takes_data, to indicate that the verification
algorithm wants to access the data to be verified directly rather than
having it digested first.
(4) If the PKCS#7 message has authenticatedAttributes (or CMS signedAtts),
then the digest contained therein will be validated as now, and the
modified attrs blob will either be digested or assigned to ->m as
appropriate.
(5) For ML-DSA, point ->m to the TBSCertificate instead of digesting it
and using the digest.
Note that whilst ML-DSA does allow for an "external mu", CMS doesn't yet
have that standardised.
Signed-off-by: David Howells <dhowells@redhat.com>
cc: Lukas Wunner <lukas@wunner.de>
cc: Ignat Korchagin <ignat@cloudflare.com>
cc: Stephan Mueller <smueller@chronox.de>
cc: Eric Biggers <ebiggers@kernel.org>
cc: Herbert Xu <herbert@gondor.apana.org.au>
cc: keyrings@vger.kernel.org
cc: linux-crypto@vger.kernel.org
---
crypto/asymmetric_keys/asymmetric_type.c | 4 +-
crypto/asymmetric_keys/pkcs7_parser.c | 4 +-
crypto/asymmetric_keys/pkcs7_verify.c | 79 ++++++++++++++++--------
crypto/asymmetric_keys/public_key.c | 3 +-
crypto/asymmetric_keys/signature.c | 3 +-
crypto/asymmetric_keys/x509_public_key.c | 19 ++++--
include/crypto/public_key.h | 6 +-
security/integrity/digsig_asymmetric.c | 4 +-
8 files changed, 79 insertions(+), 43 deletions(-)
diff --git a/crypto/asymmetric_keys/asymmetric_type.c b/crypto/asymmetric_keys/asymmetric_type.c
index 348966ea2175..2326743310b1 100644
--- a/crypto/asymmetric_keys/asymmetric_type.c
+++ b/crypto/asymmetric_keys/asymmetric_type.c
@@ -593,10 +593,10 @@ static int asymmetric_key_verify_signature(struct kernel_pkey_params *params,
{
struct public_key_signature sig = {
.s_size = params->in2_len,
- .digest_size = params->in_len,
+ .m_size = params->in_len,
.encoding = params->encoding,
.hash_algo = params->hash_algo,
- .digest = (void *)in,
+ .m = (void *)in,
.s = (void *)in2,
};
diff --git a/crypto/asymmetric_keys/pkcs7_parser.c b/crypto/asymmetric_keys/pkcs7_parser.c
index 423d13c47545..3cdbab3b9f50 100644
--- a/crypto/asymmetric_keys/pkcs7_parser.c
+++ b/crypto/asymmetric_keys/pkcs7_parser.c
@@ -599,8 +599,8 @@ int pkcs7_sig_note_set_of_authattrs(void *context, size_t hdrlen,
}
/* We need to switch the 'CONT 0' to a 'SET OF' when we digest */
- sinfo->authattrs = value - (hdrlen - 1);
- sinfo->authattrs_len = vlen + (hdrlen - 1);
+ sinfo->authattrs = value - hdrlen;
+ sinfo->authattrs_len = vlen + hdrlen;
return 0;
}
diff --git a/crypto/asymmetric_keys/pkcs7_verify.c b/crypto/asymmetric_keys/pkcs7_verify.c
index 6d6475e3a9bf..a5b2ed4d53fd 100644
--- a/crypto/asymmetric_keys/pkcs7_verify.c
+++ b/crypto/asymmetric_keys/pkcs7_verify.c
@@ -30,8 +30,18 @@ static int pkcs7_digest(struct pkcs7_message *pkcs7,
kenter(",%u,%s", sinfo->index, sinfo->sig->hash_algo);
+ if (!sinfo->authattrs && sig->algo_takes_data) {
+ /* There's no intermediate digest and the signature algo
+ * doesn't want the data prehashing.
+ */
+ sig->m = (void *)pkcs7->data;
+ sig->m_size = pkcs7->data_len;
+ sig->m_free = false;
+ return 0;
+ }
+
/* The digest was calculated already. */
- if (sig->digest)
+ if (sig->m)
return 0;
if (!sinfo->sig->hash_algo)
@@ -45,12 +55,13 @@ static int pkcs7_digest(struct pkcs7_message *pkcs7,
return (PTR_ERR(tfm) == -ENOENT) ? -ENOPKG : PTR_ERR(tfm);
desc_size = crypto_shash_descsize(tfm) + sizeof(*desc);
- sig->digest_size = crypto_shash_digestsize(tfm);
+ sig->m_size = crypto_shash_digestsize(tfm);
ret = -ENOMEM;
- sig->digest = kmalloc(sig->digest_size, GFP_KERNEL);
- if (!sig->digest)
+ sig->m = kmalloc(umax(sinfo->authattrs_len, sig->m_size), GFP_KERNEL);
+ if (!sig->m)
goto error_no_desc;
+ sig->m_free = true;
desc = kzalloc(desc_size, GFP_KERNEL);
if (!desc)
@@ -59,33 +70,30 @@ static int pkcs7_digest(struct pkcs7_message *pkcs7,
desc->tfm = tfm;
/* Digest the message [RFC2315 9.3] */
- ret = crypto_shash_digest(desc, pkcs7->data, pkcs7->data_len,
- sig->digest);
+ ret = crypto_shash_digest(desc, pkcs7->data, pkcs7->data_len, sig->m);
if (ret < 0)
goto error;
- pr_devel("MsgDigest = [%*ph]\n", 8, sig->digest);
+ pr_devel("MsgDigest = [%*ph]\n", 8, sig->m);
/* However, if there are authenticated attributes, there must be a
* message digest attribute amongst them which corresponds to the
* digest we just calculated.
*/
if (sinfo->authattrs) {
- u8 tag;
-
if (!sinfo->msgdigest) {
pr_warn("Sig %u: No messageDigest\n", sinfo->index);
ret = -EKEYREJECTED;
goto error;
}
- if (sinfo->msgdigest_len != sig->digest_size) {
+ if (sinfo->msgdigest_len != sig->m_size) {
pr_warn("Sig %u: Invalid digest size (%u)\n",
sinfo->index, sinfo->msgdigest_len);
ret = -EBADMSG;
goto error;
}
- if (memcmp(sig->digest, sinfo->msgdigest,
+ if (memcmp(sig->m, sinfo->msgdigest,
sinfo->msgdigest_len) != 0) {
pr_warn("Sig %u: Message digest doesn't match\n",
sinfo->index);
@@ -97,21 +105,33 @@ static int pkcs7_digest(struct pkcs7_message *pkcs7,
* as the contents of the digest instead. Note that we need to
* convert the attributes from a CONT.0 into a SET before we
* hash it.
+ *
+ * However, for certain algorithms, such as ML-DSA, the digest
+ * is integrated into the signing algorithm. In such a case,
+ * we copy the authattrs, modifying the tag type, and set that
+ * as the digest.
*/
- memset(sig->digest, 0, sig->digest_size);
-
- ret = crypto_shash_init(desc);
- if (ret < 0)
- goto error;
- tag = ASN1_CONS_BIT | ASN1_SET;
- ret = crypto_shash_update(desc, &tag, 1);
- if (ret < 0)
- goto error;
- ret = crypto_shash_finup(desc, sinfo->authattrs,
- sinfo->authattrs_len, sig->digest);
- if (ret < 0)
- goto error;
- pr_devel("AADigest = [%*ph]\n", 8, sig->digest);
+ if (sig->algo_takes_data) {
+ sig->m_size = sinfo->authattrs_len;
+ memcpy(sig->m, sinfo->authattrs, sinfo->authattrs_len);
+ sig->m[0] = ASN1_CONS_BIT | ASN1_SET;
+ ret = 0;
+ } else {
+ u8 tag = ASN1_CONS_BIT | ASN1_SET;
+
+ ret = crypto_shash_init(desc);
+ if (ret < 0)
+ goto error;
+ ret = crypto_shash_update(desc, &tag, 1);
+ if (ret < 0)
+ goto error;
+ ret = crypto_shash_finup(desc, sinfo->authattrs + 1,
+ sinfo->authattrs_len - 1,
+ sig->m);
+ if (ret < 0)
+ goto error;
+ }
+ pr_devel("AADigest = [%*ph]\n", 8, sig->m);
}
error:
@@ -137,9 +157,14 @@ int pkcs7_get_digest(struct pkcs7_message *pkcs7, const u8 **buf, u32 *len,
ret = pkcs7_digest(pkcs7, sinfo);
if (ret)
return ret;
+ if (!sinfo->sig->m_free) {
+ pr_notice_once("%s: No digest available\n", __func__);
+ return -EINVAL; /* TODO: MLDSA doesn't necessarily calculate an
+ * intermediate digest. */
+ }
- *buf = sinfo->sig->digest;
- *len = sinfo->sig->digest_size;
+ *buf = sinfo->sig->m;
+ *len = sinfo->sig->m_size;
i = match_string(hash_algo_name, HASH_ALGO__LAST,
sinfo->sig->hash_algo);
diff --git a/crypto/asymmetric_keys/public_key.c b/crypto/asymmetric_keys/public_key.c
index e5b177c8e842..a46356e0c08b 100644
--- a/crypto/asymmetric_keys/public_key.c
+++ b/crypto/asymmetric_keys/public_key.c
@@ -425,8 +425,7 @@ int public_key_verify_signature(const struct public_key *pkey,
if (ret)
goto error_free_key;
- ret = crypto_sig_verify(tfm, sig->s, sig->s_size,
- sig->digest, sig->digest_size);
+ ret = crypto_sig_verify(tfm, sig->s, sig->s_size, sig->m, sig->m_size);
error_free_key:
kfree_sensitive(key);
diff --git a/crypto/asymmetric_keys/signature.c b/crypto/asymmetric_keys/signature.c
index 041d04b5c953..a5ac7a53b670 100644
--- a/crypto/asymmetric_keys/signature.c
+++ b/crypto/asymmetric_keys/signature.c
@@ -28,7 +28,8 @@ void public_key_signature_free(struct public_key_signature *sig)
for (i = 0; i < ARRAY_SIZE(sig->auth_ids); i++)
kfree(sig->auth_ids[i]);
kfree(sig->s);
- kfree(sig->digest);
+ if (sig->m_free)
+ kfree(sig->m);
kfree(sig);
}
}
diff --git a/crypto/asymmetric_keys/x509_public_key.c b/crypto/asymmetric_keys/x509_public_key.c
index 6d002e3b20c5..27b4fea37845 100644
--- a/crypto/asymmetric_keys/x509_public_key.c
+++ b/crypto/asymmetric_keys/x509_public_key.c
@@ -50,6 +50,14 @@ int x509_get_sig_params(struct x509_certificate *cert)
sig->s_size = cert->raw_sig_size;
+ if (sig->algo_takes_data) {
+ /* The signature algorithm does whatever passes for hashing. */
+ sig->m = (u8 *)cert->tbs;
+ sig->m_size = cert->tbs_size;
+ sig->m_free = false;
+ goto out;
+ }
+
/* Allocate the hashing algorithm we're going to need and find out how
* big the hash operational data will be.
*/
@@ -63,12 +71,13 @@ int x509_get_sig_params(struct x509_certificate *cert)
}
desc_size = crypto_shash_descsize(tfm) + sizeof(*desc);
- sig->digest_size = crypto_shash_digestsize(tfm);
+ sig->m_size = crypto_shash_digestsize(tfm);
ret = -ENOMEM;
- sig->digest = kmalloc(sig->digest_size, GFP_KERNEL);
- if (!sig->digest)
+ sig->m = kmalloc(sig->m_size, GFP_KERNEL);
+ if (!sig->m)
goto error;
+ sig->m_free = true;
desc = kzalloc(desc_size, GFP_KERNEL);
if (!desc)
@@ -76,8 +85,7 @@ int x509_get_sig_params(struct x509_certificate *cert)
desc->tfm = tfm;
- ret = crypto_shash_digest(desc, cert->tbs, cert->tbs_size,
- sig->digest);
+ ret = crypto_shash_digest(desc, cert->tbs, cert->tbs_size, sig->m);
if (ret < 0)
goto error_2;
@@ -85,6 +93,7 @@ int x509_get_sig_params(struct x509_certificate *cert)
kfree(desc);
error:
crypto_free_shash(tfm);
+out:
pr_devel("<==%s() = %d\n", __func__, ret);
return ret;
}
diff --git a/include/crypto/public_key.h b/include/crypto/public_key.h
index 81098e00c08f..4c5199b20338 100644
--- a/include/crypto/public_key.h
+++ b/include/crypto/public_key.h
@@ -43,9 +43,11 @@ extern void public_key_free(struct public_key *key);
struct public_key_signature {
struct asymmetric_key_id *auth_ids[3];
u8 *s; /* Signature */
- u8 *digest;
+ u8 *m; /* Message data to pass to verifier */
u32 s_size; /* Number of bytes in signature */
- u32 digest_size; /* Number of bytes in digest */
+ u32 m_size; /* Number of bytes in ->m */
+ bool m_free; /* T if ->m needs freeing */
+ bool algo_takes_data; /* T if public key algo operates on data, not a hash */
const char *pkey_algo;
const char *hash_algo;
const char *encoding;
diff --git a/security/integrity/digsig_asymmetric.c b/security/integrity/digsig_asymmetric.c
index 457c0a396caf..87be85f477d1 100644
--- a/security/integrity/digsig_asymmetric.c
+++ b/security/integrity/digsig_asymmetric.c
@@ -121,8 +121,8 @@ int asymmetric_verify(struct key *keyring, const char *sig,
goto out;
}
- pks.digest = (u8 *)data;
- pks.digest_size = datalen;
+ pks.m = (u8 *)data;
+ pks.m_size = datalen;
pks.s = hdr->sig;
pks.s_size = siglen;
ret = verify_signature(key, &pks);
^ permalink raw reply related
* [PATCH v14 2/5] x509: Separately calculate sha256 for blacklist
From: David Howells @ 2026-01-21 22:36 UTC (permalink / raw)
To: Lukas Wunner, Ignat Korchagin
Cc: David Howells, Jarkko Sakkinen, Herbert Xu, Eric Biggers,
Luis Chamberlain, Petr Pavlu, Daniel Gomez, Sami Tolvanen,
Jason A . Donenfeld, Ard Biesheuvel, Stephan Mueller,
linux-crypto, keyrings, linux-modules, linux-kernel
In-Reply-To: <20260121223609.1650735-1-dhowells@redhat.com>
Calculate the SHA256 hash for blacklisting purposes independently of the
signature hash (which may be something other than SHA256).
This is necessary because when ML-DSA is used, no digest is calculated.
Note that this represents a change of behaviour in that the hash used for
the blacklist check would previously have been whatever digest was used
for, say, RSA-based signatures. It may be that this is inadvisable.
Signed-off-by: David Howells <dhowells@redhat.com>
cc: Lukas Wunner <lukas@wunner.de>
cc: Ignat Korchagin <ignat@cloudflare.com>
cc: Stephan Mueller <smueller@chronox.de>
cc: Eric Biggers <ebiggers@kernel.org>
cc: Herbert Xu <herbert@gondor.apana.org.au>
cc: keyrings@vger.kernel.org
cc: linux-crypto@vger.kernel.org
---
crypto/asymmetric_keys/x509_parser.h | 2 ++
crypto/asymmetric_keys/x509_public_key.c | 23 +++++++++++++----------
2 files changed, 15 insertions(+), 10 deletions(-)
diff --git a/crypto/asymmetric_keys/x509_parser.h b/crypto/asymmetric_keys/x509_parser.h
index 0688c222806b..b7aeebdddb36 100644
--- a/crypto/asymmetric_keys/x509_parser.h
+++ b/crypto/asymmetric_keys/x509_parser.h
@@ -9,12 +9,14 @@
#include <linux/time.h>
#include <crypto/public_key.h>
#include <keys/asymmetric-type.h>
+#include <crypto/sha2.h>
struct x509_certificate {
struct x509_certificate *next;
struct x509_certificate *signer; /* Certificate that signed this one */
struct public_key *pub; /* Public key details */
struct public_key_signature *sig; /* Signature parameters */
+ u8 sha256[SHA256_DIGEST_SIZE]; /* Hash for blacklist purposes */
char *issuer; /* Name of certificate issuer */
char *subject; /* Name of certificate subject */
struct asymmetric_key_id *id; /* Issuer + Serial number */
diff --git a/crypto/asymmetric_keys/x509_public_key.c b/crypto/asymmetric_keys/x509_public_key.c
index 12e3341e806b..6d002e3b20c5 100644
--- a/crypto/asymmetric_keys/x509_public_key.c
+++ b/crypto/asymmetric_keys/x509_public_key.c
@@ -31,6 +31,19 @@ int x509_get_sig_params(struct x509_certificate *cert)
pr_devel("==>%s()\n", __func__);
+ /* Calculate a SHA256 hash of the TBS and check it against the
+ * blacklist.
+ */
+ sha256(cert->tbs, cert->tbs_size, cert->sha256);
+ ret = is_hash_blacklisted(cert->sha256, sizeof(cert->sha256),
+ BLACKLIST_HASH_X509_TBS);
+ if (ret == -EKEYREJECTED) {
+ pr_err("Cert %*phN is blacklisted\n",
+ (int)sizeof(cert->sha256), cert->sha256);
+ cert->blacklisted = true;
+ ret = 0;
+ }
+
sig->s = kmemdup(cert->raw_sig, cert->raw_sig_size, GFP_KERNEL);
if (!sig->s)
return -ENOMEM;
@@ -65,19 +78,9 @@ int x509_get_sig_params(struct x509_certificate *cert)
ret = crypto_shash_digest(desc, cert->tbs, cert->tbs_size,
sig->digest);
-
if (ret < 0)
goto error_2;
- ret = is_hash_blacklisted(sig->digest, sig->digest_size,
- BLACKLIST_HASH_X509_TBS);
- if (ret == -EKEYREJECTED) {
- pr_err("Cert %*phN is blacklisted\n",
- sig->digest_size, sig->digest);
- cert->blacklisted = true;
- ret = 0;
- }
-
error_2:
kfree(desc);
error:
^ permalink raw reply related
* [PATCH v14 1/5] crypto: Add ML-DSA crypto_sig support
From: David Howells @ 2026-01-21 22:36 UTC (permalink / raw)
To: Lukas Wunner, Ignat Korchagin
Cc: David Howells, Jarkko Sakkinen, Herbert Xu, Eric Biggers,
Luis Chamberlain, Petr Pavlu, Daniel Gomez, Sami Tolvanen,
Jason A . Donenfeld, Ard Biesheuvel, Stephan Mueller,
linux-crypto, keyrings, linux-modules, linux-kernel
In-Reply-To: <20260121223609.1650735-1-dhowells@redhat.com>
Add verify-only public key crypto support for ML-DSA so that the
X.509/PKCS#7 signature verification code, as used by module signing,
amongst other things, can make use of it through the common crypto_sig API.
Signed-off-by: David Howells <dhowells@redhat.com>
Reviewed-by: Jarkko Sakkinen <jarkko@kernel.org>
cc: Eric Biggers <ebiggers@kernel.org>
cc: Lukas Wunner <lukas@wunner.de>
cc: Ignat Korchagin <ignat@cloudflare.com>
cc: Stephan Mueller <smueller@chronox.de>
cc: Herbert Xu <herbert@gondor.apana.org.au>
cc: keyrings@vger.kernel.org
cc: linux-crypto@vger.kernel.org
---
crypto/Kconfig | 9 +++
crypto/Makefile | 2 +
crypto/mldsa.c | 201 ++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 212 insertions(+)
create mode 100644 crypto/mldsa.c
diff --git a/crypto/Kconfig b/crypto/Kconfig
index 12a87f7cf150..a210575fa5e0 100644
--- a/crypto/Kconfig
+++ b/crypto/Kconfig
@@ -344,6 +344,15 @@ config CRYPTO_ECRDSA
One of the Russian cryptographic standard algorithms (called GOST
algorithms). Only signature verification is implemented.
+config CRYPTO_MLDSA
+ tristate "ML-DSA (Module-Lattice-Based Digital Signature Algorithm)"
+ select CRYPTO_SIG
+ select CRYPTO_LIB_MLDSA
+ help
+ ML-DSA (Module-Lattice-Based Digital Signature Algorithm) (FIPS-204).
+
+ Only signature verification is implemented.
+
endmenu
menu "Block ciphers"
diff --git a/crypto/Makefile b/crypto/Makefile
index 23d3db7be425..267d5403045b 100644
--- a/crypto/Makefile
+++ b/crypto/Makefile
@@ -60,6 +60,8 @@ ecdsa_generic-y += ecdsa-p1363.o
ecdsa_generic-y += ecdsasignature.asn1.o
obj-$(CONFIG_CRYPTO_ECDSA) += ecdsa_generic.o
+obj-$(CONFIG_CRYPTO_MLDSA) += mldsa.o
+
crypto_acompress-y := acompress.o
crypto_acompress-y += scompress.o
obj-$(CONFIG_CRYPTO_ACOMP2) += crypto_acompress.o
diff --git a/crypto/mldsa.c b/crypto/mldsa.c
new file mode 100644
index 000000000000..d8de082cc67a
--- /dev/null
+++ b/crypto/mldsa.c
@@ -0,0 +1,201 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * crypto_sig wrapper around ML-DSA library.
+ */
+#include <linux/init.h>
+#include <linux/module.h>
+#include <crypto/internal/sig.h>
+#include <crypto/mldsa.h>
+
+struct crypto_mldsa_ctx {
+ u8 pk[MAX(MAX(MLDSA44_PUBLIC_KEY_SIZE,
+ MLDSA65_PUBLIC_KEY_SIZE),
+ MLDSA87_PUBLIC_KEY_SIZE)];
+ unsigned int pk_len;
+ enum mldsa_alg strength;
+ bool key_set;
+};
+
+static int crypto_mldsa_sign(struct crypto_sig *tfm,
+ const void *msg, unsigned int msg_len,
+ void *sig, unsigned int sig_len)
+{
+ return -EOPNOTSUPP;
+}
+
+static int crypto_mldsa_verify(struct crypto_sig *tfm,
+ const void *sig, unsigned int sig_len,
+ const void *msg, unsigned int msg_len)
+{
+ const struct crypto_mldsa_ctx *ctx = crypto_sig_ctx(tfm);
+
+ if (unlikely(!ctx->key_set))
+ return -EINVAL;
+
+ return mldsa_verify(ctx->strength, sig, sig_len, msg, msg_len,
+ ctx->pk, ctx->pk_len);
+}
+
+static unsigned int crypto_mldsa_key_size(struct crypto_sig *tfm)
+{
+ struct crypto_mldsa_ctx *ctx = crypto_sig_ctx(tfm);
+
+ switch (ctx->strength) {
+ case MLDSA44:
+ return MLDSA44_PUBLIC_KEY_SIZE;
+ case MLDSA65:
+ return MLDSA65_PUBLIC_KEY_SIZE;
+ case MLDSA87:
+ return MLDSA87_PUBLIC_KEY_SIZE;
+ default:
+ WARN_ON_ONCE(1);
+ return 0;
+ }
+}
+
+static int crypto_mldsa_set_pub_key(struct crypto_sig *tfm,
+ const void *key, unsigned int keylen)
+{
+ struct crypto_mldsa_ctx *ctx = crypto_sig_ctx(tfm);
+ unsigned int expected_len = crypto_mldsa_key_size(tfm);
+
+ if (keylen != expected_len)
+ return -EINVAL;
+
+ ctx->pk_len = keylen;
+ memcpy(ctx->pk, key, keylen);
+ ctx->key_set = true;
+ return 0;
+}
+
+static int crypto_mldsa_set_priv_key(struct crypto_sig *tfm,
+ const void *key, unsigned int keylen)
+{
+ return -EOPNOTSUPP;
+}
+
+static unsigned int crypto_mldsa_max_size(struct crypto_sig *tfm)
+{
+ struct crypto_mldsa_ctx *ctx = crypto_sig_ctx(tfm);
+
+ switch (ctx->strength) {
+ case MLDSA44:
+ return MLDSA44_SIGNATURE_SIZE;
+ case MLDSA65:
+ return MLDSA65_SIGNATURE_SIZE;
+ case MLDSA87:
+ return MLDSA87_SIGNATURE_SIZE;
+ default:
+ WARN_ON_ONCE(1);
+ return 0;
+ }
+}
+
+static int crypto_mldsa44_alg_init(struct crypto_sig *tfm)
+{
+ struct crypto_mldsa_ctx *ctx = crypto_sig_ctx(tfm);
+
+ ctx->strength = MLDSA44;
+ ctx->key_set = false;
+ return 0;
+}
+
+static int crypto_mldsa65_alg_init(struct crypto_sig *tfm)
+{
+ struct crypto_mldsa_ctx *ctx = crypto_sig_ctx(tfm);
+
+ ctx->strength = MLDSA65;
+ ctx->key_set = false;
+ return 0;
+}
+
+static int crypto_mldsa87_alg_init(struct crypto_sig *tfm)
+{
+ struct crypto_mldsa_ctx *ctx = crypto_sig_ctx(tfm);
+
+ ctx->strength = MLDSA87;
+ ctx->key_set = false;
+ return 0;
+}
+
+static void crypto_mldsa_alg_exit(struct crypto_sig *tfm)
+{
+}
+
+static struct sig_alg crypto_mldsa_algs[] = {
+ {
+ .sign = crypto_mldsa_sign,
+ .verify = crypto_mldsa_verify,
+ .set_pub_key = crypto_mldsa_set_pub_key,
+ .set_priv_key = crypto_mldsa_set_priv_key,
+ .key_size = crypto_mldsa_key_size,
+ .max_size = crypto_mldsa_max_size,
+ .init = crypto_mldsa44_alg_init,
+ .exit = crypto_mldsa_alg_exit,
+ .base.cra_name = "mldsa44",
+ .base.cra_driver_name = "mldsa44-lib",
+ .base.cra_ctxsize = sizeof(struct crypto_mldsa_ctx),
+ .base.cra_module = THIS_MODULE,
+ .base.cra_priority = 5000,
+ }, {
+ .sign = crypto_mldsa_sign,
+ .verify = crypto_mldsa_verify,
+ .set_pub_key = crypto_mldsa_set_pub_key,
+ .set_priv_key = crypto_mldsa_set_priv_key,
+ .key_size = crypto_mldsa_key_size,
+ .max_size = crypto_mldsa_max_size,
+ .init = crypto_mldsa65_alg_init,
+ .exit = crypto_mldsa_alg_exit,
+ .base.cra_name = "mldsa65",
+ .base.cra_driver_name = "mldsa65-lib",
+ .base.cra_ctxsize = sizeof(struct crypto_mldsa_ctx),
+ .base.cra_module = THIS_MODULE,
+ .base.cra_priority = 5000,
+ }, {
+ .sign = crypto_mldsa_sign,
+ .verify = crypto_mldsa_verify,
+ .set_pub_key = crypto_mldsa_set_pub_key,
+ .set_priv_key = crypto_mldsa_set_priv_key,
+ .key_size = crypto_mldsa_key_size,
+ .max_size = crypto_mldsa_max_size,
+ .init = crypto_mldsa87_alg_init,
+ .exit = crypto_mldsa_alg_exit,
+ .base.cra_name = "mldsa87",
+ .base.cra_driver_name = "mldsa87-lib",
+ .base.cra_ctxsize = sizeof(struct crypto_mldsa_ctx),
+ .base.cra_module = THIS_MODULE,
+ .base.cra_priority = 5000,
+ },
+};
+
+static int __init mldsa_init(void)
+{
+ int ret, i;
+
+ for (i = 0; i < ARRAY_SIZE(crypto_mldsa_algs); i++) {
+ ret = crypto_register_sig(&crypto_mldsa_algs[i]);
+ if (ret < 0)
+ goto error;
+ }
+ return 0;
+
+error:
+ pr_err("Failed to register (%d)\n", ret);
+ for (i--; i >= 0; i--)
+ crypto_unregister_sig(&crypto_mldsa_algs[i]);
+ return ret;
+}
+module_init(mldsa_init);
+
+static void mldsa_exit(void)
+{
+ for (int i = 0; i < ARRAY_SIZE(crypto_mldsa_algs); i++)
+ crypto_unregister_sig(&crypto_mldsa_algs[i]);
+}
+module_exit(mldsa_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Crypto API support for ML-DSA signature verification");
+MODULE_ALIAS_CRYPTO("mldsa44");
+MODULE_ALIAS_CRYPTO("mldsa65");
+MODULE_ALIAS_CRYPTO("mldsa87");
^ permalink raw reply related
* [PATCH v14 0/5] x509, pkcs7, crypto: Add ML-DSA and RSASSA-PSS signing
From: David Howells @ 2026-01-21 22:36 UTC (permalink / raw)
To: Lukas Wunner, Ignat Korchagin
Cc: David Howells, Jarkko Sakkinen, Herbert Xu, Eric Biggers,
Luis Chamberlain, Petr Pavlu, Daniel Gomez, Sami Tolvanen,
Jason A . Donenfeld, Ard Biesheuvel, Stephan Mueller,
linux-crypto, keyrings, linux-modules, linux-kernel
Hi Lukas, Ignat,
[Note this is based on Eric Bigger's libcrypto-next branch].
These patches add ML-DSA module signing and RSASSA-PSS module signing. The
first half of the set adds ML-DSA signing:
(1) Add a crypto_sig interface for ML-DSA, verification only.
(2) Modify PKCS#7 support to allow kernel module signatures to carry
authenticatedAttributes as OpenSSL refuses to let them be opted out of
for ML-DSA (CMS_NOATTR). This adds an extra digest calculation to the
process.
Modify PKCS#7 to pass the authenticatedAttributes directly to the
ML-DSA algorithm rather than passing over a digest as is done with RSA
as ML-DSA wants to do its own hashing and will add other stuff into
the hash. We could use hashML-DSA or an external mu instead, but they
aren't standardised for CMS yet.
(3) Add support to the PKCS#7 and X.509 parsers for ML-DSA.
(4) Modify sign-file to handle OpenSSL not permitting CMS_NOATTR with
ML-DSA and add ML-DSA to the choice of algorithm with which to sign
modules. Note that this might need some more 'select' lines in the
Kconfig to select the lib stuff as well.
This is based on Eric's libcrypto-next branch which has the core
implementation of ML-DSA.
The second half of the set adds RSASSA-PSS signing:
(5) Add an info string parameter to the internal signature verification
routines where that does not already exist. This is necessary to pass
extra parameters and is already supported in the KEYCTL_PKEY_VERIFY
keyctl.
Both X.509 and PKCS#7 provide for these parameters to be supplied, but
it is tricky to pass the parameters in a blob with the signature or
key data as there are checks on these sizes that are then violated;
further, the way the parameters are laid out in the ASN.1 doesn't lend
itself easily to simply extracting out a larger blob.
(6) Add RSASSA-PSS support to the RSA driver in crypto/. This parses the
info string to get the verification parameters.
(7) Add support to the PKCS#7 and X.509 parsers for RSASSA-PSS.
(8) Modify sign-file to pass the extra parameters necessary to be able
generate RSASSA-PSS. For the moment, only select MGF1 with the same
hash algorithm as for the data for the mask function. Add RSASSA-PSS
to the choice of algorithm with which to sign modules.
Note that I do still need to add some FIPS tests for ML-DSA in the form of
X.509 certs, data and detached PKCS#7 signatures. I'm not sure if I can
use FIPS-standard tests for that.
The patches can also be found here:
https://git.kernel.org/pub/scm/linux/kernel/git/dhowells/linux-fs.git/log/?h=keys-pqc
David
Changes
=======
ver #14)
- public_key:
- Rename public_key::digest to public_key::m.
- X.509:
- Independently calculate the SHA256 hash for the blacklist check as
an ML-DSA-signed X.509 cert doesn't generate a digest we can use.
- Point public_key::m at the TBS data for ML-DSA.
- PKCS#7:
- Allocate a big enough digest buffer rather than reallocating in order
to store the authattrs/signedattrs instead.
- Merge the two patches that add direct signing support.
- ML-DSA:
- Use bool instead of u8.
- Remove references to SHAKE in Kconfig and mention OpenSSL requirements
there.
- Limit ML-DSA with an intermediate hash (e.g. signedAttrs) to using
SHA512 only.
- Don't select CRYPTO_LIB_SHA3 for CRYPTO_MLDSA.
- RSASSA-PSS:
- Allow use with SHA256 and SHA384.
- Fix calculation of emBits to be number of bits in the RSA modulus 'n'.
- Use strncmp() not memcmp() to avoid reading beyond end of string.
- Use correct destructor in rsassa_params_parse().
- Drop this algo for the moment.
- Drop the pefile_context::digest_free for now - it's only set to true and
is unrelated to public_key::digest_free.
ver #13)
- Allow a zero-length salt in RSASSA-PSS.
- Don't reject ECDSA/ECRDSA with SHA256 and SHA384 otherwise the FIPS
selftest panics when used.
- Add a FIPS test for RSASSA-PSS (from NIST's SigVerPSS_186-3.rsp).
- Add a FIPS test for ML-DSA (from NIST's FIPS204 JSON set).
ver #12)
- Rebased on Eric's libcrypto-next branch.
- Delete references to Dilithium (ML-DSA derived from this).
- Made sign-file supply CMS_NOATTR for ML-DSA if openssl >= v4.
- Made it possible to do ML-DSA over the data without signedAttrs.
- Made RSASSA-PSS info parser use strsep() and match_token().
- Cleaned the RSASSA-PSS param parsing.
- Added limitation on what hashes can be used with what algos.
- Moved __free()-marked variables to the point of setting.
ver #11)
- Rebased on Eric's libcrypto-next branch.
- Added RSASSA-PSS support patches.
ver #10)
- Replaced the Leancrypto ML-DSA implementation with Eric's.
- Fixed Eric's implementation to have MODULE_* info.
- Added a patch to drive Eric's ML-DSA implementation from crypto_sig.
- Removed SHAKE256 from the list of available module hash algorithms.
- Changed a some more ML_DSA to MLDSA in config symbols.
ver #9)
- ML-DSA changes:
- Separate output into four modules (1 common, 3 strength-specific).
- Solves Kconfig issue with needing to select at least one strength.
- Separate the strength-specific crypto-lib APIs.
- This is now generated by preprocessor-templating.
- Remove the multiplexor code.
- Multiplex the crypto-lib APIs by C type.
- Fix the PKCS#7/X.509 code to have the correct algo names.
ver #8)
- Moved the ML-DSA code to lib/crypto/mldsa/.
- Renamed some bits from ml-dsa to mldsa.
- Created a simplified API and placed that in include/crypto/mldsa.h.
- Made the testing code use the simplified API.
- Fixed a warning about implicitly casting between uint16_t and __le16.
ver #7)
- Rebased on Eric's tree as that now contains all the necessary SHA-3
infrastructure and drop the SHA-3 patches from here.
- Added a minimal patch to provide shake256 support for crypto_sig.
- Got rid of the memory allocation wrappers.
- Removed the ML-DSA keypair generation code and the signing code, leaving
only the signature verification code.
- Removed the secret key handling code.
- Removed the secret keys from the kunit tests and the signing testing.
- Removed some unused bits from the ML-DSA code.
- Downgraded the kdoc comments to ordinary comments, but keep the markup
for easier comparison to Leancrypto.
ver #6)
- Added a patch to make the jitterentropy RNG use lib/sha3.
- Added back the crypto/sha3_generic changes.
- Added ML-DSA implementation (still needs more cleanup).
- Added kunit test for ML-DSA.
- Modified PKCS#7 to accommodate ML-DSA.
- Modified PKCS#7 and X.509 to allow ML-DSA to be specified and used.
- Modified sign-file to not use CMS_NOATTR with ML-DSA.
- Allowed SHA3 and SHAKE* algorithms for module signing default.
- Allowed ML-DSA-{44,65,87} to be selected as the module signing default.
ver #5)
- Fix gen-hash-testvecs.py to correctly handle algo names that contain a
dash.
- Fix gen-hash-testvecs.py to not generate HMAC for SHA3-* or SHAKE* as
these don't currently have HMAC variants implemented.
- Fix algo names to be correct.
- Fix kunit module description as it now tests all SHA3 variants.
ver #4)
- Fix a couple of arm64 build problems.
- Doc fixes:
- Fix the description of the algorithm to be closer to the NIST spec's
terminology.
- Don't talk of finialising the context for XOFs.
- Don't say "Return: None".
- Declare the "Context" to be "Any context" and make no mention of the
fact that it might use the FPU.
- Change "initialise" to "initialize".
- Don't warn that the context is relatively large for stack use.
- Use size_t for size parameters/variables.
- Make the module_exit unconditional.
- Dropped the crypto/ dir-affecting patches for the moment.
ver #3)
- Renamed conflicting arm64 functions.
- Made a separate wrapper API for each algorithm in the family.
- Removed sha3_init(), sha3_reinit() and sha3_final().
- Removed sha3_ctx::digest_size.
- Renamed sha3_ctx::partial to sha3_ctx::absorb_offset.
- Refer to the output of SHAKE* as "output" not "digest".
- Moved the Iota transform into the one-round function.
- Made sha3_update() warn if called after sha3_squeeze().
- Simplified the module-load test to not do update after squeeze.
- Added Return: and Context: kdoc statements and expanded the kdoc
headers.
- Added an API description document.
- Overhauled the kunit tests.
- Only have one kunit test.
- Only call the general hash tester on one algo.
- Add separate simple cursory checks for the other algos.
- Add resqueezing tests.
- Add some NIST example tests.
- Changed crypto/sha3_generic to use this
- Added SHAKE128/256 to crypto/sha3_generic and crypto/testmgr
- Folded struct sha3_state into struct sha3_ctx.
ver #2)
- Simplify the endianness handling.
- Rename sha3_final() to sha3_squeeze() and don't clear the context at the
end as it's permitted to continue calling sha3_final() to extract
continuations of the digest (needed by ML-DSA).
- Don't reapply the end marker to the hash state in continuation
sha3_squeeze() unless sha3_update() gets called again (needed by
ML-DSA).
- Give sha3_squeeze() the amount of digest to produce as a parameter
rather than using ctx->digest_size and don't return the amount digested.
- Reimplement sha3_final() as a wrapper around sha3_squeeze() that
extracts ctx->digest_size amount of digest and then zeroes out the
context. The latter is necessary to avoid upsetting
hash-test-template.h.
- Provide a sha3_reinit() function to clear the state, but to leave the
parameters that indicate the hash properties unaffected, allowing for
reuse.
- Provide a sha3_set_digestsize() function to change the size of the
digest to be extracted by sha3_final(). sha3_squeeze() takes a
parameter for this instead.
- Don't pass the digest size as a parameter to shake128/256_init() but
rather default to 128/256 bits as per the function name.
- Provide a sha3_clear() function to zero out the context.
David Howells (5):
crypto: Add ML-DSA crypto_sig support
x509: Separately calculate sha256 for blacklist
pkcs7: Allow the signing algo to do whatever digestion it wants itself
pkcs7, x509: Add ML-DSA support
modsign: Enable ML-DSA module signing
Documentation/admin-guide/module-signing.rst | 16 +-
certs/Kconfig | 30 +++
certs/Makefile | 3 +
crypto/Kconfig | 9 +
crypto/Makefile | 2 +
crypto/asymmetric_keys/asymmetric_type.c | 4 +-
crypto/asymmetric_keys/pkcs7_parser.c | 28 ++-
crypto/asymmetric_keys/pkcs7_verify.c | 83 +++++---
crypto/asymmetric_keys/public_key.c | 13 +-
crypto/asymmetric_keys/signature.c | 3 +-
crypto/asymmetric_keys/x509_cert_parser.c | 27 ++-
crypto/asymmetric_keys/x509_parser.h | 2 +
crypto/asymmetric_keys/x509_public_key.c | 42 ++--
crypto/mldsa.c | 201 +++++++++++++++++++
include/crypto/public_key.h | 6 +-
include/linux/oid_registry.h | 5 +
scripts/sign-file.c | 34 +++-
security/integrity/digsig_asymmetric.c | 4 +-
18 files changed, 438 insertions(+), 74 deletions(-)
create mode 100644 crypto/mldsa.c
^ permalink raw reply
* Re: [PATCH v2 1/2] livepatch: Fix having __klp_objects relics in non-livepatch modules
From: Josh Poimboeuf @ 2026-01-21 21:04 UTC (permalink / raw)
To: Petr Pavlu
Cc: Jiri Kosina, Miroslav Benes, Petr Mladek, Joe Lawrence,
Luis Chamberlain, Daniel Gomez, Sami Tolvanen, Aaron Tomlin,
Peter Zijlstra, live-patching, linux-modules, linux-kernel
In-Reply-To: <20260121082842.3050453-2-petr.pavlu@suse.com>
On Wed, Jan 21, 2026 at 09:28:16AM +0100, Petr Pavlu wrote:
> +void *klp_locate_section_objs(const struct module *mod, const char *name,
> + size_t object_size, unsigned int *nr_objs)
> +{
> + struct klp_modinfo *info = mod->klp_info;
> +
> + for (int i = 1; i < info->hdr.e_shnum; i++) {
> + Elf_Shdr *shdr = &info->sechdrs[i];
> +
> + if (strcmp(info->secstrings + shdr->sh_name, name))
> + continue;
> +
> + *nr_objs = shdr->sh_size / object_size;
> + return (void *)shdr->sh_addr;
> + }
> +
> + *nr_objs = 0;
> + return NULL;
> +}
> +EXPORT_SYMBOL_GPL(klp_locate_section_objs);
How about we make it even more generic with something like
void *klp_find_section_by_name(const struct module *mod, const char *name,
size_t *sec_size);
?
I think that would help the code read more clearly.
--
Josh
^ permalink raw reply
* Re: [PATCH v5 0/6] Unload linux/kernel.h
From: Steven Rostedt @ 2026-01-21 14:53 UTC (permalink / raw)
To: Yury Norov, Andrew Morton
Cc: Andy Shevchenko, Masami Hiramatsu, Mathieu Desnoyers,
Christophe Leroy, Randy Dunlap, Ingo Molnar, Jani Nikula,
Joonas Lahtinen, David Laight, Petr Pavlu, Andi Shyti,
Rodrigo Vivi, Tvrtko Ursulin, Daniel Gomez, Greg Kroah-Hartman,
Rafael J. Wysocki, Danilo Krummrich, Joel Fernandes, linux-kernel,
intel-gfx, dri-devel, linux-modules, linux-trace-kernel,
Yury Norov (NVIDIA)
In-Reply-To: <aWpwHbrvQ2MMGgH-@yury>
On Fri, 16 Jan 2026 12:06:37 -0500
Yury Norov <ynorov@nvidia.com> wrote:
> > Thanks! Which tree should it go through?
>
> Andrew or Steven maybe? As a last resort, I can move it myself.
I think it makes the most sense for Andrew to take it.
Thanks,
-- Steve
^ permalink raw reply
* Re: [PATCH v13 05/12] modsign: Enable ML-DSA module signing
From: David Howells @ 2026-01-21 14:21 UTC (permalink / raw)
To: Eric Biggers
Cc: dhowells, Lukas Wunner, Ignat Korchagin, Jarkko Sakkinen,
Herbert Xu, Luis Chamberlain, Petr Pavlu, Daniel Gomez,
Sami Tolvanen, Jason A . Donenfeld, Ard Biesheuvel,
Stephan Mueller, linux-crypto, keyrings, linux-modules,
linux-kernel
In-Reply-To: <20260120213820.GD2657@quark>
Eric Biggers <ebiggers@kernel.org> wrote:
> If OpenSSL 3.5 is the last version that doesn't support the noattr case,
> that would mean that OpenSSL 3.6 does support it, right? OpenSSL 3.6
> was released several months ago. Yet the above code requires version 4.
3.5 and 3.6 support ML-DSA, but not with CMS_NOATTR, so I need to update this.
Version 4 will support ML-DSA with CMS_NOATTR, but that's not yet tagged.
> How about we just support the new way only? That would be simpler, and
> it sounds like it's already supported by the latest OpenSSL.
Depends what you mean by "latest OpenSSL". Latest in git, yes; latest in
distributions that people can simply install as an rpm/deb/etc., no.
Now, assuming OpenSSL releases v4 sometime in the spring, I would probably be
fine with saying you have to have OpenSSL v4 if you want ML-DSA; but others
might have a different opinion.
David
^ permalink raw reply
* Re: [PATCH v13 02/12] pkcs7: Allow the signing algo to calculate the digest itself
From: David Howells @ 2026-01-21 12:31 UTC (permalink / raw)
To: Jarkko Sakkinen
Cc: dhowells, Lukas Wunner, Ignat Korchagin, Herbert Xu, Eric Biggers,
Luis Chamberlain, Petr Pavlu, Daniel Gomez, Sami Tolvanen,
Jason A . Donenfeld, Ard Biesheuvel, Stephan Mueller,
linux-crypto, keyrings, linux-modules, linux-kernel
In-Reply-To: <aW_BAchcx2_TXASz@kernel.org>
Jarkko Sakkinen <jarkko@kernel.org> wrote:
> I'd use the wording you used already in commit message, which
> factors more descriptive than what you have here. E.g., name
> it "external_digest".
ML-DSA uses "external" to mean that the caller does the
digestion/hashing/XOF-ing/whatever Eric wants to call it, but the caller also
has to put other stuff into the digest/hash/XOF/thing that then gets passed to
ML-DSA if it does this.
For added confusion, the NIST FIPS tests seem to consider what this patch does
as 'external' but an "external mu" as 'internal':
"tgId": 1,
"testType": "AFT",
"parameterSet": "ML-DSA-44",
"signatureInterface": "external",
"preHash": "pure",
vs:
"tgId": 7,
"testType": "AFT",
"parameterSet": "ML-DSA-44",
"signatureInterface": "internal",
"externalMu": true,
I haven't come up with a better name that particularly describes this. Maybe
use "no_prehash" or "algo_takes_hash" or "algo_takes_data"?
Maybe better than using a true/false value, use an enum?
enum public_key_hash {
ALGO_SIGNS_HASH, /* RSA, ECDSA, ... */
ALGO_SIGNS_DATA, /* MLDSA, ... */
};
David
^ permalink raw reply
* [PATCH v2 2/2] livepatch: Free klp_{object,func}_ext data after initialization
From: Petr Pavlu @ 2026-01-21 8:28 UTC (permalink / raw)
To: Josh Poimboeuf, Jiri Kosina, Miroslav Benes, Petr Mladek,
Joe Lawrence
Cc: Luis Chamberlain, Petr Pavlu, Daniel Gomez, Sami Tolvanen,
Aaron Tomlin, Peter Zijlstra, live-patching, linux-modules,
linux-kernel
In-Reply-To: <20260121082842.3050453-1-petr.pavlu@suse.com>
The klp_object_ext and klp_func_ext data, which are stored in the
__klp_objects and __klp_funcs sections, respectively, are not needed
after they are used to create the actual klp_object and klp_func
instances. This operation is implemented by the init function in
scripts/livepatch/init.c.
Prefix the two sections with ".init" so they are freed after the module
is initializated.
Signed-off-by: Petr Pavlu <petr.pavlu@suse.com>
Acked-by: Joe Lawrence <joe.lawrence@redhat.com>
---
scripts/livepatch/init.c | 2 +-
scripts/module.lds.S | 4 ++--
tools/objtool/check.c | 2 +-
tools/objtool/include/objtool/klp.h | 10 +++++-----
tools/objtool/klp-diff.c | 2 +-
5 files changed, 10 insertions(+), 10 deletions(-)
diff --git a/scripts/livepatch/init.c b/scripts/livepatch/init.c
index a02252e1de03..3e658db5dfe8 100644
--- a/scripts/livepatch/init.c
+++ b/scripts/livepatch/init.c
@@ -18,7 +18,7 @@ static int __init livepatch_mod_init(void)
unsigned int nr_objs;
int ret;
- obj_exts = klp_locate_section_objs(THIS_MODULE, "__klp_objects",
+ obj_exts = klp_locate_section_objs(THIS_MODULE, ".init.klp_objects",
sizeof(*obj_exts), &nr_objs);
if (!nr_objs) {
pr_err("nothing to patch!\n");
diff --git a/scripts/module.lds.S b/scripts/module.lds.S
index 383d19beffb4..054ef99e8288 100644
--- a/scripts/module.lds.S
+++ b/scripts/module.lds.S
@@ -34,8 +34,8 @@ SECTIONS {
__patchable_function_entries : { *(__patchable_function_entries) }
- __klp_funcs 0: ALIGN(8) { KEEP(*(__klp_funcs)) }
- __klp_objects 0: ALIGN(8) { KEEP(*(__klp_objects)) }
+ .init.klp_funcs 0 : ALIGN(8) { KEEP(*(.init.klp_funcs)) }
+ .init.klp_objects 0 : ALIGN(8) { KEEP(*(.init.klp_objects)) }
#ifdef CONFIG_ARCH_USES_CFI_TRAPS
__kcfi_traps : { KEEP(*(.kcfi_traps)) }
diff --git a/tools/objtool/check.c b/tools/objtool/check.c
index 3f7999317f4d..933868ee3beb 100644
--- a/tools/objtool/check.c
+++ b/tools/objtool/check.c
@@ -4761,7 +4761,7 @@ static int validate_ibt(struct objtool_file *file)
!strcmp(sec->name, "__bug_table") ||
!strcmp(sec->name, "__ex_table") ||
!strcmp(sec->name, "__jump_table") ||
- !strcmp(sec->name, "__klp_funcs") ||
+ !strcmp(sec->name, ".init.klp_funcs") ||
!strcmp(sec->name, "__mcount_loc") ||
!strcmp(sec->name, ".llvm.call-graph-profile") ||
!strcmp(sec->name, ".llvm_bb_addr_map") ||
diff --git a/tools/objtool/include/objtool/klp.h b/tools/objtool/include/objtool/klp.h
index ad830a7ce55b..e32e5e8bc631 100644
--- a/tools/objtool/include/objtool/klp.h
+++ b/tools/objtool/include/objtool/klp.h
@@ -6,12 +6,12 @@
#define SHN_LIVEPATCH 0xff20
/*
- * __klp_objects and __klp_funcs are created by klp diff and used by the patch
- * module init code to build the klp_patch, klp_object and klp_func structs
- * needed by the livepatch API.
+ * .init.klp_objects and .init.klp_funcs are created by klp diff and used by the
+ * patch module init code to build the klp_patch, klp_object and klp_func
+ * structs needed by the livepatch API.
*/
-#define KLP_OBJECTS_SEC "__klp_objects"
-#define KLP_FUNCS_SEC "__klp_funcs"
+#define KLP_OBJECTS_SEC ".init.klp_objects"
+#define KLP_FUNCS_SEC ".init.klp_funcs"
/*
* __klp_relocs is an intermediate section which are created by klp diff and
diff --git a/tools/objtool/klp-diff.c b/tools/objtool/klp-diff.c
index 4d1f9e9977eb..fd64d5e3c3b6 100644
--- a/tools/objtool/klp-diff.c
+++ b/tools/objtool/klp-diff.c
@@ -1439,7 +1439,7 @@ static int clone_special_sections(struct elfs *e)
}
/*
- * Create __klp_objects and __klp_funcs sections which are intermediate
+ * Create .init.klp_objects and .init.klp_funcs sections which are intermediate
* sections provided as input to the patch module's init code for building the
* klp_patch, klp_object and klp_func structs for the livepatch API.
*/
--
2.52.0
^ permalink raw reply related
* [PATCH v2 1/2] livepatch: Fix having __klp_objects relics in non-livepatch modules
From: Petr Pavlu @ 2026-01-21 8:28 UTC (permalink / raw)
To: Josh Poimboeuf, Jiri Kosina, Miroslav Benes, Petr Mladek,
Joe Lawrence
Cc: Luis Chamberlain, Petr Pavlu, Daniel Gomez, Sami Tolvanen,
Aaron Tomlin, Peter Zijlstra, live-patching, linux-modules,
linux-kernel
In-Reply-To: <20260121082842.3050453-1-petr.pavlu@suse.com>
The linker script scripts/module.lds.S specifies that all input
__klp_objects sections should be consolidated into an output section of
the same name, and start/stop symbols should be created to enable
scripts/livepatch/init.c to locate this data.
This start/stop pattern is not ideal for modules because the symbols are
created even if no __klp_objects input sections are present.
Consequently, a dummy __klp_objects section also appears in the
resulting module. This unnecessarily pollutes non-livepatch modules.
Instead, since modules are relocatable files, the usual method for
locating consolidated data in a module is to read its section table.
This approach avoids the aforementioned problem.
The klp_modinfo already stores a copy of the entire section table with
the final addresses. Introduce a helper function that
scripts/livepatch/init.c can call to obtain the location of the
__klp_objects section from this data.
Signed-off-by: Petr Pavlu <petr.pavlu@suse.com>
Acked-by: Joe Lawrence <joe.lawrence@redhat.com>
---
include/linux/livepatch.h | 3 +++
kernel/livepatch/core.c | 20 ++++++++++++++++++++
scripts/livepatch/init.c | 18 +++++++-----------
scripts/module.lds.S | 7 +------
4 files changed, 31 insertions(+), 17 deletions(-)
diff --git a/include/linux/livepatch.h b/include/linux/livepatch.h
index 772919e8096a..0a663e5911f4 100644
--- a/include/linux/livepatch.h
+++ b/include/linux/livepatch.h
@@ -175,6 +175,9 @@ int klp_enable_patch(struct klp_patch *);
int klp_module_coming(struct module *mod);
void klp_module_going(struct module *mod);
+void *klp_locate_section_objs(const struct module *mod, const char *name,
+ size_t object_size, unsigned int *nr_objs);
+
void klp_copy_process(struct task_struct *child);
void klp_update_patch_state(struct task_struct *task);
diff --git a/kernel/livepatch/core.c b/kernel/livepatch/core.c
index 9917756dae46..85925abfca0f 100644
--- a/kernel/livepatch/core.c
+++ b/kernel/livepatch/core.c
@@ -1356,6 +1356,26 @@ void klp_module_going(struct module *mod)
mutex_unlock(&klp_mutex);
}
+void *klp_locate_section_objs(const struct module *mod, const char *name,
+ size_t object_size, unsigned int *nr_objs)
+{
+ struct klp_modinfo *info = mod->klp_info;
+
+ for (int i = 1; i < info->hdr.e_shnum; i++) {
+ Elf_Shdr *shdr = &info->sechdrs[i];
+
+ if (strcmp(info->secstrings + shdr->sh_name, name))
+ continue;
+
+ *nr_objs = shdr->sh_size / object_size;
+ return (void *)shdr->sh_addr;
+ }
+
+ *nr_objs = 0;
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(klp_locate_section_objs);
+
static int __init klp_init(void)
{
klp_root_kobj = kobject_create_and_add("livepatch", kernel_kobj);
diff --git a/scripts/livepatch/init.c b/scripts/livepatch/init.c
index 2274d8f5a482..a02252e1de03 100644
--- a/scripts/livepatch/init.c
+++ b/scripts/livepatch/init.c
@@ -9,19 +9,17 @@
#include <linux/slab.h>
#include <linux/livepatch.h>
-extern struct klp_object_ext __start_klp_objects[];
-extern struct klp_object_ext __stop_klp_objects[];
-
static struct klp_patch *patch;
static int __init livepatch_mod_init(void)
{
+ struct klp_object_ext *obj_exts;
struct klp_object *objs;
unsigned int nr_objs;
int ret;
- nr_objs = __stop_klp_objects - __start_klp_objects;
-
+ obj_exts = klp_locate_section_objs(THIS_MODULE, "__klp_objects",
+ sizeof(*obj_exts), &nr_objs);
if (!nr_objs) {
pr_err("nothing to patch!\n");
ret = -EINVAL;
@@ -41,7 +39,7 @@ static int __init livepatch_mod_init(void)
}
for (int i = 0; i < nr_objs; i++) {
- struct klp_object_ext *obj_ext = __start_klp_objects + i;
+ struct klp_object_ext *obj_ext = obj_exts + i;
struct klp_func_ext *funcs_ext = obj_ext->funcs;
unsigned int nr_funcs = obj_ext->nr_funcs;
struct klp_func *funcs = objs[i].funcs;
@@ -90,12 +88,10 @@ static int __init livepatch_mod_init(void)
static void __exit livepatch_mod_exit(void)
{
- unsigned int nr_objs;
-
- nr_objs = __stop_klp_objects - __start_klp_objects;
+ struct klp_object *obj;
- for (int i = 0; i < nr_objs; i++)
- kfree(patch->objs[i].funcs);
+ klp_for_each_object_static(patch, obj)
+ kfree(obj->funcs);
kfree(patch->objs);
kfree(patch);
diff --git a/scripts/module.lds.S b/scripts/module.lds.S
index 3037d5e5527c..383d19beffb4 100644
--- a/scripts/module.lds.S
+++ b/scripts/module.lds.S
@@ -35,12 +35,7 @@ SECTIONS {
__patchable_function_entries : { *(__patchable_function_entries) }
__klp_funcs 0: ALIGN(8) { KEEP(*(__klp_funcs)) }
-
- __klp_objects 0: ALIGN(8) {
- __start_klp_objects = .;
- KEEP(*(__klp_objects))
- __stop_klp_objects = .;
- }
+ __klp_objects 0: ALIGN(8) { KEEP(*(__klp_objects)) }
#ifdef CONFIG_ARCH_USES_CFI_TRAPS
__kcfi_traps : { KEEP(*(.kcfi_traps)) }
--
2.52.0
^ permalink raw reply related
* [PATCH v2 0/2] Improve handling of the __klp_{objects,funcs} sections in modules
From: Petr Pavlu @ 2026-01-21 8:28 UTC (permalink / raw)
To: Josh Poimboeuf, Jiri Kosina, Miroslav Benes, Petr Mladek,
Joe Lawrence
Cc: Luis Chamberlain, Petr Pavlu, Daniel Gomez, Sami Tolvanen,
Aaron Tomlin, Peter Zijlstra, live-patching, linux-modules,
linux-kernel
Changes since v1 [1]:
- Generalize the helper function that locates __klp_objects in a module
to allow it to find objects in other sections as well.
[1] https://lore.kernel.org/linux-modules/20260114123056.2045816-1-petr.pavlu@suse.com/
Petr Pavlu (2):
livepatch: Fix having __klp_objects relics in non-livepatch modules
livepatch: Free klp_{object,func}_ext data after initialization
include/linux/livepatch.h | 3 +++
kernel/livepatch/core.c | 20 ++++++++++++++++++++
scripts/livepatch/init.c | 18 +++++++-----------
scripts/module.lds.S | 9 ++-------
tools/objtool/check.c | 2 +-
tools/objtool/include/objtool/klp.h | 10 +++++-----
tools/objtool/klp-diff.c | 2 +-
7 files changed, 39 insertions(+), 25 deletions(-)
base-commit: 0f61b1860cc3f52aef9036d7235ed1f017632193
--
2.52.0
^ permalink raw reply
* Re: [PATCH v13 07/12] crypto: Add RSASSA-PSS support
From: Ignat Korchagin @ 2026-01-21 8:15 UTC (permalink / raw)
To: Eric Biggers
Cc: David Howells, Lukas Wunner, Jarkko Sakkinen, Herbert Xu,
Luis Chamberlain, Petr Pavlu, Daniel Gomez, Sami Tolvanen,
Jason A . Donenfeld, Ard Biesheuvel, Stephan Mueller,
linux-crypto, keyrings, linux-modules, linux-kernel,
Tadeusz Struk, David S. Miller
In-Reply-To: <20260121021413.GA998999@google.com>
On Wed, Jan 21, 2026 at 2:14 AM Eric Biggers <ebiggers@kernel.org> wrote:
>
> On Tue, Jan 20, 2026 at 02:41:11PM -0800, Eric Biggers wrote:
> > On Tue, Jan 20, 2026 at 02:50:53PM +0000, David Howells wrote:
> > > Add support for RSASSA-PSS [RFC8017 sec 8.1] signature verification support
> > > to the RSA driver in crypto/.
> >
> > This additional feature significantly increases the scope of your
> > patchset, especially considering that the kernel previously didn't
> > implement RSASSA-PSS at all. This patchset also doesn't include any
I just wanted to point out that RSASSA-PSS "existed" as supported in
kernel documentation [1] for quite a while now. So it is a matter of
actually fixing "the bug" of it not being implemented as it should
have been from UAPI perspective
> > explanation for why this additional feature is needed. It might make
> > sense to add this feature, but it needs to be properly explained, and it
> > would be preferable for it to be its own patchset.
This does seems reasonable to separate ML-DSA and RSASSA-PSS into
separate patchsets
> > > The verification function requires an info string formatted as a
> > > space-separated list of key=value pairs. The following parameters need to
> > > be provided:
> > >
> > > (1) sighash=<algo>
> > >
> > > The hash algorithm to be used to digest the data.
> > >
> > > (2) pss_mask=<type>,...
> > >
> > > The mask generation function (MGF) and its parameters.
> > >
> > > (3) pss_salt=<len>
> > >
> > > The length of the salt used.
> > >
> > > The only MGF currently supported is "mgf1". This takes an additional
> > > parameter indicating the mask-generating hash (which need not be the same
> > > as the data hash). E.g.:
> > >
> > > "sighash=sha256 pss_mask=mgf1,sha256 pss_salt=32"
> >
> > One of the issues with RSASSA-PSS is the excessive flexibility in the
> > parameters, which often end up being attacker controlled. Therefore
> > many implementations of RSASSA-PSS restrict the allowed parameters to
> > something reasonable, e.g. restricting the allowed hash algorithms,
> > requiring the two hash algorithms to be the same, and requiring the salt
> > size to match the digest size. We should do likewise if possible.
>
> Looking into this a bit more, I'm increasingly skeptical that RSASSA-PSS
> would be a worthwhile addition, especially when integrated into CMS and
> X.509. It seems that while in theory it's an improvement over PKCS#1
> v1.5 padding, the specifications were messed up and it has way too many
> unnecessary and error-prone parameters. Here are some references that
> describe some of the issues in RSASSA-PSS:
>
> * https://boringssl-review.googlesource.com/c/boringssl/+/81656
> * https://www.metzdowd.com/pipermail/cryptography/2019-November/035449.html
>
> It seems it might not be very widely used either.
>
> I think the fact that this patchset implements RSASSA-PSS verification
> incorrectly (by not verifying that the leading bit is zero) further
> validates these concerns.
>
> With RSA also being two generations behind the current generation of
> signature algorithms (RSA => elliptic curves => lattices), I'm wondering
> what the motivation for this feature is.
>
> - Eric
[1]: https://docs.kernel.org/security/keys/core.html
^ permalink raw reply
* Re: [PATCH v13 07/12] crypto: Add RSASSA-PSS support
From: Ignat Korchagin @ 2026-01-21 8:11 UTC (permalink / raw)
To: Eric Biggers
Cc: David Howells, Lukas Wunner, Jarkko Sakkinen, Herbert Xu,
Luis Chamberlain, Petr Pavlu, Daniel Gomez, Sami Tolvanen,
Jason A . Donenfeld, Ard Biesheuvel, Stephan Mueller,
linux-crypto, keyrings, linux-modules, linux-kernel,
Tadeusz Struk, David S. Miller
In-Reply-To: <20260120233617.GA10653@quark>
On Tue, Jan 20, 2026 at 11:36 PM Eric Biggers <ebiggers@kernel.org> wrote:
>
> On Tue, Jan 20, 2026 at 11:15:57PM +0000, David Howells wrote:
> > Eric Biggers <ebiggers@kernel.org> wrote:
> >
> > > As I mentioned in another reply, error-prone string parsing isn't a
> > > great choice. C has native support for function parameters.
> >
> > But is constrained that it has to work with KEYCTL_PKEY_VERIFY's info
> > parameter.
>
> The cover letter of this patchset summarizes it as "These patches add
> ML-DSA module signing and RSASSA-PSS module signing." Adding
> KEYCTL_PKEY_VERIFY support for these algorithms would be a significant
> new UAPI feature that would need its own justification and its own
> documentation and test updates.
>
> However, it was established pretty clearly in past discussions that
> KEYCTL_PKEY_* are a mistake and basically exist only for backwards
> compatibility with iwd.
I disagree that it was "established". It is some folks opinion here,
but I find it quite useful and hope it would be actually extended by
good algorithm support.
> So I don't understand why you're advocating for adding new features to
> them.
>
> - Eric
^ permalink raw reply
* Re: [PATCH v13 07/12] crypto: Add RSASSA-PSS support
From: Eric Biggers @ 2026-01-21 2:14 UTC (permalink / raw)
To: David Howells
Cc: Lukas Wunner, Ignat Korchagin, Jarkko Sakkinen, Herbert Xu,
Luis Chamberlain, Petr Pavlu, Daniel Gomez, Sami Tolvanen,
Jason A . Donenfeld, Ard Biesheuvel, Stephan Mueller,
linux-crypto, keyrings, linux-modules, linux-kernel,
Tadeusz Struk, David S. Miller
In-Reply-To: <20260120224108.GC6191@quark>
On Tue, Jan 20, 2026 at 02:41:11PM -0800, Eric Biggers wrote:
> On Tue, Jan 20, 2026 at 02:50:53PM +0000, David Howells wrote:
> > Add support for RSASSA-PSS [RFC8017 sec 8.1] signature verification support
> > to the RSA driver in crypto/.
>
> This additional feature significantly increases the scope of your
> patchset, especially considering that the kernel previously didn't
> implement RSASSA-PSS at all. This patchset also doesn't include any
> explanation for why this additional feature is needed. It might make
> sense to add this feature, but it needs to be properly explained, and it
> would be preferable for it to be its own patchset.
>
> > The verification function requires an info string formatted as a
> > space-separated list of key=value pairs. The following parameters need to
> > be provided:
> >
> > (1) sighash=<algo>
> >
> > The hash algorithm to be used to digest the data.
> >
> > (2) pss_mask=<type>,...
> >
> > The mask generation function (MGF) and its parameters.
> >
> > (3) pss_salt=<len>
> >
> > The length of the salt used.
> >
> > The only MGF currently supported is "mgf1". This takes an additional
> > parameter indicating the mask-generating hash (which need not be the same
> > as the data hash). E.g.:
> >
> > "sighash=sha256 pss_mask=mgf1,sha256 pss_salt=32"
>
> One of the issues with RSASSA-PSS is the excessive flexibility in the
> parameters, which often end up being attacker controlled. Therefore
> many implementations of RSASSA-PSS restrict the allowed parameters to
> something reasonable, e.g. restricting the allowed hash algorithms,
> requiring the two hash algorithms to be the same, and requiring the salt
> size to match the digest size. We should do likewise if possible.
Looking into this a bit more, I'm increasingly skeptical that RSASSA-PSS
would be a worthwhile addition, especially when integrated into CMS and
X.509. It seems that while in theory it's an improvement over PKCS#1
v1.5 padding, the specifications were messed up and it has way too many
unnecessary and error-prone parameters. Here are some references that
describe some of the issues in RSASSA-PSS:
* https://boringssl-review.googlesource.com/c/boringssl/+/81656
* https://www.metzdowd.com/pipermail/cryptography/2019-November/035449.html
It seems it might not be very widely used either.
I think the fact that this patchset implements RSASSA-PSS verification
incorrectly (by not verifying that the leading bit is zero) further
validates these concerns.
With RSA also being two generations behind the current generation of
signature algorithms (RSA => elliptic curves => lattices), I'm wondering
what the motivation for this feature is.
- Eric
^ permalink raw reply
* Re: [PATCH v12 06/10] crypto: Add supplementary info param to asymmetric key signature verification
From: Eric Biggers @ 2026-01-21 0:06 UTC (permalink / raw)
To: David Howells
Cc: Lukas Wunner, Ignat Korchagin, Jarkko Sakkinen, Herbert Xu,
Luis Chamberlain, Petr Pavlu, Daniel Gomez, Sami Tolvanen,
Jason A . Donenfeld, Ard Biesheuvel, Stephan Mueller,
linux-crypto, keyrings, linux-modules, linux-kernel,
David S. Miller
In-Reply-To: <1418295.1768952386@warthog.procyon.org.uk>
On Tue, Jan 20, 2026 at 11:39:46PM +0000, David Howells wrote:
> Eric Biggers <ebiggers@kernel.org> wrote:
>
> > As I'm sure you're aware, C has native support for function parameters.
>
> And we have a syscall interface to honour that takes a parameter string *for
> this very purpose*. It just wasn't threaded into the akcipher API.
This seems to be more of a bug than a feature, though. It seems the
actual goals of this patchset are to add ML-DSA and RSASSA-PSS support
to kernel module signing. But because of how the code is organized, as
a side effect it ended up extending the KEYCTL_PKEY_* UAPIs as well.
Linux's UAPI stability guarantee holds for these UAPIs; anything that we
add to them, including these ad-hoc and undocumented parameter strings,
will likely have to be supported forever.
Unless these keyctl UAPI extensions are well-justified and come with
documentation and tests, we should just hold off on them for now.
What's the hurry?
BTW, we got hit by this when there was an attempt to remove SHA-1
support from module signing. Due to the design defect where the signing
is also exposed through KEYCTL_PKEY_*, it caused a UAPI regression as
well and had to be reverted.
- Eric
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox