public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
From: Petr Pavlu <petr.pavlu@suse.com>
To: "Thomas Weißschuh" <linux@weissschuh.net>
Cc: "Nathan Chancellor" <nathan@kernel.org>,
	"Arnd Bergmann" <arnd@arndb.de>,
	"Luis Chamberlain" <mcgrof@kernel.org>,
	"Sami Tolvanen" <samitolvanen@google.com>,
	"Daniel Gomez" <da.gomez@samsung.com>,
	"Paul Moore" <paul@paul-moore.com>,
	"James Morris" <jmorris@namei.org>,
	"Serge E. Hallyn" <serge@hallyn.com>,
	"Jonathan Corbet" <corbet@lwn.net>,
	"Madhavan Srinivasan" <maddy@linux.ibm.com>,
	"Michael Ellerman" <mpe@ellerman.id.au>,
	"Nicholas Piggin" <npiggin@gmail.com>,
	"Naveen N Rao" <naveen@kernel.org>,
	"Mimi Zohar" <zohar@linux.ibm.com>,
	"Roberto Sassu" <roberto.sassu@huawei.com>,
	"Dmitry Kasatkin" <dmitry.kasatkin@gmail.com>,
	"Eric Snowberg" <eric.snowberg@oracle.com>,
	"Nicolas Schier" <nicolas.schier@linux.dev>,
	"Daniel Gomez" <da.gomez@kernel.org>,
	"Aaron Tomlin" <atomlin@atomlin.com>,
	"Christophe Leroy (CS GROUP)" <chleroy@kernel.org>,
	"Nicolas Schier" <nsc@kernel.org>,
	"Nicolas Bouchinet" <nicolas.bouchinet@oss.cyber.gouv.fr>,
	"Xiu Jianfeng" <xiujianfeng@huawei.com>,
	"Fabian Grünbichler" <f.gruenbichler@proxmox.com>,
	"Arnout Engelen" <arnout@bzzt.net>,
	"Mattia Rizzolo" <mattia@mapreri.org>,
	kpcyrd <kpcyrd@archlinux.org>,
	"Christian Heusel" <christian@heusel.eu>,
	"Câju Mihai-Drosi" <mcaju95@gmail.com>,
	"Sebastian Andrzej Siewior" <bigeasy@linutronix.de>,
	linux-kbuild@vger.kernel.org, linux-kernel@vger.kernel.org,
	linux-arch@vger.kernel.org, linux-modules@vger.kernel.org,
	linux-security-module@vger.kernel.org, linux-doc@vger.kernel.org,
	linuxppc-dev@lists.ozlabs.org, linux-integrity@vger.kernel.org
Subject: Re: [PATCH v4 15/17] module: Introduce hash-based integrity checking
Date: Tue, 3 Feb 2026 13:19:20 +0100	[thread overview]
Message-ID: <fab2af64-e396-45f9-8876-feff4002e04b@suse.com> (raw)
In-Reply-To: <20260113-module-hashes-v4-15-0b932db9b56b@weissschuh.net>

On 1/13/26 1:28 PM, Thomas Weißschuh wrote:
> The current signature-based module integrity checking has some drawbacks
> in combination with reproducible builds. Either the module signing key
> is generated at build time, which makes the build unreproducible, or a
> static signing key is used, which precludes rebuilds by third parties
> and makes the whole build and packaging process much more complicated.
> 
> The goal is to reach bit-for-bit reproducibility. Excluding certain
> parts of the build output from the reproducibility analysis would be
> error-prone and force each downstream consumer to introduce new tooling.
> 
> Introduce a new mechanism to ensure only well-known modules are loaded
> by embedding a merkle tree root of all modules built as part of the full
> kernel build into vmlinux.
> 
> Non-builtin modules can be validated as before through signatures.
> 
> Normally the .ko module files depend on a fully built vmlinux to be
> available for modpost validation and BTF generation. With
> CONFIG_MODULE_HASHES, vmlinux now depends on the modules
> to build a merkle tree. This introduces a dependency cycle which is
> impossible to satisfy. Work around this by building the modules during
> link-vmlinux.sh, after vmlinux is complete enough for modpost and BTF
> but before the final module hashes are
> 
> The PKCS7 format which is used for regular module signatures can not
> represent Merkle proofs, so a new kind of module signature is
> introduced. As this signature type is only ever used for builtin
> modules, no compatibility issues can arise.

Nit: The description uses the term "builtin modules" in a misleading
way. Typically, "builtin modules" refers to modules that are linked
directly into vmlinux. However, this text uses the term to refer to
loadable modules that are built together with the main kernel image,
which is something different.

> diff --git a/scripts/modules-merkle-tree.c b/scripts/modules-merkle-tree.c
> new file mode 100644
> index 000000000000..a6ec0e21213b
> --- /dev/null
> +++ b/scripts/modules-merkle-tree.c
> @@ -0,0 +1,467 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * Compute hashes for modules files and build a merkle tree.
> + *
> + * Copyright (C) 2025 Sebastian Andrzej Siewior <sebastian@breakpoint.cc>
> + * Copyright (C) 2025 Thomas Weißschuh <linux@weissschuh.net>
> + *
> + */
> +#define _GNU_SOURCE 1
> +#include <arpa/inet.h>
> +#include <err.h>
> +#include <unistd.h>
> +#include <fcntl.h>
> +#include <stdarg.h>
> +#include <stdio.h>
> +#include <string.h>
> +#include <stdbool.h>
> +#include <stdlib.h>
> +
> +#include <sys/stat.h>
> +#include <sys/mman.h>
> +
> +#include <openssl/evp.h>
> +#include <openssl/err.h>
> +
> +#include "ssl-common.h"
> +
> +static int hash_size;
> +static EVP_MD_CTX *ctx;
> +
> +struct module_signature {
> +	uint8_t		algo;		/* Public-key crypto algorithm [0] */
> +	uint8_t		hash;		/* Digest algorithm [0] */
> +	uint8_t		id_type;	/* Key identifier type [PKEY_ID_PKCS7] */
> +	uint8_t		signer_len;	/* Length of signer's name [0] */
> +	uint8_t		key_id_len;	/* Length of key identifier [0] */
> +	uint8_t		__pad[3];
> +	uint32_t	sig_len;	/* Length of signature data */
> +};
> +
> +#define PKEY_ID_MERKLE 3
> +
> +static const char magic_number[] = "~Module signature appended~\n";

It might make sense to put these common structures into a file under
scripts/include/ so they can be shared by both scripts/sign-file.c and
scripts/modules-merkle-tree.c.

> +
> +struct file_entry {
> +	char *name;
> +	unsigned int pos;
> +	unsigned char hash[EVP_MAX_MD_SIZE];
> +};
> +
> +static struct file_entry *fh_list;
> +static size_t num_files;
> +
> +struct leaf_hash {
> +	unsigned char hash[EVP_MAX_MD_SIZE];
> +};
> +
> +struct mtree {
> +	struct leaf_hash **l;
> +	unsigned int *entries;
> +	unsigned int levels;
> +};
> +
> +static inline void *xcalloc(size_t n, size_t size)
> +{
> +	void *p;
> +
> +	p = calloc(n, size);
> +	if (!p)
> +		errx(1, "Memory allocation failed");
> +
> +	return p;
> +}
> +
> +static void *xmalloc(size_t size)
> +{
> +	void *p;
> +
> +	p = malloc(size);
> +	if (!p)
> +		errx(1, "Memory allocation failed");
> +
> +	return p;
> +}
> +
> +static inline void *xreallocarray(void *oldp, size_t n, size_t size)
> +{
> +	void *p;
> +
> +	p = reallocarray(oldp, n, size);
> +	if (!p)
> +		errx(1, "Memory allocation failed");
> +
> +	return p;
> +}
> +
> +static inline char *xasprintf(const char *fmt, ...)
> +{
> +	va_list ap;
> +	char *strp;
> +	int ret;
> +
> +	va_start(ap, fmt);
> +	ret = vasprintf(&strp, fmt, ap);
> +	va_end(ap);
> +	if (ret == -1)
> +		err(1, "Memory allocation failed");
> +
> +	return strp;
> +}

I believe it is preferable to use xmalloc() and related functions from
scripts/include/xalloc.h, instead of defining your own variants. If
something is missing in xalloc.h, it can be extended.

> +
> +static unsigned int get_pow2(unsigned int val)
> +{
> +	return 31 - __builtin_clz(val);
> +}
> +
> +static unsigned int roundup_pow2(unsigned int val)
> +{
> +	return 1 << (get_pow2(val - 1) + 1);
> +}
> +
> +static unsigned int log2_roundup(unsigned int val)
> +{
> +	return get_pow2(roundup_pow2(val));
> +}

In the edge case when the kernel is built with only one module, the code
calls log2_roundup(1) -> roundup_pow2(1) -> get_pow2(0) ->
__builtin_clz(0). The return value of __builtin_clz() is undefined if
the input is zero.

> +
> +static void hash_data(void *p, unsigned int pos, size_t size, void *ret_hash)
> +{
> +	unsigned char magic = 0x01;
> +	unsigned int pos_be;
> +
> +	pos_be = htonl(pos);
> +
> +	ERR(EVP_DigestInit_ex(ctx, NULL, NULL) != 1, "EVP_DigestInit_ex()");
> +	ERR(EVP_DigestUpdate(ctx, &magic, sizeof(magic)) != 1, "EVP_DigestUpdate(magic)");
> +	ERR(EVP_DigestUpdate(ctx, &pos_be, sizeof(pos_be)) != 1, "EVP_DigestUpdate(pos)");
> +	ERR(EVP_DigestUpdate(ctx, p, size) != 1, "EVP_DigestUpdate(data)");
> +	ERR(EVP_DigestFinal_ex(ctx, ret_hash, NULL) != 1, "EVP_DigestFinal_ex()");
> +}
> +
> +static void hash_entry(void *left, void *right, void *ret_hash)
> +{
> +	int hash_size = EVP_MD_CTX_get_size_ex(ctx);

Nit: The local variable hash_size can be removed, as the static variable
with the same name should hold the same value.

> +	unsigned char magic = 0x02;
> +
> +	ERR(EVP_DigestInit_ex(ctx, NULL, NULL) != 1, "EVP_DigestInit_ex()");
> +	ERR(EVP_DigestUpdate(ctx, &magic, sizeof(magic)) != 1, "EVP_DigestUpdate(magic)");
> +	ERR(EVP_DigestUpdate(ctx, left, hash_size) != 1, "EVP_DigestUpdate(left)");
> +	ERR(EVP_DigestUpdate(ctx, right, hash_size) != 1, "EVP_DigestUpdate(right)");
> +	ERR(EVP_DigestFinal_ex(ctx, ret_hash, NULL) != 1, "EVP_DigestFinal_ex()");
> +}
> +
> +static void hash_file(struct file_entry *fe)
> +{
> +	struct stat sb;
> +	int fd, ret;
> +	void *mem;
> +
> +	fd = open(fe->name, O_RDONLY);
> +	if (fd < 0)
> +		err(1, "Failed to open %s", fe->name);
> +
> +	ret = fstat(fd, &sb);
> +	if (ret)
> +		err(1, "Failed to stat %s", fe->name);
> +
> +	mem = mmap(NULL, sb.st_size, PROT_READ, MAP_SHARED, fd, 0);
> +	close(fd);
> +
> +	if (mem == MAP_FAILED)
> +		err(1, "Failed to mmap %s", fe->name);

Nit: The err() call should be moved immediately after mmap(). In theory,
the interleaving close() could change the errno value, resulting in
err() printing a misleading error message.

> +
> +	hash_data(mem, fe->pos, sb.st_size, fe->hash);
> +
> +	munmap(mem, sb.st_size);
> +}
> +
> +static struct mtree *build_merkle(struct file_entry *fh, size_t num)
> +{
> +	struct mtree *mt;
> +	unsigned int le;
> +
> +	if (!num)
> +		return NULL;
> +
> +	mt = xmalloc(sizeof(*mt));
> +	mt->levels = log2_roundup(num);
> +
> +	mt->l = xcalloc(sizeof(*mt->l), mt->levels);
> +
> +	mt->entries = xcalloc(sizeof(*mt->entries), mt->levels);
> +	le = num / 2;
> +	if (num & 1)
> +		le++;
> +	mt->entries[0] = le;
> +	mt->l[0] = xcalloc(sizeof(**mt->l), le);
> +
> +	/* First level of pairs */
> +	for (unsigned int i = 0; i < num; i += 2) {
> +		if (i == num - 1) {
> +			/* Odd number of files, no pair. Hash with itself */
> +			hash_entry(fh[i].hash, fh[i].hash, mt->l[0][i / 2].hash);
> +		} else {
> +			hash_entry(fh[i].hash, fh[i + 1].hash, mt->l[0][i / 2].hash);
> +		}
> +	}
> +	for (unsigned int i = 1; i < mt->levels; i++) {
> +		int odd = 0;
> +
> +		if (le & 1) {
> +			le++;
> +			odd++;
> +		}
> +
> +		mt->entries[i] = le / 2;
> +		mt->l[i] = xcalloc(sizeof(**mt->l), le);

l[i] is overallocated. It needs only 'le / 2' entries.

> +
> +		for (unsigned int n = 0; n < le; n += 2) {
> +			if (n == le - 2 && odd) {
> +				/* Odd number of pairs, no pair. Hash with itself */
> +				hash_entry(mt->l[i - 1][n].hash, mt->l[i - 1][n].hash,
> +					   mt->l[i][n / 2].hash);
> +			} else {
> +				hash_entry(mt->l[i - 1][n].hash, mt->l[i - 1][n + 1].hash,
> +					   mt->l[i][n / 2].hash);
> +			}
> +		}
> +		le =  mt->entries[i];

Nit: It might be helpful to write both the first-level and other-level
loops in the same style to make them easier to understand, perhaps by
clearly separating the number of entries at each level. I suggest
something like the following:

static struct mtree *build_merkle(struct file_entry *fh, size_t num_files)
{
	struct mtree *mt;
	unsigned int num_cur_le, num_prev_le;

	if (!num_files)
		return NULL;

	mt = xmalloc(sizeof(*mt));
	mt->levels = log2_roundup(num_files);

	mt->l = xcalloc(sizeof(*mt->l), mt->levels);

	mt->entries = xcalloc(sizeof(*mt->entries), mt->levels);
	num_cur_le = (num_files + 1) / 2;
	mt->entries[0] = num_cur_le;
	mt->l[0] = xcalloc(sizeof(**mt->l), num_cur_le);

	/* First level of pairs */
	for (unsigned int i = 0; i < num_files; i += 2) {
		/* Hash the pair, or the last file with itself if it's odd. */
		void *right = i + 1 < num_files ? fh[i + 1].hash : fh[i].hash;
		hash_entry(fh[i].hash, right, mt->l[0][i / 2].hash);
	}

	for (unsigned int i = 1; i < mt->levels; i++) {
		num_prev_le = num_cur_le;

		num_cur_le = (num_prev_le + 1) / 2;
		mt->entries[i] = num_cur_le;
		mt->l[i] = xcalloc(sizeof(**mt->l), num_cur_le);

		for (unsigned int n = 0; n < num_prev_le; n += 2) {
			/* Hash the pair, or the last with itself if it's odd. */
			void *right = n + 1 < num_prev_le ?
					      mt->l[i - 1][n + 1].hash :
					      mt->l[i - 1][n].hash;
			hash_entry(mt->l[i - 1][n].hash, right,
				   mt->l[i][n / 2].hash);
		}
	}
	return mt;
}

> +	}
> +	return mt;
> +}
> +
> +static void free_mtree(struct mtree *mt)
> +{
> +	if (!mt)
> +		return;
> +
> +	for (unsigned int i = 0; i < mt->levels; i++)
> +		free(mt->l[i]);
> +
> +	free(mt->l);
> +	free(mt->entries);
> +	free(mt);
> +}
> +
> +static void write_be_int(int fd, unsigned int v)
> +{
> +	unsigned int be_val = htonl(v);
> +
> +	if (write(fd, &be_val, sizeof(be_val)) != sizeof(be_val))
> +		err(1, "Failed writing to file");
> +}
> +
> +static void write_hash(int fd, const void *h)
> +{
> +	ssize_t wr;
> +
> +	wr = write(fd, h, hash_size);
> +	if (wr != hash_size)
> +		err(1, "Failed writing to file");
> +}

