[edk2-devel] ArmVirt and Self-Updating Code

Ard Biesheuvel ardb at kernel.org
Sun Aug 1 16:33:31 UTC 2021


On Sat, 31 Jul 2021 at 21:08, Marvin Häuser <mhaeuser at posteo.de> wrote:
>
> On 23.07.21 16:34, Ard Biesheuvel wrote:
> > On Fri, 23 Jul 2021 at 16:27, Marvin Häuser <mhaeuser at posteo.de> wrote:
> >>
> >>
> >> On 23.07.21 16:09, Ard Biesheuvel wrote:
> >>> On Fri, 23 Jul 2021 at 12:47, Marvin Häuser <mhaeuser at posteo.de> wrote:
> >>>> On 23.07.21 12:13, Ard Biesheuvel wrote:
> >>>>> On Fri, 23 Jul 2021 at 11:55, Marvin Häuser <mhaeuser at posteo.de> wrote:
> > ...
> >>>>>> 2) emit a GOT, which ends up being converted to PE/COFF Relocations (->
> >>>>>> self-relocation), for global data that cannot be referenced relatively?
> >>>>>> Is there any way to know/force that no symbol in GOT is accessed up
> >>>>>> until the end of the self-relocation process?
> >> Do you maybe have one final comment regarding that second question,
> >> please? :)
> > The RELA section is not converted into PE/COFF relocations. This would
> > not achieve a lot, given that no prior PE/COFF loader exists to
> > process them. There is a snippet of asm code in the startup code that
> > processes the R_AARCH64_RELATIVE relocation entries before calling
> > into C code.
>
> I searched for said ASM code till my fingers fell asleep and at last
> found this:
> https://github.com/tianocore/edk2/commit/b16fd231f6d8124fa05a0f086840934b8709faf9#diff-3d563cc4775c7720900f4895bf619eed06291044aaa277fcc57eddc7618351a1L12-R148
>
> If I understand the commit message correctly, it is basically "pray the
> C code does not use globals at all", which is fair enough, so maybe I
> should document this in my proposed new library? I trust that this is
> enough of a constraint for both ARM and AArch64, because I do not know
> them at all.
>

The C code can use globals, but not global pointer variables. But you
are right, this is not very robust at all.


> What worries me is that StandaloneMmCore has no such ASM entry point at
> all and instead it's just executing C directly. Also, it is not passed
> the "-fno-jump-tables" flag that is commented to be important in the
> commit linked above.
>

This is because the StandaloneMmCore is built with -fpie, which
already implies -fno-jump-tables, although I suppose this may not
offer complete coverage for BASE libraries that are pulled into the
link.


