Page MenuHome GnuPG

The CF protection not enabled in libgcrypt
Open, NormalPublic

Description

The CF protection prevents the attacker from jumping to arbitrary places in the code by inserting the ENDBR64/ENDBR32 to the "labels" where the intended jumps destinations are. When the whole binary (including assembler sources) have this, at runtime the CET protection can be enabled and jumps to the unexpected places abort the program. More information can be found here or on the links to the intel presentation:

https://sourceware.org/annobin/annobin.html/Test-cf-protection.html

I see there is some support for this on 32b MPI assembler in mpi/i386/mpih-add1.S, but not elsewhere so this is RFE/RFC if this is something that was considered to implement for libgcrypt. My understanding is that the changes should be mostly mechanical changes.

Details

Version
master

Event Timeline

OpenBSD carries libgcrypt patch for CET which adds endbr64 instruction to CFI_STARTPROC() macro in "asm-common-amd64.h". We could do the same and also add endbr32 to i386 too. That would be easiest way to add required endbr instructions. OpenBSD also has patch for arm64 to add similar BTI instructions to aarch64 variant of CFI_STARTPROC.

One concern I have is how to test these work. Is userspace CET available/enabled in common linux distributions?

Here's patches for adding CET support to x86-64 and i386 assembly.


Thank you for having a look into this!

I tried your patches, but it does not make any difference. Sounds like there is still some assembly file that does not have the IBT flags set correctly, making the CET disabled for the whole library

Searching through the built objects, I can see that the ./cipher/.libs/rijndael-vaes-avx2-i386.o (new since 2023) does not report the IBT flags (its built also for the x86_64 build -- is it expected?). I do not see any obvious issue with it with my untrained eye though.

We are certainly working on enabling this functionaliy for centos10stream, but I think we did use this already before.

"rijndael-vaes-avx2-i386.S" should not be build for x86-64 but until now that has not had any affect as #ifdefs in that source file result empty object file on x86-64.

Here's patch that should fix the issue:

Thank you. With this patch the IBT flags are present on the shared object and CF protection test passes.

Recent changes fixed the issue for the x86_64 builds, but I see similar symptoms in the aarch64 build now. Annocheck reports the following failures:

Hardened: /usr/lib64/libgcrypt.so.20.5.0: FAIL: dynamic-tags test because the BTI_PLT flag is missing from the dynamic tags 
Hardened: /usr/lib64/libgcrypt.so.20.5.0: info: For more information visit: https://sourceware.org/annobin/annobin.html/Test-dynamic-tags.html
Hardened: /usr/lib64/libgcrypt.so.20.5.0: FAIL: property-note test because properly formatted .note.gnu.property not found (it is needed for branch protection support) 
Hardened: /usr/lib64/libgcrypt.so.20.5.0: info: For more information visit: https://sourceware.org/annobin/annobin.html/Test-property-note.html

I do not have aarch64 machine at hand now to investigate this further, but this sounds like orthogonal functionality to the CET on Intel.

Ok, so aarch64 assembly would need PAC and BTI support. As far as I have understood these, is that PAC instructions are not needed with current assembly as none of those is storing/loading LR register (all aarch64 assembly functions are leaf functions). So only BTI is needed and that is basically same modification as CET on x86.

Here's patch:

I could not get PAC/BTI property to propagate all the way to libgcrypt.so, but that might be problem with my build environment.

Tested in our build environment and indeed, just this patch does not solve the issue for aarch64.

Searching for all built .o objects, that could cause the final objects not having the right properties, I came up with the following neon objects that are built into the final so object and that do not have the right flags (likely because they are empty? readelf on them comes empty):

+ readelf -n ./cipher/.libs/sha512-armv7-neon.o
+ readelf -n ./cipher/.libs/keccak-armv7-neon.o
+ readelf -n ./cipher/.libs/chacha20-armv7-neon.o
+ readelf -n ./cipher/.libs/serpent-armv7-neon.o

All the other objects have the following output, which I believe is correct:

Displaying notes found in: .note.gnu.property
  Owner                Data size 	Description
  GNU                  0x00000010	NT_GNU_PROPERTY_TYPE_0
      Properties: AArch64 feature: BTI, PAC

Excluding them should fix this problem, I believe.

This excludes 32-bit ARM assembly from Aarch64 builds:

Thanks! Verified this builds on aarch64 correctly and generates the right flags on the output:

Hardened: /builddir/build/BUILDROOT/libgcrypt-1.11.0-3.el10.aarch64/usr/lib64/libgcrypt.so.20.5.0: Overall: PASS.

Do you have any way to test PAC/BTI on actual HW that support these extensions?

I noticed issue in one algorithm where link register was stored/loaded unnecessarily and that might have triggered fault on PAC enabled HW. Here's fix for that:

I do not have Aarch64 machine at hand so what I did was building the package with changes on the build system with previous patches and checking the correct flag are in place (previously in RHEL10, but now in Fedora):

https://src.fedoraproject.org/rpms/libgcrypt/pull-request/10

AFAIK the builder for aarch64 are aarch64 machines and they run all tests with the build so objects. But I am not sure how to check if the PAC is enabled on that HW. There is some HW info of the runner if it will help:

https://kojipkgs.fedoraproject.org//work/tasks/8874/121598874/hw_info.log