TrenchBoot / landing-zone

An open source implementation of an AMD-V Secure Loader.
GNU General Public License v2.0
23 stars 7 forks source link

Fix crash due to self-modifying entry code #49

Closed andyhhp closed 4 years ago

andyhhp commented 4 years ago

c/s b3b7cfb7ac "build: move bootloader data out of measured block" moved the lz_header variable, but didn't adjust the hard-coded LZ_FIRST_STAGESTACK{START,SIZE} constants.

Therefore, the entrypoint looked like this:

  0000000000000000 <sl_header>:
         0:       d4 01 00 d0                                         ....

  0000000000000004 <lz_first_stack>:
          ...

  00000000000001d4 <_entry>:
       1d4:       89 c5                   mov    %eax,%ebp
       1d6:       8d a5 00 02 00 00       lea    0x200(%ebp),%esp
       1dc:       6a 00                   push   $0x0
       1de:       6a 00                   push   $0x0
       1e0:       0f 01 1c 24             lidtl  (%esp)
       1e4:       83 c4 08                add    $0x8,%esp
       1e7:       b9 14 01 01 c0          mov    $0xc0010114,%ecx
       1ec:       0f 32                   rdmsr
       1ee:       83 e0 f9                and    $0xfffffff9,%eax
       1f1:       0f 30                   wrmsr
       1f3:       01 ad bc 28 00 00       add    %ebp,0x28bc(%ebp)
       1f9:       01 ad 5d 02 00 00       add    %ebp,0x25d(%ebp)
       1ff:       01 ad 00 90 00 00       add    %ebp,0x9000(%ebp) // Stack starts here
       205:       01 ad 00 80 00 00       add    %ebp,0x8000(%ebp)
       20b:       01 ad 08 80 00 00       add    %ebp,0x8008(%ebp)
       211:       01 ad 10 80 00 00       add    %ebp,0x8010(%ebp)

with the stack now starting in the middle of L4 pagetable relocation.

This functioned at the time as the stack isn't used until entering C, but c/s b19561a81 "head: Clobber the IDT limit" introduced two push $0's at the start.

Therefore, what the processor actually executes is:

  00000000000001d4 <_entry>:
       1d4:       89 c5                   mov    %eax,%ebp
       1d6:       8d a5 00 02 00 00       lea    0x200(%ebp),%esp
       1dc:       6a 00                   push   $0x0
       1de:       6a 00                   push   $0x0
       1e0:       0f 01 1c 24             lidtl  (%esp)
       1e4:       83 c4 08                add    $0x8,%esp
       1e7:       b9 14 01 01 c0          mov    $0xc0010114,%ecx
       1ec:       0f 32                   rdmsr
       1ee:       83 e0 f9                and    $0xfffffff9,%eax
       1f1:       0f 30                   wrmsr
       1f3:       01 ad bc 28 00 00       add    %ebp,0x28bc(%ebp)
       1f9:       00 00                   add    %al,(%eax)
       1fb:       00 00                   add    %al,(%eax)
       1fd:       00 00                   add    %al,(%eax)
       1ff:       00 ad 00 90 00 00       add    %ch,0x9000(%ebp)
       205:       01 ad 00 80 00 00       add    %ebp,0x8000(%ebp)

with the pushes having clobbered bytes 0x1f8 thru 0x200. This destroys the relocation of the 64bit JMP and L4 pagetable (in the 64bit setup case) or the LGDT and segment setup itself (in the 32bit setup case).

To fix things, let the linker evaluate where the stack starts. It turns out that everything in config.h is unused or stale now, so delete it completely.

Expand the stack slightly so it stays on the 0x200 boundary.

Signed-off-by: Andrew Cooper andrew.cooper3@citrix.com

P.S. This didn't show up in my testing, because I had an extra debug print which pushed the push $0's late enough to not clobber yet-to-be-executed code, and therefore wasn't actually testing the final article.