4.9-stable review patch.  If anyone has any objections, please let me know.

------------------

From: Andy Lutomirski <l...@kernel.org>

commit 23d98c204386a98d9ef9f9e744f41443ece4929f upstream.

Those are funny cases.  Make sure they work.

(Something is screwy with signal handling if a selector is 1, 2, or 3.
Anyone who wants to dive into that rabbit hole is welcome to do so.)

Signed-off-by: Andy Lutomirski <l...@kernel.org>
Cc: Borislav Petkov <b...@alien8.de>
Cc: Borislav Petkov <bpet...@suse.de>
Cc: Brian Gerst <brge...@gmail.com>
Cc: Chang Seok <chang.seok....@intel.com>
Cc: Denys Vlasenko <dvlas...@redhat.com>
Cc: H. Peter Anvin <h...@zytor.com>
Cc: Josh Poimboeuf <jpoim...@redhat.com>
Cc: Linus Torvalds <torva...@linux-foundation.org>
Cc: Peter Zijlstra <pet...@infradead.org>
Cc: Thomas Gleixner <t...@linutronix.de>
Signed-off-by: Ingo Molnar <mi...@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gre...@linuxfoundation.org>

---
 tools/testing/selftests/x86/fsgsbase.c |   41 ++++++++++++++++++++++++++++-----
 1 file changed, 35 insertions(+), 6 deletions(-)

--- a/tools/testing/selftests/x86/fsgsbase.c
+++ b/tools/testing/selftests/x86/fsgsbase.c
@@ -285,9 +285,12 @@ static void *threadproc(void *ctx)
        }
 }
 
-static void set_gs_and_switch_to(unsigned long local, unsigned long remote)
+static void set_gs_and_switch_to(unsigned long local,
+                                unsigned short force_sel,
+                                unsigned long remote)
 {
        unsigned long base;
+       unsigned short sel_pre_sched, sel_post_sched;
 
        bool hard_zero = false;
        if (local == HARD_ZERO) {
@@ -297,6 +300,8 @@ static void set_gs_and_switch_to(unsigne
 
        printf("[RUN]\tARCH_SET_GS(0x%lx)%s, then schedule to 0x%lx\n",
               local, hard_zero ? " and clear gs" : "", remote);
+       if (force_sel)
+               printf("\tBefore schedule, set selector to 0x%hx\n", force_sel);
        if (syscall(SYS_arch_prctl, ARCH_SET_GS, local) != 0)
                err(1, "ARCH_SET_GS");
        if (hard_zero)
@@ -307,18 +312,35 @@ static void set_gs_and_switch_to(unsigne
                printf("[FAIL]\tGSBASE wasn't set as expected\n");
        }
 
+       if (force_sel) {
+               asm volatile ("mov %0, %%gs" : : "rm" (force_sel));
+               sel_pre_sched = force_sel;
+               local = read_base(GS);
+
+               /*
+                * Signal delivery seems to mess up weird selectors.  Put it
+                * back.
+                */
+               asm volatile ("mov %0, %%gs" : : "rm" (force_sel));
+       } else {
+               asm volatile ("mov %%gs, %0" : "=rm" (sel_pre_sched));
+       }
+
        remote_base = remote;
        ftx = 1;
        syscall(SYS_futex, &ftx, FUTEX_WAKE, 0, NULL, NULL, 0);
        while (ftx != 0)
                syscall(SYS_futex, &ftx, FUTEX_WAIT, 1, NULL, NULL, 0);
 
+       asm volatile ("mov %%gs, %0" : "=rm" (sel_post_sched));
        base = read_base(GS);
-       if (base == local) {
-               printf("[OK]\tGSBASE remained 0x%lx\n", local);
+       if (base == local && sel_pre_sched == sel_post_sched) {
+               printf("[OK]\tGS/BASE remained 0x%hx/0x%lx\n",
+                      sel_pre_sched, local);
        } else {
                nerrs++;
-               printf("[FAIL]\tGSBASE changed to 0x%lx\n", base);
+               printf("[FAIL]\tGS/BASE changed from 0x%hx/0x%lx to 
0x%hx/0x%lx\n",
+                      sel_pre_sched, local, sel_post_sched, base);
        }
 }
 
@@ -381,8 +403,15 @@ int main()
 
        for (int local = 0; local < 4; local++) {
                for (int remote = 0; remote < 4; remote++) {
-                       set_gs_and_switch_to(bases_with_hard_zero[local],
-                                            bases_with_hard_zero[remote]);
+                       for (unsigned short s = 0; s < 5; s++) {
+                               unsigned short sel = s;
+                               if (s == 4)
+                                       asm ("mov %%ss, %0" : "=rm" (sel));
+                               set_gs_and_switch_to(
+                                       bases_with_hard_zero[local],
+                                       sel,
+                                       bases_with_hard_zero[remote]);
+                       }
                }
        }
 


Reply via email to