-
Notifications
You must be signed in to change notification settings - Fork 14
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
aarch64: enable PAC/BTI #15
Conversation
The mpg123-devel mailing list has been notified of the existence of this pr. |
Can you explain to me why this is necessary on ARM and not on x86? I got around the BTI stuff for x86 by introducing wrapper C functions, avoiding any indirect branches to the assembly code (meaning: calls via function pointer). So I didn't need to add BTI landing pads to the other assembly functions. Is ARM different? Or would just marking the code as safe make the compiler happy here, too? Is the compiler actually happy for the x86 code? What toolchain do I need to verify if this works or not? I did some testing with clang on Android using termux, but that wasn't conclusive. |
Enable Pointer Authentication Codes (PAC) and Branch Target Identification (BTI) support for ARM 64 targets. PAC works by signing the LR with either an A key or B key and verifying the return address. Since the assembly code does not push and pop the link register to the stack, and it remains in the register file, their is no need to sign the LR, so PAC is essentially just adding it to the GNU notes section for auditing purposes. BTI works by marking all call and jump positions with bti c and bti j instructions. If execution control transfers via an indirect branch or call to an instruction other than a BTI instruction, the execution is killed via SIGILL. For BTI to work, all object files linked for a unit of execution, whether an executable or a library must have the GNU Notes section of the ELF file marked to indicate BTI support. This is so loader/linkers can apply the proper permission bits (PROT_BRI) on the memory region. PAC can also be annotated in the GNU ELF notes section, but it's not required for enablement, as interleaved PAC and non-pac code works as expected since it's the callee that performs all the checking. Becuase the aarch64 assembly code does not make use of pushing the LR to the stack, only BTI targets were needed to be instrumented and the GNU notes section indicating support for BTU. Thus for PAC the only requirement was to mark the GNU notes section as supporting PAC. Testing was done under the following CFLAGS and CXXFLAGS for all combinations: 1. -mbranch-protection=none 2. -mbranch-protection=standard 3. -mbranch-protection=pac-ret 4. -mbranch-protection=pac-ret+b-key 5. -mbranch-protection=bti Signed-off-by: Bill Roberts <[email protected]>
60bfded
to
3348c23
Compare
I don't know how x86 did their implementation so no comment.
Yeah, good point. I went back through and ran the test suite as well as looked all the function calls and none are done indirectly. I don't know why my initial thought was that I needed the
I don't know about x86, but for Arm it's only indirect branches.
Yeah that appears to be all that we need.
No idea.
Any contemporary gcc or clang version that supports readelf -n ./src/libmpg123/.libs/libmpg123.so | grep -i bti
Properties: AArch64 feature: BTI, PAC
Unless you have a pac/bti enabled machine, in my case a M2, you will only get the bti/pac instructions emitted in the compiled code but they will nop. You should see the instructions in a disassembly (usually as things like hint 34 for bti c) as well as you should see the GNU Notes bits set that PAC and BTI are enabled. How to check if your system supports it: # BTI (bti)
#PAC (paca and pacg)
cat /proc/cpuinfo
Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fphp asimdhp cpuid asimdrdm jscvt fcma lrcpc dcpop sha3 asimddp sha512 asimdfhm dit uscat ilrcpc flagm ssbs sb **paca pacg** dcpodp flagm2 frint i8mm bf16 **bti** ecv |
Hm, the aarch64 cross toolchain availabl in debian (gcc 12) seems too old? Or is it readelf? even with generic CPU code, I don't see a line with Properties/Aarch64 features. Only a build ID. In termux, it's some opaque flags. Also: mbrach-potection is only a think on aarch64, anyway, as it seems. |
What OS are you on, I'll try and replicate? I would imagine gcc12 supports it so it might be a lack of support in readelf, but I doubt it as
Yes its aarch64 specific that's why it's behind a |
There are two aarch64 toolchains available in Ubuntu 22.04.4 LTS.
I tested a build with Of course, I could get a fresher toolchain and/or OS container to test, but I used what I had at hand while being busy. |
Was this is s typo? Ill reproduce with those versions, thanks. |
Good point. To make sure:
(That's on Ubuntu 22.04.) |
Ok, so while gcc13 supports it on Fedora, it does not on Ubuntu, my guess is some build time flag not getting set. However gcc-14 on Ubuntu does support it either. I need to check with the debian folks as to why. I can also confirm that current version of readelf will show the gnu notes bits. I took a confirmed shared object from Fedora and used readelf -n from Ubuntu and got the expected output. Ok it does add the instructions. I compiled with and without diff ~/d.with.txt ~/d.without.txt | grep paciasp
< 6520: d503233f paciasp |
I also see those paciasp instructions. In fact
(.asm obtained via aarch64-linux-gnu-objdump -d on the final libmpg123.so, with and without mbranch-protection=standard) There are more instances of this instruction with the assembly code, but of couse not inside the assembly objects. So, which toolchain actually does add the relevant notes section itself? Would it be confusing if our assembly files just have them and other objects not?
No gnu.notes.property section. I got binutils 2.38 here … shouldn't it support that section? I even found an old question from someone toying with assembly on how to prevent adding that section: https://stackoverflow.com/questions/52084184/how-do-i-prevent-ld-from-adding-note-gnu-property Did Ubuntu/Debian do something specific to disable that? I'd like to understand this a bit better before unconditionally adding that section ot our assembly files. |
Essentially not every library dependency in Debian has it enabled, so the linker is turning it off. If you just grab something like Fedora 40 it will show up.
No it was designed to work in this case. For PAC, it's not needed, just a nice to have for auditing. You can mix PAC and non-pac code together. Same for BTI, but when the BTI enabled code is statically linked the linker discards the note, and when the pages are mapped, the note is consulted to add You can see this behavior looking at the individually built objects: readelf -n ./src/libmpg123/.libs/check_neon.o
Displaying notes found in: .note.gnu.property
Owner Data size Description
GNU 0x00000010 NT_GNU_PROPERTY_TYPE_0
Properties: AArch64 feature: BTI, PAC
Not all sections are mandatory, gnu notes will only display if a gnu notes section is added. Its not added if its empty.
You can recreate this by running: ./configure CFLAGS='-mbranch-protection=standard' LDFLAGS='-Wl,-zforce-bti,--fatal-warnings'
Its the debian runtime AFAICT not built with support yet, but that's ok, as it's all interoperable. Here are some more projects that have picked these changes up:
|
Well, I failed to get a working build environment with Fedora 40 … their x86-64 distro doesn't havea cross-build glibc like Debian offers, and their aarch64 Qemu VM simply doesn't work for me, failing to give me the prompt to set up the root password in the qemu serial console, instead just
Very helpful, such an image. Of course, I could hack around in the image file to set the password (not even init=/bin/bash does anything? systemd in initrd seems to be special), but in any case, building mpg123 with emulated CPU that need around 10 minutes to boot. How can it be that slow on a 10th generation Core i7, even if it's just a Laptop CPU? Anyhow, that's not really mpg123 business. I verified that I can at least still build using the Ubuntu cross toolchain. Added the new header to autotools sources. The changes from the svn repo should percolate into the github mirror soon-ish and render this PR moot, which is accepted+merged in our terms. Thanks for you efforts, even if I seem stubborn in my insistence to see the thing in action, which I ultimately did not. I do carry some annoyance about this topic (BTI) coming up repeatedly, after hoping to have it settled before. I hope this is it now … at least for ARM. |
In the past, I found the toolchains on arm's website useful. On Linux, I think you need the "AArch64 GNU/Linux target (aarch64-none-linux-gnu)" one: |
merged: 3a12318 |
…h-protection variants) Backport from svn trunk r5430 Original patch discussion: madebr/mpg123#15
…h-protection variants) Backport from svn trunk r5430 Original patch discussion: madebr/mpg123#15
Enable Pointer Authentication Codes (PAC) and Branch Target Identification (BTI) support for ARM 64 targets.
PAC works by signing the LR with either an A key or B key and verifying the return address. Since the assembly code does not push and pop the link register to the stack, and it remains in the register file, their is no need to sign the LR, so PAC is essentially just adding it to the GNU notes section for auditing purposes.
BTI works by marking all call and jump positions with bti c and bti j instructions. If execution control transfers via an indirect branch or call to an instruction other than a BTI instruction, the execution is killed via SIGILL.
For BTI to work, all object files linked for a unit of execution, whether an executable or a library must have the GNU Notes section of the ELF file marked to indicate BTI support. This is so loader/linkers can apply the proper permission bits (PROT_BRI) on the memory region.
PAC can also be annotated in the GNU ELF notes section, but it's not required for enablement, as interleaved PAC and non-pac code works as expected since it's the callee that performs all the checking.
Becuase the aarch64 assembly code does not make use of pushing the LR to the stack, only BTI targets were needed to be instrumented and the GNU notes section indicating support for BTU. Thus for PAC the only requirement was to mark the GNU notes section as supporting PAC.
Testing was done under the following CFLAGS: