Re: [PATCH bpf-next 08/11] selftests/bpf: Add an end-to-end ML-DSA signed loader test

[email protected]
Newsgroups org.kernel.vger.bpf
Message-ID <531959923e7157df026710ecfec99782ad4a7483697883ea4043c582b837ee59@mail.kernel.org>
> diff --git a/tools/testing/selftests/bpf/config b/tools/testing/selftests/bpf/config
> index ea7044f30adc3..4e6d13dbf2662 100644
> --- a/tools/testing/selftests/bpf/config
> +++ b/tools/testing/selftests/bpf/config
> @@ -51,6 +51,7 @@ CONFIG_IPV6_SEG6_LWTUNNEL=y
>  CONFIG_IPV6_SIT=y
>  CONFIG_IPV6_TUNNEL=y
>  CONFIG_KEYS=y
> +CONFIG_CRYPTO_MLDSA=y
>  CONFIG_LIRC=y
>  CONFIG_LIVEPATCH=y
>  CONFIG_LWTUNNEL=y

Does this fragment need CONFIG_CRYPTO_SHA512=y alongside
CONFIG_CRYPTO_MLDSA?

mldsa_signed_load() signs with sign_buf_digest(..., "sha512"), so the
PKCS#7 blob carries signedAttrs with a SHA-512 messageDigest. On the
kernel side pkcs7_digest() takes the 'sinfo->authattrs' path and does:

    tfm = crypto_alloc_shash(sinfo->sig->hash_algo, 0, 0);
    if (IS_ERR(tfm))
        return (PTR_ERR(tfm) == -ENOENT) ? -ENOPKG : PTR_ERR(tfm);

Without CRYPTO_SHA512 that returns -ENOPKG and the load fails. It happens
to work today: the fragment has CONFIG_MODULE_SIG=y and the module-signing
default choice selects CRYPTO_SHA512, so the dependency is satisfied only
as a side effect of an unrelated option's default. It would break silently
if that default or CONFIG_MODULE_SIG ever changed. The file already lists
the RSA path's digest explicitly (CONFIG_CRYPTO_SHA256=y at line 15), so
an explicit CONFIG_CRYPTO_SHA512=y here would match the file's own
convention.

> diff --git a/tools/testing/selftests/bpf/prog_tests/signed_loader.c b/tools/testing/selftests/bpf/prog_tests/signed_loader.c
> index 4b2416903d90d..a1fa1c37815bf 100644
> --- a/tools/testing/selftests/bpf/prog_tests/signed_loader.c
> +++ b/tools/testing/selftests/bpf/prog_tests/signed_loader.c

[ ... ]

> @@ -1550,6 +1563,87 @@ static void loadtime_with_map(void)
>  	test_signed_loader_map__destroy(skel);
>  }
>
> +/*
> + * End-to-end signed load with a post-quantum key. ML-DSA (FIPS-204) is wired
> + * through the X.509 and PKCS#7 parsers, and BPF reaches them via
> + * verify_pkcs7_signature() without knowing the algorithm, so an ML-DSA key in
> + * the keyring should verify an ML-DSA signed program with no BPF-side work.
> + */
> +static void mldsa_signed_load(void)
> +{
> +	char dir_tmpl[] = "/tmp/bpfmldsaXXXXXX";
> +	int map_fd = -1, prog_fd = -1, err;
> +	__u8 *sig = NULL, *buf = NULL;
> +	struct gen_loader_fixture f;
> +	bool have_fixture = false;
> +	__u32 sig_sz = 16384;
> +	char *dir;
> +
> +	dir = mkdtemp(dir_tmpl);
> +	if (!ASSERT_OK_PTR(dir, "mkdtemp"))
> +		return;
> +
> +	err = run_setup("setup-mldsa", dir);
> +	if (err == SETUP_SKIP) {

Should mldsa_signed_load() create a session keyring before running
verify_sig_setup.sh?

Every other subtest in this file that calls run_setup() and then loads
with KEY_SPEC_SESSION_KEYRING first does:

    syscall(__NR_request_key, "keyring", "_uid.0", NULL,
            KEY_SPEC_SESSION_KEYRING);
    dir = mkdtemp(dir_tmpl);

Nine sites, one per setup-rsa user. prog_tests/verify_pkcs7_sig.c:252
spells out why: '/* Trigger creation of session keyring. */'.
mldsa_signed_load() is the only run_setup() user in the file that omits
it.

Why it matters: the setup script adds the key with 'keyctl padd
asymmetric ebpf_testing_key @s', i.e. add_key(2), which calls
lookup_user_key(ringid, KEY_LOOKUP_CREATE, KEY_NEED_WRITE). The
KEY_SPEC_SESSION_KEYRING case with KEY_LOOKUP_CREATE runs
join_session_keyring(NULL) whenever cred->session_keyring is NULL (or is
the UID keyring). That creates a brand-new session keyring inside the
forked script process only; it dies with the script.

The parent test process then loads with attr.keyring_id =
KEY_SPEC_SESSION_KEYRING, which resolves with
bpf_lookup_user_key(attr->keyring_id, 0) - no KEY_LOOKUP_CREATE - so it
gets the user-session keyring instead, which never received
ebpf_testing_key. The load then fails and ASSERT_OK_FD(prog_fd, "ML-DSA
signed loader load") reports a failure.

In a full run this is hidden: loadtime_no_map() is the first subtest and
loadtime_verify() installs the session keyring for the whole process,
which is why the log in the commit message shows #424/15
mldsa_signed_load:OK.

Running the subtest on its own, e.g.

    ./test_progs -a 'signed_loader/mldsa_signed_load'

skips every subtest that would have created the keyring, and the new
subtest fails.

> diff --git a/tools/testing/selftests/bpf/verify_sig_setup.sh b/tools/testing/selftests/bpf/verify_sig_setup.sh
> index 202e6e6418fe2..2737c1a2bcfd6 100755
> --- a/tools/testing/selftests/bpf/verify_sig_setup.sh
> +++ b/tools/testing/selftests/bpf/verify_sig_setup.sh

[ ... ]


---
AI reviewed your patch. Please fix the bug or email reply why it's not a bug.
See: https://github.com/kernel-patches/vmtest/blob/master/ci/claude/README.md

CI run summary: https://github.com/kernel-patches/bpf/actions/runs/32530917987
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.