From 862a7a02065e4deed0e9939de05e07f75b74325c Mon Sep 17 00:00:00 2001 From: mdodd Date: Thu, 19 Sep 2002 18:46:25 +0000 Subject: From Christian Zander: This patch addresses a bug that can cause a GPF in the kernel - if a process makes use of i386_set_ldt to install a LDT entry, then loads a corresponding segment descriptor into %gs, forks, and if the child execs. In this scenario, setregs executes user_ldt_free and then determines how to reset the %gs register: /* reset %gs as well */ if (pcb == curpcb) load_gs(_udatasel); else pcb->pcb_gs = _udatasel; This is insufficient in the fork/exec case, since pcb will be equal to curpcb when the child execs; load_gs will reset %gs to _udatasel but it doesn't reset pcb->pcb_gs; upon return from the system call, cpu_switch_load_gs will thus attempt to restore %gs from pcb->pcb_gs and trigger a GPF since all LDT entries have already been cleared. The fix is to always reset pcb->pcb_gs to _udatasel. Submitted by: Christian Zander Reviewed by: jake --- sys/i386/i386/machdep.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'sys/i386') diff --git a/sys/i386/i386/machdep.c b/sys/i386/i386/machdep.c index b5dd641..3516f1c 100644 --- a/sys/i386/i386/machdep.c +++ b/sys/i386/i386/machdep.c @@ -872,8 +872,15 @@ exec_setregs(td, entry, stack, ps_strings) /* reset %gs as well */ if (pcb == PCPU_GET(curpcb)) load_gs(_udatasel); - else - pcb->pcb_gs = _udatasel; + + /* + * Always reset pcb->pcb_gs to udatasel, it will be loaded into gs + * by cpu_switch_load_gs when this process returns from the system + * call. Failing to reset pcb_gs here can cause cpu_switch_load_gs + * to trigger a general protection fault if the parent process had + * modified gs to point at a LDT entry. + */ + pcb->pcb_gs = _udatasel; /* * Reset the hardware debug registers if they were in use. -- cgit v1.1