uprobes: handle_swbp() fixes
Subsystems (3)
Oleg Nesterov
maintainercover uprobes: handle_swbp() fixes
Hello.
Mostly fixes the error hanling in handle_swbp().
Srikar, please review.
Oleg.
arch/x86/kernel/signal.c | 4 +-- include/linux/uprobes.h | 1 - kernel/events/uprobes.c | 66 +++++++++++++++++++-------------------------- 3 files changed, 29 insertions(+), 42 deletions(-)
Oleg Nesterov
maintainerPATCH 1/5 uprobes: Do not leak UTASK_BP_HIT if find_active_uprobe() fails
If handle_swbp()->find_active_uprobe() fails we return with utask->state = UTASK_BP_HIT.
Change handle_swbp() to reset utask->state at the start. Note that we do this unconditionally, see the next patch(es).
--- kernel/events/uprobes.c | 5 ++++- 1 files changed, 4 insertions(+), 1 deletions(-)
kernel/events/uprobes.c +4 -1
@@ -1468,6 +1468,10 @@ static void handle_swbp(struct pt_regs *regs) bp_vaddr =uprobe_get_swbp_addr (regs); uprobe =find_active_uprobe (bp_vaddr, &is_swbp); + utask = current->utask; +if (utask) + utask->state =UTASK_RUNNING ; +if (!uprobe) {if (is_swbp >0 ) {/* No matching uprobe; signal SIGTRAP. */
@@ -1486,7 +1490,6 @@ static void handle_swbp(struct pt_regs *regs)return ; } - utask = current->utask;if (!utask) { utask =add_utask ();/* Cannot allocate; re-execute the instruction. */
Signature · 1 line
1.5.5.1
Oleg Nesterov
maintainerRe: [PATCH 1/5] uprobes: Do not leak UTASK_BP_HIT if find_active_uprobe() fails
(additional note to simplify the review)
Quoted 3 lines · Oleg Nesterov
Note
that we do this unconditionally, see the next patch(es).
IOW, we could move it under "if (!uprobe)" branch, but we do not.
This is mostly needed for 2/5, which in turn is needed for 3/5. If can_skip_sstep() succeeds we need to reset utask->state too.
ALternatively we could start with 4/5, but this is the "separate" change (and it is not bug-fix) which needs your review/ack.
Oleg.
Re: [PATCH 1/5] uprobes: Do not leak UTASK_BP_HIT if find_active_uprobe() fails
In reply to Oleg NesterovQuoted 27 lines
If handle_swbp()->find_active_uprobe() fails we return with
utask->state=UTASK_BP_HIT.Change
handle_swbp()to resetutask->stateat the start. Note that we do this unconditionally, see the next patch(es).Signed-off-by Oleg Nesterov <[email protected]>--- kernel/events/uprobes.c | 5 ++++- 1 files changed, 4 insertions(+), 1 deletions(-)kernel/events/uprobes.c +4
-0@@ -1468,6 +1468,10 @@ static void handle_swbp(struct pt_regs *regs) bp_vaddr =uprobe_get_swbp_addr (regs); uprobe =find_active_uprobe (bp_vaddr, &is_swbp); + utask = current->utask; +if (utask) + utask->state =UTASK_RUNNING ; +if (!uprobe) {if (is_swbp >0 ) {/* No matching uprobe; signal SIGTRAP. */
kernel/events/uprobes.c static void handle_swbp(struct pt_regs *regs) · line 1495
Quoted 7 lines
kernel/events/uprobes.c +0
-1@@ -1486,7 +1490,6 @@ static void handle_swbp(struct pt_regs *regs)return ; } - utask = current->utask;if (!utask) { utask =add_utask ();/* Cannot allocate; re-execute the instruction. */
Oleg Nesterov
maintainerPATCH 2/5 uprobes: Do not setup ->active_uprobe/state prematurely
In reply to Oleg Nesterovhandle_swbp() sets utask->active_uprobe before handler_chain(), and UTASK_SSTEP before pre_ssout(). This complicates the code for no reason, arch_ hooks or consumer->handler() should not (and can't) use this info.
Change handle_swbp() to initialize them after pre_ssout(), and remove the no longer needed cleanup-utask code.
--- kernel/events/uprobes.c | 9 +++------ 1 files changed, 3 insertions(+), 6 deletions(-)
kernel/events/uprobes.c +3 -6
@@ -1496,22 +1496,19 @@ static void handle_swbp(struct pt_regs *regs)if (!utask) goto cleanup_ret; } - utask->active_uprobe = uprobe; +handler_chain (uprobe, regs);if (uprobe->flags &UPROBE_SKIP_SSTEP &&can_skip_sstep (uprobe, regs)) goto cleanup_ret; - utask->state =UTASK_SSTEP ;if (!pre_ssout (uprobe, regs, bp_vaddr)) {arch_uprobe_enable_step (&uprobe->arch); + utask->active_uprobe = uprobe; + utask->state =UTASK_SSTEP ;return ; } cleanup_ret: -if (utask) { - utask->active_uprobe =NULL ; - utask->state =UTASK_RUNNING ; - }if (!(uprobe->flags &UPROBE_SKIP_SSTEP ))/*
Signature · 1 line
1.5.5.1
Re: [PATCH 2/5] uprobes: Do not setup ->active_uprobe/state prematurely
Quoted 33 lines · Oleg Nesterov
handle_swbp()setsutask->active_uprobebeforehandler_chain(), andUTASK_SSTEPbeforepre_ssout(). This complicates the code for no reason,arch_hooks orconsumer->handler()should not (and can't) use this info.Change
handle_swbp()to initialize them afterpre_ssout(), and remove the no longer needed cleanup-utask code.Signed-off-by Oleg Nesterov <[email protected]>--- kernel/events/uprobes.c | 9 +++------ 1 files changed, 3 insertions(+), 6 deletions(-)kernel/events/uprobes.c +3
-2@@ -1496,22 +1496,19 @@ static void handle_swbp(struct pt_regs *regs)if (!utask) goto cleanup_ret; } - utask->active_uprobe = uprobe; +handler_chain (uprobe, regs);if (uprobe->flags &UPROBE_SKIP_SSTEP &&can_skip_sstep (uprobe, regs)) goto cleanup_ret; - utask->state =UTASK_SSTEP ;if (!pre_ssout (uprobe, regs, bp_vaddr)) {arch_uprobe_enable_step (&uprobe->arch); + utask->active_uprobe = uprobe; + utask->state =UTASK_SSTEP ;return ;
kernel/events/uprobes.c static void handle_swbp(struct pt_regs *regs) · line 1514
Quoted 10 lines
kernel/events/uprobes.c +0
-4} cleanup_ret: -if (utask) { - utask->active_uprobe =NULL ; - utask->state =UTASK_RUNNING ; - }if (!(uprobe->flags &UPROBE_SKIP_SSTEP ))/*
Oleg Nesterov
maintainerPATCH 3/5 uprobes: Fix UPROBE_SKIP_SSTEP checks in handle_swbp()
In reply to Oleg NesterovIf handle_swbp()->add_utask() fails but UPROBE_SKIP_SSTEP is set,cleanup_ret: path do not restart the insn, this is wrong. Remove this check and add the additional label for can_skip_sstep() = T case.
Note also that UPROBE_SKIP_SSTEP can be false positive, we simply can not trust it unless arch_uprobe_skip_sstep() was already called.
Also, move another UPROBE_SKIP_SSTEP check before can_skip_sstep() into this helper, this looks more clean and understandable.
Note: probably we should rename "skip" to "emulate" and I think that "clear UPROBE_SKIP_SSTEP" should be moved to arch_can_skip.
--- kernel/events/uprobes.c | 31 +++++++++++++++---------------- 1 files changed, 15 insertions(+), 16 deletions(-)
kernel/events/uprobes.c +15 -16
@@ -1389,10 +1389,11 @@ bool uprobe_deny_signal(void)*/ static bool can_skip_sstep (struct uprobe *uprobe,struct pt_regs *regs) { -if (arch_uprobe_skip_sstep (&uprobe->arch, regs)) -return true; - - uprobe->flags &= ~UPROBE_SKIP_SSTEP ; +if (uprobe->flags &UPROBE_SKIP_SSTEP ) { +if (arch_uprobe_skip_sstep (&uprobe->arch, regs)) +return true; + uprobe->flags &= ~UPROBE_SKIP_SSTEP ; + }return false; }
@@ -1494,12 +1495,12 @@ static void handle_swbp(struct pt_regs *regs) utask =add_utask ();/* Cannot allocate; re-execute the instruction. */ if (!utask) - goto cleanup_ret; + goto restart; }handler_chain (uprobe, regs); -if (uprobe->flags &UPROBE_SKIP_SSTEP &&can_skip_sstep (uprobe, regs)) - goto cleanup_ret; +if (can_skip_sstep (uprobe, regs)) + goto out;if (!pre_ssout (uprobe, regs, bp_vaddr)) {arch_uprobe_enable_step (&uprobe->arch);
@@ -1508,15 +1509,13 @@ static void handle_swbp(struct pt_regs *regs)return ; } -cleanup_ret: -if (!(uprobe->flags &UPROBE_SKIP_SSTEP )) - -/* -* cannot singlestep; cannot skip instruction; -* re-execute the instruction. -*/ -instruction_pointer_set (regs, bp_vaddr); - +restart: +/* +* cannot singlestep; cannot skip instruction; +* re-execute the instruction. +*/ +instruction_pointer_set (regs, bp_vaddr); +out:put_uprobe (uprobe); }
Signature · 1 line
1.5.5.1
Re: [PATCH 3/5] uprobes: Fix UPROBE_SKIP_SSTEP checks in handle_swbp()
Quoted 5 lines · Oleg Nesterov
If handle_swbp()->add_utask() fails but
UPROBE_SKIP_SSTEPis set,cleanup_ret: path do not restart the insn, this is wrong. Remove this check and add the additional label forcan_skip_sstep()= T case.
Quoted 8 lines
Note also that
UPROBE_SKIP_SSTEPcan be false positive, we simply can not trust it unlessarch_uprobe_skip_sstep()was already called.Also, move another
UPROBE_SKIP_SSTEPcheck beforecan_skip_sstep()into this helper, this looks more clean and understandable.Note: probably we should rename "skip" to "emulate" and I think that "clear
UPROBE_SKIP_SSTEP" should be moved toarch_can_skip.
Agree. emulate is more accurate in this situation since, especially on powerpc, we do emulate most instructions.
Ananth
Oleg Nesterov
maintainerRe: [PATCH 3/5] uprobes: Fix UPROBE_SKIP_SSTEP checks in handle_swbp()
Quoted 8 lines · Ananth N Mavinakayanahalli
Quoted 3 lines · Oleg Nesterov
Note: probably we should rename "skip" to "emulate" and I think that "clear
UPROBE_SKIP_SSTEP" should be moved toarch_can_skip.Agree. emulate is more accurate in this situation since, especially on powerpc, we do emulate most instructions.
Yes. And even on x86, perhaps we should emulate at least pushf to not expose TF set by uprobes.
Off-topic question... I am trying to understand if arch_uprobe_skip_sstep() is correct on x86.
It doesn't update regs->ip. Probably this is fine, at least this is fine if it finds "nop" eventually. But I can't undestand what "0x66* { 0x90 | 0x0f 0x1f | 0x0f 0x19 | 0x87 0xc0 }" means. OK, 0x66 and 0x90 are clear. But, say, 0x0f 0x1f ?
I compiled this program
int main(void)
{
asm volatile (".word 0x1f0f");
return 0;
}and objdump reports:
000000000040047c <main>: 40047c: 0f 1f 31 nopl (%rcx) 40047f: c0 c3 90 rol $0x90,%bl
Could you explain?
Oleg.
Re: [PATCH 3/5] uprobes: Fix UPROBE_SKIP_SSTEP checks in handle_swbp()
Quoted 4 lines · Oleg Nesterov
Quoted 3 lines · Ananth N Mavinakayanahalli
Quoted 1 line · Oleg Nesterov
Quoted 9 lines
Quoted 5 lines
Quoted 2 lines
Note: probably we should rename "skip" to "emulate" and I think that "clear
UPROBE_SKIP_SSTEP" should be moved toarch_can_skip.Agree. emulate is more accurate in this situation since, especially on powerpc, we do emulate most instructions.
Yes. And even on x86, perhaps we should emulate at least pushf to not expose TF set by uprobes.
Good idea.
Quoted 4 lines
Off-topic question... I am trying to understand if
arch_uprobe_skip_sstep()is correct on x86.It doesn't update
regs->ip.
Right. we need to adjust for the size of the instruction.
Quoted 4 lines
Probably this is fine, at least this is
fine if it finds "nop" eventually. But I can't undestand what "0x66* {0x90|0x0f0x1f|0x0f0x19|0x870xc0}" means. OK,0x66and0x90are clear. But, say,0x0f0x1f?
we skip is 0x66 ..0x66 0x0f 0x1f
So we have a check
if (i == (MAX_UINSN_BYTES - 1))
so this ensures that we are consider 0x0f 0x1f as nop if and only if they are at the end and preceeded by 0x66. This is not an exhaustive list of nops.
So are you suggesting extending the list of nops or is it that we are considering non nop instructions as nops?
Extending the list, we certainly should not just for nops.
Quoted 9 lines
I compiled this program
int main(void) { asm volatile (".word 0x1f0f"); return 0; }
Quoted 4 lines
and objdump reports:
000000000040047c <main>: 40047c: 0f 1f 31 nopl (%rcx)
Current uprobes code wouldnt skip the above insn because it has 31 following it.
Quoted 1 line
40047f: c0 c3 90 rol $0x90,%bl
we dont skip this too.
Signature · 2 lines
Thanks and Regards Srikar
Oleg Nesterov
maintainerRe: [PATCH 3/5] uprobes: Fix UPROBE_SKIP_SSTEP checks in handle_swbp()
Quoted 15 lines · Srikar Dronamraju
Quoted 4 lines · Oleg Nesterov
Off-topic question... I am trying to understand if
arch_uprobe_skip_sstep()is correct on x86.It doesn't update
regs->ip.Right. we need to adjust for the size of the instruction.
Quoted 4 lines
Probably this is fine, at least this is
fine if it finds "nop" eventually. But I can't undestand what "0x66* {0x90|0x0f0x1f|0x0f0x19|0x870xc0}" means. OK,0x66and0x90are clear. But, say,0x0f0x1f?
Quoted 7 lines
we skip is
0x66..0x660x0f0x1fSo we have a check
if (i == (MAX_UINSN_BYTES- 1))so this ensures that we are consider
0x0f0x1fas nop if and only if they are at the end and preceeded by0x66.
Hmm. How so? The code does
if (i == (MAX_UINSN_BYTES - 1)) break; if ((auprobe->insn[i] == 0x0f) && (auprobe->insn[i+1] == 0x1f)) return true;
So, afaics, if the intent was to skip 1f0f at the end only, it should do
if (i == (MAX_UINSN_BYTES - 1)) {
if ((auprobe->insn[i] == 0x0f) && (auprobe->insn[i+1] == 0x1f))
return true;
...
}"and preceeded by 0x66" above doesn't look true too, perhaps you meant "may be preceeded by 0x66".
Quoted 2 lines
So are you suggesting extending the list of nops or is it that we are considering non nop instructions as nops?
No, I am trying to understand which insns arch_skip tries to skip. In particular, what "0x0f 0x1f" means.
Quoted 8 lines
Quoted 8 lines
I compiled this program
int main(void) { asm volatile (".word 0x1f0f"); return 0; }
Quoted 7 lines
Quoted 4 lines
and objdump reports:
000000000040047c <main>: 40047c: 0f 1f 31 nopl (%rcx)Current uprobes code wouldnt skip the above insn because it has 31 following it.
See above.
And again, could you explain which insn has 1f0f (at the end or not) ? IOW, what we are trying to skip?
Oleg.
Re: [PATCH 3/5] uprobes: Fix UPROBE_SKIP_SSTEP checks in handle_swbp()
Quoted 16 lines · Oleg Nesterov
Quoted 6 lines
Quoted 5 lines
Probably this is fine, at least this is
fine if it finds "nop" eventually. But I can't undestand what "0x66* {0x90|0x0f0x1f|0x0f0x19|0x870xc0}" means. OK,0x66and0x90are clear. But, say,0x0f0x1f?Quoted 7 lines
we skip is
0x66..0x660x0f0x1fSo we have a check
if (i == (MAX_UINSN_BYTES- 1))so this ensures that we are consider
0x0f0x1fas nop if and only if they are at the end and preceeded by0x66.Hmm. How so? The code does
Quoted 8 lines
if (i == (MAX_UINSN_BYTES - 1)) break; if ((auprobe->insn[i] == 0x0f) && (auprobe->insn[i+1] == 0x1f)) return true;So, afaics, if the intent was to skip 1f0f at the end only, it should do
Its 0f1f and not 1f0f
Quoted 10 lines
if (i == (MAX_UINSN_BYTES - 1)) { if ((auprobe->insn[i] == 0x0f) && (auprobe->insn[i+1] == 0x1f)) return true; ... }"and preceeded by
0x66" above doesn't look true too, perhaps you meant "may be preceeded by0x66".
Yup, as always you are right. We expect 0x0f 0x1f preceeded by 0x66 to be nop instructions.
Quoted 19 lines
Quoted 2 lines
So are you suggesting extending the list of nops or is it that we are considering non nop instructions as nops?
No, I am trying to understand which insns
arch_skiptries to skip. In particular, what "0x0f0x1f" means.Quoted 13 lines
Quoted 12 lines
I compiled this program
int main(void) { asm volatile (".word 0x1f0f"); return 0; }and objdump reports:
000000000040047c <main>: 40047c: 0f 1f 31 nopl (%rcx)
Quoted 7 lines
Quoted 2 lines
Current uprobes code wouldnt skip the above insn because it has 31 following it.
See above.
And again, could you explain which insn has 1f0f (at the end or not) ? IOW, what we are trying to skip?
Again its 0f1f and not 1f0f
for example
0f 1f 40 00
0f 1f 44 00 00
66 0f 1f 44 00 00
I referred arch/x86/include/asm/nops.h, arch/x86/lib/x86-opcode-map.txt and disassembly of libc. And ofcourse Jim Keniston helped me in most of the x86 stuff.
--
thanks and regards
Srikar
Oleg Nesterov
maintainerRe: [PATCH 3/5] uprobes: Fix UPROBE_SKIP_SSTEP checks in handle_swbp()
Srikar, sorry for delay, somehow I missed this email.
And I am still confused...
Quoted 19 lines · Srikar Dronamraju
Quoted 16 lines · Oleg Nesterov
Quoted 15 lines
Quoted 8 lines
I compiled this program
int main(void) { asm volatile (".word 0x1f0f"); return 0; }Quoted 4 lines
and objdump reports:
000000000040047c <main>: 40047c: 0f 1f 31 nopl (%rcx)Current uprobes code wouldnt skip the above insn because it has 31 following it.
Quoted 6 lines
Quoted 4 lines
See above.
And again, could you explain which insn has 1f0f (at the end or not) ? IOW, what we are trying to skip?
Again its 0f1f and not 1f0f
The first byte is 0x0f, the next is 0x1f, so 0x1f0f looks correct, but this doesn't matter.
Anyway,
Quoted 2 lines
for example
0f 1f 40 00
OK, thanks, objdump reports "nopl 0x0(%rax)", looks fine.
But. I do not see how __skip_sstep() can handle this case correctly. Not only it should update regs->ip afaics, it should also account 2 extra bytes _after_ 0f 1f.
Quoted 1 line
0f 1f 44 00 00
OK, nopl 0x0(%rax,%rax,1), but in this case we need to skip 3
extra bytes.
I am starting to think this code is broken and we should simply remove all checks except 0x66 and 0x90. In this case we do not even need to update regs->ip.
Otherwise this code needs to know the insn's length.
Right?
Oleg.
Oleg Nesterov
maintainerRe: [PATCH 3/5] uprobes: Fix UPROBE_SKIP_SSTEP checks in handle_swbp()
Quoted 18 lines · Oleg Nesterov
Anyway,
Quoted 2 lines
for example
0f 1f 40 00OK, thanks, objdump reports "nopl 0x0(%rax)", looks fine.
But. I do not see how
__skip_sstep()can handle this case correctly. Not only it should updateregs->ipafaics, it should also account 2 extra bytes _after_ 0f 1f.Quoted 1 line
0f 1f 44 00 00
OK, nopl 0x0(%rax,%rax,1), but in this case we need to skip 3
extra bytes.
Quoted 7 lines
I am starting to think this code is broken and we should simply remove all checks except
0x66and0x90. In this case we do not even need to updateregs->ip.Otherwise this code needs to know the insn's length.
Right?
OK, I verified that the application is really killed by SIGILL if you probe such an instruction. I'll send the fix which simply removes this code. I do not know how to figure out the actual insn length.
Oleg.
Re: [PATCH 3/5] uprobes: Fix UPROBE_SKIP_SSTEP checks in handle_swbp()
In reply to Oleg NesterovQuoted 5 lines · Oleg Nesterov
If handle_swbp()->add_utask() fails but
UPROBE_SKIP_SSTEPis set,cleanup_ret: path do not restart the insn, this is wrong. Remove this check and add the additional label forcan_skip_sstep()= T case.
Quoted 7 lines
Note also that
UPROBE_SKIP_SSTEPcan be false positive, we simply can not trust it unlessarch_uprobe_skip_sstep()was already called.Also, move another
UPROBE_SKIP_SSTEPcheck beforecan_skip_sstep()into this helper, this looks more clean and understandable.Note: probably we should rename "skip" to "emulate" and I think
yes we can rename can_skip_step to can_emulate_insn and arch_uprobe_skip_step() to arch_uprobe_emulate_insn
Similarly UPROBE_SKIP_SSTEP can be renamed as UPROBE_EMULATE_INSN
Quoted 2 lines
that "clear
UPROBE_SKIP_SSTEP" should be moved toarch_can_skip.
Currently struct uprobe is not exposed to arch specific code as suggested by Ingo. Adding a flag in arch_uprobe just for this and expecting all archs to define one is probably an overhead. Hence I am not sure moving the clear flag to arch is a good idea.
Quoted 1 line
Signed-off-by Oleg Nesterov <[email protected]>
Quoted 66 lines
--- kernel/events/uprobes.c | 31 +++++++++++++++---------------- 1 files changed, 15 insertions(+), 16 deletions(-)kernel/events/uprobes.c +15
-16@@ -1389,10 +1389,11 @@ bool uprobe_deny_signal(void)*/ static bool can_skip_sstep (struct uprobe *uprobe,struct pt_regs *regs) { -if (arch_uprobe_skip_sstep (&uprobe->arch, regs)) -return true; - - uprobe->flags &= ~UPROBE_SKIP_SSTEP ; +if (uprobe->flags &UPROBE_SKIP_SSTEP ) { +if (arch_uprobe_skip_sstep (&uprobe->arch, regs)) +return true; + uprobe->flags &= ~UPROBE_SKIP_SSTEP ; + }return false; }@@ -1494,12 +1495,12 @@ static void handle_swbp(struct pt_regs *regs) utask =add_utask ();/* Cannot allocate; re-execute the instruction. */ if (!utask) - goto cleanup_ret; + goto restart; }handler_chain (uprobe, regs); -if (uprobe->flags &UPROBE_SKIP_SSTEP &&can_skip_sstep (uprobe, regs)) - goto cleanup_ret; +if (can_skip_sstep (uprobe, regs)) + goto out;if (!pre_ssout (uprobe, regs, bp_vaddr)) {arch_uprobe_enable_step (&uprobe->arch);@@ -1508,15 +1509,13 @@ static void handle_swbp(struct pt_regs *regs)return ; } -cleanup_ret: -if (!(uprobe->flags &UPROBE_SKIP_SSTEP )) - -/* -* cannot singlestep; cannot skip instruction; -* re-execute the instruction. -*/ -instruction_pointer_set (regs, bp_vaddr); - +restart: +/* +* cannot singlestep; cannot skip instruction; +* re-execute the instruction. +*/ +instruction_pointer_set (regs, bp_vaddr); +out:put_uprobe (uprobe); }Signature · 1 line
1.5.5.1
Oleg Nesterov
maintainerPATCH 4/5 uprobes: Kill UTASK_BP_HIT state
In reply to Oleg NesterovKill UTASK_BP_HIT state, it buys nothing but complicates the code. It is only used in uprobe_notify_resume() to decide who should be called, we can check utask->active_uprobe != NULL instead. And this allows us to simplify handle_swbp(), no need to clear utask->state.
Likewise we could kill UTASK_SSTEP, but UTASK_BP_HIT is worse and imho should die. The problem is, it creates the special case when task->utask is NULL, we can't distinguish RUNNING and BP_HIT. With his patch utask == NULL always means RUNNING.
--- include/linux/uprobes.h | 1 - kernel/events/uprobes.c | 29 +++++++++-------------------- 2 files changed, 9 insertions(+), 21 deletions(-)
include/linux/uprobes.h +0 -1
@@ -59,7 +59,6 @@ struct uprobe_consumer {#ifdef CONFIG_UPROBES enum uprobe_task_state {UTASK_RUNNING , -UTASK_BP_HIT ,UTASK_SSTEP ,UTASK_SSTEP_ACK , UTASK_SSTEP_TRAPPED,
kernel/events/uprobes.c +9 -20
@@ -1469,10 +1469,6 @@ static void handle_swbp(struct pt_regs *regs) bp_vaddr =uprobe_get_swbp_addr (regs); uprobe =find_active_uprobe (bp_vaddr, &is_swbp); - utask = current->utask; -if (utask) - utask->state =UTASK_RUNNING ; -if (!uprobe) {if (is_swbp >0 ) {/* No matching uprobe; signal SIGTRAP. */
@@ -1491,6 +1487,7 @@ static void handle_swbp(struct pt_regs *regs)return ; } + utask = current->utask;if (!utask) { utask =add_utask ();/* Cannot allocate; re-execute the instruction. */
@@ -1547,13 +1544,12 @@ static void handle_singlestep(struct uprobe_task *utask, struct pt_regs *regs) }/* -* On breakpoint hit, breakpoint notifier sets the TIF_UPROBE flag. (and on -* subsequent probe hits on the thread sets the state to UTASK_BP_HIT) and -* allows the thread to return from interrupt. +* On breakpoint hit, breakpoint notifier sets the TIF_UPROBE flag and +* allows the thread to return from interrupt. After that handle_swbp() +* sets utask->active_uprobe. * -* On singlestep exception, singlestep notifier sets the TIF_UPROBE flag and -* also sets the state to UTASK_SSTEP_ACK and allows the thread to return from -* interrupt. +* On singlestep exception, singlestep notifier sets the TIF_UPROBE flag +* and allows the thread to return from interrupt. * * While returning to userspace, thread notices the TIF_UPROBE flag and calls * uprobe_notify_resume().
@@ -1563,10 +1559,10 @@ void uprobe_notify_resume(struct pt_regs *regs)struct uprobe_task *utask; utask = current->utask; -if (!utask || utask->state ==UTASK_BP_HIT ) -handle_swbp (regs); -else +if (utask && utask->active_uprobe)handle_singlestep (utask, regs); +else +handle_swbp (regs); }/*
@@ -1575,17 +1571,10 @@ void uprobe_notify_resume(struct pt_regs *regs)*/ int uprobe_pre_sstep_notifier (struct pt_regs *regs) { -struct uprobe_task *utask; -if (!current->mm || !test_bit (MMF_HAS_UPROBES , ¤t->mm->flags))return 0 ; - utask = current->utask; -if (utask) - utask->state =UTASK_BP_HIT ; -set_thread_flag (TIF_UPROBE ); -return 1 ; }
Signature · 1 line
1.5.5.1
Oleg Nesterov
maintainerRe: [PATCH 4/5] uprobes: Kill UTASK_BP_HIT state
Quoted 5 lines · Oleg Nesterov
Kill
UTASK_BP_HITstate, it buys nothing but complicates the code. It is only used inuprobe_notify_resume()to decide who should be called, we can checkutask->active_uprobe!= NULL instead. And this allows us to simplifyhandle_swbp(), no need to clearutask->state.
I am starting to think this patch makes even more sense than I thought.
Quoted 1 line
Likewise we could kill
UTASK_SSTEP,
In fact we can kill utask->state. But I just realized we can also kill uprobe_deny_signal() and simplify arch_uprobe_xol_was_trapped() logic.
But this needs some (simple) changes in arch/ code, so we need to wait until powerpc is merged.
Oleg.
Re: [PATCH 4/5] uprobes: Kill UTASK_BP_HIT state
In reply to Oleg NesterovQuoted 11 lines · Oleg Nesterov
Kill
UTASK_BP_HITstate, it buys nothing but complicates the code. It is only used inuprobe_notify_resume()to decide who should be called, we can checkutask->active_uprobe!= NULL instead. And this allows us to simplifyhandle_swbp(), no need to clearutask->state.Likewise we could kill
UTASK_SSTEP, butUTASK_BP_HITis worse and imho should die. The problem is, it creates the special case whentask->utaskis NULL, we can't distinguish RUNNING andBP_HIT. With his patch utask == NULL always means RUNNING.Signed-off-by Oleg Nesterov <[email protected]>
Quoted 94 lines
--- include/linux/uprobes.h | 1 - kernel/events/uprobes.c | 29 +++++++++-------------------- 2 files changed, 9 insertions(+), 21 deletions(-)include/linux/uprobes.h +0
-1@@ -59,7 +59,6 @@ struct uprobe_consumer {#ifdef CONFIG_UPROBES enum uprobe_task_state {UTASK_RUNNING , -UTASK_BP_HIT ,UTASK_SSTEP ,UTASK_SSTEP_ACK , UTASK_SSTEP_TRAPPED,kernel/events/uprobes.c +9
-20@@ -1469,10 +1469,6 @@ static void handle_swbp(struct pt_regs *regs) bp_vaddr =uprobe_get_swbp_addr (regs); uprobe =find_active_uprobe (bp_vaddr, &is_swbp); - utask = current->utask; -if (utask) - utask->state =UTASK_RUNNING ; -if (!uprobe) {if (is_swbp >0 ) {/* No matching uprobe; signal SIGTRAP. */ @@ -1491,6 +1487,7 @@ static void handle_swbp(struct pt_regs *regs)return ; } + utask = current->utask;if (!utask) { utask =add_utask ();/* Cannot allocate; re-execute the instruction. */ @@ -1547,13 +1544,12 @@ static void handle_singlestep(struct uprobe_task *utask, struct pt_regs *regs) }/* -* On breakpoint hit, breakpoint notifier sets the TIF_UPROBE flag. (and on -* subsequent probe hits on the thread sets the state to UTASK_BP_HIT) and -* allows the thread to return from interrupt. +* On breakpoint hit, breakpoint notifier sets the TIF_UPROBE flag and +* allows the thread to return from interrupt. After that handle_swbp() +* sets utask->active_uprobe. * -* On singlestep exception, singlestep notifier sets the TIF_UPROBE flag and -* also sets the state to UTASK_SSTEP_ACK and allows the thread to return from -* interrupt. +* On singlestep exception, singlestep notifier sets the TIF_UPROBE flag +* and allows the thread to return from interrupt. * * While returning to userspace, thread notices the TIF_UPROBE flag and calls * uprobe_notify_resume(). @@ -1563,10 +1559,10 @@ void uprobe_notify_resume(struct pt_regs *regs)struct uprobe_task *utask; utask = current->utask; -if (!utask || utask->state ==UTASK_BP_HIT ) -handle_swbp (regs); -else +if (utask && utask->active_uprobe)handle_singlestep (utask, regs); +else +handle_swbp (regs); }/* @@ -1575,17 +1571,10 @@ void uprobe_notify_resume(struct pt_regs *regs)*/ int uprobe_pre_sstep_notifier (struct pt_regs *regs) { -struct uprobe_task *utask; -if (!current->mm || !test_bit (MMF_HAS_UPROBES , ¤t->mm->flags))return 0 ; - utask = current->utask; -if (utask) - utask->state =UTASK_BP_HIT ; -set_thread_flag (TIF_UPROBE ); -return 1 ; }Signature · 1 line
1.5.5.1
Oleg Nesterov
maintainerPATCH 5/5 uprobes: Move clear_thread_flag(TIF_UPROBE) to uprobe_notify_resume()
In reply to Oleg NesterovMove clear_thread_flag(TIF_UPROBE) from do_notify_resume() to uprobe_notify_resume() for !CONFIG_UPROBES case.
--- arch/x86/kernel/signal.c | 4 +--- kernel/events/uprobes.c | 2 ++ 2 files changed, 3 insertions(+), 3 deletions(-)
arch/x86/kernel/signal.c +1 -3
@@ -785,10 +785,8 @@ do_notify_resume(struct pt_regs *regs, void *unused, __u32 thread_info_flags)mce_notify_process ();#endif /* CONFIG_X86_64 && CONFIG_X86_MCE */ -if (thread_info_flags & _TIF_UPROBE) { -clear_thread_flag (TIF_UPROBE ); +if (thread_info_flags & _TIF_UPROBE)uprobe_notify_resume (regs); - }/* deal with pending signal delivery */ if (thread_info_flags & _TIF_SIGPENDING)
kernel/events/uprobes.c +2 -0
@@ -1558,6 +1558,8 @@ void uprobe_notify_resume(struct pt_regs *regs) {struct uprobe_task *utask; +clear_thread_flag (TIF_UPROBE ); + utask = current->utask;if (utask && utask->active_uprobe)handle_singlestep (utask, regs);
Signature · 1 line
1.5.5.1
Re: [PATCH 5/5] uprobes: Move clear_thread_flag(TIF_UPROBE) to uprobe_notify_resume()
Quoted 4 lines · Oleg Nesterov
Move
clear_thread_flag(TIF_UPROBE)fromdo_notify_resume()touprobe_notify_resume()for !CONFIG_UPROBES case.Signed-off-by Oleg Nesterov <[email protected]>
Quoted 37 lines
--- arch/x86/kernel/signal.c | 4 +--- kernel/events/uprobes.c | 2 ++ 2 files changed, 3 insertions(+), 3 deletions(-)arch/x86/kernel/signal.c +1
-3@@ -785,10 +785,8 @@ do_notify_resume(struct pt_regs *regs, void *unused, __u32 thread_info_flags)mce_notify_process ();#endif /* CONFIG_X86_64 && CONFIG_X86_MCE */ -if (thread_info_flags & _TIF_UPROBE) { -clear_thread_flag (TIF_UPROBE ); +if (thread_info_flags & _TIF_UPROBE)uprobe_notify_resume (regs); - }/* deal with pending signal delivery */ if (thread_info_flags & _TIF_SIGPENDING)kernel/events/uprobes.c +2
-0@@ -1558,6 +1558,8 @@ void uprobe_notify_resume(struct pt_regs *regs) {struct uprobe_task *utask; +clear_thread_flag (TIF_UPROBE ); + utask = current->utask;if (utask && utask->active_uprobe)handle_singlestep (utask, regs);Signature · 1 line
1.5.5.1