glibc 2.33 introduced a new fortification level, _FORTIFY_SOURCE=3
. It improves the coverage of cases where _FORTIFY_SOURCE
can use _chk
functions.
For example, using GCC 13 and glibc 2.36 (Fedora Rawhide), compiling master:
0nm -C src/bitcoind | grep _chk
1 U __fprintf_chk@GLIBC_2.17
2 U __memcpy_chk@GLIBC_2.17
3 U __snprintf_chk@GLIBC_2.17
4 U __sprintf_chk@GLIBC_2.17
5 U __stack_chk_fail@GLIBC_2.17
6 U __stack_chk_guard@GLIBC_2.17
7 U __vsnprintf_chk@GLIBC_2.17
8
9objdump -d src/bitcoind | grep "_chk@plt" | wc -l
1033
vs this branch:
0nm -C src/bitcoind | grep _chk
1 U __fprintf_chk@GLIBC_2.17
2 U __memcpy_chk@GLIBC_2.17
3 U __memset_chk@GLIBC_2.17
4 U __snprintf_chk@GLIBC_2.17
5 U __sprintf_chk@GLIBC_2.17
6 U __stack_chk_fail@GLIBC_2.17
7 U __stack_chk_guard@GLIBC_2.17
8 U __vsnprintf_chk@GLIBC_2.17
9
10objdump -d src/bitcoind | grep "_chk@plt" | wc -l
1161
Usage of level 3 requires LLVM/Clang 9+, or GCC 12+. Older compilers/glibc will still use _FORTIFY_SOURCE=2. For example, in the glibc we currently use for Linux release builds (2.24), __USE_FORTIFY_LEVEL
is determined using the following:
0#if defined _FORTIFY_SOURCE && _FORTIFY_SOURCE > 0
1# if !defined __OPTIMIZE__ || __OPTIMIZE__ <= 0
2# warning _FORTIFY_SOURCE requires compiling with optimization (-O)
3# elif !__GNUC_PREREQ (4, 1)
4# warning _FORTIFY_SOURCE requires GCC 4.1 or later
5# elif _FORTIFY_SOURCE > 1
6# define __USE_FORTIFY_LEVEL 2
7# else
8# define __USE_FORTIFY_LEVEL 1
9# endif
10#endif
11#ifndef __USE_FORTIFY_LEVEL
12# define __USE_FORTIFY_LEVEL 0
13#endif
so any value > 1 will turn on _FORTIFY_SOURCE=2
. This value detection logic has become slightly more complex in later versions of glibc.
https://sourceware.org/pipermail/libc-alpha/2021-February/122207.html https://developers.redhat.com/blog/2021/04/16/broadening-compiler-checks-for-buffer-overflows-in-_fortify_source