Bug #9600
closedLDT still not happy under KPTI
100%
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
Updated by John Levon over 5 years 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.
Updated by Electric Monk over 5 years 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>
Updated by Gergő Mihály Doma over 5 years ago
- Related to Bug #9513: SBCL dumps core (SIGSEGV) added