Hi,
The most efficient method would be:
Unfortunately that requires you to patch the paging structures during task switches, such that each CPU uses a (slightly) different version of "kernel space". This only works efficiently in some cases (PAE or long mode, or if you're using one virtual address space per thread/CPU anyway).
The second most efficient method would be:
In this case, GS is treated as a constant. If malicious code could attempt to set GS to something else then you have to make sure the "add gs:ps_nesting,1" will cause some sort of exception where the exception handler corrects GS and returns. This makes the "common case" fast (at the expense of making the "worst case that should never happen" slower).
The third most efficient method would be:
In this case you use the "swapgs" instruction every time the CPU switches from CPL=3 to CPL=0, and then restore the user-space value of GS when the CPU returns to CPL=3 from CPL=0. Unfortunately it only works in long mode.
The fourth most efficient method would be to use one of the debugging registers. For example:
Code: Select all
pushfd
cli
mov eax,dr3
add dword [eax+ps_nesting],1
popfd
This means you're only able to use 3 of the 4 debugging registers for debugging.
rdos wrote:I think the GDTR method outcompetes the TR method easily, and it additionally does not require disabling interrupts.
The cost of loading a segment register is too high - the GDTR method is is probably tenth on the list of "most efficient ways".
Cheers,
Brendan