Re: [PATCH bpf-next 2/2] selftests/bpf: Test bpf_security_locked_down kfunc

[email protected]
Newsgroups org.kernel.vger.linux-security-module,org.kernel.vger.bpf,org.kernel.vger.linux-kernel
Message-ID <65c31dc7456f76e4b3012dd8dff3f7e23d136903d5cf997eb9be0662a979c1bc@mail.kernel.org>
> The selftest config guarantees the verdicts are stable: the bpf LSM is
> in CONFIG_LSM and the lockdown LSM is not, so the kernel cannot already
> be locked down.

Does the selftest config actually guarantee this? Looking at
tools/testing/selftests/bpf/config, it sets only CONFIG_BPF_LSM=y,
CONFIG_SECURITY=y and CONFIG_SECURITYFS=y. There is no CONFIG_LSM line at
all in that file.

The only CONFIG_LSM in the bpf selftest configs is
tools/testing/selftests/bpf/config.x86_64, which has
CONFIG_LSM="selinux,bpf,integrity". On other arch configs (aarch64,
s390x, riscv64, ppc64el), CONFIG_LSM falls back to the security/Kconfig
default, which does list "lockdown".

What actually prevents the lockdown LSM from being active is that
CONFIG_SECURITY_LOCKDOWN_LSM defaults to n, so the lockdown LSM registers
no hook. This is a weaker guarantee than the changelog states, and only
holds when test_progs is run against the shipped selftest config.

> diff --git a/tools/testing/selftests/bpf/prog_tests/lsm_kfuncs.c b/tools/testing/selftests/bpf/prog_tests/lsm_kfuncs.c
> new file mode 100644
> index 000000000000..c836851d8397
> --- /dev/null
> +++ b/tools/testing/selftests/bpf/prog_tests/lsm_kfuncs.c
> @@ -0,0 +1,28 @@
> +// SPDX-License-Identifier: GPL-2.0
> +#include <test_progs.h>
> +#include "lsm_kfuncs.skel.h"
> +#include "lsm_kfuncs_fail.skel.h"
> +
> +void test_lsm_kfuncs(void)
> +{
> +	LIBBPF_OPTS(bpf_test_run_opts, opts);
> +	struct lsm_kfuncs *skel;
> +
> +	RUN_TESTS(lsm_kfuncs_fail);
> +
> +	skel = lsm_kfuncs__open_and_load();
> +	if (!ASSERT_OK_PTR(skel, "open_and_load"))
> +		return;
> +	if (!ASSERT_OK(lsm_kfuncs__attach(skel), "attach"))
> +		goto out;
> +
> +	if (!ASSERT_OK(bpf_prog_test_run_opts(bpf_program__fd(skel->progs.query),
> +					      &opts), "test_run"))
> +		goto out;
> +	ASSERT_EQ(skel->data->ret_clear, 0, "not locked down");

Can this assertion produce false failures on a kernel that is already
locked down? If CONFIG_SECURITY_LOCKDOWN_LSM=y with lockdown active
(lockdown=integrity/confidentiality, or Secure Boot with
CONFIG_LOCK_DOWN_KERNEL_FORCE_*), security_locked_down() walks every
registered locked_down hook, not just the test's BPF program.

security/lockdown/lockdown.c:
    LSM_HOOK_INIT(locked_down, lockdown_is_locked_down)

would return -EPERM for LOCKDOWN_KEXEC (an integrity-level reason), so
ret_clear becomes -EPERM and the test reports a hard FAIL rather than a
skip.

> +	ASSERT_EQ(skel->data->ret_denied, -EPERM, "locked down");
> +	ASSERT_EQ(skel->data->ret_invalid_low, -EINVAL, "LOCKDOWN_NONE invalid");
> +	ASSERT_EQ(skel->data->ret_invalid_high, -EINVAL, "CONFIDENTIALITY_MAX invalid");
> +out:
> +	lsm_kfuncs__destroy(skel);
> +}

[ ... ]

> diff --git a/tools/testing/selftests/bpf/progs/lsm_kfuncs.c b/tools/testing/selftests/bpf/progs/lsm_kfuncs.c
> new file mode 100644
> index 000000000000..2637b9bc9025
> --- /dev/null
> +++ b/tools/testing/selftests/bpf/progs/lsm_kfuncs.c
> @@ -0,0 +1,34 @@
> +// SPDX-License-Identifier: GPL-2.0
> +#include "vmlinux.h"
> +#include <errno.h>
> +#include <bpf/bpf_helpers.h>
> +#include <bpf/bpf_tracing.h>
> +
> +char _license[] SEC("license") = "GPL";
> +
> +extern int bpf_security_locked_down(enum lockdown_reason what) __ksym;
> +
> +/* Reason nothing in the test environment genuinely queries or locks. */
> +#define DENY_REASON LOCKDOWN_HIBERNATION
> +#define ALLOW_REASON LOCKDOWN_KEXEC
> +
> +int ret_clear = 1;
> +int ret_denied = 1;
> +int ret_invalid_low = 1;
> +int ret_invalid_high = 1;
> +
> +SEC("lsm/locked_down")
> +int BPF_PROG(lockdown_hook, enum lockdown_reason what)
> +{
> +	return what == DENY_REASON ? -EPERM : 0;
> +}
> +
> +SEC("syscall")
> +int query(void *ctx)
> +{
> +	ret_clear = bpf_security_locked_down(ALLOW_REASON);

Would it make sense to have the test tolerate or skip when the running
kernel is already locked down? The current approach asserts on global host
state the test does not control. Consider checking if ret_clear != 0 and
skipping with a message, so the test does not produce false regression
signals on distro kernels with lockdown active.

> +	ret_denied = bpf_security_locked_down(DENY_REASON);
> +	ret_invalid_low = bpf_security_locked_down(LOCKDOWN_NONE);
> +	ret_invalid_high = bpf_security_locked_down(LOCKDOWN_CONFIDENTIALITY_MAX);
> +	return 0;
> +}

[ ... ]


---
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/31882515336
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.