On Sat, Jun 14, 2025 at 1:06 PM Eduard Zingerman <eddyz87@xxxxxxxxx> wrote: > > test_progs and test_verifier binaries execute unpriv tests under the > following conditions: > - unpriv BPF is enabled; > - CPU mitigations are enabled (see [1] for details). > > The detection of the "mitigations enabled" state is performed by > unpriv_helpers.c:get_mitigations_off() via inspecting kernel boot > command line, looking for a parameter "mitigations=off". > > Such detection scheme won't work for certain configurations, > e.g. when CONFIG_CPU_MITIGATIONS is disabled and boot parameter is > not supplied. > > Miss-detection leads to test_progs executing tests meant to be run > only with mitigations enabled, e.g. > verifier_and.c:known_subreg_with_unknown_reg(), and reporting false > failures. > > Internally, verifier sets bpf_verifier_env->bypass_spec_{v1,v4} > basing on the value returned by kernel/cpu.c:cpu_mitigations_off(). > This function is backed by a variable kernel/cpu.c:cpu_mitigations. > > This state is not fully introspect-able via sysfs. The closest proxy > is /sys/devices/system/cpu/vulnerabilities/spectre_v1, but it reports > "vulnerable" state only if mitigations are disabled *and* current cpu > is vulnerable, while verifier does not check cpu state. > > There are only two ways the kernel/cpu.c:cpu_mitigations can be set: > - via boot parameter; > - via CONFIG_CPU_MITIGATIONS option. > > This commit updates unpriv_helpers.c:get_mitigations_off() to scan > /boot/config-$(uname -r) and /proc/config.gz for > CONFIG_CPU_MITIGATIONS value in addition to boot command line check. > > Tested using the following configurations: > - mitigations enabled (unpriv tests are enabled) > - mitigations disabled via boot cmdline (unpriv tests skipped) > - mitigations disabled via CONFIG_CPU_MITIGATIONS > (unpriv tests skipped) > > [1] https://lore.kernel.org/bpf/20231025031144.5508-1-laoar.shao@xxxxxxxxx/ > > Reported-by: Mykyta Yatsenko <mykyta.yatsenko5@xxxxxxxxx> > Signed-off-by: Eduard Zingerman <eddyz87@xxxxxxxxx> Acked-by: Yafang Shao <laoar.shao@xxxxxxxxx> > --- > tools/testing/selftests/bpf/unpriv_helpers.c | 94 +++++++++++++++++++- > 1 file changed, 91 insertions(+), 3 deletions(-) > > diff --git a/tools/testing/selftests/bpf/unpriv_helpers.c b/tools/testing/selftests/bpf/unpriv_helpers.c > index 220f6a963813..625556a0e7f1 100644 > --- a/tools/testing/selftests/bpf/unpriv_helpers.c > +++ b/tools/testing/selftests/bpf/unpriv_helpers.c > @@ -1,15 +1,76 @@ > // SPDX-License-Identifier: GPL-2.0-only > > +#include <errno.h> > #include <stdbool.h> > #include <stdlib.h> > #include <stdio.h> > #include <string.h> > +#include <sys/utsname.h> > #include <unistd.h> > #include <fcntl.h> > +#include <zlib.h> > > #include "unpriv_helpers.h" > > -static bool get_mitigations_off(void) > +static gzFile open_config(void) > +{ > + struct utsname uts; > + char buf[PATH_MAX]; > + gzFile config; > + > + if (uname(&uts)) { > + perror("uname"); > + goto config_gz; > + } > + > + snprintf(buf, sizeof(buf), "/boot/config-%s", uts.release); > + config = gzopen(buf, "rb"); > + if (config) > + return config; > + fprintf(stderr, "gzopen %s: %s\n", buf, strerror(errno)); > + > +config_gz: > + config = gzopen("/proc/config.gz", "rb"); > + if (!config) > + perror("gzopen /proc/config.gz"); > + return config; > +} > + > +static int config_contains(const char *pat) > +{ > + int n, err, ret = -1; > + const char *msg; > + char buf[1024]; > + gzFile config; > + > + config = open_config(); > + if (!config) > + goto out; > + > + for (;;) { > + if (!gzgets(config, buf, sizeof(buf))) { > + msg = gzerror(config, &err); > + if (err == Z_ERRNO) > + perror("gzgets /proc/config.gz"); > + else if (err != Z_OK) > + fprintf(stderr, "gzgets /proc/config.gz: %s", msg); > + goto out; > + } > + n = strlen(buf); > + if (buf[n - 1] == '\n') > + buf[n - 1] = 0; > + if (strcmp(buf, pat) == 0) { > + ret = true; > + goto out; > + } > + } > + ret = false; > +out: > + gzclose(config); > + return ret; > +} > + > +static bool cmdline_contains(const char *pat) > { > char cmdline[4096], *c; > int fd, ret = false; > @@ -27,7 +88,7 @@ static bool get_mitigations_off(void) > > cmdline[sizeof(cmdline) - 1] = '\0'; > for (c = strtok(cmdline, " \n"); c; c = strtok(NULL, " \n")) { > - if (strncmp(c, "mitigations=off", strlen(c))) > + if (strncmp(c, pat, strlen(c))) > continue; > ret = true; > break; > @@ -37,8 +98,21 @@ static bool get_mitigations_off(void) > return ret; > } > > +static int get_mitigations_off(void) > +{ > + int enabled_in_config; > + > + if (cmdline_contains("mitigations=off")) > + return true; > + enabled_in_config = config_contains("CONFIG_CPU_MITIGATIONS=y"); > + if (enabled_in_config < 0) > + return -1; > + return !enabled_in_config; > +} > + > bool get_unpriv_disabled(void) > { > + int mitigations_off; > bool disabled; > char buf[2]; > FILE *fd; > @@ -52,5 +126,19 @@ bool get_unpriv_disabled(void) > disabled = true; > } > > - return disabled ? true : get_mitigations_off(); > + if (disabled) > + return true; > + > + /* > + * Some unpriv tests rely on spectre mitigations being on. > + * If mitigations are off or status can't be determined > + * assume that unpriv tests are disabled. > + */ > + mitigations_off = get_mitigations_off(); > + if (mitigations_off < 0) { > + fprintf(stderr, > + "Can't determine if mitigations are enabled, disabling unpriv tests."); > + return true; > + } > + return mitigations_off; > } > -- > 2.47.1 > -- Regards Yafang