Project

General

Profile

Bug #9600

LDT still not happy under KPTI

Added by John Levon over 1 year ago. Updated over 1 year ago.

Status:
Closed
Priority:
Normal
Assignee:
Category:
-
Start date:
2018-06-14
Due date:
% Done:

100%

Estimated time:
Difficulty:
Medium
Tags:
needs-triage

Description

SmartOS OS-6967

https://marc.info/?l=illumos-developer&m=152653783025575&w=2

This 32-bit smartos test case will segv.

The problem is pretty prosaic: we update an entry in p->p_ldt, but we don't re-copy the LDT into the CPU's private cpu_m.mcpu_ldt. Only if we happen to come off CPU, and invoke the context ops, will we get a populated LDT.

Testing revealed another problem, which apparently already exists:

436 static void
437 ldt_freectx(proc_t *p, int isexec)
438 {
439         ASSERT(p->p_ldt);
440 
441         if (isexec) {
442                 kpreempt_disable();
443                 cpu_fast_syscall_enable(NULL);
444                 kpreempt_enable();
445         }
446 
447         /*
448          * ldt_free() will free the memory used by the private LDT, reset the
449          * process's descriptor, and re-program the LDTR.
450          */
451         ldt_free(p);
452 }

Now consider proc_exit():


 939         if (p->p_pctx) {
 940                 kpreempt_disable();
 941                 exitpctx(p);
 942                 kpreempt_enable();
 943 
 944                 freepctx(p, 0);

On 941 we call ldt_savectx(). But if we get preempted on :942 or :943, then we'll do:

ldt_savectx()->cpu_fast_syscall_enable()
preempt();
ldt_restorectx()->cpu_fast_syscall_disable()
freepctx()->ldt_freectx(curproc, 0);

and as can be seen above, this will leave fast syscalls disabled for the next thread to come on CPU. Running lots of LDT users can fairly easily trigger seg faults in innocent processes (they take an #ud2 trap or similar on the non-allowed syscall instruction).

The fix seems to be to always do both the re-enable and the ldt_free in ldt_freectx().


Related issues

Related to OpenIndiana Distribution - Bug #9513: SBCL dumps core (SIGSEGV)Closed2018-04-29

Actions

History

#1

Updated by John Levon over 1 year ago

We'll also need to pull in the relevant parts of Alex Wilson's OS-6906. To quote Alex's comments there:

"
In lx_ldt.h in the LDT_INFO_TO_DESC macro that we use to construct both LDT and GDT segment descriptors for LX, we currently leave the lowest bit (the "accessed" bit) unset. This is unfortunate, as it means that the CPU is going to try to write this bit to 1 whenever we set a descriptor register (say, %gs) to a segment we set up like this.

In the post-KPTI world, the GDT is mapped read-only in the user page tables, which will cause a fault when the CPU tries to write to it. This is the root cause of SWSUP-1166 as well as numerous 32-bit LX crashes post-KPTI.

We should always set the "accessed" bit on GDT entries no matter what, to avoid this write altogether.
"

This applies outside of LX too.

#2

Updated by Electric Monk over 1 year ago

  • Status changed from New to Closed
  • % Done changed from 0 to 100

git commit a0955b86cd77e22e80846428a5065e871b6d8eb8

commit  a0955b86cd77e22e80846428a5065e871b6d8eb8
Author: John Levon <john.levon@joyent.com>
Date:   2018-06-15T14:50:24.000Z

    9600 LDT still not happy under KPTI
    Reviewed by: Toomas Soome <tsoome@me.com>
    Reviewed by: Igor Kozhukhov <igor@dilos.org>
    Approved by: Dan McDonald <danmcd@joyent.com>

#3

Updated by Gergő Mihály Doma over 1 year ago

  • Related to Bug #9513: SBCL dumps core (SIGSEGV) added

Also available in: Atom PDF