uprobes: mmap_region() corrupts mm->mm_rb if uprobe_mmap() fails
Subsystems (7)
Oleg Nesterov
maintainerPATCH 1/1 uprobes: mmap_region() corrupts mm->mm_rb if uprobe_mmap() fails
https://bugzilla.redhat.com/show_bug.cgi?id=843640
If mmap_region()->uprobe_mmap() fails, unmap_and_free_vma path does unmap_region() but does not remove the soon-to-be-freed vma from rb tree (actually there are more problems).
Perhaps we could do do_munmap() + return in this case, but in fact it is simply wrong to abort if uprobe_mmap() fails. Until at least we move the !UPROBE_COPY_INSN code from install_breakpoint() to uprobe_register().
For example, uprobe_mmap()->install_breakpoint() can fail if the probed insn is not supported (remember, uprobe_register() succeeds if nobody mmaps inode/offset), mmap() should not fail in this case.
dup_mmap()->uprobe_mmap() is wrong too by the same reason, fork() can race with uprobe_register() and fail for no reason if it wins the race and does install_breakpoint() first.
Change mmap_region() and dup_mmap() to ignore the error code from uprobe_mmap().
--- kernel/fork.c | 4 ++-- mm/mmap.c | 5 ++--- 2 files changed, 4 insertions(+), 5 deletions(-)
kernel/fork.c +2 -2
@@ -454,8 +454,8 @@ static int dup_mmap(struct mm_struct *mm, struct mm_struct *oldmm)if (retval) goto out; -if (file &&uprobe_mmap (tmp)) - goto out; +if (file) +uprobe_mmap (tmp); }/* a new mm has just been created */ arch_dup_mmap (oldmm, mm);
mm/mmap.c +2 -3
@@ -1355,9 +1355,8 @@ out: }else if ((flags &MAP_POPULATE ) && !(flags &MAP_NONBLOCK ))make_pages_present (addr, addr + len); -if (file &&uprobe_mmap (vma)) -/* matching probes but cannot insert */ - goto unmap_and_free_vma; +if (file) +uprobe_mmap (vma);return addr;
Signature · 1 line
1.5.5.1
Oleg Nesterov
maintainerQuoted 6 lines · Oleg Nesterov
https://bugzilla.redhat.com/show_bug.cgi?id=843640
If mmap_region()->uprobe_mmap() fails,
unmap_and_free_vmapath doesunmap_region()but does not remove the soon-to-be-freed vma from rb tree (actually there are more problems).
Just in case...
Ingo, this is orthogonal to other pending changes I sent. I think 3.6 (and 3.5-stable) needs this fix.
Oleg.
Quoted 1 line · Oleg Nesterov
Hi Oleg,
I checked the following patch and it does fix the problem on the 3.5.0+ kernel.
-Will
Quoted 60 lines
If mmap_region()->uprobe_mmap() fails,
unmap_and_free_vmapath doesunmap_region()but does not remove the soon-to-be-freed vma from rb tree (actually there are more problems).Perhaps we could do
do_munmap()+ return in this case, but in fact it is simply wrong to abort ifuprobe_mmap()fails. Until at least we move the !UPROBE_COPY_INSN code frominstall_breakpoint()touprobe_register().For example, uprobe_mmap()->install_breakpoint() can fail if the probed insn is not supported (remember,
uprobe_register()succeeds if nobody mmaps inode/offset),mmap()should not fail in this case.dup_mmap()->uprobe_mmap() is wrong too by the same reason,
fork()can race withuprobe_register()and fail for no reason if it wins the race and doesinstall_breakpoint()first.Change
mmap_region()anddup_mmap()to ignore the error code fromuprobe_mmap().Reported-by William Cohen <[email protected]>Signed-off-by Oleg Nesterov <[email protected]>Cc <[email protected]> # v3.5--- kernel/fork.c | 4 ++-- mm/mmap.c | 5 ++--- 2 files changed, 4 insertions(+), 5 deletions(-)kernel/fork.c +2
-2@@ -454,8 +454,8 @@ static int dup_mmap(struct mm_struct *mm, struct mm_struct *oldmm)if (retval) goto out; -if (file &&uprobe_mmap (tmp)) - goto out; +if (file) +uprobe_mmap (tmp); }/* a new mm has just been created */ arch_dup_mmap (oldmm, mm);mm/mmap.c +2
-3@@ -1355,9 +1355,8 @@ out: }else if ((flags &MAP_POPULATE ) && !(flags &MAP_NONBLOCK ))make_pages_present (addr, addr + len); -if (file &&uprobe_mmap (vma)) -/* matching probes but cannot insert */ - goto unmap_and_free_vma; +if (file) +uprobe_mmap (vma);return addr;
Quoted 34 lines
If mmap_region()->uprobe_mmap() fails,
unmap_and_free_vmapath doesunmap_region()but does not remove the soon-to-be-freed vma from rb tree (actually there are more problems).Perhaps we could do
do_munmap()+ return in this case, but in fact it is simply wrong to abort ifuprobe_mmap()fails. Until at least we move the !UPROBE_COPY_INSN code frominstall_breakpoint()touprobe_register().For example, uprobe_mmap()->install_breakpoint() can fail if the probed insn is not supported (remember,
uprobe_register()succeeds if nobody mmaps inode/offset),mmap()should not fail in this case.dup_mmap()->uprobe_mmap() is wrong too by the same reason,
fork()can race withuprobe_register()and fail for no reason if it wins the race and doesinstall_breakpoint()first.Change
mmap_region()anddup_mmap()to ignore the error code fromuprobe_mmap().Reported-by William Cohen <[email protected]>Signed-off-by Oleg Nesterov <[email protected]>Cc <[email protected]> # v3.5--- kernel/fork.c | 4 ++-- mm/mmap.c | 5 ++--- 2 files changed, 4 insertions(+), 5 deletions(-)kernel/fork.c +0
-0
kernel/fork.c static int dup_mmap(struct mm_struct *mm, struct mm_struct *oldmm) · line 458
Quoted 7 lines
kernel/fork.c +2
-2@@ -454,8 +454,8 @@ static int dup_mmap(struct mm_struct *mm, struct mm_struct *oldmm)if (retval) goto out; -if (file &&uprobe_mmap (tmp)) - goto out; +if (file) +uprobe_mmap (tmp);
I am not comfortable with this fix.
Lets say there were 10 probes that were to be installed in that vma. we were able to install five probes and the 6th one happened to fail because of invalid instruction; we dont continue with the registering probes for the remaining 4 probes.
Your fix allows probe hits for 5 registered probes that can lead to misleading analysis. For example if one of the first five probes was a malloc and the probe at free() was one of the last probes which wasnt registered, then a person doing an analysis based on probes can say there was a memory leak.
The intention behind failing mmap()/fork() if uprobe_mmap failed, was to make sure that we always report the correct number of events.
Infact this was something that Peter advocated very strongly
http://article.gmane.org/gmane.linux.kernel.mm/59956
I think the long term solution is as you mentioned, move the instruction analysis to register.
Till then should we just ignore invalid instruction probes similar to existing probes. i.e we return -ESRCH or some such which is ignored in uprobe_mmap(), but is taken care of in the uprobe_register path.
The above may not be an elegant solution but..
Signature · 2 lines
thanks and regards Srikar
Oleg Nesterov
maintainerQuoted 7 lines · Srikar Dronamraju
Quoted 7 lines
kernel/fork.c +0
-0@@ -454,8 +454,8 @@ static int dup_mmap(struct mm_struct *mm, struct mm_struct *oldmm)if (retval) goto out;
Quoted 6 lines
kernel/fork.c static int dup_mmap(struct mm_struct *mm, struct mm_struct *oldmm) · line 458
Quoted 4 lines
kernel/fork.c +2
-2-if (file &&uprobe_mmap (tmp)) - goto out; +if (file) +uprobe_mmap (tmp);I am not comfortable with this fix.
OK, so what you suggest for now?
Please note that it is very trivial to crash the kernel. Just do something like
echo "p /bin/true:OFFSET_OF_SYSCALL_INSN" > /sys/kernel/debug/tracing/uprobe_events /bin/true
(or any other unsupported insn)
Yes sure, I agree that in the long term this change should be reconsidered.
Quoted 2 lines
I think the long term solution is as you mentioned, move the instruction analysis to register.
Exactly. And we already discusssed this, we have a lot of other reasons to do this.
Quoted 4 lines
Lets say there were 10 probes that were to be installed in that vma. we were able to install five probes and the 6th one happened to fail because of invalid instruction; we dont continue with the registering probes for the remaining 4 probes.
Yes. And I already have the patch. I didn't send it because, unlike this fix, it depends on other changes (already in -tip).
Until we move analysis to register, until we teach the callers of uprobe_mmap() to bailout (and please note that vma_adjust() ignores the result too), uprobe_mmap() should not give up if install fails, it should continue.
Quoted 2 lines
The intention behind failing mmap()/fork() if
uprobe_mmapfailed, was to make sure that we always report the correct number of events.
Sure, I understand and agree.
But what we can do right now?
Oleg.
Oleg Nesterov
maintainerQuoted 8 lines · Oleg Nesterov
OK, so what you suggest for now?
Please note that it is very trivial to crash the kernel. Just do something like
echo "p /bin/true:OFFSET_OF_SYSCALL_INSN" >
/sys/kernel/debug/tracing/uprobe_events/bin/true
Forgot to mention...
And even it it didn't crash, mmap() (and thus exec) should not fail.
Oleg.
PATCH 1/1 uprobes: Ignore unsupported instructions in uprobe_mmap
In reply to Oleg Nesterovuprobe_mmap()->install_breakpoint() can fail if the probed insn is not supported (remember, uprobe_register() succeeds if nobody mmaps inode/offset). Failure in uprobe_mmap() causes mmap_region/do_fork to fail too.
However failing mmap_region()/do_fork() because of a probe on an unsupported instruction is wrong.
Hence change uprobe_mmap() to ignore unsupported instructions.
Oleg Nesterov analyzed the root cause of this problem.
While at it, add a missing put_uprobe() in the path where uprobe_mmap() races with uprobe_unregister().
--- kernel/events/uprobes.c | 13 ++++++++++++- 1 files changed, 12 insertions(+), 1 deletions(-)
kernel/events/uprobes.c +12 -1
@@ -1051,8 +1051,10 @@ int uprobe_mmap(struct vm_area_struct *vma)if (ret == -EEXIST ) { ret =0 ; -if (!is_swbp_at_addr (vma->vm_mm, vaddr)) +if (!is_swbp_at_addr (vma->vm_mm, vaddr)) { +put_uprobe (uprobe);continue ; + }/* * Unable to insert a breakpoint, but
@@ -1060,6 +1062,15 @@ int uprobe_mmap(struct vm_area_struct *vma)* probe count. */ atomic_inc (&vma->vm_mm->uprobes_state.count); + }else if (ret == -ENOTSUPP ) { +/* +* A probe at unsupported instruction +* shouldnt cause mmap_region() / do_fork() +* to fail. +*/ + ret =0 ; +put_uprobe (uprobe); +continue ; }if (!ret)
Oleg Nesterov
maintainerRe: [PATCH] uprobes: Ignore unsupported instructions in uprobe_mmap
Quoted 3 lines · Srikar Dronamraju
uprobe_mmap()->install_breakpoint() can fail if the probed insn is not supported
But there are other reasons why it can fail,
Quoted 2 lines
However failing mmap_region()/do_fork() because of a probe on an unsupported instruction is wrong.
Srikar, I strongly, absolutely disagree. Please correct me, but..
Do you realize how much uprobes hooks in mmap_region/dup_mmap are broken?
(cough, can't resist, vma_adjust()->uprobe_mmap() is not right too, but
this is another story).
OK, lets start with dup_mmap:
// retval == 0 if (file && uprobe_mmap(tmp)) goto out; out: up_write(&mm->mmap_sem); flush_tlb_mm(oldmm); up_write(&oldmm->mmap_sem); return retval;
Given that retval == 0, what do you think dup_mmap() returns if uprobe_mmap() fails? And note that we didn't copy all vmas. OK, at least this can't crash (afaics), and easy to fix.
But mmap_region() is worse, much worse. It simply can _not_ fail after uprobe_mmap (of course, I am not saying this is unfixable) without the crash. And note that the crash is "delayed". And btw, like dup_mmap(), mmap_region() doesn't return the error too.
Srikar, I strongly believe this horror must not exist. Either we should teach mmap_region() and dup_mmap() (and vma_adjust!) to fail correctly, or we should ignore the error code.
It is that simple, isn't it?
Whatever you do with uprobe_mmap(), even if you change it to always return 0, the code in mmap_region() is absolutely, absolutely broken.
Do you agree?
And once again. I agree, in the long term we should reconsider this change. But we need a simple fix for now/stable.
Quoted 1 line
Hence change
uprobe_mmap()to ignore unsupported instructions.
OK. Now suppose that mmap_region()-> uprobe_mmap() fails because the caller is SIGKILL'ed (so __get_user_pages fails). Given that mmap_region() can't handle the error correctly, the kernel can crash.
Oleg.
Re: [PATCH] uprobes: Ignore unsupported instructions in uprobe_mmap
Quoted 33 lines
Quoted 2 lines
uprobe_mmap()->install_breakpoint() can fail if the probed insn is not supported
But there are other reasons why it can fail,
Quoted 2 lines
However failing mmap_region()/do_fork() because of a probe on an unsupported instruction is wrong.
Srikar, I strongly, absolutely disagree. Please correct me, but..
Do you realize how much uprobes hooks in mmap_region/dup_mmap are broken?
(cough, can't resist, vma_adjust()->uprobe_mmap() is not right too, but
this is another story).OK, lets start with
dup_mmap:// retval == 0 if (file && uprobe_mmap(tmp)) goto out; out: up_write(&mm->mmap_sem); flush_tlb_mm(oldmm); up_write(&oldmm->mmap_sem); return retval;Given that retval == 0, what do you think
dup_mmap()returns ifuprobe_mmap()fails? And note that we didn't copy all vmas. OK, at least this can't crash (afaics), and easy to fix.
Quoted 4 lines
But
mmap_region()is worse, much worse. It simply can _not_ fail afteruprobe_mmap(of course, I am not saying this is unfixable) without the crash. And note that the crash is "delayed". And btw, likedup_mmap(),mmap_region()doesn't return the error too.
Oh, thats really a bad mistake from my side. I apologize.
Quoted 7 lines
Srikar, I strongly believe this horror must not exist. Either we should teach
mmap_region()anddup_mmap()(andvma_adjust!) to fail correctly, or we should ignore the error code.It is that simple, isn't it?
Right.
Quoted 3 lines
Whatever you do with
uprobe_mmap(), even if you change it to always return 0, the code inmmap_region()is absolutely, absolutely broken.
But uprobe_mmap() still needs to walk thro the probe list and insert the other probes. Currently we just ignore the remaining probes and that has to be fixed within uprobe_mmap.
Quoted 5 lines
Do you agree?
And once again. I agree, in the long term we should reconsider this change. But we need a simple fix for now/stable.
Agree.
Quoted 7 lines
Quoted 1 line
Hence change
uprobe_mmap()to ignore unsupported instructions.OK. Now suppose that mmap_region()->
uprobe_mmap()fails because the caller is SIGKILL'ed (so__get_user_pagesfails). Given thatmmap_region()can't handle the error correctly, the kernel can crash.
How about having your fix + my patch to fix the uprobe_mmap()?
Signature · 2 lines
Thanks and Regards Srikar
Oleg Nesterov
maintainerRe: [PATCH] uprobes: Ignore unsupported instructions in uprobe_mmap
Quoted 2 lines · Srikar Dronamraju
How about having your fix + my patch to fix the
uprobe_mmap()?
(I guess you mean -ENOTSUPP part)
Perhaps...
But, as I said, I think that until we fix the callers uprobe_mmap() should ignore all errors and proceed. Except, perhaps, it makes sense to check fatal_signal_pending() to not upset oom-killer.
I already had this patch, but then I decided it would be better to do other changes first. See my next reply to your another email.
Oleg.
Re: [PATCH] uprobes: Ignore unsupported instructions in uprobe_mmap
In reply to Oleg NesterovQuoted 23 lines
OK, lets start with
dup_mmap:// retval == 0 if (file && uprobe_mmap(tmp)) goto out; out: up_write(&mm->mmap_sem); flush_tlb_mm(oldmm); up_write(&oldmm->mmap_sem); return retval;Given that retval == 0, what do you think
dup_mmap()returns ifuprobe_mmap()fails? And note that we didn't copy all vmas. OK, at least this can't crash (afaics), and easy to fix.But
mmap_region()is worse, much worse. It simply can _not_ fail afteruprobe_mmap(of course, I am not saying this is unfixable) without the crash. And note that the crash is "delayed". And btw, likedup_mmap(),mmap_region()doesn't return the error too.
Quoted 5 lines
Srikar, I strongly believe this horror must not exist. Either we should teach
mmap_region()anddup_mmap()(andvma_adjust!) to fail correctly, or we should ignore the error code.It is that simple, isn't it?
I think you would have thought of this approach already but just wanted to check if below is fine with you.
kernel/fork.c +3 -3
@@ -456,10 +456,10 @@ static int dup_mmap(struct mm_struct *mm, struct mm_struct *oldmm)if (tmp->vm_ops && tmp->vm_ops->open) tmp->vm_ops->open (tmp); -if (retval) - goto out; +if (!retval && file) + retval =uprobe_mmap (tmp); -if (file &&uprobe_mmap (tmp)) +if (retval) goto out; }/* a new mm has just been created */
mm/mmap.c +5 -2
@@ -1355,9 +1355,12 @@ unsigned long mmap_region(struct file *file, unsigned long addr, }else if ((flags &MAP_POPULATE ) && !(flags &MAP_NONBLOCK ))make_pages_present (addr, addr + len); -if (file &&uprobe_mmap (vma)) +if (file) { + error =uprobe_mmap (vma) /* matching probes but cannot insert */ - goto unmap_and_free_vma; +if (error) + goto unmap_and_free_vma; + }return addr;
Basically, I am setting the return value of uprobe_mmap() so that mmap_region and do_fork() fail. This still needs the fix in uprobe_mmap() to ignore unsupported instructions.
I am completely _okay_ with not setting the return values as proposed by you. Just that setting return values and the fix in uprobe_mmap() might help in minor issues
- We either probe all probes where possible or intimate to the user that the requested operation wasnt successful.
- If valid probes follow a probe with invalid instruction, we still allow valid probes.
- If get_user_pages()/set_swbp() fail because of genuine reasons like ENOMEM, then we dont retry to place probes on the subsequent vmas.
Signature · 2 lines
thanks and regards Srikar
Oleg Nesterov
maintainerRe: [PATCH] uprobes: Ignore unsupported instructions in uprobe_mmap
Quoted 18 lines · Srikar Dronamraju
Quoted 11 lines
But
mmap_region()is worse, much worse. It simply can _not_ fail afteruprobe_mmap(of course, I am not saying this is unfixable) without the crash. And note that the crash is "delayed". And btw, likedup_mmap(),mmap_region()doesn't return the error too.Srikar, I strongly believe this horror must not exist. Either we should teach
mmap_region()anddup_mmap()(andvma_adjust!) to fail correctly, or we should ignore the error code.It is that simple, isn't it?
I think you would have thought of this approach already but just wanted to check if below is fine with you.
mm/mmap.c unsigned long mmap_region(struct file *file, unsigned long addr, · line 1362
Quoted 10 lines
mm/mmap.c +4
-2@@ -1355,9 +1355,12 @@ unsigned long mmap_region(struct file *file, unsigned long addr, }else if ((flags &MAP_POPULATE ) && !(flags &MAP_NONBLOCK ))make_pages_present (addr, addr + len); -if (file &&uprobe_mmap (vma)) +if (file) { + error =uprobe_mmap (vma) /* matching probes but cannot insert */ - goto unmap_and_free_vma; +if (error) + goto unmap_and_free_vma;
No, this is wrong.
Please look at the code under unmap_and_free_vma. The main part is unmap_region(), but this does NOT remove vma from mm->mm_rb and then this vma is kmem_cache_free'ed. IOW, this leaves the freed object in rb tree.
Afaics, there are other things this error path doesn't do but this is how William noticed the bug (kernel hang). I don't think the fix is suitable for stable.
Srikar, can't we make these fixes on top of my simple patch which fixes the easy-to-trigger kernel crashes/hangs?
If yes, may be you can ack that patch for Ingo?
And yes, uprobe_mmap() needs changes too. But can't we do this a bit later? Currently uprobes_state.count is very wrong, it simply does not count uprobes correctly even in the very simple cases.
Oleg.
Oleg Nesterov
maintainerRe: [PATCH] uprobes: Ignore unsupported instructions in uprobe_mmap
In reply to Srikar DronamrajuForgot to mention...
kernel/events/uprobes.c int uprobe_mmap(struct vm_area_struct *vma) · line 1057
Quoted 13 lines · Srikar Dronamraju
While at it, add a missing
put_uprobe()in the path whereuprobe_mmap()races withuprobe_unregister().
...kernel/events/uprobes.c +3
-1@@ -1051,8 +1051,10 @@ int uprobe_mmap(struct vm_area_struct *vma)if (ret == -EEXIST ) { ret =0 ; -if (!is_swbp_at_addr (vma->vm_mm, vaddr)) +if (!is_swbp_at_addr (vma->vm_mm, vaddr)) { +put_uprobe (uprobe);continue ; + }
Yes, this part looks correct.
In fact, I think this is not really correct anyway (wrt counter) but we are going to kill it.
Oleg.
Re: [PATCH] uprobes: Ignore unsupported instructions in uprobe_mmap
Quoted 19 lines · Oleg Nesterov
Forgot to mention...
kernel/events/uprobes.c int uprobe_mmap(struct vm_area_struct *vma) · line 1057
Quoted 13 lines · Srikar Dronamraju
While at it, add a missing
put_uprobe()in the path whereuprobe_mmap()races withuprobe_unregister().
...kernel/events/uprobes.c +3
-1@@ -1051,8 +1051,10 @@ int uprobe_mmap(struct vm_area_struct *vma)if (ret == -EEXIST ) { ret =0 ; -if (!is_swbp_at_addr (vma->vm_mm, vaddr)) +if (!is_swbp_at_addr (vma->vm_mm, vaddr)) { +put_uprobe (uprobe);continue ; + }Yes, this part looks correct.
Quoted 4 lines
In fact, I think this is not really correct anyway (wrt counter) but we are going to kill it.
Are you expecting the counter to be decreased/increased here?
This is case where the uprobe_mmap() and uprobe_unregister() raced, and by the time install_breakpoint() was called by uprobe_mmap(), there were no consumers. i.e there are no uprobe->consumers and the underlying instruction is still not a breakpoint instruction.
Since we are refusing to add a breakpoint and that there is no breakpoint, there is no need to increment/decrement the counter here.
Do let me know if I have missed something.
Signature · 2 lines
Thanks and Regards Srikar
Oleg Nesterov
maintainerRe: [PATCH] uprobes: Ignore unsupported instructions in uprobe_mmap
Quoted 22 lines · Srikar Dronamraju
Quoted 19 lines · Oleg Nesterov
Forgot to mention...
kernel/events/uprobes.c int uprobe_mmap(struct vm_area_struct *vma) · line 1057
Quoted 13 lines · Srikar Dronamraju
While at it, add a missing
put_uprobe()in the path whereuprobe_mmap()races withuprobe_unregister().
...kernel/events/uprobes.c +3
-1@@ -1051,8 +1051,10 @@ int uprobe_mmap(struct vm_area_struct *vma)if (ret == -EEXIST ) { ret =0 ; -if (!is_swbp_at_addr (vma->vm_mm, vaddr)) +if (!is_swbp_at_addr (vma->vm_mm, vaddr)) { +put_uprobe (uprobe);continue ; + }Yes, this part looks correct.
Quoted 6 lines
Quoted 4 lines
In fact, I think this is not really correct anyway (wrt counter) but we are going to kill it.
Are you expecting the counter to be decreased/increased here?
uprobes_state.count is very wrong, afaics. I'll try to send the fixes "soon", after we solve the pending problems (this one + stepping).
Quoted 3 lines
This is case where the
uprobe_mmap()anduprobe_unregister()raced, and by the timeinstall_breakpoint()was called byuprobe_mmap(), there were no consumers.
Yes, exactly, and this case doesn't look 100% right too,
Quoted 2 lines
i.e there are no
uprobe->consumersand the underlying instruction is still not a breakpoint instruction.
Yes, but what if it _IS_ "int3" ?
Yet another reason to move arch_uprobe_analyze_insn/etc to _register.
Oleg.
Re: [PATCH] uprobes: Ignore unsupported instructions in uprobe_mmap
Quoted 37 lines · Oleg Nesterov
Quoted 22 lines · Srikar Dronamraju
Quoted 19 lines · Oleg Nesterov
Forgot to mention...
kernel/events/uprobes.c int uprobe_mmap(struct vm_area_struct *vma) · line 1057
Quoted 13 lines · Srikar Dronamraju
While at it, add a missing
put_uprobe()in the path whereuprobe_mmap()races withuprobe_unregister().
...kernel/events/uprobes.c +3
-1@@ -1051,8 +1051,10 @@ int uprobe_mmap(struct vm_area_struct *vma)if (ret == -EEXIST ) { ret =0 ; -if (!is_swbp_at_addr (vma->vm_mm, vaddr)) +if (!is_swbp_at_addr (vma->vm_mm, vaddr)) { +put_uprobe (uprobe);continue ; + }Yes, this part looks correct.
Quoted 6 lines
Quoted 4 lines
In fact, I think this is not really correct anyway (wrt counter) but we are going to kill it.
Are you expecting the counter to be decreased/increased here?
uprobes_state.count is very wrong, afaics. I'll try to send the fixes "soon", after we solve the pending problems (this one + stepping).
Quoted 3 lines
This is case where the
uprobe_mmap()anduprobe_unregister()raced, and by the timeinstall_breakpoint()was called byuprobe_mmap(), there were no consumers.
Quoted 6 lines
Yes, exactly, and this case doesn't look 100% right too,
Quoted 2 lines
i.e there are no
uprobe->consumersand the underlying instruction is still not a breakpoint instruction.Yes, but what if it _IS_ "int3" ?
for int3, install_breakpoint returns -ENOTSUPP as install_breakpoint does an explicit check if the instruction is breakpoint instruction and x86 analyse_insn() also returns -ENOTSUPP.
Quoted 3 lines
Yet another reason to move arch_uprobe_analyze_insn/etc to
_register.
I am for moving the stuff to _register that avoids us from looking at these cases.
Signature · 1 line
Thanks and Regards
Oleg Nesterov
maintainerRe: [PATCH] uprobes: Ignore unsupported instructions in uprobe_mmap
Quoted 11 lines · Srikar Dronamraju
Quoted 8 lines · Oleg Nesterov
Quoted 4 lines · Srikar Dronamraju
This is case where the
uprobe_mmap()anduprobe_unregister()raced, and by the timeinstall_breakpoint()was called byuprobe_mmap(), there were no consumers.Yes, exactly, and this case doesn't look 100% right too,
Quoted 8 lines
Quoted 4 lines
Quoted 2 lines
i.e there are no
uprobe->consumersand the underlying instruction is still not a breakpoint instruction.Yes, but what if it _IS_ "int3" ?
for int3,
install_breakpointreturns-ENOTSUPPasinstall_breakpointdoes an explicit check if the instruction is breakpoint instruction and x86analyse_insn()also returns-ENOTSUPP.
install_breakpoint() checks ->consumers first and returns EEXIST.
OK. Suppose that the probed insn is int3, and nobody mmaps it.
1. uprobe_register() succeeds
2. uprobe_unregister() is called, it does consumer_del(), but before it calls delete_uprobe()...
3. uprobe_mmap() finds this uprobe and install_breakpoint() returns -EEXIST.
We could fix this particular problem (and other similar), but I think this is pointless. This all is broken. Please give me some time to try to make a patch which removes this all.
Quoted 5 lines
Quoted 2 lines
Yet another reason to move arch_uprobe_analyze_insn/etc to
_register.I am for moving the stuff to
_registerthat avoids us from looking at these cases.
Yes. Lets try to do this step-by-step, after we fix the pending/discussed problems.
Oleg.
Quoted 19 lines · Oleg Nesterov
https://bugzilla.redhat.com/show_bug.cgi?id=843640
If mmap_region()->uprobe_mmap() fails,
unmap_and_free_vmapath doesunmap_region()but does not remove the soon-to-be-freed vma from rb tree (actually there are more problems).Perhaps we could do
do_munmap()+ return in this case, but in fact it is simply wrong to abort ifuprobe_mmap()fails. Until at least we move the !UPROBE_COPY_INSN code frominstall_breakpoint()touprobe_register().For example, uprobe_mmap()->install_breakpoint() can fail if the probed insn is not supported (remember,
uprobe_register()succeeds if nobody mmaps inode/offset),mmap()should not fail in this case.dup_mmap()->uprobe_mmap() is wrong too by the same reason,
fork()can race withuprobe_register()and fail for no reason if it wins the race and doesinstall_breakpoint()first.
Quoted 6 lines
Change
mmap_region()anddup_mmap()to ignore the error code fromuprobe_mmap().Reported-by William Cohen <[email protected]>Signed-off-by Oleg Nesterov <[email protected]>Cc <[email protected]> # v3.5
After discussions with Oleg, its very clear that this apt fix for now.
Quoted 40 lines
--- kernel/fork.c | 4 ++-- mm/mmap.c | 5 ++--- 2 files changed, 4 insertions(+), 5 deletions(-)kernel/fork.c +2
-2@@ -454,8 +454,8 @@ static int dup_mmap(struct mm_struct *mm, struct mm_struct *oldmm)if (retval) goto out; -if (file &&uprobe_mmap (tmp)) - goto out; +if (file) +uprobe_mmap (tmp); }/* a new mm has just been created */ arch_dup_mmap (oldmm, mm);mm/mmap.c +2
-3@@ -1355,9 +1355,8 @@ out: }else if ((flags &MAP_POPULATE ) && !(flags &MAP_NONBLOCK ))make_pages_present (addr, addr + len); -if (file &&uprobe_mmap (vma)) -/* matching probes but cannot insert */ - goto unmap_and_free_vma; +if (file) +uprobe_mmap (vma);return addr;Signature · 1 line
1.5.5.1