From: Oleg Nesterov <oleg@redhat.com>
To: Ravi Bangoria <ravi.bangoria@linux.ibm.com>
Cc: srikar@linux.vnet.ibm.com, rostedt@goodmis.org,
mhiramat@kernel.org, liu.song.a23@gmail.com,
peterz@infradead.org, mingo@redhat.com, acme@kernel.org,
alexander.shishkin@linux.intel.com, jolsa@redhat.com,
namhyung@kernel.org, linux-kernel@vger.kernel.org,
ananth@linux.vnet.ibm.com, alexis.berlemont@gmail.com,
naveen.n.rao@linux.vnet.ibm.com,
linux-arm-kernel@lists.infradead.org, linux-mips@linux-mips.org,
linux@armlinux.org.uk, ralf@linux-mips.org, paul.burton@mips.com
Subject: Re: [PATCH v7 3/6] Uprobes: Support SDT markers having reference count (semaphore)
Date: Fri, 3 Aug 2018 13:24:55 +0200 [thread overview]
Message-ID: <20180803112455.GA13794@redhat.com> (raw)
In-Reply-To: <20180731035143.11942-4-ravi.bangoria@linux.ibm.com>
Hi Ravi,
I was going to give up and ack this series, but it seems I noticed
a bug...
On 07/31, Ravi Bangoria wrote:
>
> +static int delayed_uprobe_add(struct uprobe *uprobe, struct mm_struct *mm)
> +{
> + struct delayed_uprobe *du;
> +
> + if (delayed_uprobe_check(uprobe, mm))
> + return 0;
> +
> + du = kzalloc(sizeof(*du), GFP_KERNEL);
> + if (!du)
> + return -ENOMEM;
> +
> + du->uprobe = uprobe;
> + du->mm = mm;
I am surprised I didn't notice this before...
So
du->mm = mm;
is fine, mm can't go away, uprobe_clear_state() does delayed_uprobe_remove(NULL,mm).
But
du->uprobe = uprobe;
doesn't look right, uprobe can go away and it can be freed, its memory can be reused.
We can't rely on remove_breakpoint(), the application can unmap the probed page/vma.
Yes we do not care about the application in this case, say, the next uprobe_mmap() can
wrongly increment the counter, we do not care although this can lead to hard-to-debug
problems. But, if nothing else, the kernel can crash if the freed memory is unmapped.
So I think put_uprobe() should do delayed_uprobe_remove(uprobe, NULL) before kfree()
and delayed_uprobe_remove() should be updated to handle the mm==NULL case.
Also. delayed_uprobe_add() should check the list and avoid duplicates. Otherwise the
trivial
for (;;)
munmap(mmap(uprobed_file));
will eat the memory until uprobe is unregistered.
> +static bool valid_ref_ctr_vma(struct uprobe *uprobe,
> + struct vm_area_struct *vma)
> +{
> + unsigned long vaddr = offset_to_vaddr(vma, uprobe->ref_ctr_offset);
> +
> + return uprobe->ref_ctr_offset &&
> + vma->vm_file &&
> + file_inode(vma->vm_file) == uprobe->inode &&
> + vma->vm_flags & VM_WRITE &&
> + !(vma->vm_flags & VM_SHARED) &&
vma->vm_flags & (VM_WRITE|VM_SHARED) == VM_WRITE &&
looks a bit better to me, but I won't insist.
> +static int delayed_uprobe_install(struct vm_area_struct *vma)
> +{
> + struct list_head *pos, *q;
> + struct delayed_uprobe *du;
> + unsigned long vaddr;
> + int ret = 0, err = 0;
> +
> + mutex_lock(&delayed_uprobe_lock);
> + list_for_each_safe(pos, q, &delayed_uprobe_list) {
> + du = list_entry(pos, struct delayed_uprobe, list);
> +
> + if (!valid_ref_ctr_vma(du->uprobe, vma))
> + continue;
> +
> + vaddr = offset_to_vaddr(vma, du->uprobe->ref_ctr_offset);
> + ret = __update_ref_ctr(vma->vm_mm, vaddr, 1);
> + /* Record an error and continue. */
> + err = ret & !err ? ret : err;
I try to avoid the cosmetic nits, but I simply can't look at this line ;)
if (ret && !err)
err = ret;
> @@ -1072,7 +1281,14 @@ int uprobe_mmap(struct vm_area_struct *vma)
> struct uprobe *uprobe, *u;
> struct inode *inode;
>
> - if (no_uprobe_events() || !valid_vma(vma, true))
> + if (no_uprobe_events())
> + return 0;
> +
> + if (vma->vm_flags & VM_WRITE &&
> + test_bit(MMF_HAS_UPROBES, &vma->vm_mm->flags))
> + delayed_uprobe_install(vma);
OK, so you also added the VM_WRITE check and I agree. But then I think we
should also check VM_SHARED, just like valid_ref_ctr_vma() does?
Oleg.
WARNING: multiple messages have this Message-ID (diff)
From: oleg@redhat.com (Oleg Nesterov)
To: linux-arm-kernel@lists.infradead.org
Subject: [PATCH v7 3/6] Uprobes: Support SDT markers having reference count (semaphore)
Date: Fri, 3 Aug 2018 13:24:55 +0200 [thread overview]
Message-ID: <20180803112455.GA13794@redhat.com> (raw)
In-Reply-To: <20180731035143.11942-4-ravi.bangoria@linux.ibm.com>
Hi Ravi,
I was going to give up and ack this series, but it seems I noticed
a bug...
On 07/31, Ravi Bangoria wrote:
>
> +static int delayed_uprobe_add(struct uprobe *uprobe, struct mm_struct *mm)
> +{
> + struct delayed_uprobe *du;
> +
> + if (delayed_uprobe_check(uprobe, mm))
> + return 0;
> +
> + du = kzalloc(sizeof(*du), GFP_KERNEL);
> + if (!du)
> + return -ENOMEM;
> +
> + du->uprobe = uprobe;
> + du->mm = mm;
I am surprised I didn't notice this before...
So
du->mm = mm;
is fine, mm can't go away, uprobe_clear_state() does delayed_uprobe_remove(NULL,mm).
But
du->uprobe = uprobe;
doesn't look right, uprobe can go away and it can be freed, its memory can be reused.
We can't rely on remove_breakpoint(), the application can unmap the probed page/vma.
Yes we do not care about the application in this case, say, the next uprobe_mmap() can
wrongly increment the counter, we do not care although this can lead to hard-to-debug
problems. But, if nothing else, the kernel can crash if the freed memory is unmapped.
So I think put_uprobe() should do delayed_uprobe_remove(uprobe, NULL) before kfree()
and delayed_uprobe_remove() should be updated to handle the mm==NULL case.
Also. delayed_uprobe_add() should check the list and avoid duplicates. Otherwise the
trivial
for (;;)
munmap(mmap(uprobed_file));
will eat the memory until uprobe is unregistered.
> +static bool valid_ref_ctr_vma(struct uprobe *uprobe,
> + struct vm_area_struct *vma)
> +{
> + unsigned long vaddr = offset_to_vaddr(vma, uprobe->ref_ctr_offset);
> +
> + return uprobe->ref_ctr_offset &&
> + vma->vm_file &&
> + file_inode(vma->vm_file) == uprobe->inode &&
> + vma->vm_flags & VM_WRITE &&
> + !(vma->vm_flags & VM_SHARED) &&
vma->vm_flags & (VM_WRITE|VM_SHARED) == VM_WRITE &&
looks a bit better to me, but I won't insist.
> +static int delayed_uprobe_install(struct vm_area_struct *vma)
> +{
> + struct list_head *pos, *q;
> + struct delayed_uprobe *du;
> + unsigned long vaddr;
> + int ret = 0, err = 0;
> +
> + mutex_lock(&delayed_uprobe_lock);
> + list_for_each_safe(pos, q, &delayed_uprobe_list) {
> + du = list_entry(pos, struct delayed_uprobe, list);
> +
> + if (!valid_ref_ctr_vma(du->uprobe, vma))
> + continue;
> +
> + vaddr = offset_to_vaddr(vma, du->uprobe->ref_ctr_offset);
> + ret = __update_ref_ctr(vma->vm_mm, vaddr, 1);
> + /* Record an error and continue. */
> + err = ret & !err ? ret : err;
I try to avoid the cosmetic nits, but I simply can't look at this line ;)
if (ret && !err)
err = ret;
> @@ -1072,7 +1281,14 @@ int uprobe_mmap(struct vm_area_struct *vma)
> struct uprobe *uprobe, *u;
> struct inode *inode;
>
> - if (no_uprobe_events() || !valid_vma(vma, true))
> + if (no_uprobe_events())
> + return 0;
> +
> + if (vma->vm_flags & VM_WRITE &&
> + test_bit(MMF_HAS_UPROBES, &vma->vm_mm->flags))
> + delayed_uprobe_install(vma);
OK, so you also added the VM_WRITE check and I agree. But then I think we
should also check VM_SHARED, just like valid_ref_ctr_vma() does?
Oleg.
next prev parent reply other threads:[~2018-08-03 11:25 UTC|newest]
Thread overview: 22+ messages / expand[flat|nested] mbox.gz Atom feed top
2018-07-31 3:51 [PATCH v7 0/6] Uprobes: Support SDT markers having reference count (semaphore) Ravi Bangoria
2018-07-31 3:51 ` Ravi Bangoria
2018-07-31 3:51 ` [PATCH v7 1/6] Uprobes: Simplify uprobe_register() body Ravi Bangoria
2018-07-31 3:51 ` Ravi Bangoria
2018-07-31 3:51 ` [PATCH v7 2/6] Uprobe: Additional argument arch_uprobe to uprobe_write_opcode() Ravi Bangoria
2018-07-31 3:51 ` Ravi Bangoria
2018-07-31 3:51 ` [PATCH v7 3/6] Uprobes: Support SDT markers having reference count (semaphore) Ravi Bangoria
2018-07-31 3:51 ` Ravi Bangoria
2018-08-03 11:24 ` Oleg Nesterov [this message]
2018-08-03 11:24 ` Oleg Nesterov
2018-08-06 9:52 ` Ravi Bangoria
2018-08-06 9:52 ` Ravi Bangoria
2018-08-07 11:36 ` Oleg Nesterov
2018-08-07 11:36 ` Oleg Nesterov
2018-08-07 12:33 ` Ravi Bangoria
2018-08-07 12:33 ` Ravi Bangoria
2018-07-31 3:51 ` [PATCH v7 4/6] Uprobes/sdt: Prevent multiple reference counter for same uprobe Ravi Bangoria
2018-07-31 3:51 ` Ravi Bangoria
2018-07-31 3:51 ` [PATCH v7 5/6] trace_uprobe/sdt: " Ravi Bangoria
2018-07-31 3:51 ` Ravi Bangoria
2018-07-31 3:51 ` [PATCH v7 6/6] perf probe: Support SDT markers having reference counter (semaphore) Ravi Bangoria
2018-07-31 3:51 ` Ravi Bangoria
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20180803112455.GA13794@redhat.com \
--to=oleg@redhat.com \
--cc=acme@kernel.org \
--cc=alexander.shishkin@linux.intel.com \
--cc=alexis.berlemont@gmail.com \
--cc=ananth@linux.vnet.ibm.com \
--cc=jolsa@redhat.com \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-mips@linux-mips.org \
--cc=linux@armlinux.org.uk \
--cc=liu.song.a23@gmail.com \
--cc=mhiramat@kernel.org \
--cc=mingo@redhat.com \
--cc=namhyung@kernel.org \
--cc=naveen.n.rao@linux.vnet.ibm.com \
--cc=paul.burton@mips.com \
--cc=peterz@infradead.org \
--cc=ralf@linux-mips.org \
--cc=ravi.bangoria@linux.ibm.com \
--cc=rostedt@goodmis.org \
--cc=srikar@linux.vnet.ibm.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.