Nit: This could be

if (write(fd, h, hash_size) != hash_size)

to keep the style of write_be_int() and write_hash() consistent.

> +
> +static void build_proof(struct mtree *mt, unsigned int n, int fd)
> +{
> +	unsigned char cur[EVP_MAX_MD_SIZE];
> +	unsigned char tmp[EVP_MAX_MD_SIZE];
> +	struct file_entry *fe, *fe_sib;
> +
> +	fe = &fh_list[n];
> +
> +	if ((n & 1) == 0) {
> +		/* No pair, hash with itself */
> +		if (n + 1 == num_files)
> +			fe_sib = fe;
> +		else
> +			fe_sib = &fh_list[n + 1];
> +	} else {
> +		fe_sib = &fh_list[n - 1];
> +	}
> +	/* First comes the node position into the file */
> +	write_be_int(fd, n);
> +
> +	if ((n & 1) == 0)
> +		hash_entry(fe->hash, fe_sib->hash, cur);
> +	else
> +		hash_entry(fe_sib->hash, fe->hash, cur);
> +
> +	/* Next is the sibling hash, followed by hashes in the tree */
> +	write_hash(fd, fe_sib->hash);
> +
> +	for (unsigned int i = 0; i < mt->levels - 1; i++) {
> +		n >>= 1;
> +		if ((n & 1) == 0) {
> +			void *h;
> +
> +			/* No pair, hash with itself */
> +			if (n + 1 == mt->entries[i])
> +				h = cur;
> +			else
> +				h = mt->l[i][n + 1].hash;
> +
> +			hash_entry(cur, h, tmp);
> +			write_hash(fd, h);
> +		} else {
> +			hash_entry(mt->l[i][n - 1].hash, cur, tmp);
> +			write_hash(fd, mt->l[i][n - 1].hash);
> +		}
> +		memcpy(cur, tmp, hash_size);
> +	}
> +
> +	 /* After all that, the end hash should match the root hash */
> +	if (memcmp(cur, mt->l[mt->levels - 1][0].hash, hash_size))
> +		errx(1, "hash mismatch");
> +}
> +
> +static void append_module_signature_magic(int fd, unsigned int sig_len)
> +{
> +	struct module_signature sig_info = {
> +		.id_type	= PKEY_ID_MERKLE,
> +		.sig_len	= htonl(sig_len),
> +	};
> +
> +	if (write(fd, &sig_info, sizeof(sig_info)) < 0)
> +		err(1, "write(sig_info) failed");
> +
> +	if (write(fd, &magic_number, sizeof(magic_number) - 1) < 0)
> +		err(1, "write(magic_number) failed");

Nit: Checking that the written size exactly matches the size of the
input data would be safer and consistent with other uses of write() in
write_be_int() and write_hash(). Additionally, it would be good to make
the error messages consistent in all cases.

> +}
> +
> +static void write_merkle_root(struct mtree *mt, const char *fp)
> +{
> +	char buf[1024];
> +	unsigned int levels;
> +	unsigned char *h;
> +	FILE *f;
> +
> +	if (mt) {
> +		levels = mt->levels;
> +		h = mt->l[mt->levels - 1][0].hash;
> +	} else {
> +		levels = 0;
> +		h = xcalloc(1, hash_size);
> +	}
> +
> +	f = fopen(fp, "w");
> +	if (!f)
> +		err(1, "Failed to create %s", buf);

The last parameter to err() should be fp. The buf variable is then
unused and can be removed.

> +
> +	fprintf(f, "#include <linux/module_hashes.h>\n\n");
> +	fprintf(f, "const struct module_hashes_root module_hashes_root __module_hashes_section = {\n");
> +
> +	fprintf(f, "\t.levels = %u,\n", levels);
> +	fprintf(f, "\t.hash = {");
> +	for (unsigned int i = 0; i < hash_size; i++) {
> +		char *space = "";
> +
> +		if (!(i % 8))
> +			fprintf(f, "\n\t\t");
> +
> +		if ((i + 1) % 8)
> +			space = " ";
> +
> +		fprintf(f, "0x%02x,%s", h[i], space);
> +	}
> +	fprintf(f, "\n\t},");
> +
> +	fprintf(f, "\n};\n");
> +	fclose(f);

Is it ok not to check the return values when writing to this output
file? Other code checks that its output was successful.

> +
> +	if (!mt)
> +		free(h);
> +}
> +
> +static char *xstrdup_replace_suffix(const char *str, const char *new_suffix)
> +{
> +	const char *current_suffix;
> +	size_t base_len;
> +
> +	current_suffix = strchr(str, '.');

It is safer to use strrchr() in case the module path happens to contain
a dot.

> +	if (!current_suffix)
> +		errx(1, "No existing suffix in '%s'", str);
> +
> +	base_len = current_suffix - str;
> +
> +	return xasprintf("%.*s%s", (int)base_len, str, new_suffix);
> +}
> +
> +static void read_modules_order(const char *fname, const char *suffix)
> +{
> +	char line[PATH_MAX];

<limits.h> should be included at the top to provide the definition of
PATH_MAX.

> +	FILE *in;
> +
> +	in = fopen(fname, "r");
> +	if (!in)
> +		err(1, "fopen(%s)", fname);

Nit: The error message could be "Failed to open %s" to maintain
consistency with a similar error in write_merkle_root().

> +
> +	while (fgets(line, PATH_MAX, in)) {
> +		struct file_entry *entry;
> +
> +		fh_list = xreallocarray(fh_list, num_files + 1, sizeof(*fh_list));

It might be useful to not reallocate this array for each file, although
I don't immediately see that it contributes any significant time to the
runtime.

> +		entry = &fh_list[num_files];
> +
> +		entry->pos = num_files;
> +		entry->name = xstrdup_replace_suffix(line, suffix);
> +		hash_file(entry);
> +
> +		num_files++;
> +	}
> +
> +	fclose(in);
> +}
> +
> +static __attribute__((noreturn))
> +void format(void)
> +{
> +	fprintf(stderr,
> +		"Usage: scripts/modules-merkle-tree <root definition>\n");

The usage string should mention the second parameter, which is the
module suffix.

> +	exit(2);
> +}
> +
> +int main(int argc, char *argv[])
> +{
> +	const EVP_MD *hash_evp;
> +	struct mtree *mt;
> +
> +	if (argc != 3)
> +		format();
> +
> +	hash_evp = EVP_get_digestbyname("sha256");
> +	ERR(!hash_evp, "EVP_get_digestbyname");
> +
> +	ctx = EVP_MD_CTX_new();
> +	ERR(!ctx, "EVP_MD_CTX_new()");
> +
> +	hash_size = EVP_MD_get_size(hash_evp);
> +	ERR(hash_size <= 0, "EVP_get_digestbyname");
> +
> +	if (EVP_DigestInit_ex(ctx, hash_evp, NULL) != 1)
> +		ERR(1, "EVP_DigestInit_ex()");
> +
> +	read_modules_order("modules.order", argv[2]);
> +
> +	mt = build_merkle(fh_list, num_files);
> +	write_merkle_root(mt, argv[1]);
> +	for (unsigned int i = 0; i < num_files; i++) {
> +		char *signame;
> +		int fd;
> +
> +		signame = xstrdup_replace_suffix(fh_list[i].name, ".merkle");
> +
> +		fd = open(signame, O_WRONLY | O_CREAT | O_TRUNC, 0644);
> +		if (fd < 0)
> +			err(1, "Can't create %s", signame);
> +
> +		build_proof(mt, i, fd);
> +		append_module_signature_magic(fd, lseek(fd, 0, SEEK_CUR));
> +		close(fd);

The return code of close() should be checked, otherwise it is
meaningless to check the write() calls in
append_module_signature_magic().

> +	}
> +
> +	free_mtree(mt);
> +	for (unsigned int i = 0; i < num_files; i++)
> +		free(fh_list[i].name);
> +	free(fh_list);
> +
> +	EVP_MD_CTX_free(ctx);
> +	return 0;
> +}

