Skip to content

Instantly share code, notes, and snippets.

@hed0rah
Last active April 8, 2026 17:16
Show Gist options
  • Select an option

  • Save hed0rah/f5c976fdc602688a0fd40288fde6d886 to your computer and use it in GitHub Desktop.

Select an option

Save hed0rah/f5c976fdc602688a0fd40288fde6d886 to your computer and use it in GitHub Desktop.
GCC security related flags reference.
GCC security related flags reference.
Source material:
http://security.stackexchange.com/questions/24444/what-is-the-most-hardened-set-of-options-for-gcc-compiling-c-c
https://wiki.gentoo.org/wiki/Hardened_Gentoo
https://wiki.debian.org/Hardening
===================================================================================
GCC Security related flags and options:
CFLAGS="-fPIE -fstack-protector-all -D_FORTIFY_SOURCE=2"
LDFLAGS="-Wl,-z,now -Wl,-z,relro"
Hardened Gentoo default flags. On GCC 14+ see also -fhardened below.
-Wall -Wextra
Turn on all warnings.
-Wconversion -Wsign-conversion
Warn on unsigned/signed conversions.
-Wformat-security
Warn about uses of format functions that represent possible security problems.
-Werror
Turns all warnings into errors.
-arch x86_64
Compile for 64-bit to take max advantage of address space (important for ASLR;
more virtual address space to choose from when randomising layout).
-fstack-protector-strong -Wstack-protector --param ssp-buffer-size=4
Recommended middle ground (GCC 4.9+). Protects functions with local arrays,
address-taken locals, or alloca -- without the blanket overhead of -all.
Use -fstack-protector-all to guarantee guards on every function regardless.
-Wstack-protector warns for any functions that would not get protected.
-pie -fPIE
Position-independent executable; required for ASLR to be effective.
-ftrapv
Generates traps for signed overflow via library calls (__addvsi3 etc.).
NOTE: GCC's implementation is ~12x slower than baseline due to calling
runtime helper functions instead of emitting inline branch instructions.
Prefer: -fsanitize=signed-integer-overflow -fsanitize-undefined-trap-on-error
which emits jo+ud2 inline (same efficient pattern as clang -ftrapv).
Benchmark and disassembly comparison:
https://lemire.me/blog/2020/09/23/how-expensive-is-integer-overflow-trapping-in-c/
-D_FORTIFY_SOURCE=2 -O1
Compile-time and runtime buffer overflow checks for calls to glibc functions
(memcpy, strcpy, printf, etc.) where the destination size is statically known.
Requires at least -O1 to be effective. =2 adds format string checks on top of =1.
GCC 12+ / glibc 2.35+: -D_FORTIFY_SOURCE=3 extends coverage to dynamic sizes.
-Wl,-z,relro,-z,now
RELRO (read-only relocation). relro+now together is "Full RELRO": marks the
GOT and other ELF sections read-only after startup, blocking GOT overwrites.
Omitting now gives "Partial RELRO" (GOT still writable during execution).
-fcf-protection=full
Intel CET (Control-flow Enforcement Technology), GCC 8+ / Clang 7+.
Enables IBT (Indirect Branch Tracking) and SHSTK (Shadow Stack) on supported
CPUs (Intel Tiger Lake+, AMD Zen 3+). Hardware-enforced forward and backward
edge CFI; stops ROP/JOP chains at the CPU level.
-fhardened
GCC 14+ composite flag. Equivalent to enabling: -fstack-protector-strong,
-fstack-clash-protection, -fcf-protection=full, -D_FORTIFY_SOURCE=3,
-D_GLIBCXX_ASSERTIONS, -pie -fPIE. Convenient single flag for production builds.
Sanitizers (development/testing, not production):
-fsanitize=address
AddressSanitizer (ASan): detects heap/stack buffer overflows, use-after-free,
double-free, use-after-return, and memory leaks. ~2x slowdown.
-fsanitize=undefined
UndefinedBehaviorSanitizer (UBSan): traps signed overflow, null dereference,
misaligned access, integer truncation, and other UB at the point it occurs.
-fsanitize=thread
ThreadSanitizer (TSan): detects data races. ~5-15x slowdown. Cannot be used
with ASan simultaneously.
-fsanitize=signed-integer-overflow -fsanitize-undefined-trap-on-error
Efficient signed overflow trapping (see -ftrapv note above). Emits jo+ud2
inline rather than calling a library function.
---
If compiling on Windows, prefer Visual Studio over GCC, as some Windows
protections (SEHOP, CFG) are not exposed through GCC. If GCC is required:
-Wl,dynamicbase Tell linker to use ASLR protection
-Wl,nxcompat Tell linker to use DEP protection
>>>
From https://wiki.debian.org/Hardening#Notes_on_Memory_Corruption_Mitigation_Methods
User Space:
----------
Stack Protector
gcc's -fstack-protector attempts to detect when a stack has been overwritten
and aborts the program. Ubuntu has had this enabled by default since Edgy.
Some programs do not play nice with it and can be worked around with
-fno-stack-protector. Already done in sendmail.
heap protection
In glibc 2.5, no additional work needed.
libc pointer encryption
In mainline glibc, as PTR_MANGLE.
gcc -D_FORTIFY_SOURCE=2 -O1
Compile-time protection against static sized buffer overflows. No known
regressions or performance loss. Should be enabled system-wide.
gcc -Wformat -Wformat-security
Calls out simple printf format string vulnerabilities. Programs whose builds
become noisy as a result should be fixed regardless.
gcc -pie -fPIE
Requires the executable be built with -fPIE for all linked .o files. Some
performance loss from -fPIE; already true for all linked libraries via -fPIC.
Already done with openssh, sendmail.
ld -z relro
(Or via gcc with -Wl,-z,relro) Already done with sendmail.
ld -z now
(Or via gcc with -Wl,-z,now).
Kernel Space:
------------
non-exec memory segmentation (ExecShield)
Stops execution of code in heap/stack. i386 specific (NX already does this
for amd64). Some applications break in the protected layout.
-fstack-protector
Available for amd64 builds: config CC_STACKPROTECTOR.
runtime memory allocation validation
Detect double-frees in kernel space.
Address Space Layout Randomization
mmap: in mainline
stack: in mainline
vdso: in since 2.6.18 (COMPAT_VDSO disables it)
heap/exec: in -mm, 2.6.24
brk: 2.6.25
Having heap/exec ASLR is a prerequisite for -pie being useful.
/proc/$pid/maps protection
Present in 2.6.22; requires sysctl toggle (kernel.maps_protect=1).
Became non-optional in 2.6.27.
/dev/mem protection
Included in 2.6.25.
link protections
In Linux 3.6, enabled by default.
https://git.kernel.org/?p=linux/kernel/git/torvalds/linux.git;a=commitdiff;h=800179c9b8a1e796e441674776d11cd4c05d61d7
Via sysctl: fs.protected_hardlinks and fs.protected_symlinks.
From GRSecurity: protections against hardlink/symlink creation and following
in world-writable directories. Solves tmp races.
chroot, dmesg, fifo protections
From GRSecurity patchset.
References (from hardened Gentoo page):
https://wiki.ubuntu.com/CompilerFlags
http://people.redhat.com/drepper/nonselsec.pdf
http://www.suse.de/~krahmer/no-nx.pdf
http://www.phrack.org/archives/issues/58/4.txt
http://www.phrack.org/archives/issues/59/9.txt
http://www.coresecurity.com/files/attachments/Richarte_Stackguard_2002.pdf
http://www.gentoo.org/proj/en/hardened/hardened-toolchain.xml
@huglovefan
Copy link
Copy Markdown

-ftrapv in gcc is not very well optimized so it may be better to use -fsanitize=signed-integer-overflow -fsanitize-undefined-trap-on-error instead

in this microbenchmark, clang -ftrapv was 3x slower while gcc -ftrapv was 12x slower

  • clang -ftrapv on x86-64 uses the jo (jump on overflow) instruction to check if an operation caused overflow
  • gcc -ftrapv calls a library function (like int __addvsi3(int, int)) to do an operation and check for overflow

with the sanitizer flags, gcc will have the same behavior as clang and use the jump instruction instead

you can verify what it does with something like:

% echo 'int n; void fn(void) { n++; }' > test.c
% gcc -O2 -ftrapv test.c -o test.so -fPIC -shared
% objdump --disassemble=fn --section=.text test.so
output of gcc-10.2.0 -O2 -ftrapv
0000000000001120 <fn>:
    1120:       53                      push   %rbx
    1121:       48 8b 1d b8 2e 00 00    mov    0x2eb8(%rip),%rbx        # 3fe0 <n@@Base-0x4c>
    1128:       be 01 00 00 00          mov    $0x1,%esi
    112d:       8b 3b                   mov    (%rbx),%edi
    112f:       e8 3c 00 00 00          callq  1170 <__addvsi3>
    1134:       89 03                   mov    %eax,(%rbx)
    1136:       5b                      pop    %rbx
    1137:       c3                      retq
output of gcc-10.2.0 -O2 -fsanitize=signed-integer-overflow -fsanitize-undefined-trap-on-error
0000000000001100 <fn>:
    1100:       48 8b 15 d9 2e 00 00    mov    0x2ed9(%rip),%rdx        # 3fe0 <n@@Base-0x44>
    1107:       8b 02                   mov    (%rdx),%eax
    1109:       83 c0 01                add    $0x1,%eax
    110c:       70 03                   jo     1111 <fn+0x11>
    110e:       89 02                   mov    %eax,(%rdx)
    1110:       c3                      retq
    1111:       0f 0b                   ud2
output of clang-12 -O2 -ftrapv
00000000000015d0 <fn>:
    15d0:       48 8b 05 19 12 00 00    mov    0x1219(%rip),%rax        # 27f0 <n@@Base-0x1034>
    15d7:       8b 08                   mov    (%rax),%ecx
    15d9:       ff c1                   inc    %ecx
    15db:       70 03                   jo     15e0 <fn+0x10>
    15dd:       89 08                   mov    %ecx,(%rax)
    15df:       c3                      retq
    15e0:       67 0f b9 00             ud1    (%eax),%eax

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment