|
|
Message-ID: <b7aad232-76e1-241f-00e2-77783ce30f87@linux.com>
Date: Wed, 14 Nov 2018 21:24:28 +0300
From: Alexander Popov <alex.popov@...ux.com>
To: Kees Cook <keescook@...omium.org>, Ingo Molnar <mingo@...nel.org>,
Andy Lutomirski <luto@...nel.org>, Tycho Andersen <tycho@...ho.ws>,
Laura Abbott <labbott@...hat.com>, Mark Rutland <mark.rutland@....com>,
Ard Biesheuvel <ard.biesheuvel@...aro.org>, Borislav Petkov <bp@...en8.de>,
Richard Sandiford <richard.sandiford@....com>,
Thomas Gleixner <tglx@...utronix.de>, "H . Peter Anvin" <hpa@...or.com>,
Peter Zijlstra <a.p.zijlstra@...llo.nl>, Emese Revfy <re.emese@...il.com>,
Thomas Garnier <thgarnie@...gle.com>, Alexei Starovoitov <ast@...nel.org>,
Masami Hiramatsu <mhiramat@...nel.org>,
"David S . Miller" <davem@...emloft.net>,
Steven Rostedt <rostedt@...dmis.org>,
Dave Hansen <dave.hansen@...ux.intel.com>, Will Deacon
<will.deacon@....com>, Florian Weimer <fweimer@...hat.com>,
"kernel-hardening@...ts.openwall.com" <kernel-hardening@...ts.openwall.com>,
linux-arm-kernel@...ts.infradead.org, gcc-bugs@....gnu.org,
gcc-help@....gnu.org
Subject: Investigating a stack state mismatch in Linux kernel
Hello everyone!
I'm investigating an interesting issue with gcc-5 compilation of Linux kernel,
which is triggered by stackleak gcc plugin.
I would really appreciate any help (especially from gcc experts)!
The kbuild test robot reported a build warning for some special kernel config:
https://lists.01.org/pipermail/kbuild-all/2018-November/054567.html
drivers/acpi/acpi_processor.o: warning: objtool:
acpi_duplicate_processor_id()+0x49: stack state mismatch: cfa1=7+8 cfa2=6+16
The compiler misses pop instructions at the end of the function for some
execution path. That makes the frame pointer state inconsistent.
I can reproduce this issue for gcc 5.4.0 (Ubuntu 5.4.0-6ubuntu1~16.04.10). The
newer gcc 7.3.0 (Ubuntu 7.3.0-16ubuntu3) doesn't make this mistake.
This bug happens after stackleak gcc plugin worked with RTL representation of
the code. This plugin registers the 'stackleak_cleanup' pass after the 'reload'
pass, when the stack frame size is final. The plugin does a simple thing: it
removes the stackleak_track_stack() call from the functions with a small stack
frame, it uses delete_insn_and_edges() to do that.
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=2d6bb6adb714b133db92ccd4bfc9c20f75f71f3f
But after this CALL insn is deleted, gcc-5 misses the pop instruction during RTL
optimization :/
The compiled C function is not complicated:
bool acpi_duplicate_processor_id(int proc_id)
{
int i;
/*
* compare the proc_id with duplicate IDs, if the proc_id is already
* in the duplicate IDs, return true, otherwise, return false.
*/
for (i = 0; i < nr_duplicate_ids; i++) {
if (duplicate_processor_ids[i] == proc_id)
return true;
}
return false;
}
Let me show you asm listings.
1. GCC-5: without removing stackleak_track_stack() call, stack frame pointer is
consistent.
ffffffff8144a170 <acpi_duplicate_processor_id>:
ffffffff8144a170: 53 push %rbx
ffffffff8144a171: 89 fb mov %edi,%ebx
ffffffff8144a173: e8 88 33 d2 ff callq ffffffff8116d500
ffffffff8144a178: 8b 15 e6 68 46 02 mov 0x24668e6(%rip),%edx
ffffffff8144a17e: 48 83 05 9a 68 46 02 addq $0x1,0x246689a(%rip)
ffffffff8144a185: 01
ffffffff8144a186: 85 d2 test %edx,%edx
ffffffff8144a188: 7e 32 jle ffffffff8144a1bc
ffffffff8144a18a: 48 8b 05 9f 68 46 02 mov 0x246689f(%rip),%rax
ffffffff8144a191: 3b 1d d1 99 19 01 cmp 0x11999d1(%rip),%ebx
ffffffff8144a197: 48 8d 48 01 lea 0x1(%rax),%rcx
ffffffff8144a19b: 48 89 0d 8e 68 46 02 mov %rcx,0x246688e(%rip)
ffffffff8144a1a2: 74 1c je ffffffff8144a1c0
ffffffff8144a1a4: 48 83 05 7c 68 46 02 addq $0x1,0x246687c(%rip)
ffffffff8144a1ab: 01
ffffffff8144a1ac: 83 fa 01 cmp $0x1,%edx
ffffffff8144a1af: 74 0b je ffffffff8144a1bc
ffffffff8144a1b1: 48 83 c0 02 add $0x2,%rax
ffffffff8144a1b5: 48 89 05 74 68 46 02 mov %rax,0x2466874(%rip)
ffffffff8144a1bc: 31 c0 xor %eax,%eax
ffffffff8144a1be: 5b pop %rbx
ffffffff8144a1bf: c3 retq
ffffffff8144a1c0: b8 01 00 00 00 mov $0x1,%eax
ffffffff8144a1c5: 5b pop %rbx
ffffffff8144a1c6: c3 retq
2. GCC-5: with removed stackleak_track_stack() call, stack frame pointer IS NOT
consistent.
ffffffff8144a170 <acpi_duplicate_processor_id>:
ffffffff8144a170: 8b 15 ee 68 46 02 mov 0x24668ee(%rip),%edx
ffffffff8144a176: 48 83 05 a2 68 46 02 addq $0x1,0x24668a2(%rip)
ffffffff8144a17d: 01
ffffffff8144a17e: 85 d2 test %edx,%edx
ffffffff8144a180: 7e 33 jle ffffffff8144a1b5
ffffffff8144a182: 48 8b 05 a7 68 46 02 mov 0x24668a7(%rip),%rax
ffffffff8144a189: 3b 3d d9 99 19 01 cmp 0x11999d9(%rip),%edi
ffffffff8144a18f: 53 push %rbx
ffffffff8144a190: 48 8d 48 01 lea 0x1(%rax),%rcx
ffffffff8144a194: 48 89 0d 95 68 46 02 mov %rcx,0x2466895(%rip)
ffffffff8144a19b: 74 1f je ffffffff8144a1bc
ffffffff8144a19d: 48 83 05 83 68 46 02 addq $0x1,0x2466883(%rip)
ffffffff8144a1a4: 01
ffffffff8144a1a5: 83 fa 01 cmp $0x1,%edx
ffffffff8144a1a8: 74 0e je ffffffff8144a1b8
ffffffff8144a1aa: 48 83 c0 02 add $0x2,%rax
ffffffff8144a1ae: 48 89 05 7b 68 46 02 mov %rax,0x246687b(%rip)
ffffffff8144a1b5: 31 c0 xor %eax,%eax
ffffffff8144a1b7: c3 retq # BUG HERE! POP IS ABSENT!
ffffffff8144a1b8: 31 c0 xor %eax,%eax
ffffffff8144a1ba: 5b pop %rbx
ffffffff8144a1bb: c3 retq
ffffffff8144a1bc: b8 01 00 00 00 mov $0x1,%eax
ffffffff8144a1c1: 5b pop %rbx
ffffffff8144a1c2: c3 retq
3. GCC-7: with removed stackleak_track_stack() call, stack frame pointer is
consistent, NO BUG.
ffffffff8144be60 <acpi_duplicate_processor_id>:
ffffffff8144be60: 8b 15 3e d5 44 02 mov 0x244d53e(%rip),%edx
ffffffff8144be66: 48 83 05 f2 d4 44 02 addq $0x1,0x244d4f2(%rip)
ffffffff8144be6d: 01
ffffffff8144be6e: 85 d2 test %edx,%edx
ffffffff8144be70: 7e 3e jle ffffffff8144beb0
ffffffff8144be72: 48 8b 05 f7 d4 44 02 mov 0x244d4f7(%rip),%rax
ffffffff8144be79: 3b 3d e9 79 19 01 cmp 0x11979e9(%rip),%edi
ffffffff8144be7f: 53 push %rbx
ffffffff8144be80: 48 8d 48 01 lea 0x1(%rax),%rcx
ffffffff8144be84: 48 89 0d e5 d4 44 02 mov %rcx,0x244d4e5(%rip)
ffffffff8144be8b: 74 1c je ffffffff8144bea9
ffffffff8144be8d: 48 83 05 d3 d4 44 02 addq $0x1,0x244d4d3(%rip)
ffffffff8144be94: 01
ffffffff8144be95: 83 fa 01 cmp $0x1,%edx
ffffffff8144be98: 74 0b je ffffffff8144bea5
ffffffff8144be9a: 48 83 c0 02 add $0x2,%rax
ffffffff8144be9e: 48 89 05 cb d4 44 02 mov %rax,0x244d4cb(%rip)
ffffffff8144bea5: 31 c0 xor %eax,%eax
ffffffff8144bea7: 5b pop %rbx
ffffffff8144bea8: c3 retq
ffffffff8144bea9: b8 01 00 00 00 mov $0x1,%eax
ffffffff8144beae: 5b pop %rbx
ffffffff8144beaf: c3 retq
ffffffff8144beb0: 31 c0 xor %eax,%eax
ffffffff8144beb2: c3 retq
Of course, there is a naive solution for this issue -- just skip stackleak
instrumentation for acpi_duplicate_processor_id(). But it would be great to find
out the reasons behind this compiler behavior. It might help to create a better
solution.
Right now I don't have answers for the following questions:
1. Which gcc patch fixed this error in RTL optimization?
2. What is so special about acpi_duplicate_processor_id(), that triggers this
bug? Maybe we can determine that particular feature of C code and skip the
instrumentation for all similar functions?
3. Can stackleak plugin mitigate this bug in gcc-5? Maybe we can register this
pass to work with RTL later, after the buggy optimization?
I would really appreciate your help!
Best regards,
Alexander
Powered by blists - more mailing lists
Confused about mailing lists and their use? Read about mailing lists on Wikipedia and check out these guidelines on proper formatting of your messages.