@@ -40,24 +40,108 @@*/#include<linux/seq_file.h>++staticstructseq_file*cmdline_seq_file=NULL;++intfunc_with_lots_of_args(inta,intb,intc,intd,inte,intf,intg,+inth,inti,intj,intk,intl);++intfunc_with_nested_func(inta,intb,intc);+staticintlivepatch_cmdline_proc_show(structseq_file*m,void*v){-seq_printf(m,"%s\n","this has been live patched");+inti,j;++cmdline_seq_file=m;++i=func_with_lots_of_args(1,2,3,4,5,6,7,8,9,10,11,12);+j=func_with_nested_func(8,9,10);++seq_printf(m,"%s %p i = %d j = %d\n","this has been live patched",m,i,j);+return0;}+staticvoidlivepatch_seq_printf(structseq_file*m,constchar*f,...)+{+va_listargs;++va_start(args,f);+seq_vprintf(m,f,args);+va_end(args);++if(m==cmdline_seq_file){+printk("livepatch: patched seq_printf() called\n");+dump_stack();+m=NULL;+}+}++staticintlivepatch_func_with_lots_of_args(inta,intb,intc,intd,inte,+intf,intg,inth,inti,intj,+intk,intl)+{+printk("%s: %d %d %d %d %d %d %d %d %d %d %d %d\n",+__func__,a,b,c,d,e,f,g,h,i,j,k,l);++return1+a+b+c+d+e+f+g+h+i+j+k+l;+}++structscsi_lun{+__u8scsi_lun[8];+};++staticvoidlivepatch_int_to_scsilun(u64lun,structscsi_lun*scsilun)+{+inti;++memset(scsilun->scsi_lun,0,sizeof(scsilun->scsi_lun));++for(i=0;i<sizeof(lun);i+=2){+scsilun->scsi_lun[i]=(lun>>8)&0xFF;+scsilun->scsi_lun[i+1]=lun&0xFF;+lun=lun>>16;+}++printk("livepatch: patched int_to_scsilun()\n");+}+staticstructklp_funcfuncs[]={{.old_name="cmdline_proc_show",.new_func=livepatch_cmdline_proc_show,-},{}+},+{+.old_name="seq_printf",+.new_func=livepatch_seq_printf,+},+{+.old_name="func_with_lots_of_args",+.new_func=livepatch_func_with_lots_of_args,+},+{}+};++staticstructklp_funcscsi_funcs[]={+{+.old_name="int_to_scsilun",+.new_func=livepatch_int_to_scsilun,+},+{}};staticstructklp_objectobjs[]={{/* name being NULL means vmlinux */.funcs=funcs,-},{}+},+{+#if IS_MODULE(CONFIG_SCSI)+.name="scsi_mod",+#endif+.funcs=scsi_funcs,+},+{}};staticstructklp_patchpatch={
From: Michael Ellerman <mpe@ellerman.id.au> Date: 2016-03-24 11:04:38
In order to support live patching on powerpc we would like to call
ftrace_location_range(), so make it global.
Signed-off-by: Torsten Duwe <redacted>
Signed-off-by: Balbir Singh <bsingharora@gmail.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
---
include/linux/ftrace.h | 1 +
kernel/trace/ftrace.c | 14 +++++++++++++-
2 files changed, 14 insertions(+), 1 deletion(-)
@@ -455,6 +455,7 @@ int ftrace_update_record(struct dyn_ftrace *rec, int enable);intftrace_test_record(structdyn_ftrace*rec,intenable);voidftrace_run_stop_machine(intcommand);unsignedlongftrace_location(unsignedlongip);+unsignedlongftrace_location_range(unsignedlongstart,unsignedlongend);unsignedlongftrace_get_addr_new(structdyn_ftrace*rec);unsignedlongftrace_get_addr_curr(structdyn_ftrace*rec);
From: Michael Ellerman <mpe@ellerman.id.au> Date: 2016-03-24 11:04:50
Add the kconfig logic & assembly support for handling live patched
functions. This depends on DYNAMIC_FTRACE_WITH_REGS, which in turn
depends on the new -mprofile-kernel ftrace ABI, which is only supported
currently on ppc64le.
Live patching is handled by a special ftrace handler. This means it runs
from ftrace_caller(). The live patch handler modifies the NIP so as to
redirect the return from ftrace_caller() to the new patched function.
However there is one particularly tricky case we need to handle.
If a function A calls another function B, and it is known at link time
that they share the same TOC, then A will not save or restore its TOC,
and will call the local entry point of B.
When we live patch B, we replace it with a new function C, which may
not have the same TOC as A. At live patch time it's too late to modify A
to do the TOC save/restore, so the live patching code must interpose
itself between A and C, and do the TOC save/restore that A omitted.
An additionaly complication is that the livepatch code can not create a
stack frame in order to save the TOC. That is because if C takes > 8
arguments, or is varargs, A will have written the arguments for C in
A's stack frame.
To solve this, we introduce a "livepatch stack" which grows upward from
the base of the regular stack, and is used to store the TOC & LR when
calling a live patched function.
When the patched function returns, we retrieve the real LR & TOC from
the livepatch stack, restore them, and pop the livepatch "stack frame".
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
---
arch/powerpc/Kconfig | 3 ++
arch/powerpc/kernel/asm-offsets.c | 4 ++
arch/powerpc/kernel/entry_64.S | 97 +++++++++++++++++++++++++++++++++++++++
3 files changed, 104 insertions(+)
@@ -1305,6 +1317,91 @@ _GLOBAL(ftrace_graph_stub) _GLOBAL(ftrace_stub)blr++#ifdef CONFIG_LIVEPATCH+/*+*Thisfunctionrunsinthemcountcontext,betweentwofunctions.As+*suchitcanonlyclobberregisterswhicharevolatileandusedin+*functionlinkage.+*+*WegetherewhenafunctionA,callsanotherfunctionB,butBhas+*beenlivepatchedwithanewfunctionC.+*+*Onentry:+*-wehavenostackframeandcannotallocateone+*-LRpointsbacktotheoriginalcaller (inA)+*-CTRholdsthenewNIPinC+*-r0&r12arefree+*+*r0can't be used as the base register for a DS-form load or store, so+*wetemporarilyshuffler1 (stackpointer)intor0andthenputitback.+*/+livepatch_handler:+CURRENT_THREAD_INFO(r12,r1)++/*Savestackpointerintor0*/+mrr0,r1++/*Allocate3x8bytes*/+ldr1,TI_livepatch_sp(r12)+addir1,r1,24+stdr1,TI_livepatch_sp(r12)++/*Savetoc&realLRonlivepatchstack*/+stdr2,-24(r1)+mflrr12+stdr12,-16(r1)++/*Storestackendmarker*/+lisr12,STACK_END_MAGIC@h+orir12,r12,STACK_END_MAGIC@l+stdr12,-8(r1)++/*Restorerealstackpointer*/+mrr1,r0++/*Putctrinr12forglobalentryandbranchthere*/+mfctrr12+bctrl++/*+*Nowwearereturningfromthepatchedfunctiontotheoriginal+*callerA.Wearefreetouser0andr12,andwecanuser2untilwe+*restoreit.+*/++CURRENT_THREAD_INFO(r12,r1)++/*Savestackpointerintor0*/+mrr0,r1++ldr1,TI_livepatch_sp(r12)++/*Checkstackmarkerhasn't been trashed */+lisr2,STACK_END_MAGIC@h+orir2,r2,STACK_END_MAGIC@l+ldr12,-8(r1)+1:tdner12,r2+EMIT_BUG_ENTRY1b,__FILE__,__LINE__-1,0++/*RestoreLR&tocfromlivepatchstack*/+ldr12,-16(r1)+mtlrr12+ldr2,-24(r1)++/*Poplivepatchstackframe*/+CURRENT_THREAD_INFO(r12,r0)+subir1,r1,24+stdr1,TI_livepatch_sp(r12)++/*Restorerealstackpointer*/+mrr1,r0++/*Returntooriginalcalleroflivepatchedfunction*/+blr+#endif++#else _GLOBAL_TOC(_mcount)/*Takenfromoutputofobjdumpfromlib64/glibc*/
From: Michael Ellerman <mpe@ellerman.id.au> Date: 2016-03-24 11:05:00
In order to support live patching we need to maintain an alternate
stack of TOC & LR values. We use the base of the stack for this, and
store the "live patch stack pointer" in struct thread_info.
Unlike the other fields of thread_info, we can not statically initialise
that value, so it must be done at run time.
This patch just adds the code to support that, it is not enabled until
the next patch which actually adds live patch support.
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
---
arch/powerpc/include/asm/livepatch.h | 8 ++++++++
arch/powerpc/include/asm/thread_info.h | 4 +++-
arch/powerpc/kernel/irq.c | 3 +++
arch/powerpc/kernel/process.c | 6 +++++-
arch/powerpc/kernel/setup_64.c | 17 ++++++++++-------
5 files changed, 29 insertions(+), 9 deletions(-)
@@ -1400,13 +1402,15 @@ int copy_thread(unsigned long clone_flags, unsigned long usp,externvoidret_from_kernel_thread(void);void(*f)(void);unsignedlongsp=(unsignedlong)task_stack_page(p)+THREAD_SIZE;+structthread_info*ti=task_thread_info(p);++klp_init_thread_info(ti);/* Copy registers */sp-=sizeof(structpt_regs);childregs=(structpt_regs*)sp;if(unlikely(p->flags&PF_KTHREAD)){/* kernel thread */-structthread_info*ti=(void*)task_stack_page(p);memset(childregs,0,sizeof(structpt_regs));childregs->gpr[1]=sp+sizeof(structpt_regs);/* function */
From: Michael Ellerman <mpe@ellerman.id.au> Date: 2016-03-24 11:05:11
Add the powerpc specific livepatch definitions. In particular we provide
a non-default implementation of klp_get_ftrace_location().
This is required because the location of the mcount call is not constant
when using -mprofile-kernel (which we always do for live patching).
Signed-off-by: Torsten Duwe <redacted>
Signed-off-by: Balbir Singh <bsingharora@gmail.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
---
arch/powerpc/include/asm/livepatch.h | 54 ++++++++++++++++++++++++++++++++++++
1 file changed, 54 insertions(+)
create mode 100644 arch/powerpc/include/asm/livepatch.h
From: Michael Ellerman <mpe@ellerman.id.au> Date: 2016-03-24 11:05:19
When livepatch tries to patch a function it takes the function address
and asks ftrace to install the livepatch handler at that location.
ftrace will look for an mcount call site at that exact address.
On powerpc the mcount location is not the first instruction of the
function, and in fact it's not at a constant offset from the start of
the function. To accommodate this add a hook which arch code can
override to customise the behaviour.
Signed-off-by: Torsten Duwe <redacted>
Signed-off-by: Balbir Singh <bsingharora@gmail.com>
Signed-off-by: Petr Mladek <pmladek@suse.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
---
kernel/livepatch/core.c | 34 +++++++++++++++++++++++++++++++---
1 file changed, 31 insertions(+), 3 deletions(-)
@@ -338,6 +357,15 @@ static int klp_enable_func(struct klp_func *func)ops=klp_find_ops(func->old_addr);if(!ops){+unsignedlongftrace_loc;++ftrace_loc=klp_get_ftrace_location(func->old_addr);+if(!ftrace_loc){+pr_err("failed to find location for function '%s'\n",+func->old_name);+return-EINVAL;+}+ops=kzalloc(sizeof(*ops),GFP_KERNEL);if(!ops)return-ENOMEM;
@@ -352,7 +380,7 @@ static int klp_enable_func(struct klp_func *func)INIT_LIST_HEAD(&ops->func_stack);list_add_rcu(&func->stack_node,&ops->func_stack);-ret=ftrace_set_filter_ip(&ops->fops,func->old_addr,0,0);+ret=ftrace_set_filter_ip(&ops->fops,ftrace_loc,0,0);if(ret){pr_err("failed to set ftrace filter for function '%s' (%d)\n",func->old_name,ret);
@@ -363,7 +391,7 @@ static int klp_enable_func(struct klp_func *func)if(ret){pr_err("failed to register ftrace handler for function '%s' (%d)\n",func->old_name,ret);-ftrace_set_filter_ip(&ops->fops,func->old_addr,1,0);+ftrace_set_filter_ip(&ops->fops,ftrace_loc,1,0);gotoerr;}
+ /* Put ctr in r12 for global entry and branch there */
+ mfctr r12
+ bctrl
^
I like this piece. No need to fiddle out the return helper address.
+ /*
+ * Now we are returning from the patched function to the original
+ * caller A. We are free to use r0 and r12, and we can use r2 until we
+ * restore it.
+ */
+
+ CURRENT_THREAD_INFO(r12, r1)
+
+ /* Save stack pointer into r0 */
+ mr r0, r1
+
+ ld r1, TI_livepatch_sp(r12)
+
+ /* Check stack marker hasn't been trashed */
+ lis r2, STACK_END_MAGIC@h
+ ori r2, r2, STACK_END_MAGIC@l
+ ld r12, -8(r1)
+1: tdne r12, r2
+ EMIT_BUG_ENTRY 1b, __FILE__, __LINE__ - 1, 0
This however worries me a bit. Sure, in the end, a stack overflow is
a stack overflow, and if all the information does not fit there,
there's little you can do.
But wouldn't it be better to kmalloc that area and realloc in
klp_arch_set_pc when it's full? Maybe along with a warning message?
That way a live patched kernel will not run into stack size problems
any earlier than an unpatched kernel would.
Just a thought.
Anyway, patch 5+6
Reviewed-by: Torsten Duwe <redacted>
Torsten
In order to support live patching on powerpc we would like to call
ftrace_location_range(), so make it global.
Do you want me to try to get this into this merge window?
I don't think that's necessary. The dependency (rest of livepatching bits
for ppc64le) will not go in before 4.7 merge window anyway.
Thanks,
--
Jiri Kosina
SUSE Labs
On Fri, Mar 25, 2016 at 3:37 AM, Kamalesh Babulal
[off-list ref] wrote:
* Michael Ellerman [off-list ref] [2016-03-24 22:04:00]:
quoted
Not for merging.
Hi Michael,
Loading the livepatch sample module, trigger following warning
The #if IS_MODULE(CONFIG_SCSI) code is buggy, you probably have
CONFIG_SCSI=y, make it M or you can fix the code yourself. I had the
same issue while testing
BTW, the tests worked fine with the changes proposed by Michael.
Balbir Singh
On Fri, Mar 25, 2016 at 3:37 AM, Kamalesh Babulal
[off-list ref] wrote:
quoted
* Michael Ellerman [off-list ref] [2016-03-24 22:04:00]:
quoted
Not for merging.
Hi Michael,
Loading the livepatch sample module, trigger following warning
The #if IS_MODULE(CONFIG_SCSI) code is buggy, you probably have
CONFIG_SCSI=y, make it M or you can fix the code yourself. I had the
same issue while testing
BTW, the tests worked fine with the changes proposed by Michael.
Thanks, It helped. I was able to load the sample livepatch module
with proposed changes.
Thanks,
Kamalesh.
In order to support live patching we need to maintain an alternate
stack of TOC & LR values. We use the base of the stack for this, and
store the "live patch stack pointer" in struct thread_info.
Unlike the other fields of thread_info, we can not statically initialise
that value, so it must be done at run time.
This patch just adds the code to support that, it is not enabled until
the next patch which actually adds live patch support.
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
---
arch/powerpc/include/asm/livepatch.h | 8 ++++++++
arch/powerpc/include/asm/thread_info.h | 4 +++-
arch/powerpc/kernel/irq.c | 3 +++
arch/powerpc/kernel/process.c | 6 +++++-
arch/powerpc/kernel/setup_64.c | 17 ++++++++++-------
5 files changed, 29 insertions(+), 9 deletions(-)
@@ -1400,13 +1402,15 @@ int copy_thread(unsigned long clone_flags, unsigned long usp,externvoidret_from_kernel_thread(void);void(*f)(void);unsignedlongsp=(unsignedlong)task_stack_page(p)+THREAD_SIZE;+structthread_info*ti=task_thread_info(p);++klp_init_thread_info(ti);/* Copy registers */sp-=sizeof(structpt_regs);childregs=(structpt_regs*)sp;if(unlikely(p->flags&PF_KTHREAD)){/* kernel thread */-structthread_info*ti=(void*)task_stack_page(p);memset(childregs,0,sizeof(structpt_regs));childregs->gpr[1]=sp+sizeof(structpt_regs);/* function */
Do we care about live-patching in this context? Are we mixing per-thread and per-cpu contexts?
Well we probably don't want to be doing live patching when we're on the
emergency stacks. But we have no control over whether that happens so we have
to support it.
cheers
+ /* Put ctr in r12 for global entry and branch there */
+ mfctr r12
+ bctrl
^
I like this piece. No need to fiddle out the return helper address.
Good.
quoted
+ /*
+ * Now we are returning from the patched function to the original
+ * caller A. We are free to use r0 and r12, and we can use r2 until we
+ * restore it.
+ */
+
+ CURRENT_THREAD_INFO(r12, r1)
+
+ /* Save stack pointer into r0 */
+ mr r0, r1
+
+ ld r1, TI_livepatch_sp(r12)
+
+ /* Check stack marker hasn't been trashed */
+ lis r2, STACK_END_MAGIC@h
+ ori r2, r2, STACK_END_MAGIC@l
+ ld r12, -8(r1)
+1: tdne r12, r2
+ EMIT_BUG_ENTRY 1b, __FILE__, __LINE__ - 1, 0
This however worries me a bit. Sure, in the end, a stack overflow is
a stack overflow, and if all the information does not fit there,
there's little you can do.
Yeah stack overflow in the kernel is very very fatal.
But wouldn't it be better to kmalloc that area and realloc in
klp_arch_set_pc when it's full? Maybe along with a warning message?
You can't realloc in klp_arch_set_pc(), you might be patching sl*b and holding
one of its locks. You might also recurse.
We could allocate a larger buffer as a "klp stack" for each task when the first
live patch is installed, and for every task created afterward. But that
potentially significantly increases memory usage on live patched kernels :)
That way a live patched kernel will not run into stack size problems
any earlier than an unpatched kernel would.
Yeah that's true. I'm not sure what the best trade off is.
cheers
At this point ti->livepatch_sp points to the next CPUs thread_info for softirq_ctx?
Sorry I'm not sure what you mean.
None of this relates to the current CPUs thread info.
Oh! I meant that klp_init_thread_info points to the end of (struct thread_info {} + 1) in the stack of the thread/task, but with the irq_contexts they are a separate array and not on stack
Do we care about live-patching in this context? Are we mixing per-thread and per-cpu contexts?
Well we probably don't want to be doing live patching when we're on the
emergency stacks. But we have no control over whether that happens so we have
to support it.
OK.. I was wondering if the code will even work.. I wonder if the ftrace data structures will work in real mode, including the hash/etc.
Balbir
In order to support live patching we need to maintain an alternate
stack of TOC & LR values. We use the base of the stack for this, and
store the "live patch stack pointer" in struct thread_info.
Unlike the other fields of thread_info, we can not statically initialise
that value, so it must be done at run time.
This patch just adds the code to support that, it is not enabled until
the next patch which actually adds live patch support.
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
---
arch/powerpc/include/asm/livepatch.h | 8 ++++++++
arch/powerpc/include/asm/thread_info.h | 4 +++-
arch/powerpc/kernel/irq.c | 3 +++
arch/powerpc/kernel/process.c | 6 +++++-
arch/powerpc/kernel/setup_64.c | 17 ++++++++++-------
5 files changed, 29 insertions(+), 9 deletions(-)
Add the kconfig logic & assembly support for handling live patched
functions. This depends on DYNAMIC_FTRACE_WITH_REGS, which in turn
depends on the new -mprofile-kernel ftrace ABI, which is only supported
currently on ppc64le.
Live patching is handled by a special ftrace handler. This means it runs
from ftrace_caller(). The live patch handler modifies the NIP so as to
redirect the return from ftrace_caller() to the new patched function.
However there is one particularly tricky case we need to handle.
If a function A calls another function B, and it is known at link time
that they share the same TOC, then A will not save or restore its TOC,
and will call the local entry point of B.
When we live patch B, we replace it with a new function C, which may
not have the same TOC as A. At live patch time it's too late to modify A
to do the TOC save/restore, so the live patching code must interpose
itself between A and C, and do the TOC save/restore that A omitted.
An additionaly complication is that the livepatch code can not create a
stack frame in order to save the TOC. That is because if C takes > 8
arguments, or is varargs, A will have written the arguments for C in
A's stack frame.
To solve this, we introduce a "livepatch stack" which grows upward from
the base of the regular stack, and is used to store the TOC & LR when
calling a live patched function.
When the patched function returns, we retrieve the real LR & TOC from
the livepatch stack, restore them, and pop the livepatch "stack frame".
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>