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

"Linux Kernel Mailing List" <[email protected]> Thu, 15 Feb 2018 01:31:43 +0000 (UTC)
Newsgroups gmane.linux.kernel.commits.head
Message-ID <[email protected]>
Web:        https://git.kernel.org/torvalds/c/198ee8e17502da2634f7366395db1d77630e0219
Commit:     198ee8e17502da2634f7366395db1d77630e0219
Parent:     b498c261107461d5c42140dfddd05df83d8ca078
Refname:    refs/heads/master
Author:     Dominik Brodowski <[email protected]>
AuthorDate: Sun Feb 11 12:10:10 2018 +0100
Committer:  Ingo Molnar <[email protected]>
CommitDate: Tue Feb 13 09:04:55 2018 +0100

    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]>
---
 tools/testing/selftests/x86/test_vdso.c | 50 ++++++++++++++++++++++++++++-----
 1 file changed, 43 insertions(+), 7 deletions(-)

diff --git a/tools/testing/selftests/x86/test_vdso.c b/tools/testing/selftests/x86/test_vdso.c
index 29973cde06d3..558c8207e7b9 100644
--- a/tools/testing/selftests/x86/test_vdso.c
+++ b/tools/testing/selftests/x86/test_vdso.c
@@ -28,18 +28,52 @@
 
 int nerrs = 0;
 
+typedef long (*getcpu_t)(unsigned *, unsigned *, void *);
+
+getcpu_t vgetcpu;
+getcpu_t vdso_getcpu;
+
+static void *vsyscall_getcpu(void)
+{
 #ifdef __x86_64__
-# define VSYS(x) (x)
+	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
-# define VSYS(x) 0
+	return NULL;
 #endif
+}
 
-typedef long (*getcpu_t)(unsigned *, unsigned *, void *);