Re: [lldb-dev] RFC: AArch64 Linux Memory Tagging Support for LLDB

2020-08-13 Thread Peter Collingbourne via lldb-dev
On Mon, Aug 10, 2020 at 3:41 AM David Spickett via lldb-dev <
lldb-dev@lists.llvm.org> wrote:

> Hi all,
>
> What follows is my proposal for supporting AArch64's memory tagging
> extension in LLDB. I think the link in the first paragraph is a good
> introduction if you haven't come across memory tagging before.
>
> I've also put the document in a Google Doc if that's easier for you to
> read:
> https://docs.google.com/document/d/13oRtTujCrWOS_2RSciYoaBPNPgxIvTF2qyOfhhUTj1U/edit?usp=sharing
> (please keep comments to this list though)
>
> Any and all comments welcome. Particularly I would like opinions on
> the naming of the commands, as this extension is AArch64 specific but
> the concept of memory tagging itself is not.
> (I've added some people on Cc who might have particular interest)
>
> Thanks,
> David Spickett.
>
> 
>
> # RFC: AArch64 Linux Memory Tagging Support for LLDB
>
> ## What is memory tagging?
>
> Memory tagging is an extension added in the Armv8.5-a architecture for
> AArch64.
> It allows tagging pointers and storing those tags so that hardware can
> validate
> that a pointer matches the memory address it is trying to access. These
> paired
> tags are stored in the upper bits of the pointer (the “logical” tag) and in
> special memory in hardware (the “allocation” tag). Each tag is 4 bits in
> size.
>
>
> https://community.arm.com/developer/ip-products/processors/b/processors-ip-blog/posts/enhancing-memory-safety
>
> ## Definitions
>
> * memtag - This is the clang name for the extension as in
> “-march=armv8.5-a+memtag”
> * mte - An alternative name for mmtag, also the llvm backend name for
> the extension.
>   This document may use memtag/memory tagging/MTE at times, they mean
> the same thing.
> * logical tag - The tag stored inside a pointer variable (accessible
> via normal shift and mask)
> * allocation tag - The tag stored in tag memory (which the hardware
> provides)
>   for a particular tag granule
> * tag granule - The amount of memory that a single tag applies to,
> which is 16 bytes.
>
> ## Existing Tool Support
>
> * GCC/Clang can generate MTE instructions
> * Clang has an option to memory tag the stack (discussed later)
> * QEMU support has been merged
> * Linux Kernel patches are in progress
>   (git://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux
> “devel/mte-v5” branch)
> * GDB support is in review and this design takes a lot of direction from
> that
>   (
> https://sourceware.org/git/?p=binutils-gdb.git;a=shortlog;h=refs/heads/users/luisgpm/aarch64-mte-v2
> )
>   (originally proposed
> https://sourceware.org/pipermail/gdb-patches/2019-August/159881.html)
>
> ## New lldb features
>
> Assuming your software is acting correctly, memory tagging can “just work”
> without debugger support. This assumes the compiler/toolchain/user are
> always correct.
>
> For when that isn’t the case we want to be able to:
> * Read/write the logical tags in a pointer
> * Read/write the allocation tags assigned to a given area of memory
> * Test whether the logical tag in a pointer matches the allocation tag of
> the
>   memory it refers to
> * Read/write memory even when tags are mismatched
>
> The most obvious use case for this is working through issues where bugs in
> the
> toolchain don’t generate correct code. On the other hand there’s a good
> case for
> deliberately messing with pointers in your code to prove that such
> protection
> actually works.
>
> Note: potential extensions to scripting such as tags as attributes of
> values and
> such are not being proposed here. Of course the new commands will be
> added in the
> standard ways so you can use those.
>
> ## New Commands
>
> ### Command Availability
>
> Note: commands will be listed in tab completion and help regardless of
> these checks
>
> * The remote server must support memory tagging packets. lldb will
> send/check
>   for the “memory-tagging” feature in the qSupported packet. (this
> name aligns with gdb)
> * The process must have MTE available. We check HWCAP2_MTE for this.
> * The process must have enabled tagged addressing using prctl
>   (see “New Registers” for details)
> * The address given must be in a range that has MTE enabled, since you can
> mmap
>   with or without MTE. (this information is in /proc/.../smaps)
>
>  Interaction With Clang’s Stack Tagging
>
> We’re relying on the kernel to tell us if MTE is enabled, so stack tagging
> will
> not be visible to the debugger this way.
> (
> https://github.com/google/sanitizers/wiki/Stack-instrumentation-with-ARM-Memory-Tagging-Extension-(MTE)
> )
>
> E.g. {int x; use(); } where x is void x(int* ptr);
> “ptr” will have a memory tag but the kernel won’t know this.
>
> To work around this a setting will be added to tell lldb to assume that
> MTE is
> enabled, so that you can at least see the logical tags of a pointer.
> (see “New Settings”)
>
> ### General Properties/Errors
>
> *  must resolve to some value that can be handled as an
>   address by lldb. (though it 

Re: [lldb-dev] RFC: AArch64 Linux Memory Tagging Support for LLDB

2020-08-13 Thread Jason Molenda via lldb-dev
Hm, another approach would be to have an ABI method that takes an address (with 
pac bits), an enumerated value describing the type of address it is, and then 
the ABI method would know whether to strip pac bits or not.  the linux Aarch64 
armv8.3 ABI might know it needs to strip PAC bits from a spilled fp, whereas 
the darwin arm64e ABI does not, or whatever.  But I come back to the point 
that, when we're talking about PAC authentication bits here, if we know the # 
of addressible bits, and we know this value is an address in memory, it's 
harmless to strip, so having everyone pass the spilled FP value through the 
ABI::GetAsVirtualAddress method is fine if any ABI requires it.  I may have 
ARMv8.3 too much in my mind here.


> On Aug 13, 2020, at 3:06 PM, Jason Molenda  wrote:
> 
> Hi Omair, yea I need to start working with the upstream sources and you to 
> coordinate this.  My current implementation in the apple branch was something 
> I've revised over the last two years, and further revision will be needed as 
> we integrate it in the llvm.org source base.
> 
> My general design is that the Process object will keep track of the # of bits 
> used for virtual addresses.  For instance, with a gdb remote serial protocol 
> connection, in the qHostInfo packet, the addressing_bits: key-value pair is 
> sent with the number of bits used for addressing.  Similarly, we use an 
> LC_NOTE (similar to an ELF NOTE) to get the number of addressing bits that 
> were in use for the corefile.  These #'s are derived from TCR_EL0.T0SZ or 
> TCR_EL1.T0SZ, where those numbers are the opposite of what we want.  e.g. 
> T0SZ might have a value of 25, which means that 39 bits are used for virtual 
> addressing, 64-25=39.  So at Process setup, we get the number of bits used 
> for addressing by Some Appropriate Mechanism.
> 
> I have an ABI method to strip off the PAC bits.  This is a part of my design 
> that needs a little more consideration -- I have a single method for getting 
> a virtual address, and I have calls to it across the codebase, every time we 
> know something *must* be an address, and it likely has authentication bits.  
> Inside lldb, we're using the same ABI plugin for both PAC and non-PAC, 
> because setting the high bits is harmless when we know a given bit cannot be 
> used in addressing.  
> 
> The problem is that different ABIs have different things signed in memory, so 
> we'll need different calls into the ABI method to get the virtual address.  
> For instance, in any ABI the lr is surely signed before it is spilled to 
> stack on function entry - but is fp signed before being spilled?  Should we 
> have a single ABI::GetAsVirtualAddress that we put in every location that any 
> ABI uses, or should we have a ABI::GetSpilledLRAsVirtualAddress, 
> ABI::GetSpilledFPAsVirtualAddress, ABI::GetFunctionPointerAsVirtualAddress, 
> ABI::GetVTablePointerAsVirtualAddress, and so on?  The fact that passing a 
> valid address through ABI::GetAsVirtualAddress (or whatever we call it) is 
> *harmless* when we know it is addressable memory, makes me lean towards 
> having generic lldb pass the superset of what all ABIs need through this 
> single method.
> 
> You mentioned unwinding - a quick peek at our local sources, I have four 
> places in RegisterContextLLDB.cpp (now RegisterContextUnwind.cpp) which 
> needed to pass addresses through this ABI method.
> 
> There are user interface issues to consider.  For instance, when you do 
> "register read", lldb will print a register value, and if it resolves to a 
> symbol, lldb will print the symbol name.  With PAC bits, I print the actual 
> register value (with PAC bits), strip the PAC bits, and if this value 
> resolves to a symbolcontext, then I print the address-sans-PAC and the symbol 
> name.  There are probably a half dozen other places where I had to do the 
> same thing --- the goal is to always show the user the actual 
> register/pointer value with its PAC bits, and add information to that if 
> we're confident that it's actually an virtual address.
> 
> Developers can add type qualifiers to their own structs to indicate that 
> pointers should use pointer authentication.  We have patches to represent 
> this in the DWARF, and lldb reads those, so we know to strip the pac bits off 
> of non-ABI objects that are using pointer auth - there are some changes to 
> the Value object for this, and such.  For SB API developers, we added a 
> SBValue::GetValueAsAddress method (similar to SBValue::GetValueAsUnsigned, 
> etc) so that people coding at the SB API layer can do the same thing lldb 
> does -- show the value with PAC bits (GetValueAsUnsigned) and as an actual 
> address (GetValueAsAddress) if they want to do that.
> 
> There's some additional changes for jitting expressions, and to be honest 
> it's been ages since I've looked at that code so I can't speak on it very 
> authoritatively without re-reading a bunch (and I authored very little of 
> it).  

Re: [lldb-dev] RFC: AArch64 Linux Memory Tagging Support for LLDB

2020-08-13 Thread Jason Molenda via lldb-dev
Hi Omair, yea I need to start working with the upstream sources and you to 
coordinate this.  My current implementation in the apple branch was something 
I've revised over the last two years, and further revision will be needed as we 
integrate it in the llvm.org source base.

My general design is that the Process object will keep track of the # of bits 
used for virtual addresses.  For instance, with a gdb remote serial protocol 
connection, in the qHostInfo packet, the addressing_bits: key-value pair is 
sent with the number of bits used for addressing.  Similarly, we use an LC_NOTE 
(similar to an ELF NOTE) to get the number of addressing bits that were in use 
for the corefile.  These #'s are derived from TCR_EL0.T0SZ or TCR_EL1.T0SZ, 
where those numbers are the opposite of what we want.  e.g. T0SZ might have a 
value of 25, which means that 39 bits are used for virtual addressing, 
64-25=39.  So at Process setup, we get the number of bits used for addressing 
by Some Appropriate Mechanism.

I have an ABI method to strip off the PAC bits.  This is a part of my design 
that needs a little more consideration -- I have a single method for getting a 
virtual address, and I have calls to it across the codebase, every time we know 
something *must* be an address, and it likely has authentication bits.  Inside 
lldb, we're using the same ABI plugin for both PAC and non-PAC, because setting 
the high bits is harmless when we know a given bit cannot be used in 
addressing.  

The problem is that different ABIs have different things signed in memory, so 
we'll need different calls into the ABI method to get the virtual address.  For 
instance, in any ABI the lr is surely signed before it is spilled to stack on 
function entry - but is fp signed before being spilled?  Should we have a 
single ABI::GetAsVirtualAddress that we put in every location that any ABI 
uses, or should we have a ABI::GetSpilledLRAsVirtualAddress, 
ABI::GetSpilledFPAsVirtualAddress, ABI::GetFunctionPointerAsVirtualAddress, 
ABI::GetVTablePointerAsVirtualAddress, and so on?  The fact that passing a 
valid address through ABI::GetAsVirtualAddress (or whatever we call it) is 
*harmless* when we know it is addressable memory, makes me lean towards having 
generic lldb pass the superset of what all ABIs need through this single method.

You mentioned unwinding - a quick peek at our local sources, I have four places 
in RegisterContextLLDB.cpp (now RegisterContextUnwind.cpp) which needed to pass 
addresses through this ABI method.

There are user interface issues to consider.  For instance, when you do 
"register read", lldb will print a register value, and if it resolves to a 
symbol, lldb will print the symbol name.  With PAC bits, I print the actual 
register value (with PAC bits), strip the PAC bits, and if this value resolves 
to a symbolcontext, then I print the address-sans-PAC and the symbol name.  
There are probably a half dozen other places where I had to do the same thing 
--- the goal is to always show the user the actual register/pointer value with 
its PAC bits, and add information to that if we're confident that it's actually 
an virtual address.

Developers can add type qualifiers to their own structs to indicate that 
pointers should use pointer authentication.  We have patches to represent this 
in the DWARF, and lldb reads those, so we know to strip the pac bits off of 
non-ABI objects that are using pointer auth - there are some changes to the 
Value object for this, and such.  For SB API developers, we added a 
SBValue::GetValueAsAddress method (similar to SBValue::GetValueAsUnsigned, etc) 
so that people coding at the SB API layer can do the same thing lldb does -- 
show the value with PAC bits (GetValueAsUnsigned) and as an actual address 
(GetValueAsAddress) if they want to do that.

There's some additional changes for jitting expressions, and to be honest it's 
been ages since I've looked at that code so I can't speak on it very 
authoritatively without re-reading a bunch (and I authored very little of it).  



A good place to start IMO, is the base idea of Process being the knower of the 
# of addressing bits, and the ABI being the knower of how to strip PAC bits 
off.  I chose the ABI for this method because this *is* ABI, but given my ideas 
about an all-encompassing ABI::GetAsVirtualAddress that different parts of lldb 
pass things that can be signed in every ABI, maybe it doesn't even make sense 
to bother putting it in the ABI, it could go in Process and only strip off bits 
if the # of virtual addressing bits has been set.


> On Aug 13, 2020, at 12:56 AM, Omair Javaid  wrote:
> 
> Hi Jason,
> 
> I wanted to bring this to your attention that we are also working on pointer 
> authentication support. We have so far only done register context changes to 
> allow for enabling/disabling pointer authentication features and read/write 
> pauth Cmask/Dmask registers when available. I am currently investigating 
> 

Re: [lldb-dev] RFC: AArch64 Linux Memory Tagging Support for LLDB

2020-08-13 Thread Omair Javaid via lldb-dev
Hi Jason,

I wanted to bring this to your attention that we are also working on
pointer authentication support. We have so far only done register context
changes to allow for enabling/disabling pointer authentication features and
read/write pauth Cmask/Dmask registers when available. I am currently
investigating unwinder support which means any further implementation from
my side will be an overlap with what you guys have done already. There can
also be design conflicts and I would really appreciate it if we can come on
some common ground regarding upstreaming of Apple's downstream pointer
authentication patches. We may collaborate and upstream unwinder support.

Thanks!

On Tue, 11 Aug 2020 at 04:13, Jason Molenda via lldb-dev <
lldb-dev@lists.llvm.org> wrote:

> Hi David, thanks for the great writeup.  I hadn't been following the gdb
> MTE support.
>
> This all looks reasonable to me.  A few quick thoughts --
>
> The initial idea of commands like "memory showptrtag", "memory showtag",
> "memory checktag" - it might be better to put all of these under "memory
> tag ...", similar to how "breakpoint command ..." works.
>
> It makes sense to have lldb read/write the control pseudo-register as if
> it were a normal reg, in its own register grouping.  You mentioned that you
> had some thoughts about how to make it more readable to users - I know this
> is something Greg has been hoping to do / see done at some point, for
> control registers where we could annotate the registers a lot better.  I
> noticed that qemu for x86 provides exactly this kind of annotation
> information in its register target.xml definitions (v.
> lldb/test/API/functionalities/gdb_remote_client/TestRegDefinitionInParts.py
> ) but I don't THINK we do anything with these annotations today.  Not at
> all essential to this work, but just noting that this is something we all
> would like to see better support for.
>
> As for annotating the reason the program stopped on an MTE exception,
> Ismail was working on something similar in the past - although as you note,
> the really cool thing would be decoding the faulting instruction to
> understand what target register was responsible for the fault (and maybe
> even working back via the debug info to figure out what user-level variable
> it was??) to annotate it, which is something we're not doing anywhere right
> now.  There was a little proof-of-concept thing that Sean Callanan did
> years ago "frame diagnose" which would try to annotate to the user in
> high-level source terms why a fault happened, but I think it was using some
> string matching of x86 instructions to figure out what happened. :)
>
> We're overdue to upstream the PAC support for lldb that we're using, it's
> dependent on some other work being upstreamed that hasn't been done yet,
> but the general scheme involves querying the lldb-server / debugserver /
> corefile to get the number of bits used for virtual addressing, and then it
> just stomps on all the other high bits when trying to dereference values.
> If you do 'register read' of a function pointer, we show the actual value
> with PAC bits, then we strip the PAC bits off and if it resolves to a
> symbol, we print the stripped value and symbol that we're pointing to. It
> seems similar to what MTE will need -- if you have a variable pointing to
> heap using MTE, and you do `x/g var`, lldb should strip off the MTE bits
> before sending the address to read to lldb-server. The goal with the PAC UI
> design is to never hide the PAC details from the user, but to additionally
> show the PAC-less address when we're sure that it's an address in memory.
> Tougher to do that with MTE because we'll never be pointing to a symbol, it
> will be heap or stack.
>
> J
>
>
>
>
>
> > On Aug 10, 2020, at 3:41 AM, David Spickett via lldb-dev <
> lldb-dev@lists.llvm.org> wrote:
> >
> > Hi all,
> >
> > What follows is my proposal for supporting AArch64's memory tagging
> > extension in LLDB. I think the link in the first paragraph is a good
> > introduction if you haven't come across memory tagging before.
> >
> > I've also put the document in a Google Doc if that's easier for you to
> > read:
> https://docs.google.com/document/d/13oRtTujCrWOS_2RSciYoaBPNPgxIvTF2qyOfhhUTj1U/edit?usp=sharing
> > (please keep comments to this list though)
> >
> > Any and all comments welcome. Particularly I would like opinions on
> > the naming of the commands, as this extension is AArch64 specific but
> > the concept of memory tagging itself is not.
> > (I've added some people on Cc who might have particular interest)
> >
> > Thanks,
> > David Spickett.
> >
> > 
> >
> > # RFC: AArch64 Linux Memory Tagging Support for LLDB
> >
> > ## What is memory tagging?
> >
> > Memory tagging is an extension added in the Armv8.5-a architecture for
> AArch64.
> > It allows tagging pointers and storing those tags so that hardware can
> validate
> > that a pointer matches the memory address it is trying to access. These
> paired