Re: [PATCH v3 5/6] x86/alternative: Use a single access in text_poke() where possible

From: Alexandre Chartre
Date: Tue Jan 15 2019 - 06:13:17 EST



On 01/11/2019 05:57 PM, Josh Poimboeuf wrote:
On Fri, Jan 11, 2019 at 05:46:36PM +0100, Alexandre Chartre wrote:


On 01/11/2019 04:28 PM, Josh Poimboeuf wrote:
On Fri, Jan 11, 2019 at 01:10:52PM +0100, Alexandre Chartre wrote:
To avoid any issue with live patching the call instruction, what about
toggling between two call instructions: one would be the currently active
call, while the other would currently be inactive but to be used after a
change is made. You can safely patch the inactive call and then toggle
the call flow (using a jump label) between the active and inactive calls.

So instead of having a single call instruction:

call function

You would have:

STATIC_JUMP_IF_TRUE label, key
call function1
jmp done
label:
call function2
done:

If the key is set so that function1 is currently called then you can
safely update the call instruction for function2. Once this is done,
just flip the key to make the function2 call active. On a next update,
you would, of course, have to switch and update the call for function1.

What about the following race?

CPU1 CPU2
static key is false, doesn't jump
task gets preempted before calling function1
change static key to true
start patching "call function1"
task resumes, sees inconsistent call instruction


If the function1 call is active then it won't be changed, you will change
function2. However, I presume you can still have a race but if the function
is changed twice before calling function1:

CPU1 CPU2
static key is false, doesn't jump
task gets preempted before calling function1
-- first function change --
patch "call function2"
change static key to true
-- second function change --
start patching "call function1"
task resumes, sees inconsistent call instruction

So right, that's a problem.

Right, that's what I meant to say :-)


Thinking more about it (and I've probably missed something or I am just being
totally stupid because this seems way too simple), can't we just replace the
"call" with "push+jmp" and patch the jmp instruction?

Instead of having:

call target

Have:

push $done
static_call:
jmp target
done:

Then we can safely patch the "jmp" instruction to jump to a new target
with text_poke_bp(), using the new target as the text_poke_bp() handler:

new_jmp_code = opcode of "jmp new_target"

text_poke_bp(static_call, new_jmp_code, new_jmp_code_size, new_target);

Problems come with patching a call instruction, but there's no issue with patching
a jmp, no? (that's what jump labels do).

No change to the int3 handler, no thunk, this seems really too simple... :-)


alex.