selftests/x86: Fix vDSO selftest segfault for vsyscall=none

The vDSO selftest tries to execute a vsyscall unconditionally, even if it
is not present on the test system (e.g. if booted with vsyscall=none or
with CONFIG_LEGACY_VSYSCALL_NONE=y set. Fix this by copying (and tweaking)
the vsyscall check from test_vsyscall.c

Signed-off-by: Dominik Brodowski <[email protected]>
Cc: Andrew Lutomirski <[email protected]>
Cc: Linus Torvalds <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Thomas Gleixner <[email protected]>
Cc: [email protected]
Cc: [email protected]
Link: http://lkml.kernel.org/r/[email protected]
Signed-off-by: Ingo Molnar <[email protected]>
This commit is contained in:
Dominik Brodowski 2018-02-11 12:10:10 +01:00 • committed by Ingo Molnar
commit 198ee8e175

View file

@ -28,18 +28,52 @@
int nerrs = 0;
#ifdef __x86_64__
# define VSYS(x) (x)
#else
# define VSYS(x) 0
#endif
typedef long (*getcpu_t)(unsigned *, unsigned *, void *);
const getcpu_t vgetcpu = (getcpu_t)VSYS(0xffffffffff600800);
getcpu_t vgetcpu;
getcpu_t vdso_getcpu;
void fill_function_pointers()
static void *vsyscall_getcpu(void)
{
#ifdef __x86_64__
FILE *maps;
char line[128];
bool found = false;
maps = fopen("/proc/self/maps", "r");
if (!maps) /* might still be present, but ignore it here, as we test vDSO not vsyscall */
return NULL;
while (fgets(line, sizeof(line), maps)) {
char r, x;
void *start, *end;
char name[128];
if (sscanf(line, "%p-%p %c-%cp %*x %*x:%*x %*u %s",
&start, &end, &r, &x, name) != 5)
continue;
if (strcmp(name, "[vsyscall]"))
continue;
/* assume entries are OK, as we test vDSO here not vsyscall */
found = true;
break;
}
fclose(maps);
if (!found) {
printf("Warning: failed to find vsyscall getcpu\n");
return NULL;
}
return (void *) (0xffffffffff600800);
#else
return NULL;
#endif
}
static void fill_function_pointers()
{
void *vdso = dlopen("linux-vdso.so.1",
RTLD_LAZY | RTLD_LOCAL | RTLD_NOLOAD);
@ -54,6 +88,8 @@ void fill_function_pointers()
vdso_getcpu = (getcpu_t)dlsym(vdso, "__vdso_getcpu");
if (!vdso_getcpu)
printf("Warning: failed to find getcpu in vDSO\n");
vgetcpu = (getcpu_t) vsyscall_getcpu();
}
static long sys_getcpu(unsigned * cpu, unsigned * node,