-
Notifications
You must be signed in to change notification settings - Fork 184
Clarify -D_FORTIFY_SOURCE
interaction with optimization levels
#620
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -494,11 +494,11 @@ Some tools, such as `autoconf`, automatically determine what the compiler suppor | |
|
||
### Fortify sources for unsafe libc usage and buffer overflows | ||
|
||
| Compiler Flag | Supported since | Description | | ||
| ------------------------------------------------------------------------------------------ | ----------------------- | -------------------------------------------------------------------------------------------- | | ||
| <span id="-D_FORTIFY_SOURCE=1">`-D_FORTIFY_SOURCE=1`</span> | GCC 4.0.0<br/>Clang 5.0.0 | Fortify sources with compile- and run-time checks for unsafe libc usage and buffer overflows | | ||
| <span id="-D_FORTIFY_SOURCE=2">`-D_FORTIFY_SOURCE=2`</span><br/>(requires `-O1` or higher) | GCC 4.0.0<br/>Clang 5.0.0[^Guelton20] | In addition to checks covered by `-D_FORTIFY_SOURCE=1`, also trap code that may be conforming to the C standard but still unsafe | | ||
| <span id="-D_FORTIFY_SOURCE=3">`-D_FORTIFY_SOURCE=3`</span><br/>(requires `-O1` or higher) | GCC 12.0.0<br/>Clang 9.0.0[^Guelton20] | Same checks as in `-D_FORTIFY_SOURCE=2`, but with significantly more calls fortified with a potential to impact performance in some rare cases | | ||
| Compiler Flag | Supported since | Description | | ||
| ----------------------------------------------------------- | -------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | ||
| <span id="-D_FORTIFY_SOURCE=3">`-D_FORTIFY_SOURCE=3`</span> | GCC 12.0.0<br/>Clang 9.0.0[^Guelton20] | Same checks as in `-D_FORTIFY_SOURCE=2`, but with significantly more calls fortified with a potential to impact performance in some rare cases. Requires `-O1` or higher. | | ||
| <span id="-D_FORTIFY_SOURCE=2">`-D_FORTIFY_SOURCE=2`</span> | GCC 4.0.0<br/>Clang 5.0.0[^Guelton20] | In addition to checks covered by `-D_FORTIFY_SOURCE=1`, also trap code that may be conforming to the C standard but still unsafe. Requires `-O1` or higher. | | ||
| <span id="-D_FORTIFY_SOURCE=1">`-D_FORTIFY_SOURCE=1`</span> | GCC 4.0.0<br/>Clang 5.0.0 | Fortify sources with compile- and run-time checks for unsafe libc usage and buffer overflows | | ||
|
||
#### Synopsis | ||
|
||
|
@@ -535,14 +535,20 @@ Both `_FORTIFY_SOURCE=1` and `_FORTIFY_SOURCE=2` are expected to have a negligib | |
|
||
#### Additional Considerations | ||
|
||
- Applications that incorrectly use `malloc_usable_size`[^malloc_usable_size] to use the additional size reported by the function may abort at runtime. This is a bug in the application because the additional size reported by `malloc_usable_size` is not generally safe to dereference and is for diagnostic uses only. The correct fix for such issues is to avoid using `malloc_usable_size` as the glibc manual specifically states that it is for diagnostic purposes *only* [^malloc_usable_size]. On many Linux systems these incorrect uses can be detected by running `readelf -Ws <path>` on the ELF binaries and searching for `malloc_usable_size@GLIBC`[^kpyrd23]. If avoiding `malloc_usable_size` is not possible, one may call `realloc` to resize the block to its usable size and to benefit from `_FORTIFY_SOURCE=3`. | ||
Internally `-D_FORTIFY_SOURCE` relies on the built-in functions for object size checking in GCC[^gcc-objectsizechecks] and Clang[^clang-evaluatingobjectsize], namely `__builtin_object_size` and `__builtin_dynamic_object_size`. These builtins provide conservative approximations of the object size and are sensitive to compiler optimizations. With optimization enabled they produce more accurate estimates, especially when a call to `__builtin_object_size` is in a different function from where its argument pointer is formed. In addition, GCC allows more information about subobject bounds to be determined with higher optimization levels. Hence we recommending enabling `-D_FORTIFY_SOURCE=3` with at least optimization level `-O2`. | ||
|
||
Applications that incorrectly use `malloc_usable_size`[^malloc_usable_size] to use the additional size reported by the function may abort at runtime. This is a bug in the application because the additional size reported by `malloc_usable_size` is not generally safe to dereference and is for diagnostic uses only. The correct fix for such issues is to avoid using `malloc_usable_size` as the glibc manual specifically states that it is for diagnostic purposes *only* [^malloc_usable_size]. On many Linux systems these incorrect uses can be detected by running `readelf -Ws <path>` on the ELF binaries and searching for `malloc_usable_size@GLIBC`[^kpyrd23]. If avoiding `malloc_usable_size` is not possible, one may call `realloc` to resize the block to its usable size and to benefit from `_FORTIFY_SOURCE=3`. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. systemd for example uses a dummy realloc hack to fool the compiler into thinking that the larger block is available, but I don't know if it's a good idea to recommend such practice: https://github.com/systemd/systemd/blob/main/src/basic/alloc-util.h#L192 Also, I had introduced a fast path in There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If we're in the business of telling people what best practice is, we should indeed actively tell them not to do that at all. The only reason we haven't completely killed it in glibc is because we can't quite agree on how to move forward, but everyone accepts that using it like this is bad. (I haven't brought it up again given that I haven't hit any other instances.) |
||
|
||
[^glibc-fortification]: GNU C Library team, [Source Fortification in the GNU C Library](https://www.gnu.org/software/libc/manual/html_node/Source-Fortification.html), GNU C Library (glibc) manual, 2023-02-01. | ||
|
||
[^Poyarekar23]: Poyarekar, Siddhesh, [How to improve application security using _FORTIFY_SOURCE=3](https://developers.redhat.com/articles/2023/02/06/how-improve-application-security-using-fortifysource3), Red Hat Developer, 2023-02-06. | ||
|
||
[^gcc-zerolengtharrays]: GCC team, [Arrays of Length Zero](https://gcc.gnu.org/onlinedocs/gcc/extensions-to-the-c-language-family/arrays-of-length-zero.html), GCC Manual (experimental 20221114 documentation), 2022-11-14. | ||
|
||
[^gcc-objectsizechecks]: GCC team, [Using the GNU Compiler Collection (GCC): 6.62 Object Size Checking](https://gcc.gnu.org/onlinedocs/gcc/Object-Size-Checking.html), GCC Manual, 2024-08-01. | ||
|
||
[^clang-evaluatingobjectsize]: LLVM team, [Clang Language Extensions: Evaluating Object Size](https://clang.llvm.org/docs/LanguageExtensions.html#evaluating-object-size), Clang Documentation, 2024-09-17. | ||
|
||
[^malloc_usable_size]: Linux Man Pages team, [malloc_usable_size(3)](https://man7.org/linux/man-pages/man3/malloc_usable_size.3.html), Linux manual page, 2023-03-30. | ||
|
||
[^kpyrd23]: kpcyrd, [Task Todo List Prepare packages for -D_FORTIFY_SOURCE=3](https://archlinux.org/todo/prepare-packages-for-d_fortify_source3/), Arch Linux Task Todo List, 2023-09-05. | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wouldn't call out the subobject bounds so prominently because in practice better optimization can also sometimes result in subobject information being lost. I think a more reliable claim would be that higher optimization allows more number of
__builtin_object_size
and__builtin_dynamic_object_size
calls to succeed, not the accuracy of their size estimates.