[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#1113774: Disabling -fcf-protection in sudo for bookworm



El 02/09/2025 a las 18:28, Helmut Grohne escribió:> From a technical point of view, I note that -fcf-protection is not
> enabled for i386 at the toolchain level for any Debian release. It was
> added to the default flags for amd64 in trixie. This wasn't fully
> evident from the discussion to me. It really is sudo that is adding this
> flag.
> https://sources.debian.org/src/sudo/1.9.13p3-1%2Bdeb12u1/m4/hardening.m4#L108
> 
> There seem to be two major arguments involved both of which I have not
> yet verified in depth.
> 
> 1. The -fcf-protection flag bears no benefit in 32bit user applications.
> 2. The ENDBR32 instruction inserted by -fcf-protection is not supported
>    in some CPUs that were considered supported by bookworm's baseline.

Hello Helmut,

I am surprised that bare "-fcf-protection" was enabled by default on Trixie,
as that enables both shadow stacks (supported in user mode, actually
protecting users with zero size overhead) and IBT (not supported in
user-mode, doing nothing but increasing thus the size of all binaries)

I can easily prove that (and also your point 1) with one simple C program:

------

#include <stdio.h>
#include <stdint.h>

void test_func() {
	puts("IBT not working\n");
}

int main() {
	void (* func_ptr)();

	/*
	 * ENDBR32 is F3 0F 1E FB
	 * ENDBR64 is F3 0F 1E FA
	 *
	 * Both are 4-bytes long. By adding 4 to the start of the function,
	 * we skip past the ENDBR that IBT uses as landing instructions.
	 */
	func_ptr = (void *) ((uint8_t *) test_func + 4);

	/*
	 * Now perform an invalid indirect call.
	 *
	 * If IBT actually worked, the program would be immediately halted now
	 * since the first fetched after an indirect call when IBT is enabled
	 * MUST be an ENDBR, which is not as we skipped it.
	 *
	 * However, as I said, since IBT is not supported in user-mode, this
	 * will run just fine on both 32-bit and 64-bit, proving IBT at this
	 * point just increases code size, causes compatibility issues on these
	 * i686 machines, all while providing no security whatsoever.
	 */
	func_ptr();

	return 0;
}

------

Compiling this with "gcc -fcf-protection ibt.c -o ibt && ./ibt" on
an IBT-capable machine will run without problems. On an Intel N100 a
friend (Manawyrm, which tells me Marc Haber knows about) has:

root@vmhost ~ # gcc -fcf-protection ibt.c -o ibt
root@vmhost ~ # ./ibt
IBT not working

root@vmhost ~ # gcc ibt.c -o ibt
root@vmhost ~ # ./ibt
IBT not working

Speicherzugriffsfehler
root@vmhost ~ # cat /proc/cpuinfo | grep Intel
vendor_id : GenuineIntel
model name : Intel(R) N100
vendor_id : GenuineIntel
model name : Intel(R) N100
vendor_id : GenuineIntel
model name : Intel(R) N100
vendor_id : GenuineIntel
model name : Intel(R) N100
root@vmhost ~ # uname -a
Linux vmhost 6.5.0-0.deb12.4-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.5.10-1~bpo12+1 (2023-11-23) x86_64 GNU/Linux
root@vmhost ~ # cat /etc/debian_version
12.5

This is on a Bookworm installation but the same should apply for Trixie,
Sid or any other Linux - it's a limitation of the kernel. Not even in the
current Linux's master branch IBT is supported for user-mode.

(Note that the execution without -fcf-protection crashes with
"Speicherzugriffsfehler" - SIGSEGV - because it's jumping past the
first PUSH instruction that stores the return address on the stack,
instead of the ENDBR64 that the former is)

Enabling "-fcf-protection=return" for Trixie which compiles with only
shadow stacks would have resulted in smaller binaries with the same level
of protection (and also would fix the issue with "sudo" for these i686).

Greetings,
Marcos


Reply to: