<div dir="ltr"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">static int a[8];<br>static int *p = a - 5;<br>...<br>        p[10] = 1;<br>should work (even if it's not valid in c it can be valid as<br>a c extension or written in asm, so ELF should support it).</blockquote><br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">IMO this is exactly the kind of thing that MTE is trying to prevent. I don't see why we would want to support something like this.</blockquote><div><br></div><div>Sorry - I misinterpreted your comment here. This type of relocation is why TAGGED_RELATIVE exists.</div><div><br></div><div>In saying that - I do like the idea of encoding the tag derivation address in the r_info field. This would allow us to support platforms that use REL (as TAGGED_RELATIVE is RELA-only). Let me think about it some more, but this sounds like a good idea on face value.</div><div><br></div><div>You've also made me think a little more about the LDG that's done by the dynamic loader when processing RELATIVE relocations. For binaries (DSO or executable) produced by old compilers, the relocations could point out of bounds. The LDG needs to be conditional - we could ensure that it lands in a PT_LOAD segment, or we could just make the LDG conditional on the presence of the MTEGLOBTAB segment.</div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Fri, Oct 9, 2020 at 1:17 PM Mitch Phillips <<a href="mailto:mitchp@google.com" target="_blank">mitchp@google.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">note: these bits are not really reserved for os or processor<br>specific use in ELF. in practice they are processor specific<br>so it will be STO_AARCH64_TAGGED.<br></blockquote><div><br></div><div>Correct.</div><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">note2: undefined symbol references will need correct marking<br>too if objects may get copy relocated into the main exe and<br>linkers should check if definitions match references.</blockquote><div><br></div><div>Yep - at this point I expect that resolving an untagged reference with a tagged symbol (or vice versa) should result in a link-time error, but I don't feel particularly strongly about this. Downgrading to untagged should always be safe - but I think this subverts the object files' desire to have tagged globals. This also affects linking object files that are some tagged, some untagged into the same DSO.</div><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">it would be better to discuss on a linux abi or arm abi forum</blockquote><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">than on llvm-dev</blockquote><div><br></div><div>If you have any recommendations, that would be much appreciated. We have some ARM ELF folks on the line here, but it's probably not as broad as I would like.</div><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">are object sizes reliable in the dynamic symbol table?<br>is this why there is a need for per symbol marking? </blockquote><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">so it can be a completely dynamic linker internal decision</blockquote><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">what globals to tag and how. (it is also backward compat<br>with existing binaries, but it might make sense to have<br>an opt-in mechanism for such tagging.)</blockquote><div><br></div><div>Object sizes are reliable - but marking symbols explicitly allows us to have mixed tagged and untagged symbols in the same segment (think of a symbol we know is being used by non-compliant assembly, we can mark it with __attribute__((nosanitize("mte"))).</div><div><br></div><div>IMO marking symbols in the dynamic symbol table gives us greater flexibility than indiscriminately tagging granule-aligned symbols that fall in the right segments.</div><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">i think a design that prevents sharing is not acceptable.<br></blockquote><div><br></div><div>Unfortunately shared memory isn't required to be tag capable (<a href="https://www.kernel.org/doc/Documentation/filesystems/dax.txt" target="_blank">DAX</a> is an example) - so any PROT_MTE mappings must be anonymous. That's why we'd like to carve out rodata into its own segment, to continue to allow page sharing for the rest of the 80% of the stuff in that segment.</div><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"> static int a[8];</blockquote><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">static int *p = a - 5;<br>...<br>        p[10] = 1;<br>should work (even if it's not valid in c it can be valid as<br>a c extension or written in asm, so ELF should support it).</blockquote><div><br></div><div>IMO this is exactly the kind of thing that MTE is trying to <i>prevent</i>. I don't see why we would want to support something like this.</div><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">i think tls needs some thought too, arrays are probably<br>not common there, but some protection may be possible in<br>some cases..<br></blockquote><div><br></div><div>Definitely agreed - we haven't fleshed out a TLS story at this point in time -- we're considering it for later iterations though. </div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Thu, Oct 8, 2020 at 11:42 AM Szabolcs Nagy via llvm-dev <<a href="mailto:llvm-dev@lists.llvm.org" target="_blank">llvm-dev@lists.llvm.org</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">* Mitch Phillips via llvm-dev <<a href="mailto:llvm-dev@lists.llvm.org" target="_blank">llvm-dev@lists.llvm.org</a>> [2020-09-17 15:05:18 -0700]:<br>
> ARM v8.5 introduces the Memory Tagging Extension (MTE), a hardware that<br>
> allows for detection of memory safety bugs (buffer overflows,<br>
> use-after-free, etc) with low overhead. So far, MTE support is implemented<br>
> in the Scudo hardened allocator (compiler-rt/lib/scudo/standalone) for<br>
> heap, and stack allocation is implemented in LLVM/Clang behind<br>
> -fsanitize=memtag <<a href="https://llvm.org/docs/MemTagSanitizer.html" rel="noreferrer" target="_blank">https://llvm.org/docs/MemTagSanitizer.html</a>>.<br>
> <br>
> As part of a holistic MTE implementation, global memory should also be<br>
> properly tagged. HWASan<br>
> <<a href="http://clang.llvm.org/docs/HardwareAssistedAddressSanitizerDesign.html" rel="noreferrer" target="_blank">http://clang.llvm.org/docs/HardwareAssistedAddressSanitizerDesign.html</a>> (a<br>
> software-only implementation of MTE) has a schema that uses static tags,<br>
> however these can be trivially determined by an attacker with access to the<br>
> ELF file. This would allow attackers with arbitrary read/write to trivially<br>
> attack global variables. It would also allow attackers with a semilinear RW<br>
> primitive to trivially attack global variables if the offset is<br>
> controllable. Dynamic global tags are required to provide the same MTE<br>
> mitigation guarantees that are afforded to stack and heap memory.<br>
> <br>
> We've got a plan in mind about how to do MTE globals with fully dynamic<br>
> tags, but we'd love to get feedback from the community. In particular -<br>
> we'd like to try and align implementation details with GCC as the scheme<br>
> requires cooperation from the compiler, linker, and loader.<br>
> <br>
> Our current ideas are outlined below. All the compiler features (including<br>
> realignment, etc.) would be guarded behind -fsanitize=memtag. Protection of<br>
> read-only globals would be enabled-by-default, but can be disabled at<br>
> compile time behind a flag (likely -f(no)sanitize-memtag-ro-globals).<br>
<br>
i think -fsanitize is not appropriate for an mte abi.<br>
<br>
(i mean you can have an -fsanitize for it, but mte can be<br>
a proper abi between libc, linkers and compilers that<br>
several toolchains can implement independently, not an<br>
llvm vs compiler-rt internal design or android only design.)<br>
<br>
> <br>
> a) Dynamic symbols (int f; extern int f;)<br>
> <br>
>    1.<br>
> <br>
>    Mark all tagged global data symbols in the dynamic symbol table as<br>
>    st_other.STO_TAGGED.<br>
<br>
note: these bits are not really reserved for os or processor<br>
specific use in ELF. in practice they are processor specific<br>
so it will be STO_AARCH64_TAGGED.<br>
<br>
note2: undefined symbol references will need correct marking<br>
too if objects may get copy relocated into the main exe and<br>
linkers should check if definitions match references.<br>
<br>
this will require an ABI bump (otherwise old tools will<br>
silently ignore the new STO flag).<br>
<br>
but i'm not convinced yet that per symbol marking is needed.<br>
<br>
it would be better to discuss on a linux abi or arm abi forum<br>
than on llvm-dev (at least in my experience unsubscribed mail<br>
gets dropped or significantly delayed here and many linux or<br>
arm abi folks are not subscribed)<br>
<br>
>    2.<br>
> <br>
>    Teach the loader to read the symbol table at load time (and dlopen())<br>
>    prior to relocations, and apply random memory tags (via. `irg -> stg`) to<br>
>    each STO_TAGGED carrying global.<br>
<br>
are object sizes reliable in the dynamic symbol table?<br>
is this why there is a need for per symbol marking?<br>
<br>
> <br>
> b) Hidden Symbols (static int g; or -fvisibility=hidden)<br>
> <br>
>    1.<br>
> <br>
>    Have the compiler mark hidden tagged globals in the symbol table as<br>
>    st_other.STO_TAGGED.<br>
>    2.<br>
> <br>
>    Have the linker read the symbol table and create a table of {<br>
>    unrelocated virtual address, size } pairs for each STO_TAGGED carrying<br>
>    hidden global, storing this in a new section (.mteglobtab).<br>
>    3.<br>
> <br>
>    Create a new dynamic entry "DT_MTEGLOBTAB" that points to this segment,<br>
>    along with "DT_MTEGLOBENT" for the size of each entry and "DT_MTEGLOBSZ"<br>
>    for the size (in bytes) of the table.<br>
>    4.<br>
> <br>
>    Similar to dynamic symbols, teach the loader to read this table and<br>
>    apply random memory tags to each global prior to relocations.<br>
<br>
for static linking it's possible to make a static exe self<br>
relocating like how static pie handles RELATIVE relocs, but<br>
this sounds a bit nasty (and will need to use rcrt1.o or a<br>
new *crt1.o entry that guarantees such self relocation).<br>
<br>
>    5.<br>
> <br>
>    Materialization of hidden symbols now fetch and insert the memory tag<br>
>    via. `ldg`. On aarch64, this means non PC-relative<br>
>    loads/stores/address-taken (*g = 7;) generates:<br>
>      adrp x0, g;<br>
>      ldg x0, [x0, :lo12:g]; // new instruction<br>
>      mov x1, #7;<br>
>      str x1, [x0, :lo12:g];<br>
> <br>
>    Note that this materialization sequence means that executables built<br>
>    with MTE globals are not able to run on non-MTE hardware.<br>
<br>
i need to think about this, i think a compiler may transform<br>
<br>
static int a[8];<br>
<br>
void f(int i)<br>
{<br>
        a[i-5] = 0;<br>
}<br>
<br>
to<br>
<br>
        (a-5)[i] = 0;<br>
