[U-Boot] Sharing code between U-Boot and its secure monitor

Alexander Graf agraf at suse.de
Tue Jun 26 11:08:43 UTC 2018


On 06/25/2018 10:44 PM, Stephen Warren 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.


Hm, yeah, that does sound plausible. I guess once you grow more 
functionality a separate build is the more robust solution.



Alex




More information about the U-Boot mailing list