[U-Boot] Sharing code between U-Boot and its secure monitor
Simon Glass
sjg at chromium.org
Tue Jun 26 03:58:58 UTC 2018
Hi,
On 25 June 2018 at 14:44, Stephen Warren <swarren at wwwdotorg.org> wrote:
> On 06/24/2018 12:17 AM, Alexander Graf wrote:
>>
>>
>>
>>> Am 22.06.2018 um 21:24 schrieb Stephen Warren <swarren at wwwdotorg.org>:
>>>
>>> I am writing more secure monitor (PSCI) support for Jetson TK1. In
>>> particular, this code will support resume from the LP0 system suspend state,
>>> which entails signing a block of code for the boot ROM to validate during
>>> resume. The signing code uses lib/aes.c. This code is linked into U-Boot in
>>> the "main" part of U-Boot, rather than into the secure section that contains
>>> the monitor code. The monitor should only call code within the monitor
>>> section, not within the main part of U-Boot (in general, the monitor
>>> continues to run after U-Boot has been replaced in RAM, so cannot call code
>>> in U-Boot since it may no longer exist, and even if it does, that code is
>>> not in the secure DRAM carve-out, and hence it's not secure to call it). So,
>>> I need to duplicate the lib/aes.c object code into the monitor. The question
>>> is: what's the best way to do that.
>>>
>>> So far, here's what I implemented:
>>>
>>> a) Edit lib/aes.c to mark each function with an optional attribute which
>>> will force the object code into the secure section when compiled for the
>>> monitor:
>>>
>>> -static const u8 sbox[256] = {
>>> +static const u8 mon_rodata sbox[256] = {
>>>
>>> -void aes_cbc_decrypt_blocks(...
>>> +void mon_text aes_cbc_decrypt_blocks(...
>>>
>>> ... where mon_text evaluates to:
>>>
>>> +#define mon_rodata
>>> +#define mon_text
>>>
>>> or:
>>>
>>> +#define mon_data __attribute__((section("._secure.data")))
>>> +#define mon_rodata __attribute__((section("._secure.rodata")))
>>> +#define mon_text __attribute__((section("._secure.text")))
>>
>>
>> Please check my recent fix to rename the efi sections. Gcc may under some
>> conditions generate implicit symbols, such as rodata constants. You can only
>> catch them if your text section for the function starts with .text.
>>
>>>
>>> b) Since the main U-Boot and the monitor code are part of the same ELF
>>> file, the same symbol name cannot exist in both. So, we must play similar
>>> games in order to rename the symbols:
>>>
>>> -void aes_cbc_decrypt_blocks(...
>>> +void mon_text MON_SYM(aes_cbc_decrypt_blocks)(...
>>>
>>> (all call sites have to be updated similarly)
>>>
>>> ... where MON_SYM(x) is either:
>>>
>>> +#define MON_SYM(x) x
>>>
>>> or:
>>>
>>> +#define MON_SYM(x) mon_##x
>>>
>>> c) In the monitor, create a file mon_aes.c that sets up all the macros
>>> mentioned above, then #includes the main lib/aes.c. Add this file to a
>>> Makefile.
>>>
>>> +#include "mon_section.h"
>>> +#include "../../../../../lib/aes.c"
>>>
>>> This is all rather nasty and invasive, especially when you consider more
>>> widely used utility functions such as malloc(), printf(), udelay(), etc..
>>> Instead, I wonder if we can:
>>>
>>> a) Link the monitor to an ELF file and extract a binary. We won't need
>>> any special section or symbol name logic here, since we can assume that all
>>> of .text/.data are part of the monitor. Simple and non-invasive!
>>>
>>> b) Link the LP0 resume code to an ELF file and extract a binary. (It's
>>> nice to separate this block of code since it runs on a different CPU to the
>>> main U-Boot or monitor, and hence gets compiled with different compiler
>>> flags).
>>>
>>> c) Include the binaries from (a) and (b) above in the main U-Boot ELF
>>> file or binary somehow; perhaps use binman to allow the main U-Boot to know
>>> where those merged binaries end up in memory.
>>>
>>> In a slightly different context, I've talked to Simon in the past about
>>> building many separate binaries from U-Boot's source and chaining between
>>> them and merging them together and he objected to that approach. However, I
>>> wonder if this new requirement changes anything?
>>>
>>> Thanks for any thoughts.
>>
>>
>> This looks quite similar to efi runtime services requirements to me. Maybe
>> we can share code.
>>
>> The way those work is that we mark all functions and data required in
>> special sections too. We also include all relocations inside a special
>> section as well though.
>>
>> If you follow the same scheme, you could simply clone parts of U-Boot at
>> runtime with different relocations to either main U-Boot or mon. During that
>> relocation you could also find out if there is any relication that is
>> unreachable from mon code. That could trigger a warning that CI should be
>> able to quickly find.
>
>
> So we'd have the following chunks of code (lets say sections):
>
> 1) U-Boot only
> 2) Monitor (or UEFI) only
> 3) Shared code between 1 and 2.
>
> ... then memcpy (3) to two places, one for (1) and one for (2)?
>
> On the surface that seems plausible, but what happens if we have the
> following main chunks of code:
>
> 1) U-Boot
> 2) Monitor
> 3) UEFI
> 4) Something else.
>
> Now we either have a relatively large and bloated dumping ground for all
> common code:
>
> 5) Common code, which gets copied 4 other places, and contains many
> functions some of the copy targets don't need.
>
> ... or many combinations:
>
> 5) Code shared between 1, 2, 3, 4
> 6) Code shared between 1, 2, 3
> 7) Code shared between 1, 2, 4
> 8) Code shared between 1, 3, 4
> ...
>
> Or a per-function section and the relocator iterates over each per-function
> section separately, and works out which of 1..4 it gets copied into.
>
> None of those options seem very tractable once you get more than a couple of
> potential copy destinations.
>
> Building each binary separately means the linker works out which functions
> to add to each binary at compile time, so saves complexity or manual
> management of function sections, and saves runtime work.
I think building a completely separate image is the most robust way,
but it would be nice if Alex's approach would work. I suspect it would
build faster too.
Regards,
Simon
More information about the U-Boot
mailing list