<br>
i.e. instead of offsetting i, compute the address of a-5 with<br>
adrp and then less instructions can be used for indexing.<br>
<br>
but then ldg on the computed address is not valid.<br>
(this is likely not a performance concern, but implies that<br>
there may be code generation troubles if we assume anything<br>
that is computed with adrp can be fixed up with ldg.)<br>
<br>
> <br>
> Note: Some dynamic symbols can be transformed at link time into hidden<br>
> symbols if:<br>
> <br>
>    1.<br>
> <br>
>    The symbol is in an object file that is statically linked into an<br>
>    executable and is not referenced in any shared libraries, or<br>
>    2.<br>
> <br>
>    The symbol has its visibility changed with a version script.<br>
> <br>
> These globals always have their addresses derived from a GOT entry, and<br>
> thus have their address tag materialized through the RELATIVE relocation of<br>
> the GOT entry. Due to the lack of dynamic symbol table entry however, the<br>
> memory would go untagged. The linker must ensure it creates an MTEGLOBTAB<br>
> entry for all hidden MTE-globals, including those that are transformed from<br>
> external to hidden. DSO's linked with -Bsymbolic retain their dynamic<br>
> symbol table entries, and thus require no special handling.<br>
> <br>
> c) All symbols<br>
> <br>
>    1.<br>
> <br>
>    Realign to granule size (16 bytes), resize to multiple of granule size<br>
>    (e.g. 40B -> 48B).<br>
>    2.<br>
> <br>
>    Ban data folding (except where contents and size are same, no tail<br>
>    merging).<br>
>    3.<br>
> <br>
>    In the loader, ensure writable segments (and possibly .rodata, see next<br>
>    dot point) are mapped MAP_ANONYMOUS and PROT_MTE (with the contents of the<br>
>    mappings filled from the file), as file-based mappings aren't necessarily<br>
>    backed by tag-capable memory. It also requires in-place remapping of data<br>
>    segments from the program image (as they're already mapped by the kernel<br>
>    before PT_INTERP invokes the loader).<br>
<br>
copying file data is a bit ugly but i think this is ok.<br>
<br>
>    4.<br>
> <br>
>    Make .rodata protection optional. When read-only protection is in use,<br>
>    the .rodata section should be moved into a separate segment. For Bionic<br>
>    libc, the rodata section takes up 20% of its ALLOC | READ segment, and we'd<br>
>    like to be able to maintain page sharing for the remaining 189KiB of other<br>
>    read-only data in this segment.<br>
<br>
i think a design that prevents sharing is not acceptable.<br>
<br>
> <br>
> d) Relocations<br>
> <br>
>    1.<br>
> <br>
>    GLOB_DAT, ABS64, and RELATIVE relocations change semantics - they would<br>
>    be required to retrieve and insert the memory tag of the symbol into the<br>
>    relocated value. For example, the ABS64 relocation becomes:<br>
>      sym_addr = get_symbol_address() // sym_addr = 0x1008<br>
>      sym_addr |= get_tag(sym_addr & 0xf) // get_tag(0x1008 & 0xf == 0x1000)<br>
>      *r_offset = sym_addr + r_addend;<br>
>    2.<br>
> <br>
>    Introduce a TAGGED_RELATIVE relocation - in order to solve the problem<br>
>    where the tag derivation shouldn't be from the relocation result, e.g.<br>
>    static int array[16] = {};<br>
>    // array_end must have the same tag as array[]. array_end is out of<br>
>    // bounds w.r.t. array, and may point to a completely different global.<br>
>    int *array_end = &array[16];<br>
> <br>
>    TAGGED_RELATIVE stores the untagged symbol value in the place (*r_offset<br>
>    == &array[16]), and keeps the address where the tag should be derived in<br>
>    the addend (RELA-only r_addend == &array[0]).<br>
> <br>
>    For derived symbols where the granule-aligned address is in-bounds of<br>
>    the tag (e.g. array_end = &array[7] implies the tag can be derived<br>
> from (&array[0]<br>
>    & 0xf)), we can use a normal RELATIVE relocation.<br>
> <br>
>    The TAGGED_RELATIVE operand looks like:<br>
>      *r_offset |= get_tag(r_addend & ~0xf);<br>
>    3.<br>
> <br>
>    ABS64, RELATIVE, and TAGGED_RELATIVE relocations need a slight tweak to<br>
>    grab the place's memory tag before use, as the place itself may be tagged.<br>
>    So, for example, the TAGGED_RELATIVE operation above actually becomes:<br>
>      r_offset = ldg(r_offset);<br>
>      *r_offset |= get_tag(r_addend & ~0xf);<br>
>    4.<br>
> <br>
>    Introduce an R_AARCH64_LDG_LO9_SHORT_NC relocation for relocating the<br>
>    9-bit immediate for the LDG instruction. This isn't MTE-globals specific,<br>
>    we just seem to be missing the relocation to encode the 9-bit immediate for<br>
>    LDG at bits [12..20]. This would save us an additional ADD instruction in<br>
>    the inline-LDG sequence for hidden symbols.<br>
> <br>
> We considered a few other schemes, including:<br>
> <br>
>    1.<br>
> <br>
>    Creating a dynamic symbol table entry for all hidden globals and giving<br>
>    them the same st_other.STO_TAGGED treatment. These entries would not<br>
>    require symbol names, but Elf(Sym) entries are 24 bytes (in comparison to 8<br>
>    bytes for the MTEGLOBTAB schema under the small code model). For an AOSP<br>
>    build, using dynamic symbol entries instead of MTEGLOBTAB results in a<br>
>    2.3MiB code size increase across all DSO's.<br>
>    2.<br>
> <br>
>    Making all hidden symbol accesses go through a local-GOT. Requires an<br>
>    extra indirection for all local symbols - resulting in increased cache<br>
>    pressure (and thus decreased performance) over a simple `ldg` of the tag<br>
>    (as the dcache and tag-cache are going to be warmed anyway for the<br>
>    load/store). Unlike the MTEGLOBTAG scheme however, this scheme is backwards<br>
>    compatible, allowing MTE-globals built binaries to run on old ARM64<br>
>    hardware (as no incompatible instructions are emitted), the same as heap<br>
>    tagging. Stack tagging requires a new ABI - and we expect the MTE globals<br>
>    scheme to be enabled in partnership with stack tagging, thus we are<br>
>    unconcerned about the ABI requirement for the MTEGLOBTAG scheme.<br>
<br>
if object access goes via symbolic dynamic relocation<br>
(GOT, ABS) then there is no need to do anything special:<br>
<br>
- pointer representation is controlled by the dynamic<br>
  linker via the relocs<br>
<br>
- location of object is known (object bounds and<br>
  if it's in a PROT_MTE segment)<br>
<br>
so it can be a completely dynamic linker internal decision<br>
what globals to tag and how. (it is also backward compat<br>
with existing binaries, but it might make sense to have<br>
an opt-in mechanism for such tagging.)<br>
<br>
<br>
new abi is needed to protect local accesses, i'm not yet<br>
sure about the proposed design with two RELATIVE relocs.<br>
i think RELATIVE reloc should not assume that the computed<br>
pointer can be dereferenced, this is not just for the array<br>
end case but for other oob computed pointers too. e.g.<br>
<br>
static int a[8];<br>
static int *p = a - 5;<br>
...<br>
        p[10] = 1;<br>
<br>
should work (even if it's not valid in c it can be valid as<br>
a c extension or written in asm, so ELF should support it).<br>
<br>
e.g. the r_info field in the RELATIVE reloc can index the<br>
MTEGLOBTAB and use the object bounds from there for ldg<br>
(and if r_info==0 means untagged this falls back to normal<br>
RELATIVE reloc processing), but i don't yet know what is<br>
the best solution here.<br>
<br>
i think tls needs some thought too, arrays are probably<br>
not common there, but some protection may be possible in<br>
some cases..<br>
<br>
> <br>
> <br>
> Please let us know any feedback you have. We're currently working on an<br>
> experimental version and will update with any more details as they arise.<br>
> <br>
> Thanks,<br>
> <br>
> Mitch.<br>
<br>
> _______________________________________________<br>
> LLVM Developers mailing list<br>
> <a href="mailto:llvm-dev@lists.llvm.org" target="_blank">llvm-dev@lists.llvm.org</a><br>
> <a href="https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev" rel="noreferrer" target="_blank">https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev</a><br>
<br>
_______________________________________________<br>
LLVM Developers mailing list<br>
<a href="mailto:llvm-dev@lists.llvm.org" target="_blank">llvm-dev@lists.llvm.org</a><br>
<a href="https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev" rel="noreferrer" target="_blank">https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev</a><br>
</blockquote></div>
</blockquote></div>