-- 
Thanks,
Petr

  parent reply	other threads:[~2026-02-03 12:19 UTC|newest]

Thread overview: 80+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-01-13 12:28 [PATCH v4 00/17] module: Introduce hash-based integrity checking Thomas Weißschuh
2026-01-13 12:28 ` [PATCH v4 01/17] module: Only declare set_module_sig_enforced when CONFIG_MODULE_SIG=y Thomas Weißschuh
2026-01-13 12:28 ` [PATCH v4 02/17] powerpc/ima: Drop unnecessary check for CONFIG_MODULE_SIG Thomas Weißschuh
2026-01-30 20:43   ` Aaron Tomlin
2026-02-06  8:25   ` Nicolas Schier
2026-03-10 21:11   ` Eric Biggers
2026-01-13 12:28 ` [PATCH v4 03/17] ima: efi: Drop unnecessary check for CONFIG_MODULE_SIG/CONFIG_KEXEC_SIG Thomas Weißschuh
2026-01-30 20:49   ` Aaron Tomlin
2026-02-06  8:25   ` Nicolas Schier
2026-03-10 21:11   ` Eric Biggers
2026-01-13 12:28 ` [PATCH v4 04/17] module: Make mod_verify_sig() static Thomas Weißschuh
2026-01-30 20:53   ` Aaron Tomlin
2026-02-06  8:25   ` Nicolas Schier
2026-03-10 21:12   ` Eric Biggers
2026-01-13 12:28 ` [PATCH v4 05/17] module: Switch load_info::len to size_t Thomas Weißschuh
2026-02-06  8:18   ` David Howells
2026-02-06  8:34     ` Thomas Weißschuh
2026-02-06  8:30   ` Nicolas Schier
2026-02-06  8:38     ` Thomas Weißschuh
2026-02-06  8:55       ` Nicolas Schier
2026-02-06  9:09   ` Christophe Leroy (CS GROUP)
2026-02-06  9:18     ` Thomas Weißschuh
2026-01-13 12:28 ` [PATCH v4 06/17] kbuild: add stamp file for vmlinux BTF data Thomas Weißschuh
2026-02-06 16:28   ` Nicolas Schier
2026-03-10 21:36   ` Eric Biggers
2026-03-11 12:58     ` Thomas Weißschuh
2026-01-13 12:28 ` [PATCH v4 07/17] kbuild: generate module BTF based on vmlinux.unstripped Thomas Weißschuh
2026-02-06 16:37   ` Nicolas Schier
2026-02-20  9:29   ` Fwd: " Thomas Weißschuh
2026-02-20 16:55     ` Ihor Solodrai
2026-02-23  7:40       ` Thomas Weißschuh
2026-01-13 12:28 ` [PATCH v4 08/17] module: Deduplicate signature extraction Thomas Weißschuh
2026-01-27 15:20   ` Petr Pavlu
2026-02-03 12:41     ` Thomas Weißschuh
2026-01-13 12:28 ` [PATCH v4 09/17] module: Make module loading policy usable without MODULE_SIG Thomas Weißschuh
2026-03-10 22:01   ` Eric Biggers
2026-03-11 12:59     ` Thomas Weißschuh
2026-01-13 12:28 ` [PATCH v4 10/17] module: Move integrity checks into dedicated function Thomas Weißschuh
2026-02-13 15:09   ` Nicolas Schier
2026-03-10 22:06   ` Eric Biggers
2026-01-13 12:28 ` [PATCH v4 11/17] module: Move lockdown check into generic module loader Thomas Weißschuh
2026-02-13 15:14   ` Nicolas Schier
2026-01-13 12:28 ` [PATCH v4 12/17] module: Move signature splitting up Thomas Weißschuh
2026-01-29 14:41   ` Petr Pavlu
2026-02-03 12:42     ` Thomas Weißschuh
2026-01-13 12:28 ` [PATCH v4 13/17] module: Report signature type to users Thomas Weißschuh
2026-01-29 14:44   ` Petr Pavlu
2026-02-03 12:44     ` Thomas Weißschuh
2026-01-13 12:28 ` [PATCH v4 14/17] lockdown: Make the relationship to MODULE_SIG a dependency Thomas Weißschuh
2026-02-13 15:32   ` Nicolas Schier
2026-01-13 12:28 ` [PATCH v4 15/17] module: Introduce hash-based integrity checking Thomas Weißschuh
2026-01-13 14:56   ` Sebastian Andrzej Siewior
2026-01-30 17:06   ` Petr Pavlu
2026-02-03 12:55     ` Thomas Weißschuh
2026-02-06 17:12       ` Nicolas Schier
2026-02-19 14:27       ` Nicolas Schier
2026-02-03 12:19   ` Petr Pavlu [this message]
2026-02-03 12:59     ` Thomas Weißschuh
2026-03-11  1:18     ` Eric Biggers
2026-02-21 21:38   ` Nicolas Schier
2026-02-23  7:53     ` Thomas Weißschuh
2026-02-23 18:41       ` Nicolas Schier
2026-02-23 21:43         ` Thomas Weißschuh
2026-02-24 16:14           ` Nicolas Schier
2026-03-11  1:12   ` Eric Biggers
2026-03-11  8:50     ` Sebastian Andrzej Siewior
2026-03-11 13:19     ` Thomas Weißschuh
2026-03-11 21:14       ` Eric Biggers
2026-01-13 12:29 ` [PATCH v4 16/17] kbuild: move handling of module stripping to Makefile.lib Thomas Weißschuh
2026-01-13 12:29 ` [PATCH v4 17/17] kbuild: make CONFIG_MODULE_HASHES compatible with module stripping Thomas Weißschuh
2026-01-31  7:36 ` [PATCH v4 00/17] module: Introduce hash-based integrity checking Mihai-Drosi Câju
2026-02-01 16:22   ` Thomas Weißschuh
2026-02-01 17:09   ` David Howells
2026-02-01 20:12     ` Eric Biggers
2026-02-02  9:21       ` David Howells
2026-02-02 18:30         ` Eric Biggers
2026-02-02 18:38           ` David Howells
2026-02-02 18:47             ` Eric Biggers
2026-02-03  8:18     ` James Bottomley
2026-02-03  8:22       ` David Howells

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=fab2af64-e396-45f9-8876-feff4002e04b@suse.com \
    --to=petr.pavlu@suse.com \
    --cc=arnd@arndb.de \
    --cc=arnout@bzzt.net \
    --cc=atomlin@atomlin.com \
    --cc=bigeasy@linutronix.de \
    --cc=chleroy@kernel.org \
    --cc=christian@heusel.eu \
    --cc=corbet@lwn.net \
    --cc=da.gomez@kernel.org \
    --cc=da.gomez@samsung.com \
    --cc=dmitry.kasatkin@gmail.com \
    --cc=eric.snowberg@oracle.com \
    --cc=f.gruenbichler@proxmox.com \
    --cc=jmorris@namei.org \
    --cc=kpcyrd@archlinux.org \
    --cc=linux-arch@vger.kernel.org \
    --cc=linux-doc@vger.kernel.org \
    --cc=linux-integrity@vger.kernel.org \
    --cc=linux-kbuild@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-modules@vger.kernel.org \
    --cc=linux-security-module@vger.kernel.org \
    --cc=linux@weissschuh.net \
    --cc=linuxppc-dev@lists.ozlabs.org \
    --cc=maddy@linux.ibm.com \
    --cc=mattia@mapreri.org \
    --cc=mcaju95@gmail.com \
    --cc=mcgrof@kernel.org \
    --cc=mpe@ellerman.id.au \
    --cc=nathan@kernel.org \
    --cc=naveen@kernel.org \
    --cc=nicolas.bouchinet@oss.cyber.gouv.fr \
    --cc=nicolas.schier@linux.dev \
    --cc=npiggin@gmail.com \
    --cc=nsc@kernel.org \
    --cc=paul@paul-moore.com \
    --cc=roberto.sassu@huawei.com \
    --cc=samitolvanen@google.com \
    --cc=serge@hallyn.com \
    --cc=xiujianfeng@huawei.com \
    --cc=zohar@linux.ibm.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox