Messages in this thread Patch in this message | | | Date | Fri, 23 Apr 2010 11:01:05 -0700 | From | "H. Peter Anvin" <> | Subject | Re: X86_64 BUG: missing FS/GS LDT reload on fork() |
| |
On 04/23/2010 10:04 AM, Samuel Thibault wrote: > Hello, > > I have an issue with FS/GS LDT reload in the child of fork(). The > attached testcase fails quite often. It sets an LDT entry up, uses > prctl to set gs's base to a 64bit value, then loads gs with the LDT > entry. The LDT entry is now in effect. After a fork call, the LDT entry > is not in effect any more, the 64bit base is back! >
Okay... I have to say that I'm more than a bit confused why you're doing this, but the __switch_no code in process_64.c has the following:
/* * Check if the user used a selector != 0; if yes * clear 64bit base, since overloaded base is always * mapped to the Null selector */ if (fsindex) prev->fs = 0;
[and the same for gs]
However, copy_thread() doesn't have the equivalent code, and __switch_to clearly expects that to be maintained as an invariant -- it doesn't check on entry, only on exit.
The following patch looks like it should address that.
-hpa diff --git a/arch/x86/kernel/process_64.c b/arch/x86/kernel/process_64.c index dc9690b..17cb329 100644 --- a/arch/x86/kernel/process_64.c +++ b/arch/x86/kernel/process_64.c @@ -276,12 +276,12 @@ int copy_thread(unsigned long clone_flags, unsigned long sp, set_tsk_thread_flag(p, TIF_FORK); - p->thread.fs = me->thread.fs; - p->thread.gs = me->thread.gs; p->thread.io_bitmap_ptr = NULL; savesegment(gs, p->thread.gsindex); + p->thread.gs = p->thread.gsindex ? 0 : me->thread.gs; savesegment(fs, p->thread.fsindex); + p->thread.fs = p->thread.fsindex ? 0 : me->thread.fs; savesegment(es, p->thread.es); savesegment(ds, p->thread.ds); | |