> Best regards,
> Marvin
>
> > This also gives us the guarantee that no GOT indirections are
> > dereferenced, given that our asm code simply does not do that.
> >
> >> Let's drop "GOT" and make it "any instruction that requires prior
> >> relocation to function correctly".
> >>
> > The thing to keep in mind here is that R_AARCH64_RELATIVE relocations
> > never target instructions, but only memory locations that carry
> > absolute addresses. This could be locations in .rodata or .data
> > (global vars carrying pointer values), or GOT entries.
> >
> >>>>> It is not really a GOT. Actually, a GOT is undesirable, as it forces
> >>>>> global variables to be referenced via an absolute address, even when a
> >>>>> relative reference could be used.
> >>>> Hmm, the GCC docs say a GOT is used for "all constant addresses" (I took
> >>>> it as "absolute"?), it is kind of vague. I understood it this way:
> >>>> 1) no-pie emits relocations that can target the .text and .data sections
> >>>> for instructions that embed and variables that hold an absolute address
> >>>> (I thought this was RELA?)
> >>>> 2) pie emits a GOT such that there are no relocations as described in
> >>>> 1), because all absolute addresses are indirected by GOT (just GOT
> >>>> references are relocated)
> >>>>
> >>> Correct. And this works really well for shared libraries, where all
> >>> text and data sections can be shared between processes, as they will
> >>> not be modified by the loader. All locations targeted by relocations
> >>> will be nicely lumped together in the GOT.
> >>>
> >>> However, for bare metal style programs, there is no sharing, and there
> >>> is no advantage to lumping anything together. It is much better to use
> >>> relative references where possible, and simply apply relocations
> >>> wherever needed across the text and data sections,
> >>>
> >>>> If I understood the process right, but the term (GOT) is wrong, sorry,
> >>>> that is what I gathered from the docs. :)
> >>>> I have a x86 + PE background, so ARM + ELF is a bit of a learning curve...
> >>>>
> >>> The GOT is a special data structure used for implicit variable
> >>> accesses, i.e., global vars used in the code. Statically initialized
> >>> pointer variables are the other category, which are not code, and for
> >>> which the same considerations do not apply, given that the right value
> >>> simply needs to be stored in the variable before the program starts.
> >>>
> >>>>> For instance, a statically initialized pointer always carries an
> >>>>> absolute address, and so it always needs an entry in the RELA table
> >>>>>
> >>>>> E.g.,
> >>>>>
> >>>>> int foo = 10; // external linkage
> >>>>> static int *bar = &foo;
> >>>>>
> >>>>> In this case, there is no way to use relative addressing because the
> >>>>> address of foo is taken at build time.
> >>>>>
> >>>>> However, if bar would be something like
> >>>>>
> >>>>> static int *bar() { return &foo; }
> >>>>>
> >>>>> the address is only taken at runtime, and the compiler can use a
> >>>>> relative reference instead, and no RELA entry is needed. With a GOT,
> >>>>> we force the compiler to allocate a variable that holds the absolute
> >>>>> address, which we would prefer to avoid.
> >>>> And this is not forced by whatever table -fpie uses, as per my
> >>>> understanding above?
> >>>>
> >>> The selection of 'code model' as it is called is controlled by GCC's
> >>> -mcmodel= argument, which defaults to 'small' on AArch64, regardless
> >>> of whether you use PIC/PIE or not.
> >> Aha, makes sense, thanks!
> >>
> >> Best regards,
> >> Marvin
> >>
> >>>>>>>> “Now, StandaloneMmPkg has similar (self-)relocation code too:https://github.com/tianocore/edk2/blob/17143c4837393d42c484b42d1789b85b2cff1aaf/StandaloneMmPkg/Library/StandaloneMmCoreEntryPoint/AArch64/StandaloneMmCoreEntryPoint.c#L379-L386
> >>>>>>>>
> >>>>>>>> Because I cannot find such elsewhere, I assume it must be for the same ARM virtualised environment as above.
> >>>>>>> No.
> >>>>>>>
> >>>>>>>> The binary it applies the Relocations to is documented to be the Standalone MM core, but in fact SecCore is located:
> >>>>>>>>
> >>>>>>>> https://github.com/tianocore/edk2/blob/17143c4837393d42c484b42d1789b85b2cff1aaf/StandaloneMmPkg/Library/StandaloneMmCoreEntryPoint/AArch64/SetPermissions.c#L131-L158
> >>>>>> As per your comments below, I think SecCore should not be located here.
> >>>>>> Is the Standalone MM core of *type* SecCore in the FFS (without *being*
> >>>>>> SecCore)? This confused me the most.
> >>>>>>
> >>>>> If the FFS SecCore section type is used here, it does not mean that
> >>>>> the image is a SEC image in the strict PI sense.
> >>>>>
> >>>>> Perhaps we were just too lazy to add a new type to the FFS spec?
> >>>> That is what I meant to imply with the middle question (well, not
> >>>> necessarily "lazy", for ARM there simply seems to not be any reason to
> >>>> distinguish if the environments are fully separate), just wanted to make
> >>>> sure I understand what the code does before modifying it.
> >>>>
> >>>> Thank you again!
> >>>>
> >>>> Best regards,
> >>>> Marvin
> >>>>
> >>>>>>>> “This yields the following questions to me:
> >>>>>>>>
> >>>>>>>> 1) What even invokes Standalone MM on ARM? It is documented it is spawned during SEC, but I could not find any actual invocation.
> >>>>>>>>
> >>>>>>> It is not spawned by the normal world code that runs UEFI. It is a
> >>>>>>> secure world component that runs in a completely different execution
> >>>>>>> context (TrustZone). The code does run with the MMU enabled from the
> >>>>>>> start, but running from an a priori fixed offset was considered to be
> >>>>>>> a security hazard, so we added self relocation support.
> >>>>>>>
> >>>>>>> The alternative would have been to add metadata to the StMmCore
> >>>>>>> component that can be interpreted by the secure world component that
> >>>>>>> loads it, but this would go beyond any existing specs, and make
> >>>>>>> portability more problematic.
> >>>>>>>
> >>>>>>>> 2) Why does Standalone MM (self-)relocation locate SecCore? Should it not already have been relocated with the code from ArmPlatformPkg? Is Standalone MM embedded into ARM SecCore?
> >>>>>>>>
> >>>>>>> No and no. Standalone MM has nothing to do with the code that runs as
> >>>>>>> part of UEFI itself. ArmPlatformPkg is completely separate from
> >>>>>>> StandaloneMmPkg.
> >>>>>>>
> >>>>>>>> 3) Why is SecCore the only module relocated? Are all others guaranteed to be "properly" loaded?
> >>>>>>>>
> >>>>>>> SecCore contains a PE/COFF loader, so all subsequent modules are
> >>>>>>> loaded normally. This is similar to the ArmVirtQemuKernel
> >>>>>>> self-relocating SEC module, which only relocates itself in this
> >>>>>>> manner, and relies on standard PE/COFF metadata for loading other
> >>>>>>> modules.
> >>>>>> Interesting... this definitely is vastly different from the x86 side of
> >>>>>> things. I think most things became very clear. Thanks a lot!
> >>>>>>
> >>>>>>>> 4) Is there maybe some high-level documented about the ARM boot flow? It seems to be significantly different from the x86 routes quite vastly.”
> >>>>>>>>
> >>>>>>> trustedfirmware.org may have some useful documentation.
> >>>>>> I'll check it some time, hopefully this weekend. Thanks!
> >>>>>>
> >>>>> My pleasure.
>


-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#78468): https://edk2.groups.io/g/devel/message/78468
Mute This Topic: https://groups.io/mt/84380729/1813853
Group Owner: devel+owner at edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [edk2-devel-archive at redhat.com]
-=-=-=-=-=-=-=-=-=-=-=-






More information about the edk2-devel-archive mailing list