* Re: [PATCH 2/2] lib: Introduce test_stackinit module [not found] ` <20190212180441.15340-3-keescook@chromium.org> @ 2019-03-11 10:52 ` Geert Uytterhoeven 2019-04-23 22:42 ` Kees Cook 0 siblings, 1 reply; 2+ messages in thread From: Geert Uytterhoeven @ 2019-03-11 10:52 UTC (permalink / raw) To: Kees Cook Cc: Linux Kernel Mailing List, Emese Revfy, Alexander Popov, Ard Biesheuvel, Laura Abbott, Jann Horn, Alexander Potapenko, kernel-hardening, Linux/m68k Hi Kees, On Tue, Feb 12, 2019 at 7:08 PM Kees Cook <keescook@chromium.org> wrote: > Adds test for stack initialization coverage. We have several build options > that control the level of stack variable initialization. This test lets us > visualize which options cover which cases, and provide tests for some of > the pathological padding conditions the compiler will sometimes fail to > initialize. With current upstream, using gcc Ubuntu 8.2.0-1ubuntu2~18.04, I get on m68k: test_stackinit: u8_zero: stack fill missed target!? test_stackinit: u8_zero: fill 1 wide test_stackinit: u8_zero: target offset by 20 test_stackinit: u16_zero: stack fill missed target!? test_stackinit: u16_zero: fill 2 wide test_stackinit: u16_zero: target offset by 20 test_stackinit: u32_zero: stack fill missed target!? test_stackinit: u32_zero: fill 4 wide test_stackinit: u32_zero: target offset by 20 test_stackinit: u64_zero: stack fill missed target!? test_stackinit: u64_zero: fill 8 wide test_stackinit: u64_zero: target offset by 20 test_stackinit: char_array_zero: stack fill missed target!? test_stackinit: char_array_zero: fill 16 wide test_stackinit: char_array_zero: target offset by -12 test_stackinit: small_hole_zero: stack fill missed target!? test_stackinit: small_hole_zero: fill 14 wide test_stackinit: small_hole_zero: target offset by -12 test_stackinit: big_hole_zero ok test_stackinit: trailing_hole_zero: stack fill missed target!? test_stackinit: trailing_hole_zero: fill 14 wide test_stackinit: trailing_hole_zero: target offset by -12 test_stackinit: packed_zero: stack fill missed target!? test_stackinit: packed_zero: fill 16 wide test_stackinit: packed_zero: target offset by -12 test_stackinit: small_hole_dynamic_partial: stack fill missed target!? test_stackinit: small_hole_dynamic_partial: fill 14 wide test_stackinit: small_hole_dynamic_partial: target offset by -12 test_stackinit: big_hole_dynamic_partial ok test_stackinit: trailing_hole_dynamic_partial: stack fill missed target!? test_stackinit: trailing_hole_dynamic_partial: fill 14 wide test_stackinit: trailing_hole_dynamic_partial: target offset by -12 test_stackinit: packed_dynamic_partial: stack fill missed target!? test_stackinit: packed_dynamic_partial: fill 16 wide test_stackinit: packed_dynamic_partial: target offset by -12 test_stackinit: small_hole_static_partial: stack fill missed target!? test_stackinit: small_hole_static_partial: fill 14 wide test_stackinit: small_hole_static_partial: target offset by -12 test_stackinit: big_hole_static_partial ok test_stackinit: trailing_hole_static_partial: stack fill missed target!? test_stackinit: trailing_hole_static_partial: fill 14 wide test_stackinit: trailing_hole_static_partial: target offset by -12 test_stackinit: packed_static_partial: stack fill missed target!? test_stackinit: packed_static_partial: fill 16 wide test_stackinit: packed_static_partial: target offset by -12 test_stackinit: small_hole_static_all: stack fill missed target!? test_stackinit: small_hole_static_all: fill 14 wide test_stackinit: small_hole_static_all: target offset by -12 test_stackinit: big_hole_static_all FAIL (uninit bytes: 61) test_stackinit: trailing_hole_static_all: stack fill missed target!? test_stackinit: trailing_hole_static_all: fill 14 wide test_stackinit: trailing_hole_static_all: target offset by -12 test_stackinit: packed_static_all: stack fill missed target!? test_stackinit: packed_static_all: fill 16 wide test_stackinit: packed_static_all: target offset by -12 test_stackinit: small_hole_dynamic_all: stack fill missed target!? test_stackinit: small_hole_dynamic_all: fill 14 wide test_stackinit: small_hole_dynamic_all: target offset by -12 test_stackinit: big_hole_dynamic_all FAIL (uninit bytes: 61) test_stackinit: trailing_hole_dynamic_all: stack fill missed target!? test_stackinit: trailing_hole_dynamic_all: fill 14 wide test_stackinit: trailing_hole_dynamic_all: target offset by -12 test_stackinit: packed_dynamic_all: stack fill missed target!? test_stackinit: packed_dynamic_all: fill 16 wide test_stackinit: packed_dynamic_all: target offset by -12 test_stackinit: small_hole_runtime_partial: stack fill missed target!? test_stackinit: small_hole_runtime_partial: fill 14 wide test_stackinit: small_hole_runtime_partial: target offset by -12 test_stackinit: big_hole_runtime_partial FAIL (uninit bytes: 127) test_stackinit: trailing_hole_runtime_partial: stack fill missed target!? test_stackinit: trailing_hole_runtime_partial: fill 14 wide test_stackinit: trailing_hole_runtime_partial: target offset by -12 test_stackinit: packed_runtime_partial: stack fill missed target!? test_stackinit: packed_runtime_partial: fill 16 wide test_stackinit: packed_runtime_partial: target offset by -12 test_stackinit: small_hole_runtime_all: stack fill missed target!? test_stackinit: small_hole_runtime_all: fill 14 wide test_stackinit: small_hole_runtime_all: target offset by -12 test_stackinit: big_hole_runtime_all FAIL (uninit bytes: 61) test_stackinit: trailing_hole_runtime_all: stack fill missed target!? test_stackinit: trailing_hole_runtime_all: fill 14 wide test_stackinit: trailing_hole_runtime_all: target offset by -12 test_stackinit: packed_runtime_all: stack fill missed target!? test_stackinit: packed_runtime_all: fill 16 wide test_stackinit: packed_runtime_all: target offset by -12 test_stackinit: u8_none: stack fill missed target!? test_stackinit: u8_none: fill 1 wide test_stackinit: u8_none: target offset by 20 test_stackinit: u16_none: stack fill missed target!? test_stackinit: u16_none: fill 2 wide test_stackinit: u16_none: target offset by 20 test_stackinit: u32_none: stack fill missed target!? test_stackinit: u32_none: fill 4 wide test_stackinit: u32_none: target offset by 20 test_stackinit: u64_none: stack fill missed target!? test_stackinit: u64_none: fill 8 wide test_stackinit: u64_none: target offset by 20 test_stackinit: char_array_none: stack fill missed target!? test_stackinit: char_array_none: fill 16 wide test_stackinit: char_array_none: target offset by -12 test_stackinit: switch_1_none: stack fill missed target!? test_stackinit: switch_1_none: fill 8 wide test_stackinit: switch_1_none: target offset by 16 test_stackinit: switch_2_none: stack fill missed target!? test_stackinit: switch_2_none: fill 8 wide test_stackinit: switch_2_none: target offset by 16 test_stackinit: small_hole_none: stack fill missed target!? test_stackinit: small_hole_none: fill 14 wide test_stackinit: small_hole_none: target offset by -12 test_stackinit: big_hole_none FAIL (uninit bytes: 128) test_stackinit: trailing_hole_none: stack fill missed target!? test_stackinit: trailing_hole_none: fill 14 wide test_stackinit: trailing_hole_none: target offset by -12 test_stackinit: packed_none: stack fill missed target!? test_stackinit: packed_none: fill 16 wide test_stackinit: packed_none: target offset by -12 test_stackinit: user: stack fill missed target!? test_stackinit: user: fill 14 wide test_stackinit: user: target offset by -12 test_stackinit: failures: 42 Any idea what is wrong? I find the test code a bit hard to understand... Also, I see comments making assumptions that are not true: struct test_small_hole { size_t one; char two; /* 3 byte padding hole here. */ int three; unsigned long four; }; On m68k (and a few other architectures), integrals of 16-bit and larger are aligned to a 2-byte address, so the padding may be only a single byte. Thanks! Gr{oetje,eeting}s, Geert -- Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org In personal conversations with technical people, I call myself a hacker. But when I'm talking to journalists I just say "programmer" or something like that. -- Linus Torvalds ^ permalink raw reply [flat|nested] 2+ messages in thread
* Re: [PATCH 2/2] lib: Introduce test_stackinit module 2019-03-11 10:52 ` [PATCH 2/2] lib: Introduce test_stackinit module Geert Uytterhoeven @ 2019-04-23 22:42 ` Kees Cook 0 siblings, 0 replies; 2+ messages in thread From: Kees Cook @ 2019-04-23 22:42 UTC (permalink / raw) To: Geert Uytterhoeven Cc: Linux Kernel Mailing List, Emese Revfy, Alexander Popov, Ard Biesheuvel, Laura Abbott, Jann Horn, Alexander Potapenko, Kernel Hardening, Linux/m68k On Mon, Mar 11, 2019 at 3:52 AM Geert Uytterhoeven <geert@linux-m68k.org> wrote: > > Hi Kees, > > On Tue, Feb 12, 2019 at 7:08 PM Kees Cook <keescook@chromium.org> wrote: > > Adds test for stack initialization coverage. We have several build options > > that control the level of stack variable initialization. This test lets us > > visualize which options cover which cases, and provide tests for some of > > the pathological padding conditions the compiler will sometimes fail to > > initialize. > > With current upstream, using gcc Ubuntu 8.2.0-1ubuntu2~18.04, I get > on m68k: Thanks for testing this on other architectures! > test_stackinit: u8_zero: stack fill missed target!? Hmpf. That's frustrating. That implies that the leaf function is assembled in such a way that the "leaking" memory address and the "controlled" memory address on the stack end up in different locations. I had a lot of problems with this before I unified my leaf function. I wonder if some inlining is happening with the m68k compiler that I haven't accounted for? > Any idea what is wrong? I find the test code a bit hard to understand... Yeah, there was a lot of repetition, so I tried to save my sanity and build macros. The particular problem above is with the "test_..."'s call of the "leaf_..." functions: /* Fill stack with 0xFF. */ \ ignored = leaf_ ##name((unsigned long)&ignored, 1, \ FETCH_ARG_ ## which(zero)); \ /* Clear entire check buffer for later bit tests. */ \ memset(check_buf, 0x00, sizeof(check_buf)); \ /* Extract stack-defined variable contents. */ \ ignored = leaf_ ##name((unsigned long)&ignored, 0, \ FETCH_ARG_ ## which(zero)); \ those two leaf_* invocations should produce stack variables at the same location on the stack: var_type var INIT_ ## which ## _ ## init_level; \ \ target_start = &var; \ target_size = sizeof(var); \ /* \ * Keep this buffer around to make sure we've got a \ * stack frame of SOME kind... \ */ \ memset(buf, (char)(sp && 0xff), sizeof(buf)); \ /* Fill variable with 0xFF. */ \ if (fill) { \ fill_start = &var; \ fill_size = sizeof(var); \ (note "target_start" and "fill_start" being assigned the location of (in theory) the same stack location) This gets checked later: /* Validate that compiler lined up fill and target. */ \ if (!range_contains(fill_start, fill_size, \ target_start, target_size)) { \ pr_err(#name ": stack fill missed target!?\n"); \ pr_err(#name ": fill %zu wide\n", fill_size); \ pr_err(#name ": target offset by %d\n", \ (int)((ssize_t)(uintptr_t)fill_start - \ (ssize_t)(uintptr_t)target_start)); \ return 1; \ which is where you're seeing the report. > Also, I see comments making assumptions that are not true: > > struct test_small_hole { > size_t one; > char two; > /* 3 byte padding hole here. */ > int three; > unsigned long four; > }; > > On m68k (and a few other architectures), integrals of 16-bit and larger > are aligned to a 2-byte address, so the padding may be only a single byte. Ah! Good point. I can update the comments, but the test should still be valid (it just has a smaller hole). Thanks again! -- Kees Cook ^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2019-04-23 22:42 UTC | newest] Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- [not found] <20190212180441.15340-1-keescook@chromium.org> [not found] ` <20190212180441.15340-3-keescook@chromium.org> 2019-03-11 10:52 ` [PATCH 2/2] lib: Introduce test_stackinit module Geert Uytterhoeven 2019-04-23 22:42 ` Kees Cook
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).