mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-08-05 16:54:27 +00:00
selftests/bpf: More precise cpu_mitigations state detection
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@gmail.com/ Reported-by: Mykyta Yatsenko <mykyta.yatsenko5@gmail.com> Signed-off-by: Eduard Zingerman <eddyz87@gmail.com> Signed-off-by: Andrii Nakryiko <andrii@kernel.org> Link: https://lore.kernel.org/bpf/20250617005710.1066165-2-eddyz87@gmail.com
This commit is contained in:
parent
a633dab4b4
commit
fc2915bb8b
1 changed files with 90 additions and 3 deletions
|
@ -1,15 +1,75 @@
|
||||||
// SPDX-License-Identifier: GPL-2.0-only
|
// SPDX-License-Identifier: GPL-2.0-only
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <sys/utsname.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
#include <zlib.h>
|
||||||
|
|
||||||
#include "unpriv_helpers.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)
|
||||||
|
{
|
||||||
|
const char *msg;
|
||||||
|
char buf[1024];
|
||||||
|
gzFile config;
|
||||||
|
int n, err;
|
||||||
|
|
||||||
|
config = open_config();
|
||||||
|
if (!config)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
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);
|
||||||
|
gzclose(config);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
n = strlen(buf);
|
||||||
|
if (buf[n - 1] == '\n')
|
||||||
|
buf[n - 1] = 0;
|
||||||
|
if (strcmp(buf, pat) == 0) {
|
||||||
|
gzclose(config);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gzclose(config);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool cmdline_contains(const char *pat)
|
||||||
{
|
{
|
||||||
char cmdline[4096], *c;
|
char cmdline[4096], *c;
|
||||||
int fd, ret = false;
|
int fd, ret = false;
|
||||||
|
@ -27,7 +87,7 @@ static bool get_mitigations_off(void)
|
||||||
|
|
||||||
cmdline[sizeof(cmdline) - 1] = '\0';
|
cmdline[sizeof(cmdline) - 1] = '\0';
|
||||||
for (c = strtok(cmdline, " \n"); c; c = strtok(NULL, " \n")) {
|
for (c = strtok(cmdline, " \n"); c; c = strtok(NULL, " \n")) {
|
||||||
if (strncmp(c, "mitigations=off", strlen(c)))
|
if (strncmp(c, pat, strlen(c)))
|
||||||
continue;
|
continue;
|
||||||
ret = true;
|
ret = true;
|
||||||
break;
|
break;
|
||||||
|
@ -37,8 +97,21 @@ out:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int get_mitigations_off(void)
|
||||||
|
{
|
||||||
|
int enabled_in_config;
|
||||||
|
|
||||||
|
if (cmdline_contains("mitigations=off"))
|
||||||
|
return 1;
|
||||||
|
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)
|
bool get_unpriv_disabled(void)
|
||||||
{
|
{
|
||||||
|
int mitigations_off;
|
||||||
bool disabled;
|
bool disabled;
|
||||||
char buf[2];
|
char buf[2];
|
||||||
FILE *fd;
|
FILE *fd;
|
||||||
|
@ -52,5 +125,19 @@ bool get_unpriv_disabled(void)
|
||||||
disabled = true;
|
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;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue