* [PATCH bpf-next] selftests/bpf: more precise cpu_mitigations state detection
@ 2025-06-10 21:52 Eduard Zingerman
2025-06-11 2:54 ` Yafang Shao
2025-06-12 21:19 ` Andrii Nakryiko
0 siblings, 2 replies; 5+ messages in thread
From: Eduard Zingerman @ 2025-06-10 21:52 UTC (permalink / raw)
To: bpf, ast, andrii
Cc: daniel, martin.lau, kernel-team, yonghong.song, eddyz87,
mykyta.yatsenko5, laoar.shao
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_MIGITGATIONS 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_MIGITGATIONS option.
This commit updates unpriv_helpers.c:get_mitigations_off() to scan
/proc/config.gz for CONFIG_CPU_MIGITGATIONS 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_MIGITGATIONS
(unpriv tests skipped)
[1] https://lore.kernel.org/bpf/20231025031144.5508-1-laoar.shao@gmail.com/
Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
---
tools/testing/selftests/bpf/unpriv_helpers.c | 45 +++++++++++++++++++-
1 file changed, 43 insertions(+), 2 deletions(-)
diff --git a/tools/testing/selftests/bpf/unpriv_helpers.c b/tools/testing/selftests/bpf/unpriv_helpers.c
index 220f6a963813..1dec3c6b3d70 100644
--- a/tools/testing/selftests/bpf/unpriv_helpers.c
+++ b/tools/testing/selftests/bpf/unpriv_helpers.c
@@ -6,10 +6,46 @@
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
+#include <zlib.h>
#include "unpriv_helpers.h"
-static bool get_mitigations_off(void)
+static bool scan_config(const char *pat)
+{
+ bool ret = false;
+ const char *msg;
+ char buf[1024];
+ gzFile config;
+ int n, err;
+
+ config = gzopen("/proc/config.gz", "rb");
+ if (!config) {
+ perror("gzopen /proc/config.gz");
+ 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;
+ }
+ }
+out:
+ gzclose(config);
+ return ret;
+}
+
+static bool scan_cmdline(const char *pat)
{
char cmdline[4096], *c;
int fd, ret = false;
@@ -27,7 +63,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,6 +73,11 @@ static bool get_mitigations_off(void)
return ret;
}
+static bool get_mitigations_off(void)
+{
+ return scan_cmdline("mitigations=off") || !scan_config("CONFIG_CPU_MITIGATIONS=y");
+}
+
bool get_unpriv_disabled(void)
{
bool disabled;
--
2.47.1
^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH bpf-next] selftests/bpf: more precise cpu_mitigations state detection
2025-06-10 21:52 [PATCH bpf-next] selftests/bpf: more precise cpu_mitigations state detection Eduard Zingerman
@ 2025-06-11 2:54 ` Yafang Shao
2025-06-11 5:31 ` Eduard Zingerman
2025-06-12 21:19 ` Andrii Nakryiko
1 sibling, 1 reply; 5+ messages in thread
From: Yafang Shao @ 2025-06-11 2:54 UTC (permalink / raw)
To: Eduard Zingerman
Cc: bpf, ast, andrii, daniel, martin.lau, kernel-team, yonghong.song,
mykyta.yatsenko5
On Wed, Jun 11, 2025 at 5:52 AM Eduard Zingerman <eddyz87@gmail.com> 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_MIGITGATIONS 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_MIGITGATIONS option.
>
> This commit updates unpriv_helpers.c:get_mitigations_off() to scan
> /proc/config.gz for CONFIG_CPU_MIGITGATIONS 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_MIGITGATIONS
> (unpriv tests skipped)
>
> [1] https://lore.kernel.org/bpf/20231025031144.5508-1-laoar.shao@gmail.com/
>
> Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
> ---
> tools/testing/selftests/bpf/unpriv_helpers.c | 45 +++++++++++++++++++-
> 1 file changed, 43 insertions(+), 2 deletions(-)
>
> diff --git a/tools/testing/selftests/bpf/unpriv_helpers.c b/tools/testing/selftests/bpf/unpriv_helpers.c
> index 220f6a963813..1dec3c6b3d70 100644
> --- a/tools/testing/selftests/bpf/unpriv_helpers.c
> +++ b/tools/testing/selftests/bpf/unpriv_helpers.c
> @@ -6,10 +6,46 @@
> #include <string.h>
> #include <unistd.h>
> #include <fcntl.h>
> +#include <zlib.h>
>
> #include "unpriv_helpers.h"
>
> -static bool get_mitigations_off(void)
> +static bool scan_config(const char *pat)
> +{
> + bool ret = false;
> + const char *msg;
> + char buf[1024];
> + gzFile config;
> + int n, err;
> +
> + config = gzopen("/proc/config.gz", "rb");
The /proc/config.gz file is not enabled in certain kernel releases.
Should we also check "/boot/config-$(uname -r)" as an alternative?
> + if (!config) {
> + perror("gzopen /proc/config.gz");
> + 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;
> + }
> + }
> +out:
> + gzclose(config);
> + return ret;
> +}
> +
> +static bool scan_cmdline(const char *pat)
> {
> char cmdline[4096], *c;
> int fd, ret = false;
> @@ -27,7 +63,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,6 +73,11 @@ static bool get_mitigations_off(void)
> return ret;
> }
>
> +static bool get_mitigations_off(void)
> +{
> + return scan_cmdline("mitigations=off") || !scan_config("CONFIG_CPU_MITIGATIONS=y");
> +}
> +
> bool get_unpriv_disabled(void)
> {
> bool disabled;
> --
> 2.47.1
>
--
Regards
Yafang
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH bpf-next] selftests/bpf: more precise cpu_mitigations state detection
2025-06-11 2:54 ` Yafang Shao
@ 2025-06-11 5:31 ` Eduard Zingerman
2025-06-11 5:49 ` Yafang Shao
0 siblings, 1 reply; 5+ messages in thread
From: Eduard Zingerman @ 2025-06-11 5:31 UTC (permalink / raw)
To: Yafang Shao
Cc: bpf, ast, andrii, daniel, martin.lau, kernel-team, yonghong.song,
mykyta.yatsenko5
On Wed, 2025-06-11 at 10:54 +0800, Yafang Shao wrote:
[...]
> > + config = gzopen("/proc/config.gz", "rb");
>
> The /proc/config.gz file is not enabled in certain kernel releases.
> Should we also check "/boot/config-$(uname -r)" as an alternative?
>
Oh, my... It's a zoo, on Fedora the config location is:
/usr/lib/modules/$(uname -r)/config
Tbh, I was fixing a problem with tests execution in a specific
environment. Adding a list of common locations for config is an
option.
Another option I tried but discarded is [1], where
kernel/cpu.c:cpu_mitigations variable is read directly by a BPF
program. But this is probably too heavy-handed.
[1] https://github.com/eddyz87/bpf/tree/better-unpriv-disabled-detector
[...]
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH bpf-next] selftests/bpf: more precise cpu_mitigations state detection
2025-06-11 5:31 ` Eduard Zingerman
@ 2025-06-11 5:49 ` Yafang Shao
0 siblings, 0 replies; 5+ messages in thread
From: Yafang Shao @ 2025-06-11 5:49 UTC (permalink / raw)
To: Eduard Zingerman
Cc: bpf, ast, andrii, daniel, martin.lau, kernel-team, yonghong.song,
mykyta.yatsenko5
On Wed, Jun 11, 2025 at 1:31 PM Eduard Zingerman <eddyz87@gmail.com> wrote:
>
> On Wed, 2025-06-11 at 10:54 +0800, Yafang Shao wrote:
>
> [...]
>
> > > + config = gzopen("/proc/config.gz", "rb");
> >
> > The /proc/config.gz file is not enabled in certain kernel releases.
> > Should we also check "/boot/config-$(uname -r)" as an alternative?
> >
>
> Oh, my... It's a zoo, on Fedora the config location is:
>
> /usr/lib/modules/$(uname -r)/config
>
> Tbh, I was fixing a problem with tests execution in a specific
> environment. Adding a list of common locations for config is an
> option.
Another option could be aligning with libbpf's approach here [0].
[0] https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next.git/tree/tools/lib/bpf/libbpf.c#n2275
--
Regards
Yafang
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH bpf-next] selftests/bpf: more precise cpu_mitigations state detection
2025-06-10 21:52 [PATCH bpf-next] selftests/bpf: more precise cpu_mitigations state detection Eduard Zingerman
2025-06-11 2:54 ` Yafang Shao
@ 2025-06-12 21:19 ` Andrii Nakryiko
1 sibling, 0 replies; 5+ messages in thread
From: Andrii Nakryiko @ 2025-06-12 21:19 UTC (permalink / raw)
To: Eduard Zingerman
Cc: bpf, ast, andrii, daniel, martin.lau, kernel-team, yonghong.song,
mykyta.yatsenko5, laoar.shao
On Tue, Jun 10, 2025 at 2:52 PM Eduard Zingerman <eddyz87@gmail.com> 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_MIGITGATIONS is disabled and boot parameter is
here and everywhere else (copy/paste FTW), typo: MITIGATIONS
> 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_MIGITGATIONS option.
>
> This commit updates unpriv_helpers.c:get_mitigations_off() to scan
> /proc/config.gz for CONFIG_CPU_MIGITGATIONS 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_MIGITGATIONS
> (unpriv tests skipped)
>
> [1] https://lore.kernel.org/bpf/20231025031144.5508-1-laoar.shao@gmail.com/
>
> Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
> ---
> tools/testing/selftests/bpf/unpriv_helpers.c | 45 +++++++++++++++++++-
> 1 file changed, 43 insertions(+), 2 deletions(-)
>
As Yanfang mentioned, seems like libbpf does
snprintf(buf, PATH_MAX, "/boot/config-%s", uts.release);
before going for /proc/config.gz. Let's add that to be a bit more
consistent (and it will be a touch faster to not have to unzip the
config, right?)
pw-bot: cr
> diff --git a/tools/testing/selftests/bpf/unpriv_helpers.c b/tools/testing/selftests/bpf/unpriv_helpers.c
> index 220f6a963813..1dec3c6b3d70 100644
> --- a/tools/testing/selftests/bpf/unpriv_helpers.c
> +++ b/tools/testing/selftests/bpf/unpriv_helpers.c
> @@ -6,10 +6,46 @@
> #include <string.h>
> #include <unistd.h>
> #include <fcntl.h>
> +#include <zlib.h>
>
> #include "unpriv_helpers.h"
>
> -static bool get_mitigations_off(void)
> +static bool scan_config(const char *pat)
> +{
> + bool ret = false;
> + const char *msg;
> + char buf[1024];
> + gzFile config;
> + int n, err;
> +
> + config = gzopen("/proc/config.gz", "rb");
> + if (!config) {
> + perror("gzopen /proc/config.gz");
> + 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;
> + }
> + }
> +out:
> + gzclose(config);
> + return ret;
> +}
> +
> +static bool scan_cmdline(const char *pat)
nit: I find "scan_xxx" quite unreadable when used in the expression
(did you scan? yes! did you find anything?... who knows... it's
similar with "filter_" or "check_" prefixes, but I digress). Can we
use "cmdline_contains" and "config_contains" or something along those
lines, so that the condition above reads more naturally?
> {
> char cmdline[4096], *c;
> int fd, ret = false;
> @@ -27,7 +63,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,6 +73,11 @@ static bool get_mitigations_off(void)
> return ret;
> }
>
> +static bool get_mitigations_off(void)
> +{
> + return scan_cmdline("mitigations=off") || !scan_config("CONFIG_CPU_MITIGATIONS=y");
> +}
> +
> bool get_unpriv_disabled(void)
> {
> bool disabled;
> --
> 2.47.1
>
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2025-06-12 21:19 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-06-10 21:52 [PATCH bpf-next] selftests/bpf: more precise cpu_mitigations state detection Eduard Zingerman
2025-06-11 2:54 ` Yafang Shao
2025-06-11 5:31 ` Eduard Zingerman
2025-06-11 5:49 ` Yafang Shao
2025-06-12 21:19 ` Andrii Nakryiko
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox