lkml.org 
[lkml]   [2019]   [May]   [8]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH v7 02/18] selftests/x86/fsgsbase: Test ptracer-induced GSBASE write
    Date
    The test validates to make sure the selector is not changed when a
    ptracer writes a ptracee's GSBASE.

    Suggested-by: Andy Lutomirski <luto@kernel.org>
    Signed-off-by: Chang S. Bae <chang.seok.bae@intel.com>
    Cc: Thomas Gleixner <tglx@linutronix.de>
    Cc: Ingo Molnar <mingo@kernel.org>
    Cc: H. Peter Anvin <hpa@zytor.com>
    Cc: Andi Kleen <ak@linux.intel.com>
    ---
    tools/testing/selftests/x86/fsgsbase.c | 70 ++++++++++++++++++++++++++++++++++
    1 file changed, 70 insertions(+)

    diff --git a/tools/testing/selftests/x86/fsgsbase.c b/tools/testing/selftests/x86/fsgsbase.c
    index f249e04..1c2dda0 100644
    --- a/tools/testing/selftests/x86/fsgsbase.c
    +++ b/tools/testing/selftests/x86/fsgsbase.c
    @@ -23,6 +23,9 @@
    #include <pthread.h>
    #include <asm/ldt.h>
    #include <sys/mman.h>
    +#include <stddef.h>
    +#include <sys/ptrace.h>
    +#include <sys/wait.h>

    #ifndef __x86_64__
    # error This test is 64-bit only
    @@ -367,6 +370,71 @@ static void test_unexpected_base(void)
    }
    }

    +#define USER_REGS_OFFSET(r) offsetof(struct user_regs_struct, r)
    +
    +static void test_ptrace_write_gsbase(void)
    +{
    + int status;
    + pid_t child = fork();
    +
    + if (child < 0)
    + err(1, "fork");
    +
    + if (child == 0) {
    + printf("[RUN]\tPTRACE_POKE(), write GSBASE from ptracer\n");
    +
    + /*
    + * Use the LDT setup and fetch the GSBASE from the LDT
    + * by switching to the (nonzero) selector (again)
    + */
    + do_unexpected_base();
    + asm volatile ("mov %0, %%gs" : : "rm" ((unsigned short)0x7));
    +
    + if (ptrace(PTRACE_TRACEME, 0, NULL, NULL) != 0)
    + err(1, "PTRACE_TRACEME");
    +
    + raise(SIGTRAP);
    + _exit(0);
    + }
    +
    + wait(&status);
    +
    + if (WSTOPSIG(status) == SIGTRAP) {
    + unsigned long gs;
    + unsigned long gs_offset = USER_REGS_OFFSET(gs);
    + unsigned long base_offset = USER_REGS_OFFSET(gs_base);
    +
    + gs = ptrace(PTRACE_PEEKUSER, child, gs_offset, NULL);
    +
    + if (gs != 0x7) {
    + nerrs++;
    + printf("[FAIL]\tGS is not prepared with nonzero\n");
    + goto END;
    + }
    +
    + if (ptrace(PTRACE_POKEUSER, child, base_offset, 0xFF) != 0)
    + err(1, "PTRACE_POKEUSER");
    +
    + gs = ptrace(PTRACE_PEEKUSER, child, gs_offset, NULL);
    +
    + /*
    + * In a non-FSGSBASE system, the nonzero selector will load
    + * GSBASE (again). But what is tested here is whether the
    + * selector value is changed or not by the GSBASE write in
    + * a ptracer.
    + */
    + if (gs != 0x7) {
    + nerrs++;
    + printf("[FAIL]\tGS changed to %lx\n", gs);
    + } else {
    + printf("[OK]\tGS remained 0x7\n");
    + }
    + }
    +
    +END:
    + ptrace(PTRACE_CONT, child, NULL, NULL);
    +}
    +
    int main()
    {
    pthread_t thread;
    @@ -423,5 +491,7 @@ int main()
    if (pthread_join(thread, NULL) != 0)
    err(1, "pthread_join");

    + test_ptrace_write_gsbase();
    +
    return nerrs == 0 ? 0 : 1;
    }
    --
    2.7.4
    \
     
     \ /
      Last update: 2019-05-08 19:04    [W:3.666 / U:0.024 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site