From: Alexander Popov <hidden> Date: 2020-06-04 13:50:41
In this patch series I collected various improvements of the stackleak
gcc plugin.
The first patch excludes alloca() from the stackleak instrumentation logic
to make it simpler.
The second patch is the main improvement. It eliminates an unwanted
side-effect of kernel code instrumentation. This patch is a deep
reengineering of the idea described on grsecurity blog:
https://grsecurity.net/resolving_an_unfortunate_stackleak_interaction
The third patch adds 'verbose' plugin parameter for printing additional
info about the kernel code instrumentation.
Two other patches disable unneeded stackleak instrumentation for some
files.
I would like to thank Alexander Monakov [off-list ref] for his
advisory on gcc internals.
This patch series was tested for gcc version 4.8, 5, 6, 7, 8, 9, and 10
on x86_64, i386 and arm64.
That was done using the project 'kernel-build-containers':
https://github.com/a13xp0p0v/kernel-build-containers
Alexander Popov (5):
gcc-plugins/stackleak: Exclude alloca() from the instrumentation logic
gcc-plugins/stackleak: Use asm instrumentation to avoid useless
register saving
gcc-plugins/stackleak: Add 'verbose' plugin parameter
gcc-plugins/stackleak: Don't instrument itself
gcc-plugins/stackleak: Don't instrument vgettimeofday.c in arm64 VDSO
arch/arm64/kernel/vdso/Makefile | 3 +-
include/linux/compiler_attributes.h | 13 ++
kernel/Makefile | 1 +
kernel/stackleak.c | 16 +-
scripts/Makefile.gcc-plugins | 2 +
scripts/gcc-plugins/stackleak_plugin.c | 260 ++++++++++++++++++++-----
6 files changed, 232 insertions(+), 63 deletions(-)
--
2.25.2
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
From: Alexander Popov <hidden> Date: 2020-06-04 13:50:51
Some time ago Variable Length Arrays (VLA) were removed from the kernel.
The kernel is built with '-Wvla'. Let's exclude alloca() from the
instrumentation logic and make it simpler. The build-time assertion
against alloca() is added instead.
Unfortunately, for that assertion we can't simply check cfun->calls_alloca
during RTL phase. It turned out that gcc before version 7 called
allocate_dynamic_stack_space() from expand_stack_vars() for runtime
alignment of constant-sized stack variables. That caused cfun->calls_alloca
to be set for functions that don't use alloca().
Signed-off-by: Alexander Popov <redacted>
---
scripts/gcc-plugins/stackleak_plugin.c | 51 +++++++++++---------------
1 file changed, 21 insertions(+), 30 deletions(-)
@@ -111,27 +104,17 @@ static unsigned int stackleak_instrument_execute(void)*/FOR_EACH_BB_FN(bb,cfun){for(gsi=gsi_start_bb(bb);!gsi_end_p(gsi);gsi_next(&gsi)){-gimplestmt;--stmt=gsi_stmt(gsi);+gimplestmt=gsi_stmt(gsi);/* Leaf function is a function which makes no calls */if(is_gimple_call(stmt))is_leaf=false;-if(!is_alloca(stmt))-continue;--/* Insert stackleak_track_stack() call after alloca() */-stackleak_add_track_stack(&gsi,true);-if(bb==entry_bb)-prologue_instrumented=true;+/* Variable Length Arrays are forbidden in the kernel */+gcc_assert(!is_alloca(stmt));}}-if(prologue_instrumented)-return0;-/**Specialcasestoskiptheinstrumentation.*
@@ -168,7 +151,7 @@ static unsigned int stackleak_instrument_execute(void)bb=single_succ(ENTRY_BLOCK_PTR_FOR_FN(cfun));}gsi=gsi_after_labels(bb);-stackleak_add_track_stack(&gsi,false);+stackleak_add_track_stack(&gsi);return0;}
From: Alexander Popov <hidden> Date: 2020-06-04 13:51:00
The kernel code instrumentation in stackleak gcc plugin works in two stages.
At first, stack tracking is added to GIMPLE representation of every function
(except some special cases). And later, when stack frame size info is
available, stack tracking is removed from the RTL representation of the
functions with small stack frame. There is an unwanted side-effect for these
functions: some of them do useless work with caller-saved registers.
As an example of such case, proc_sys_write without instrumentation:
55 push %rbp
41 b8 01 00 00 00 mov $0x1,%r8d
48 89 e5 mov %rsp,%rbp
e8 11 ff ff ff callq ffffffff81284610 <proc_sys_call_handler>
5d pop %rbp
c3 retq
0f 1f 44 00 00 nopl 0x0(%rax,%rax,1)
66 2e 0f 1f 84 00 00 nopw %cs:0x0(%rax,%rax,1)
00 00 00
proc_sys_write with instrumentation:
55 push %rbp
48 89 e5 mov %rsp,%rbp
41 56 push %r14
41 55 push %r13
41 54 push %r12
53 push %rbx
49 89 f4 mov %rsi,%r12
48 89 fb mov %rdi,%rbx
49 89 d5 mov %rdx,%r13
49 89 ce mov %rcx,%r14
4c 89 f1 mov %r14,%rcx
4c 89 ea mov %r13,%rdx
4c 89 e6 mov %r12,%rsi
48 89 df mov %rbx,%rdi
41 b8 01 00 00 00 mov $0x1,%r8d
e8 f2 fe ff ff callq ffffffff81298e80 <proc_sys_call_handler>
5b pop %rbx
41 5c pop %r12
41 5d pop %r13
41 5e pop %r14
5d pop %rbp
c3 retq
66 0f 1f 84 00 00 00 nopw 0x0(%rax,%rax,1)
00 00
Let's improve the instrumentation to avoid this:
1. Make stackleak_track_stack() save all register that it works with.
Use no_caller_saved_registers attribute for that function. This attribute
is available for x86_64 and i386 starting from gcc-7.
2. Insert calling stackleak_track_stack() in asm:
asm volatile("call stackleak_track_stack" :: "r" (current_stack_pointer))
Here we use ASM_CALL_CONSTRAINT trick from arch/x86/include/asm/asm.h.
The input constraint is taken into account during gcc shrink-wrapping
optimization. It is needed to be sure that stackleak_track_stack() call is
inserted after the prologue of the containing function, when the stack
frame is prepared.
This work is a deep reengineering of the idea described on grsecurity blog
https://grsecurity.net/resolving_an_unfortunate_stackleak_interaction
Signed-off-by: Alexander Popov <redacted>
---
include/linux/compiler_attributes.h | 13 ++
kernel/stackleak.c | 16 +-
scripts/Makefile.gcc-plugins | 2 +
scripts/gcc-plugins/stackleak_plugin.c | 206 +++++++++++++++++++++----
4 files changed, 196 insertions(+), 41 deletions(-)
@@ -125,6 +115,8 @@ void __used notrace stackleak_track_stack(void)*/BUILD_BUG_ON(CONFIG_STACKLEAK_TRACK_MIN_SIZE>STACKLEAK_SEARCH_DEPTH);+/* 'lowest_stack' should be aligned on the register width boundary */+sp=ALIGN(sp,sizeof(unsignedlong));if(sp<current->lowest_stack&&sp>=(unsignedlong)task_stack_page(current)+sizeof(unsignedlong)){
@@ -42,27 +43,28 @@ static GTY(()) tree track_function_decl;staticstructplugin_infostackleak_plugin_info={.version="201707101337",.help="track-min-size=nn\ttrack stack for functions with a stack frame size >= nn bytes\n"+"arch=target_arch\tspecify target build arch\n""disable\t\tdo not activate the plugin\n"};-staticvoidstackleak_add_track_stack(gimple_stmt_iterator*gsi)+staticvoidadd_stack_tracking_gcall(gimple_stmt_iterator*gsi){gimplestmt;-gcall*stackleak_track_stack;+gcall*gimple_call;cgraph_node_ptrnode;basic_blockbb;-/* Insert call to void stackleak_track_stack(void) */+/* Insert calling stackleak_track_stack() */stmt=gimple_build_call(track_function_decl,0);-stackleak_track_stack=as_a_gcall(stmt);-gsi_insert_before(gsi,stackleak_track_stack,GSI_SAME_STMT);+gimple_call=as_a_gcall(stmt);+gsi_insert_before(gsi,gimple_call,GSI_SAME_STMT);/* Update the cgraph */-bb=gimple_bb(stackleak_track_stack);+bb=gimple_bb(gimple_call);node=cgraph_get_create_node(track_function_decl);gcc_assert(node);cgraph_create_edge(cgraph_get_node(current_function_decl),node,-stackleak_track_stack,bb->count,+gimple_call,bb->count,compute_call_stmt_bb_frequency(current_function_decl,bb));}
@@ -79,6 +81,76 @@ static bool is_alloca(gimple stmt)returnfalse;}+statictreeget_current_stack_pointer_decl(void)+{+varpool_node_ptrnode;++FOR_EACH_VARIABLE(node){+treevar=NODE_DECL(node);+treename=DECL_NAME(var);++if(DECL_NAME_LENGTH(var)!=sizeof("current_stack_pointer")-1)+continue;++if(strcmp(IDENTIFIER_POINTER(name),"current_stack_pointer"))+continue;++returnvar;+}++returnNULL_TREE;+}++staticvoidadd_stack_tracking_gasm(gimple_stmt_iterator*gsi)+{+gasm*asm_call=NULL;+treesp_decl,input;+vec<tree,va_gc>*inputs=NULL;++/* 'no_caller_saved_registers' is currently supported only for x86 */+gcc_assert(build_for_x86);++/*+*Insertcallingstackleak_track_stack()inasm:+*asmvolatile("call stackleak_track_stack"+*::"r"(current_stack_pointer))+*UseASM_CALL_CONSTRAINTtrickfromarch/x86/include/asm/asm.h.+*Thisconstraintistakenintoaccountduringgccshrink-wrapping+*optimization.Itisneededtobesurethatstackleak_track_stack()+*callisinsertedaftertheprologueofthecontainingfunction,+*whenthestackframeisprepared.+*/+sp_decl=get_current_stack_pointer_decl();+if(sp_decl==NULL_TREE){+add_stack_tracking_gcall(gsi);+return;+}+input=build_tree_list(NULL_TREE,build_const_char_string(2,"r"));+input=chainon(NULL_TREE,build_tree_list(input,sp_decl));+vec_safe_push(inputs,input);+asm_call=gimple_build_asm_vec("call stackleak_track_stack",+inputs,NULL,NULL,NULL);+gimple_asm_set_volatile(asm_call,true);+gsi_insert_before(gsi,asm_call,GSI_SAME_STMT);+update_stmt(asm_call);+}++staticvoidadd_stack_tracking(gimple_stmt_iterator*gsi)+{+/*+*The'no_caller_saved_registers'attributeisusedfor+*stackleak_track_stack().Ifthecompilersupportsthisattributefor+*thetargetarch,wecanaddcallingstackleak_track_stack()inasm.+*Thatimprovesperformance:weavoiduselessoperationswiththe+*caller-savedregistersinthefunctionsfromwhichwewillremove+*stackleak_track_stack()callduringthestackleak_cleanuppass.+*/+if(lookup_attribute_spec(get_identifier("no_caller_saved_registers")))+add_stack_tracking_gasm(gsi);+else+add_stack_tracking_gcall(gsi);+}+/**WorkwiththeGIMPLErepresentationofthecode.Insertthe*stackleak_track_stack()callintothebeginningofthefunction.
@@ -151,7 +223,7 @@ static unsigned int stackleak_instrument_execute(void)bb=single_succ(ENTRY_BLOCK_PTR_FOR_FN(cfun));}gsi=gsi_after_labels(bb);-stackleak_add_track_stack(&gsi);+add_stack_tracking(&gsi);return0;}
@@ -248,6 +301,92 @@ static unsigned int stackleak_cleanup_execute(void)}#endif}+}++staticboolremove_stack_tracking_gasm(void)+{+boolremoved=false;+rtx_insn*insn,*next;++/* 'no_caller_saved_registers' is currently supported only for x86 */+gcc_assert(build_for_x86);++/*+*Findstackleak_track_stack()asmcalls.Loopthroughthechainof+*insns,whichisanRTLrepresentationofthecodeforafunction.+*+*Theexampleofamatchinginsn:+*(insn115122(parallel[(asm_operands/v+*("call stackleak_track_stack")("")0+*[(reg/v:DI7sp[current_stack_pointer])]+*[(asm_input:DI("r"))][])+*(clobber(reg:CC17flags))])-1(nil))+*/+for(insn=get_insns();insn;insn=next){+rtxbody;++next=NEXT_INSN(insn);++/* Check the expression code of the insn */+if(!NONJUMP_INSN_P(insn))+continue;++/*+*Checktheexpressioncodeoftheinsnbody,whichisanRTL+*Expression(RTX)describingthesideeffectperformedby+*thatinsn.+*/+body=PATTERN(insn);++if(GET_CODE(body)!=PARALLEL)+continue;++body=XVECEXP(body,0,0);++if(GET_CODE(body)!=ASM_OPERANDS)+continue;++if(strcmp(ASM_OPERANDS_TEMPLATE(body),+"call stackleak_track_stack")){+continue;+}++delete_insn_and_edges(insn);+gcc_assert(!removed);+removed=true;+}++returnremoved;+}++/*+*WorkwiththeRTLrepresentationofthecode.+*Removetheunneededstackleak_track_stack()callsfromthefunctions+*thatdon'thavealargeenoughstackframesize.+*/+staticunsignedintstackleak_cleanup_execute(void)+{+boolremoved=false;++/*+*gccbeforeversion7calledallocate_dynamic_stack_space()from+*expand_stack_vars()forruntimealignmentofconstant-sizedstack+*variables.Thatcausedcfun->calls_allocatobesetforfunctions+*thatdon'tusealloca().+*Formoreinfoseegcccommit7072df0aae0c59ae437e.+*Let'sleavesuchfunctionsinstrumented.+*/+if(cfun->calls_alloca)+return0;++if(large_stack_frame())+return0;++if(lookup_attribute_spec(get_identifier("no_caller_saved_registers")))+removed=remove_stack_tracking_gasm();++if(!removed)+remove_stack_tracking_gcall();return0;}
@@ -383,6 +522,15 @@ __visible int plugin_init(struct plugin_name_args *plugin_info,plugin_name,argv[i].key,argv[i].value);return1;}+}elseif(!strcmp(argv[i].key,"arch")){+if(!argv[i].value){+error(G_("no value supplied for option '-fplugin-arg-%s-%s'"),+plugin_name,argv[i].key);+return1;+}++if(!strcmp(argv[i].value,"x86"))+build_for_x86=true;}else{error(G_("unknown option '-fplugin-arg-%s-%s'"),plugin_name,argv[i].key);
--
2.25.2
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
From: Alexander Popov <hidden> Date: 2020-06-04 13:51:07
Add 'verbose' plugin parameter for stackleak gcc plugin.
It can be used for printing additional info about the kernel code
instrumentation.
For using it add the following to scripts/Makefile.gcc-plugins:
gcc-plugin-cflags-$(CONFIG_GCC_PLUGIN_STACKLEAK) \
+= -fplugin-arg-stackleak_plugin-verbose
Signed-off-by: Alexander Popov <redacted>
---
scripts/gcc-plugins/stackleak_plugin.c | 31 +++++++++++++++++++++-----
1 file changed, 26 insertions(+), 5 deletions(-)
@@ -33,6 +33,8 @@ __visible int plugin_is_GPL_compatible;staticinttrack_frame_size=-1;staticboolbuild_for_x86=false;staticconstchartrack_function[]="stackleak_track_stack";+staticbooldisable=false;+staticboolverbose=false;/**Marktheseglobalvariables(roots)forgccgarbagecollectorsince
@@ -45,6 +47,7 @@ static struct plugin_info stackleak_plugin_info = {.help="track-min-size=nn\ttrack stack for functions with a stack frame size >= nn bytes\n""arch=target_arch\tspecify target build arch\n""disable\t\tdo not activate the plugin\n"+"verbose\t\tprint info about the instrumentation\n"};staticvoidadd_stack_tracking_gcall(gimple_stmt_iterator*gsi)
@@ -98,6 +101,10 @@ static tree get_current_stack_pointer_decl(void)returnvar;}+if(verbose){+fprintf(stderr,"stackleak: missing current_stack_pointer in %s()\n",+DECL_NAME_POINTER(current_function_decl));+}returnNULL_TREE;}
@@ -506,9 +520,6 @@ __visible int plugin_init(struct plugin_name_args *plugin_info,/* Parse the plugin arguments */for(i=0;i<argc;i++){-if(!strcmp(argv[i].key,"disable"))-return0;-if(!strcmp(argv[i].key,"track-min-size")){if(!argv[i].value){error(G_("no value supplied for option '-fplugin-arg-%s-%s'"),
@@ -538,6 +553,12 @@ __visible int plugin_init(struct plugin_name_args *plugin_info,}}+if(disable){+if(verbose)+fprintf(stderr,"stackleak: disabled for this translation unit\n");+return0;+}+/* Give the information about the plugin */register_callback(plugin_name,PLUGIN_INFO,NULL,&stackleak_plugin_info);
--
2.25.2
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
From: Alexander Popov <hidden> Date: 2020-06-04 13:51:11
There is no need to try instrumenting functions in kernel/stackleak.c.
Otherwise that can cause issues if the cleanup pass of stackleak gcc plugin
is disabled.
Signed-off-by: Alexander Popov <redacted>
---
kernel/Makefile | 1 +
1 file changed, 1 insertion(+)
From: Alexander Popov <hidden> Date: 2020-06-04 13:51:17
Don't try instrumenting functions in arch/arm64/kernel/vdso/vgettimeofday.c.
Otherwise that can cause issues if the cleanup pass of stackleak gcc plugin
is disabled.
Signed-off-by: Alexander Popov <redacted>
---
arch/arm64/kernel/vdso/Makefile | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
From: Will Deacon <will@kernel.org> Date: 2020-06-04 13:58:16
On Thu, Jun 04, 2020 at 04:49:57PM +0300, Alexander Popov wrote:
quoted hunk
Don't try instrumenting functions in arch/arm64/kernel/vdso/vgettimeofday.c.
Otherwise that can cause issues if the cleanup pass of stackleak gcc plugin
is disabled.
Signed-off-by: Alexander Popov <redacted>
---
arch/arm64/kernel/vdso/Makefile | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
I can pick this one up via arm64, thanks. Are there any other plugins we
should be wary of? It looks like x86 filters out $(GCC_PLUGINS_CFLAGS)
when building the vDSO.
Will
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
On Thu, Jun 4, 2020 at 3:51 PM Alexander Popov [off-list ref] wrote:
Some time ago Variable Length Arrays (VLA) were removed from the kernel.
The kernel is built with '-Wvla'. Let's exclude alloca() from the
instrumentation logic and make it simpler. The build-time assertion
against alloca() is added instead.
[...]
+ /* Variable Length Arrays are forbidden in the kernel */
+ gcc_assert(!is_alloca(stmt));
On Thu, Jun 4, 2020 at 3:58 PM Will Deacon [off-list ref] wrote:
On Thu, Jun 04, 2020 at 04:49:57PM +0300, Alexander Popov wrote:
quoted
Don't try instrumenting functions in arch/arm64/kernel/vdso/vgettimeofday.c.
Otherwise that can cause issues if the cleanup pass of stackleak gcc plugin
is disabled.
Signed-off-by: Alexander Popov <redacted>
---
arch/arm64/kernel/vdso/Makefile | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
I can pick this one up via arm64, thanks. Are there any other plugins we
should be wary of? It looks like x86 filters out $(GCC_PLUGINS_CFLAGS)
when building the vDSO.
Maybe at some point we should replace exclusions based on
GCC_PLUGINS_CFLAGS and KASAN_SANITIZE and UBSAN_SANITIZE and
OBJECT_FILES_NON_STANDARD and so on with something more generic...
something that says "this file will not be built into the normal
kernel, it contains code that runs in realmode / userspace / some
similarly weird context, and none of our instrumentation
infrastructure is available there"...
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
From: Alexander Popov <hidden> Date: 2020-06-04 14:21:10
On 04.06.2020 17:14, Jann Horn wrote:
On Thu, Jun 4, 2020 at 3:58 PM Will Deacon [off-list ref] wrote:
quoted
On Thu, Jun 04, 2020 at 04:49:57PM +0300, Alexander Popov wrote:
quoted
Don't try instrumenting functions in arch/arm64/kernel/vdso/vgettimeofday.c.
Otherwise that can cause issues if the cleanup pass of stackleak gcc plugin
is disabled.
Signed-off-by: Alexander Popov <redacted>
---
arch/arm64/kernel/vdso/Makefile | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
I can pick this one up via arm64, thanks. Are there any other plugins we
should be wary of?
I can't tell exactly. I'm sure Kees has the whole picture.
quoted
It looks like x86 filters out $(GCC_PLUGINS_CFLAGS)
when building the vDSO.
Yes, that's why building x86 vDSO doesn't need $(DISABLE_STACKLEAK_PLUGIN).
Maybe at some point we should replace exclusions based on
GCC_PLUGINS_CFLAGS and KASAN_SANITIZE and UBSAN_SANITIZE and
OBJECT_FILES_NON_STANDARD and so on with something more generic...
something that says "this file will not be built into the normal
kernel, it contains code that runs in realmode / userspace / some
similarly weird context, and none of our instrumentation
infrastructure is available there"...
Good idea. I would also add 'notrace' to that list.
Best regards,
Alexander
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
On Thu, Jun 4, 2020 at 4:21 PM Alexander Popov [off-list ref] wrote:
On 04.06.2020 17:14, Jann Horn wrote:
quoted
Maybe at some point we should replace exclusions based on
GCC_PLUGINS_CFLAGS and KASAN_SANITIZE and UBSAN_SANITIZE and
OBJECT_FILES_NON_STANDARD and so on with something more generic...
something that says "this file will not be built into the normal
kernel, it contains code that runs in realmode / userspace / some
similarly weird context, and none of our instrumentation
infrastructure is available there"...
Good idea. I would also add 'notrace' to that list.
Hm? notrace code should definitely still be subject to sanitizer
instrumentation.
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
From: Alexander Popov <hidden> Date: 2020-06-04 14:44:55
On 04.06.2020 17:25, Jann Horn wrote:
On Thu, Jun 4, 2020 at 4:21 PM Alexander Popov [off-list ref] wrote:
quoted
On 04.06.2020 17:14, Jann Horn wrote:
quoted
Maybe at some point we should replace exclusions based on
GCC_PLUGINS_CFLAGS and KASAN_SANITIZE and UBSAN_SANITIZE and
OBJECT_FILES_NON_STANDARD and so on with something more generic...
something that says "this file will not be built into the normal
kernel, it contains code that runs in realmode / userspace / some
similarly weird context, and none of our instrumentation
infrastructure is available there"...
Good idea. I would also add 'notrace' to that list.
Hm? notrace code should definitely still be subject to sanitizer
instrumentation.
I mean ftrace is sometimes disabled for functions that are executed in those
weird contexts. As well as kcov instrumentation.
It would be nice if that generic mechanism could help with choosing which kernel
code instrumentation technologies should be disabled in the given context.
Best regards,
Alexander
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
Nit: if you do another version, please move it before `noclone` to
keep the order (`fallthrough` was added in the wrong place).
Otherwise don't worry, I will sort it together with `fallthrough` when
I send a patch.
From: Alexander Popov <hidden> Date: 2020-06-04 15:23:55
On 04.06.2020 17:01, Jann Horn wrote:
On Thu, Jun 4, 2020 at 3:51 PM Alexander Popov [off-list ref] wrote:
quoted
Some time ago Variable Length Arrays (VLA) were removed from the kernel.
The kernel is built with '-Wvla'. Let's exclude alloca() from the
instrumentation logic and make it simpler. The build-time assertion
against alloca() is added instead.
[...]
quoted
+ /* Variable Length Arrays are forbidden in the kernel */
+ gcc_assert(!is_alloca(stmt));
Thanks, Jann.
At first glance, leaving alloca() handling in stackleak instrumentation logic
would allow to integrate stackleak and this version of random_kstack_offset.
Kees, Elena, did you try random_kstack_offset with upstream stackleak?
It looks to me that without stackleak erasing random_kstack_offset can be
weaker. I mean, if next syscall has a bigger stack randomization gap, the data
on thread stack from the previous syscall is not overwritten and can be used. Am
I right?
Another aspect: CONFIG_STACKLEAK_METRICS can be used for guessing kernel stack
offset, which is bad. It should be disabled if random_kstack_offset is on.
Best regards,
Alexander
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
On Thu, Jun 04, 2020 at 04:49:52PM +0300, Alexander Popov wrote:
In this patch series I collected various improvements of the stackleak
gcc plugin.
Great; thank you! I'll take a closer look at this shortly!
--
Kees Cook
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
On Thu, Jun 04, 2020 at 06:23:38PM +0300, Alexander Popov wrote:
On 04.06.2020 17:01, Jann Horn wrote:
quoted
On Thu, Jun 4, 2020 at 3:51 PM Alexander Popov [off-list ref] wrote:
quoted
Some time ago Variable Length Arrays (VLA) were removed from the kernel.
The kernel is built with '-Wvla'. Let's exclude alloca() from the
instrumentation logic and make it simpler. The build-time assertion
against alloca() is added instead.
[...]
quoted
+ /* Variable Length Arrays are forbidden in the kernel */
+ gcc_assert(!is_alloca(stmt));
Thanks, Jann.
At first glance, leaving alloca() handling in stackleak instrumentation logic
would allow to integrate stackleak and this version of random_kstack_offset.
Right, it seems there would be a need for this coverage to remain,
otherwise the depth of stack erasure might be incorrect.
It doesn't seem like the other patches strictly depend on alloca()
support being removed, though?
Kees, Elena, did you try random_kstack_offset with upstream stackleak?
I didn't try that combination yet, no. It seemed there would likely
still be further discussion about the offset series first (though the
thread has been silent -- I'll rebase and resend it after rc2).
It looks to me that without stackleak erasing random_kstack_offset can be
weaker. I mean, if next syscall has a bigger stack randomization gap, the data
on thread stack from the previous syscall is not overwritten and can be used. Am
I right?
That's correct. I think the combination is needed, but I don't think
they need to be strictly tied together.
Another aspect: CONFIG_STACKLEAK_METRICS can be used for guessing kernel stack
offset, which is bad. It should be disabled if random_kstack_offset is on.
On Thu, Jun 04, 2020 at 04:49:54PM +0300, Alexander Popov wrote:
Let's improve the instrumentation to avoid this:
1. Make stackleak_track_stack() save all register that it works with.
Use no_caller_saved_registers attribute for that function. This attribute
is available for x86_64 and i386 starting from gcc-7.
2. Insert calling stackleak_track_stack() in asm:
asm volatile("call stackleak_track_stack" :: "r" (current_stack_pointer))
Here we use ASM_CALL_CONSTRAINT trick from arch/x86/include/asm/asm.h.
The input constraint is taken into account during gcc shrink-wrapping
optimization. It is needed to be sure that stackleak_track_stack() call is
inserted after the prologue of the containing function, when the stack
frame is prepared.
Very cool; nice work!
+static void add_stack_tracking(gimple_stmt_iterator *gsi)
+{
+ /*
+ * The 'no_caller_saved_registers' attribute is used for
+ * stackleak_track_stack(). If the compiler supports this attribute for
+ * the target arch, we can add calling stackleak_track_stack() in asm.
+ * That improves performance: we avoid useless operations with the
+ * caller-saved registers in the functions from which we will remove
+ * stackleak_track_stack() call during the stackleak_cleanup pass.
+ */
+ if (lookup_attribute_spec(get_identifier("no_caller_saved_registers")))
+ add_stack_tracking_gasm(gsi);
+ else
+ add_stack_tracking_gcall(gsi);
+}
The build_for_x86 flag is only ever used as an assert() test against
no_caller_saved_registers, but we're able to test for that separately.
Why does the architecture need to be tested? (i.e. when this flag
becomes supported o other architectures, why must it still be x86-only?)
--
Kees Cook
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
On Thu, Jun 04, 2020 at 04:49:55PM +0300, Alexander Popov wrote:
Add 'verbose' plugin parameter for stackleak gcc plugin.
It can be used for printing additional info about the kernel code
instrumentation.
For using it add the following to scripts/Makefile.gcc-plugins:
gcc-plugin-cflags-$(CONFIG_GCC_PLUGIN_STACKLEAK) \
+= -fplugin-arg-stackleak_plugin-verbose
Signed-off-by: Alexander Popov <redacted>
On Thu, Jun 04, 2020 at 04:49:56PM +0300, Alexander Popov wrote:
There is no need to try instrumenting functions in kernel/stackleak.c.
Otherwise that can cause issues if the cleanup pass of stackleak gcc plugin
is disabled.
Signed-off-by: Alexander Popov <redacted>
On Thu, Jun 04, 2020 at 02:58:06PM +0100, Will Deacon wrote:
On Thu, Jun 04, 2020 at 04:49:57PM +0300, Alexander Popov wrote:
quoted
Don't try instrumenting functions in arch/arm64/kernel/vdso/vgettimeofday.c.
Otherwise that can cause issues if the cleanup pass of stackleak gcc plugin
is disabled.
Signed-off-by: Alexander Popov <redacted>
---
arch/arm64/kernel/vdso/Makefile | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
I can pick this one up via arm64, thanks. Are there any other plugins we
should be wary of? It looks like x86 filters out $(GCC_PLUGINS_CFLAGS)
when building the vDSO.
I didn't realize/remember that arm64 retained the kernel build flags for
vDSO builds. (I'm used to x86 throwing all its flags away for its vDSO.)
How does 32-bit ARM do its vDSO?
My quick run-through on plugins:
arm_ssp_per_task_plugin.c
32-bit ARM only (but likely needs disabling for 32-bit ARM vDSO?)
cyc_complexity_plugin.c
compile-time reporting only
latent_entropy_plugin.c
this shouldn't get triggered for the vDSO (no __latent_entropy
nor __init attributes in vDSO), but perhaps explicitly disabling
it would be a sensible thing to do, just for robustness?
randomize_layout_plugin.c
this shouldn't get triggered (again, lacking attributes), but
should likely be disabled too.
sancov_plugin.c
This should be tracking the KCOV directly (see
scripts/Makefile.kcov), which is already disabled here.
structleak_plugin.c
This should be fine in the vDSO, but there's not security
boundary here, so it wouldn't be important to KEEP it enabled.
--
Kees Cook
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
On Thu, Jun 04, 2020 at 04:49:52PM +0300, Alexander Popov wrote:
In this patch series I collected various improvements of the stackleak
gcc plugin.
Thanks!
Alexander Popov (5):
gcc-plugins/stackleak: Exclude alloca() from the instrumentation logic
gcc-plugins/stackleak: Use asm instrumentation to avoid useless
register saving
These look like they might need tweaks (noted in their separate
replies).
If you wanted to reorder the series and move these first, I could take
these into my tree right away (they're logically separate from the other
fixes).
gcc-plugins/stackleak: Don't instrument vgettimeofday.c in arm64 VDSO
This seems good -- though I'm curious about 32-bit ARM and the other
HAVE_GCC_PLUGINS architectures with vDSOs (which appears to be all of
them except um).
--
Kees Cook
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
From: Will Deacon <will@kernel.org> Date: 2020-06-10 07:30:58
On Tue, Jun 09, 2020 at 12:09:27PM -0700, Kees Cook wrote:
On Thu, Jun 04, 2020 at 02:58:06PM +0100, Will Deacon wrote:
quoted
On Thu, Jun 04, 2020 at 04:49:57PM +0300, Alexander Popov wrote:
quoted
Don't try instrumenting functions in arch/arm64/kernel/vdso/vgettimeofday.c.
Otherwise that can cause issues if the cleanup pass of stackleak gcc plugin
is disabled.
Signed-off-by: Alexander Popov <redacted>
---
arch/arm64/kernel/vdso/Makefile | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
I can pick this one up via arm64, thanks. Are there any other plugins we
should be wary of? It looks like x86 filters out $(GCC_PLUGINS_CFLAGS)
when building the vDSO.
I didn't realize/remember that arm64 retained the kernel build flags for
vDSO builds. (I'm used to x86 throwing all its flags away for its vDSO.)
How does 32-bit ARM do its vDSO?
My quick run-through on plugins:
arm_ssp_per_task_plugin.c
32-bit ARM only (but likely needs disabling for 32-bit ARM vDSO?)
On arm64, the 32-bit toolchain is picked up via CC_COMPAT -- does that still
get the plugins?
cyc_complexity_plugin.c
compile-time reporting only
latent_entropy_plugin.c
this shouldn't get triggered for the vDSO (no __latent_entropy
nor __init attributes in vDSO), but perhaps explicitly disabling
it would be a sensible thing to do, just for robustness?
randomize_layout_plugin.c
this shouldn't get triggered (again, lacking attributes), but
should likely be disabled too.
sancov_plugin.c
This should be tracking the KCOV directly (see
scripts/Makefile.kcov), which is already disabled here.
structleak_plugin.c
This should be fine in the vDSO, but there's not security
boundary here, so it wouldn't be important to KEEP it enabled.
Thanks for going through these. In general though, it seems like an
opt-in strategy would make more sense, as it doesn't make an awful lot
of sense to me for the plugins to be used to build the vDSO.
So I would prefer that this patch filters out $(GCC_PLUGINS_CFLAGS).
Will
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
From: Alexander Popov <hidden> Date: 2020-06-10 15:15:08
On 09.06.2020 22:15, Kees Cook wrote:
On Thu, Jun 04, 2020 at 04:49:52PM +0300, Alexander Popov wrote:
quoted
In this patch series I collected various improvements of the stackleak
gcc plugin.
Thanks!
quoted
Alexander Popov (5):
gcc-plugins/stackleak: Exclude alloca() from the instrumentation logic
gcc-plugins/stackleak: Use asm instrumentation to avoid useless
register saving
These look like they might need tweaks (noted in their separate
replies).
If you wanted to reorder the series and move these first, I could take
these into my tree right away (they're logically separate from the other
fixes).
Ok, I will put "don't instrument itself" at the beginning of v2.
The patch adding 'verbose' plugin parameter depends on the previous patches, so
I will not move it.
quoted
gcc-plugins/stackleak: Don't instrument vgettimeofday.c in arm64 VDSO
This seems good -- though I'm curious about 32-bit ARM and the other
HAVE_GCC_PLUGINS architectures with vDSOs (which appears to be all of
them except um).
From: Alexander Popov <hidden> Date: 2020-06-10 15:19:06
On 10.06.2020 10:30, Will Deacon wrote:
On Tue, Jun 09, 2020 at 12:09:27PM -0700, Kees Cook wrote:
quoted
On Thu, Jun 04, 2020 at 02:58:06PM +0100, Will Deacon wrote:
quoted
On Thu, Jun 04, 2020 at 04:49:57PM +0300, Alexander Popov wrote:
quoted
Don't try instrumenting functions in arch/arm64/kernel/vdso/vgettimeofday.c.
Otherwise that can cause issues if the cleanup pass of stackleak gcc plugin
is disabled.
Signed-off-by: Alexander Popov <redacted>
---
arch/arm64/kernel/vdso/Makefile | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
I can pick this one up via arm64, thanks. Are there any other plugins we
should be wary of? It looks like x86 filters out $(GCC_PLUGINS_CFLAGS)
when building the vDSO.
I didn't realize/remember that arm64 retained the kernel build flags for
vDSO builds. (I'm used to x86 throwing all its flags away for its vDSO.)
How does 32-bit ARM do its vDSO?
My quick run-through on plugins:
arm_ssp_per_task_plugin.c
32-bit ARM only (but likely needs disabling for 32-bit ARM vDSO?)
On arm64, the 32-bit toolchain is picked up via CC_COMPAT -- does that still
get the plugins?
quoted
cyc_complexity_plugin.c
compile-time reporting only
latent_entropy_plugin.c
this shouldn't get triggered for the vDSO (no __latent_entropy
nor __init attributes in vDSO), but perhaps explicitly disabling
it would be a sensible thing to do, just for robustness?
randomize_layout_plugin.c
this shouldn't get triggered (again, lacking attributes), but
should likely be disabled too.
sancov_plugin.c
This should be tracking the KCOV directly (see
scripts/Makefile.kcov), which is already disabled here.
structleak_plugin.c
This should be fine in the vDSO, but there's not security
boundary here, so it wouldn't be important to KEEP it enabled.
Thanks for going through these. In general though, it seems like an
opt-in strategy would make more sense, as it doesn't make an awful lot
of sense to me for the plugins to be used to build the vDSO.
So I would prefer that this patch filters out $(GCC_PLUGINS_CFLAGS).
Ok, I will do that in the v2 of the patch series.
Best regards,
Alexander
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
From: Alexander Popov <hidden> Date: 2020-06-10 15:24:36
On 09.06.2020 21:39, Kees Cook wrote:
On Thu, Jun 04, 2020 at 06:23:38PM +0300, Alexander Popov wrote:
quoted
On 04.06.2020 17:01, Jann Horn wrote:
quoted
On Thu, Jun 4, 2020 at 3:51 PM Alexander Popov [off-list ref] wrote:
quoted
Some time ago Variable Length Arrays (VLA) were removed from the kernel.
The kernel is built with '-Wvla'. Let's exclude alloca() from the
instrumentation logic and make it simpler. The build-time assertion
against alloca() is added instead.
[...]
quoted
+ /* Variable Length Arrays are forbidden in the kernel */
+ gcc_assert(!is_alloca(stmt));
Thanks, Jann.
At first glance, leaving alloca() handling in stackleak instrumentation logic
would allow to integrate stackleak and this version of random_kstack_offset.
Right, it seems there would be a need for this coverage to remain,
otherwise the depth of stack erasure might be incorrect.
It doesn't seem like the other patches strictly depend on alloca()
support being removed, though?
Ok, I will leave alloca() support, reorganize the patch series and send v2.
quoted
Kees, Elena, did you try random_kstack_offset with upstream stackleak?
I didn't try that combination yet, no. It seemed there would likely
still be further discussion about the offset series first (though the
thread has been silent -- I'll rebase and resend it after rc2).
Ok, please add me to CC list.
Best regards,
Alexander
quoted
It looks to me that without stackleak erasing random_kstack_offset can be
weaker. I mean, if next syscall has a bigger stack randomization gap, the data
on thread stack from the previous syscall is not overwritten and can be used. Am
I right?
That's correct. I think the combination is needed, but I don't think
they need to be strictly tied together.
quoted
Another aspect: CONFIG_STACKLEAK_METRICS can be used for guessing kernel stack
offset, which is bad. It should be disabled if random_kstack_offset is on.
From: Alexander Popov <hidden> Date: 2020-06-10 15:47:40
On 09.06.2020 21:46, Kees Cook wrote:
On Thu, Jun 04, 2020 at 04:49:54PM +0300, Alexander Popov wrote:
quoted
Let's improve the instrumentation to avoid this:
1. Make stackleak_track_stack() save all register that it works with.
Use no_caller_saved_registers attribute for that function. This attribute
is available for x86_64 and i386 starting from gcc-7.
2. Insert calling stackleak_track_stack() in asm:
asm volatile("call stackleak_track_stack" :: "r" (current_stack_pointer))
Here we use ASM_CALL_CONSTRAINT trick from arch/x86/include/asm/asm.h.
The input constraint is taken into account during gcc shrink-wrapping
optimization. It is needed to be sure that stackleak_track_stack() call is
inserted after the prologue of the containing function, when the stack
frame is prepared.
Very cool; nice work!
quoted
+static void add_stack_tracking(gimple_stmt_iterator *gsi)
+{
+ /*
+ * The 'no_caller_saved_registers' attribute is used for
+ * stackleak_track_stack(). If the compiler supports this attribute for
+ * the target arch, we can add calling stackleak_track_stack() in asm.
+ * That improves performance: we avoid useless operations with the
+ * caller-saved registers in the functions from which we will remove
+ * stackleak_track_stack() call during the stackleak_cleanup pass.
+ */
+ if (lookup_attribute_spec(get_identifier("no_caller_saved_registers")))
+ add_stack_tracking_gasm(gsi);
+ else
+ add_stack_tracking_gcall(gsi);
+}
The build_for_x86 flag is only ever used as an assert() test against
no_caller_saved_registers, but we're able to test for that separately.
Why does the architecture need to be tested? (i.e. when this flag
becomes supported o other architectures, why must it still be x86-only?)
The inline asm statement that is used for instrumentation is arch-specific.
Trying to add
asm volatile("call stackleak_track_stack")
in gcc plugin on aarch64 makes gcc break spectacularly.
I pass the target arch name to the plugin and check it explicitly to avoid that.
Moreover, I'm going to create a gcc enhancement request for supporting
no_caller_saved_registers attribute on aarch64.
Best regards,
Alexander
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
From: Alexander Popov <hidden> Date: 2020-06-10 15:52:34
On 09.06.2020 21:47, Kees Cook wrote:
On Thu, Jun 04, 2020 at 04:49:55PM +0300, Alexander Popov wrote:
quoted
Add 'verbose' plugin parameter for stackleak gcc plugin.
It can be used for printing additional info about the kernel code
instrumentation.
For using it add the following to scripts/Makefile.gcc-plugins:
gcc-plugin-cflags-$(CONFIG_GCC_PLUGIN_STACKLEAK) \
+= -fplugin-arg-stackleak_plugin-verbose
Signed-off-by: Alexander Popov <redacted>
Acked-by: Kees Cook <redacted>
I see that I will change this patch after leaving alloca() support.
I'm going to add debug printing about functions that call alloca().
I have to omit your 'acked-by' for the changed patch, right?
Best regards,
Alexander
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
On Wed, Jun 10, 2020 at 06:47:14PM +0300, Alexander Popov wrote:
On 09.06.2020 21:46, Kees Cook wrote:
The inline asm statement that is used for instrumentation is arch-specific.
Trying to add
asm volatile("call stackleak_track_stack")
in gcc plugin on aarch64 makes gcc break spectacularly.
Ah! Thank you, that eluded my eyes. :)
I pass the target arch name to the plugin and check it explicitly to avoid that.
Moreover, I'm going to create a gcc enhancement request for supporting
no_caller_saved_registers attribute on aarch64.
For arm64 right now it looks like the plugin will just remain
"inefficient" in these cleanup, as before, yes?
--
Kees Cook
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
On Wed, Jun 10, 2020 at 06:52:10PM +0300, Alexander Popov wrote:
On 09.06.2020 21:47, Kees Cook wrote:
quoted
On Thu, Jun 04, 2020 at 04:49:55PM +0300, Alexander Popov wrote:
quoted
Add 'verbose' plugin parameter for stackleak gcc plugin.
It can be used for printing additional info about the kernel code
instrumentation.
For using it add the following to scripts/Makefile.gcc-plugins:
gcc-plugin-cflags-$(CONFIG_GCC_PLUGIN_STACKLEAK) \
+= -fplugin-arg-stackleak_plugin-verbose
Signed-off-by: Alexander Popov <redacted>
Acked-by: Kees Cook <redacted>
I see that I will change this patch after leaving alloca() support.
I'm going to add debug printing about functions that call alloca().
I have to omit your 'acked-by' for the changed patch, right?
If it changes dramatically, drop my Ack, yes. But since it's going via
my tree, my Ack is mostly just a quick email marker to say "yes, looks
good". :)
--
Kees Cook
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
From: Alexander Popov <hidden> Date: 2020-06-11 23:45:10
On 10.06.2020 23:03, Kees Cook wrote:
On Wed, Jun 10, 2020 at 06:47:14PM +0300, Alexander Popov wrote:
quoted
On 09.06.2020 21:46, Kees Cook wrote:
The inline asm statement that is used for instrumentation is arch-specific.
Trying to add
asm volatile("call stackleak_track_stack")
in gcc plugin on aarch64 makes gcc break spectacularly.
Ah! Thank you, that eluded my eyes. :)
quoted
I pass the target arch name to the plugin and check it explicitly to avoid that.
Moreover, I'm going to create a gcc enhancement request for supporting
no_caller_saved_registers attribute on aarch64.
For arm64 right now it looks like the plugin will just remain
"inefficient" in these cleanup, as before, yes?
Yes, for arm64 the instrumentation didn't change in this patch series.
I checked the disasm and see the similar issue with useless register saving.
I'm going to add asm instrumentation for arm64 when (I hope) the
no_caller_saved_registers attribute becomes available for that platform.
Best regards,
Alexander
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel