Message ID | 20200618064307.32739-3-hch@lst.de (mailing list archive) |
---|---|
State | Mainlined |
Commit | 10d5e97c1bf816facbc7c431c6caf47ee35fc1ed |
Headers | show |
Series | [1/3] x86/hyperv: allocate the hypercall page with only read and execute bits | expand |
On 18.06.20 08:43, Christoph Hellwig wrote: > Use PAGE_KERNEL_ROX directly instead of allocating RWX and setting the > page read-only just after the allocation. > > Signed-off-by: Christoph Hellwig <hch@lst.de> > --- > arch/arm64/kernel/probes/kprobes.c | 12 +++--------- > 1 file changed, 3 insertions(+), 9 deletions(-) > > diff --git a/arch/arm64/kernel/probes/kprobes.c b/arch/arm64/kernel/probes/kprobes.c > index d1c95dcf1d7833..cbe49cd117cfec 100644 > --- a/arch/arm64/kernel/probes/kprobes.c > +++ b/arch/arm64/kernel/probes/kprobes.c > @@ -120,15 +120,9 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p) > > void *alloc_insn_page(void) > { > - void *page; > - > - page = vmalloc_exec(PAGE_SIZE); > - if (page) { > - set_memory_ro((unsigned long)page, 1); > - set_vm_flush_reset_perms(page); > - } > - > - return page; > + return __vmalloc_node_range(PAGE_SIZE, 1, VMALLOC_START, VMALLOC_END, > + GFP_KERNEL, PAGE_KERNEL_ROX, VM_FLUSH_RESET_PERMS, > + NUMA_NO_NODE, __func__); I do wonder if something like vmalloc_prot(size, prot) would make this (and the other two users) easier to read. So instead of ripping out vmalloc_exec(), converting it into vmalloc_prot() instead. Did you consider that? Apart from that LGTM > } > > /* arm kprobe: install breakpoint in text */ >
On Thu, Jun 18, 2020 at 08:43:06AM +0200, Christoph Hellwig wrote: > Use PAGE_KERNEL_ROX directly instead of allocating RWX and setting the > page read-only just after the allocation. > > Signed-off-by: Christoph Hellwig <hch@lst.de> > --- > arch/arm64/kernel/probes/kprobes.c | 12 +++--------- > 1 file changed, 3 insertions(+), 9 deletions(-) > > diff --git a/arch/arm64/kernel/probes/kprobes.c b/arch/arm64/kernel/probes/kprobes.c > index d1c95dcf1d7833..cbe49cd117cfec 100644 > --- a/arch/arm64/kernel/probes/kprobes.c > +++ b/arch/arm64/kernel/probes/kprobes.c > @@ -120,15 +120,9 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p) > > void *alloc_insn_page(void) > { > - void *page; > - > - page = vmalloc_exec(PAGE_SIZE); > - if (page) { > - set_memory_ro((unsigned long)page, 1); > - set_vm_flush_reset_perms(page); > - } > - > - return page; > + return __vmalloc_node_range(PAGE_SIZE, 1, VMALLOC_START, VMALLOC_END, > + GFP_KERNEL, PAGE_KERNEL_ROX, VM_FLUSH_RESET_PERMS, > + NUMA_NO_NODE, __func__); > } I think this has the exact same range issue as the x86 user. But it might be less fatal if their PLT magic can cover the full range.
On Thu, Jun 18, 2020 at 10:55:58AM +0200, David Hildenbrand wrote: > On 18.06.20 08:43, Christoph Hellwig wrote: > > Use PAGE_KERNEL_ROX directly instead of allocating RWX and setting the > > page read-only just after the allocation. > > > > Signed-off-by: Christoph Hellwig <hch@lst.de> > > --- > > arch/arm64/kernel/probes/kprobes.c | 12 +++--------- > > 1 file changed, 3 insertions(+), 9 deletions(-) > > > > diff --git a/arch/arm64/kernel/probes/kprobes.c b/arch/arm64/kernel/probes/kprobes.c > > index d1c95dcf1d7833..cbe49cd117cfec 100644 > > --- a/arch/arm64/kernel/probes/kprobes.c > > +++ b/arch/arm64/kernel/probes/kprobes.c > > @@ -120,15 +120,9 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p) > > > > void *alloc_insn_page(void) > > { > > - void *page; > > - > > - page = vmalloc_exec(PAGE_SIZE); > > - if (page) { > > - set_memory_ro((unsigned long)page, 1); > > - set_vm_flush_reset_perms(page); > > - } > > - > > - return page; > > + return __vmalloc_node_range(PAGE_SIZE, 1, VMALLOC_START, VMALLOC_END, > > + GFP_KERNEL, PAGE_KERNEL_ROX, VM_FLUSH_RESET_PERMS, > > + NUMA_NO_NODE, __func__); > > I do wonder if something like vmalloc_prot(size, prot) would make this > (and the other two users) easier to read. > > So instead of ripping out vmalloc_exec(), converting it into > vmalloc_prot() instead. > > Did you consider that? For x86 Christoph did module_alloc_prot(), which is in his more extensive set of patches addressing this. I suspect that would be the right thing for ARM64 as well.
On Thu, Jun 18, 2020 at 12:35:06PM +0200, Peter Zijlstra wrote: > On Thu, Jun 18, 2020 at 10:55:58AM +0200, David Hildenbrand wrote: > > On 18.06.20 08:43, Christoph Hellwig wrote: > > > Use PAGE_KERNEL_ROX directly instead of allocating RWX and setting the > > > page read-only just after the allocation. > > > > > > Signed-off-by: Christoph Hellwig <hch@lst.de> > > > --- > > > arch/arm64/kernel/probes/kprobes.c | 12 +++--------- > > > 1 file changed, 3 insertions(+), 9 deletions(-) > > > > > > diff --git a/arch/arm64/kernel/probes/kprobes.c b/arch/arm64/kernel/probes/kprobes.c > > > index d1c95dcf1d7833..cbe49cd117cfec 100644 > > > --- a/arch/arm64/kernel/probes/kprobes.c > > > +++ b/arch/arm64/kernel/probes/kprobes.c > > > @@ -120,15 +120,9 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p) > > > > > > void *alloc_insn_page(void) > > > { > > > - void *page; > > > - > > > - page = vmalloc_exec(PAGE_SIZE); > > > - if (page) { > > > - set_memory_ro((unsigned long)page, 1); > > > - set_vm_flush_reset_perms(page); > > > - } > > > - > > > - return page; > > > + return __vmalloc_node_range(PAGE_SIZE, 1, VMALLOC_START, VMALLOC_END, > > > + GFP_KERNEL, PAGE_KERNEL_ROX, VM_FLUSH_RESET_PERMS, > > > + NUMA_NO_NODE, __func__); > > > > I do wonder if something like vmalloc_prot(size, prot) would make this > > (and the other two users) easier to read. > > > > So instead of ripping out vmalloc_exec(), converting it into > > vmalloc_prot() instead. > > > > Did you consider that? > > For x86 Christoph did module_alloc_prot(), which is in his more > extensive set of patches addressing this. I suspect that would be the > right thing for ARM64 as well. Yes. The somewhat hacky way I added it cause problems for UML, so I instead plan to do a series converting all architectures over to module_alloc_prot, plus lots of other cleanups in the area that I noticed. I don't think vmalloc_prot is a good idea per se, as there only few potential users, and I don't want too many vmalloc APIs.
On Thu, 18 Jun 2020 08:43:06 +0200 Christoph Hellwig <hch@lst.de> wrote: > Use PAGE_KERNEL_ROX directly instead of allocating RWX and setting the > page read-only just after the allocation. > > --- a/arch/arm64/kernel/probes/kprobes.c > +++ b/arch/arm64/kernel/probes/kprobes.c > @@ -120,15 +120,9 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p) > > void *alloc_insn_page(void) > { > - void *page; > - > - page = vmalloc_exec(PAGE_SIZE); > - if (page) { > - set_memory_ro((unsigned long)page, 1); > - set_vm_flush_reset_perms(page); > - } > - > - return page; > + return __vmalloc_node_range(PAGE_SIZE, 1, VMALLOC_START, VMALLOC_END, > + GFP_KERNEL, PAGE_KERNEL_ROX, VM_FLUSH_RESET_PERMS, > + NUMA_NO_NODE, __func__); > } > > /* arm kprobe: install breakpoint in text */ But why. I think this is just a cleanup, doesn't address any runtime issue?
On Sat, Jun 20, 2020 at 07:16:16PM -0700, Andrew Morton wrote: > On Thu, 18 Jun 2020 08:43:06 +0200 Christoph Hellwig <hch@lst.de> wrote: > > > Use PAGE_KERNEL_ROX directly instead of allocating RWX and setting the > > page read-only just after the allocation. > > > > --- a/arch/arm64/kernel/probes/kprobes.c > > +++ b/arch/arm64/kernel/probes/kprobes.c > > @@ -120,15 +120,9 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p) > > > > void *alloc_insn_page(void) > > { > > - void *page; > > - > > - page = vmalloc_exec(PAGE_SIZE); > > - if (page) { > > - set_memory_ro((unsigned long)page, 1); > > - set_vm_flush_reset_perms(page); > > - } > > - > > - return page; > > + return __vmalloc_node_range(PAGE_SIZE, 1, VMALLOC_START, VMALLOC_END, > > + GFP_KERNEL, PAGE_KERNEL_ROX, VM_FLUSH_RESET_PERMS, > > + NUMA_NO_NODE, __func__); > > } > > > > /* arm kprobe: install breakpoint in text */ > > But why. I think this is just a cleanup, doesn't address any runtime issue? It doesn't "fix" an issue - it just simplifies and speeds up the code.
On Tue, Jun 23, 2020 at 11:05:05AM +0200, Christoph Hellwig wrote: > On Sat, Jun 20, 2020 at 07:16:16PM -0700, Andrew Morton wrote: > > On Thu, 18 Jun 2020 08:43:06 +0200 Christoph Hellwig <hch@lst.de> wrote: > > > > > Use PAGE_KERNEL_ROX directly instead of allocating RWX and setting the > > > page read-only just after the allocation. > > > > > > --- a/arch/arm64/kernel/probes/kprobes.c > > > +++ b/arch/arm64/kernel/probes/kprobes.c > > > @@ -120,15 +120,9 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p) > > > > > > void *alloc_insn_page(void) > > > { > > > - void *page; > > > - > > > - page = vmalloc_exec(PAGE_SIZE); > > > - if (page) { > > > - set_memory_ro((unsigned long)page, 1); > > > - set_vm_flush_reset_perms(page); > > > - } > > > - > > > - return page; > > > + return __vmalloc_node_range(PAGE_SIZE, 1, VMALLOC_START, VMALLOC_END, > > > + GFP_KERNEL, PAGE_KERNEL_ROX, VM_FLUSH_RESET_PERMS, > > > + NUMA_NO_NODE, __func__); > > > } > > > > > > /* arm kprobe: install breakpoint in text */ > > > > But why. I think this is just a cleanup, doesn't address any runtime issue? > > It doesn't "fix" an issue - it just simplifies and speeds up the code. Ok, but I don't understand the PLT comment from Peter in 20200618092754.GF576905@hirez.programming.kicks-ass.net: | I think this has the exact same range issue as the x86 user. But it | might be less fatal if their PLT magic can cover the full range. Peter, please could you elaborate on your concern? I feel like I'm missing some context. Cheers, Will
On Tue, Jun 23, 2020 at 10:07:58AM +0100, Will Deacon wrote: > On Tue, Jun 23, 2020 at 11:05:05AM +0200, Christoph Hellwig wrote: > > On Sat, Jun 20, 2020 at 07:16:16PM -0700, Andrew Morton wrote: > > > On Thu, 18 Jun 2020 08:43:06 +0200 Christoph Hellwig <hch@lst.de> wrote: > > > > > > > Use PAGE_KERNEL_ROX directly instead of allocating RWX and setting the > > > > page read-only just after the allocation. > > > > > > > > --- a/arch/arm64/kernel/probes/kprobes.c > > > > +++ b/arch/arm64/kernel/probes/kprobes.c > > > > @@ -120,15 +120,9 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p) > > > > > > > > void *alloc_insn_page(void) > > > > { > > > > - void *page; > > > > - > > > > - page = vmalloc_exec(PAGE_SIZE); > > > > - if (page) { > > > > - set_memory_ro((unsigned long)page, 1); > > > > - set_vm_flush_reset_perms(page); > > > > - } > > > > - > > > > - return page; > > > > + return __vmalloc_node_range(PAGE_SIZE, 1, VMALLOC_START, VMALLOC_END, > > > > + GFP_KERNEL, PAGE_KERNEL_ROX, VM_FLUSH_RESET_PERMS, > > > > + NUMA_NO_NODE, __func__); > > > > } > > > > > > > > /* arm kprobe: install breakpoint in text */ > > > > > > But why. I think this is just a cleanup, doesn't address any runtime issue? > > > > It doesn't "fix" an issue - it just simplifies and speeds up the code. > > Ok, but I don't understand the PLT comment from Peter in > 20200618092754.GF576905@hirez.programming.kicks-ass.net: > > | I think this has the exact same range issue as the x86 user. But it > | might be less fatal if their PLT magic can cover the full range. > > Peter, please could you elaborate on your concern? I feel like I'm missing > some context. On x86 we can only directly call code in a (signed) 32bit immediate range (2G) and our kernel text and module range are constrained by that. IIRC ARM64 has an even smaller immediate range and needs to play fixup games with trampolines or somesuch (there was an ARM specific name for it that I've misplaced again). Does that machinery cover the entire vmalloc space or are you only able to fix up for a smaller range? Your arch/arm64/kernel/module.c:module_alloc() implementation seems to have an explicit module range different from the full vmalloc range, I'm thinking this is for a reason.
On Tue, Jun 23, 2020 at 11:37:14AM +0200, Peter Zijlstra wrote: > On Tue, Jun 23, 2020 at 10:07:58AM +0100, Will Deacon wrote: > > On Tue, Jun 23, 2020 at 11:05:05AM +0200, Christoph Hellwig wrote: > > > On Sat, Jun 20, 2020 at 07:16:16PM -0700, Andrew Morton wrote: > > > > On Thu, 18 Jun 2020 08:43:06 +0200 Christoph Hellwig <hch@lst.de> wrote: > > > > > --- a/arch/arm64/kernel/probes/kprobes.c > > > > > +++ b/arch/arm64/kernel/probes/kprobes.c > > > > > @@ -120,15 +120,9 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p) > > > > > > > > > > void *alloc_insn_page(void) > > > > > { > > > > > - void *page; > > > > > - > > > > > - page = vmalloc_exec(PAGE_SIZE); > > > > > - if (page) { > > > > > - set_memory_ro((unsigned long)page, 1); > > > > > - set_vm_flush_reset_perms(page); > > > > > - } > > > > > - > > > > > - return page; > > > > > + return __vmalloc_node_range(PAGE_SIZE, 1, VMALLOC_START, VMALLOC_END, > > > > > + GFP_KERNEL, PAGE_KERNEL_ROX, VM_FLUSH_RESET_PERMS, > > > > > + NUMA_NO_NODE, __func__); > > > > > } > > > > > > > > > > /* arm kprobe: install breakpoint in text */ > > > > > > > > But why. I think this is just a cleanup, doesn't address any runtime issue? > > > > > > It doesn't "fix" an issue - it just simplifies and speeds up the code. > > > > Ok, but I don't understand the PLT comment from Peter in > > 20200618092754.GF576905@hirez.programming.kicks-ass.net: > > > > | I think this has the exact same range issue as the x86 user. But it > > | might be less fatal if their PLT magic can cover the full range. > > > > Peter, please could you elaborate on your concern? I feel like I'm missing > > some context. > > On x86 we can only directly call code in a (signed) 32bit immediate > range (2G) and our kernel text and module range are constrained by that. > > IIRC ARM64 has an even smaller immediate range and needs to play fixup > games with trampolines or somesuch (there was an ARM specific name for > it that I've misplaced again). Does that machinery cover the entire > vmalloc space or are you only able to fix up for a smaller range? > > Your arch/arm64/kernel/module.c:module_alloc() implementation seems to > have an explicit module range different from the full vmalloc range, I'm > thinking this is for a reason. Ah, gotcha. In this case, we're talking about the kprobe out-of-line buffer. We don't directly branch to that; instead we take a BRK exception and either exception return + singlestep the OOL buffer, or we simulate the instruction if it's doing anything PC-relative, so I don't see the need for a PLT. Will
On Thu, 18 Jun 2020 at 08:44, Christoph Hellwig <hch@lst.de> wrote: > > Use PAGE_KERNEL_ROX directly instead of allocating RWX and setting the > page read-only just after the allocation. > > Signed-off-by: Christoph Hellwig <hch@lst.de> > --- > arch/arm64/kernel/probes/kprobes.c | 12 +++--------- > 1 file changed, 3 insertions(+), 9 deletions(-) > > diff --git a/arch/arm64/kernel/probes/kprobes.c b/arch/arm64/kernel/probes/kprobes.c > index d1c95dcf1d7833..cbe49cd117cfec 100644 > --- a/arch/arm64/kernel/probes/kprobes.c > +++ b/arch/arm64/kernel/probes/kprobes.c > @@ -120,15 +120,9 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p) > > void *alloc_insn_page(void) > { > - void *page; > - > - page = vmalloc_exec(PAGE_SIZE); > - if (page) { > - set_memory_ro((unsigned long)page, 1); > - set_vm_flush_reset_perms(page); > - } > - > - return page; > + return __vmalloc_node_range(PAGE_SIZE, 1, VMALLOC_START, VMALLOC_END, > + GFP_KERNEL, PAGE_KERNEL_ROX, VM_FLUSH_RESET_PERMS, > + NUMA_NO_NODE, __func__); Why is this passing a string for the 'caller' argument, and not the address of the caller? > } > > /* arm kprobe: install breakpoint in text */ > -- > 2.26.2 > > > _______________________________________________ > linux-arm-kernel mailing list > linux-arm-kernel@lists.infradead.org > http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
On Sat, Jun 27, 2020 at 09:34:42AM +0200, Ard Biesheuvel wrote: > > + return __vmalloc_node_range(PAGE_SIZE, 1, VMALLOC_START, VMALLOC_END, > > + GFP_KERNEL, PAGE_KERNEL_ROX, VM_FLUSH_RESET_PERMS, > > + NUMA_NO_NODE, __func__); > > Why is this passing a string for the 'caller' argument, and not the > address of the caller? Dementia. Fix sent.
On Sat, 27 Jun 2020 at 09:57, Christoph Hellwig <hch@lst.de> wrote: > > On Sat, Jun 27, 2020 at 09:34:42AM +0200, Ard Biesheuvel wrote: > > > + return __vmalloc_node_range(PAGE_SIZE, 1, VMALLOC_START, VMALLOC_END, > > > + GFP_KERNEL, PAGE_KERNEL_ROX, VM_FLUSH_RESET_PERMS, > > > + NUMA_NO_NODE, __func__); > > > > Why is this passing a string for the 'caller' argument, and not the > > address of the caller? > > Dementia. Fix sent. :-)
diff --git a/arch/arm64/kernel/probes/kprobes.c b/arch/arm64/kernel/probes/kprobes.c index d1c95dcf1d7833..cbe49cd117cfec 100644 --- a/arch/arm64/kernel/probes/kprobes.c +++ b/arch/arm64/kernel/probes/kprobes.c @@ -120,15 +120,9 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p) void *alloc_insn_page(void) { - void *page; - - page = vmalloc_exec(PAGE_SIZE); - if (page) { - set_memory_ro((unsigned long)page, 1); - set_vm_flush_reset_perms(page); - } - - return page; + return __vmalloc_node_range(PAGE_SIZE, 1, VMALLOC_START, VMALLOC_END, + GFP_KERNEL, PAGE_KERNEL_ROX, VM_FLUSH_RESET_PERMS, + NUMA_NO_NODE, __func__); } /* arm kprobe: install breakpoint in text */
Use PAGE_KERNEL_ROX directly instead of allocating RWX and setting the page read-only just after the allocation. Signed-off-by: Christoph Hellwig <hch@lst.de> --- arch/arm64/kernel/probes/kprobes.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-)