1*8d67ca89SAndroid Build Coastguard Worker*This document was originally written for a broad audience, and it was* 2*8d67ca89SAndroid Build Coastguard Worker*determined that it'd be good to hold in Bionic's docs, too. Due to the* 3*8d67ca89SAndroid Build Coastguard Worker*ever-changing nature of code, it tries to link to a stable tag of* 4*8d67ca89SAndroid Build Coastguard Worker*Bionic's libc, rather than the live code in Bionic. Same for Clang.* 5*8d67ca89SAndroid Build Coastguard Worker*Reader beware. :)* 6*8d67ca89SAndroid Build Coastguard Worker 7*8d67ca89SAndroid Build Coastguard Worker# The Anatomy of Clang FORTIFY 8*8d67ca89SAndroid Build Coastguard Worker 9*8d67ca89SAndroid Build Coastguard Worker## Objective 10*8d67ca89SAndroid Build Coastguard Worker 11*8d67ca89SAndroid Build Coastguard WorkerThe intent of this document is to run through the minutiae of how Clang FORTIFY 12*8d67ca89SAndroid Build Coastguard Workeractually works in Bionic at the time of writing. Other FORTIFY implementations 13*8d67ca89SAndroid Build Coastguard Workerthat target Clang should use very similar mechanics. This document exists in part 14*8d67ca89SAndroid Build Coastguard Workerbecause many Clang-specific features serve multiple purposes simultaneously, so 15*8d67ca89SAndroid Build Coastguard Workergetting up-to-speed on how things function can be quite difficult. 16*8d67ca89SAndroid Build Coastguard Worker 17*8d67ca89SAndroid Build Coastguard Worker## Background 18*8d67ca89SAndroid Build Coastguard Worker 19*8d67ca89SAndroid Build Coastguard WorkerFORTIFY is a broad suite of extensions to libc aimed at catching misuses of 20*8d67ca89SAndroid Build Coastguard Workercommon library functions. Textually, these extensions exist purely in libc, but 21*8d67ca89SAndroid Build Coastguard Workerall implementations of FORTIFY rely heavily on C language extensions in order 22*8d67ca89SAndroid Build Coastguard Workerto function at all. 23*8d67ca89SAndroid Build Coastguard Worker 24*8d67ca89SAndroid Build Coastguard WorkerBroadly, FORTIFY implementations try to guard against many misuses of C 25*8d67ca89SAndroid Build Coastguard Workerstandard(-ish) libraries: 26*8d67ca89SAndroid Build Coastguard Worker- Buffer overruns in functions where pointers+sizes are passed (e.g., `memcpy`, 27*8d67ca89SAndroid Build Coastguard Worker `poll`), or where sizes exist implicitly (e.g., `strcpy`). 28*8d67ca89SAndroid Build Coastguard Worker- Arguments with incorrect values passed to libc functions (e.g., 29*8d67ca89SAndroid Build Coastguard Worker out-of-bounds bits in `umask`). 30*8d67ca89SAndroid Build Coastguard Worker- Missing arguments to functions (e.g., `open()` with `O_CREAT`, but no mode 31*8d67ca89SAndroid Build Coastguard Worker bits). 32*8d67ca89SAndroid Build Coastguard Worker 33*8d67ca89SAndroid Build Coastguard WorkerFORTIFY is traditionally enabled by passing `-D_FORTIFY_SOURCE=N` to your 34*8d67ca89SAndroid Build Coastguard Workercompiler. `N==0` disables FORTIFY, whereas `N==1`, `N==2`, and `N==3` enable 35*8d67ca89SAndroid Build Coastguard Workerincreasingly strict versions of it. In general, FORTIFY doesn't require user 36*8d67ca89SAndroid Build Coastguard Workercode changes; that said, some code patterns 37*8d67ca89SAndroid Build Coastguard Workerare [incompatible with stricter versions of FORTIFY checking]. This is largely 38*8d67ca89SAndroid Build Coastguard Workerbecause FORTIFY has significant flexibility in what it considers to be an 39*8d67ca89SAndroid Build Coastguard Worker"out-of-bounds" access. 40*8d67ca89SAndroid Build Coastguard Worker 41*8d67ca89SAndroid Build Coastguard WorkerFORTIFY implementations use a mix of compiler diagnostics and runtime checks to 42*8d67ca89SAndroid Build Coastguard Workerflag and/or mitigate the impacts of the misuses mentioned above. 43*8d67ca89SAndroid Build Coastguard Worker 44*8d67ca89SAndroid Build Coastguard WorkerFurther, given FORTIFY's design, the effectiveness of FORTIFY is a function of 45*8d67ca89SAndroid Build Coastguard Worker-- among other things -- the optimization level you're compiling your code at. 46*8d67ca89SAndroid Build Coastguard WorkerMany FORTIFY implementations are implicitly disabled when building with `-O0`, 47*8d67ca89SAndroid Build Coastguard Workersince FORTIFY's design for both Clang and GCC relies on optimizations in order 48*8d67ca89SAndroid Build Coastguard Workerto provide useful run-time checks. For the purpose of this document, all 49*8d67ca89SAndroid Build Coastguard Workeranalysis of FORTIFY functions and commentary on builtins assume that code is 50*8d67ca89SAndroid Build Coastguard Workerbeing built with some optimization level > `-O0`. 51*8d67ca89SAndroid Build Coastguard Worker 52*8d67ca89SAndroid Build Coastguard Worker### A note on GCC 53*8d67ca89SAndroid Build Coastguard Worker 54*8d67ca89SAndroid Build Coastguard WorkerThis document talks specifically about Bionic's FORTIFY implementation targeted 55*8d67ca89SAndroid Build Coastguard Workerat Clang. While GCC also provides a set of language extensions necessary to 56*8d67ca89SAndroid Build Coastguard Workerimplement FORTIFY, these tools are different from what Clang offers. This 57*8d67ca89SAndroid Build Coastguard Workerdivergence is an artifact of Clang and GCC's differing architecture as 58*8d67ca89SAndroid Build Coastguard Workercompilers. 59*8d67ca89SAndroid Build Coastguard Worker 60*8d67ca89SAndroid Build Coastguard WorkerTextually, quite a bit can be shared between a FORTIFY implementation for GCC 61*8d67ca89SAndroid Build Coastguard Workerand one for Clang (e.g., see [ChromeOS' Glibc patch]), but this kind of sharing 62*8d67ca89SAndroid Build Coastguard Workerrequires things like macros that expand to unbalanced braces depending on your 63*8d67ca89SAndroid Build Coastguard Workercompiler: 64*8d67ca89SAndroid Build Coastguard Worker 65*8d67ca89SAndroid Build Coastguard Worker```c 66*8d67ca89SAndroid Build Coastguard Worker/* 67*8d67ca89SAndroid Build Coastguard Worker * Highly simplified; if you're interested in FORTIFY's actual implementation, 68*8d67ca89SAndroid Build Coastguard Worker * please see the patch linked above. 69*8d67ca89SAndroid Build Coastguard Worker */ 70*8d67ca89SAndroid Build Coastguard Worker#ifdef __clang__ 71*8d67ca89SAndroid Build Coastguard Worker# define FORTIFY_PRECONDITIONS 72*8d67ca89SAndroid Build Coastguard Worker# define FORTIFY_FUNCTION_END 73*8d67ca89SAndroid Build Coastguard Worker#else 74*8d67ca89SAndroid Build Coastguard Worker# define FORTIFY_PRECONDITIONS { 75*8d67ca89SAndroid Build Coastguard Worker# define FORTIFY_FUNCTION_END } 76*8d67ca89SAndroid Build Coastguard Worker#endif 77*8d67ca89SAndroid Build Coastguard Worker 78*8d67ca89SAndroid Build Coastguard Worker/* 79*8d67ca89SAndroid Build Coastguard Worker * FORTIFY_WARNING_ONLY_IF_SIZE_OF_BUF_LESS_THAN is not defined, due to its 80*8d67ca89SAndroid Build Coastguard Worker * complexity and irrelevance. It turns into a compile-time warning if the 81*8d67ca89SAndroid Build Coastguard Worker * compiler can determine `*buf` has fewer than `size` bytes available. 82*8d67ca89SAndroid Build Coastguard Worker */ 83*8d67ca89SAndroid Build Coastguard Worker 84*8d67ca89SAndroid Build Coastguard Workerchar *getcwd(char *buf, size_t size) 85*8d67ca89SAndroid Build Coastguard WorkerFORTIFY_PRECONDITIONS 86*8d67ca89SAndroid Build Coastguard Worker FORTIFY_WARNING_ONLY_IF_SIZE_OF_BUF_LESS_THAN(buf, size, "`buf` is too smol.") 87*8d67ca89SAndroid Build Coastguard Worker{ 88*8d67ca89SAndroid Build Coastguard Worker // Actual shared function implementation goes here. 89*8d67ca89SAndroid Build Coastguard Worker} 90*8d67ca89SAndroid Build Coastguard WorkerFORTIFY_FUNCTION_END 91*8d67ca89SAndroid Build Coastguard Worker``` 92*8d67ca89SAndroid Build Coastguard Worker 93*8d67ca89SAndroid Build Coastguard WorkerAll talk of GCC-focused implementations and how to merge Clang and GCC 94*8d67ca89SAndroid Build Coastguard Workerimplementations is out-of-scope for this doc, however. 95*8d67ca89SAndroid Build Coastguard Worker 96*8d67ca89SAndroid Build Coastguard Worker## The Life of a Clang FORTIFY Function 97*8d67ca89SAndroid Build Coastguard Worker 98*8d67ca89SAndroid Build Coastguard WorkerAs referenced in the Background section, FORTIFY performs many different checks 99*8d67ca89SAndroid Build Coastguard Workerfor many functions. This section intends to go through real-world examples of 100*8d67ca89SAndroid Build Coastguard WorkerFORTIFY functions in Bionic, breaking down how each part of these functions 101*8d67ca89SAndroid Build Coastguard Workerwork, and how the pieces fit together to provide FORTIFY-like functionality. 102*8d67ca89SAndroid Build Coastguard Worker 103*8d67ca89SAndroid Build Coastguard WorkerWhile FORTIFY implementations may differ between stdlibs, they broadly follow 104*8d67ca89SAndroid Build Coastguard Workerthe same patterns when implementing their checks for Clang, and they try to 105*8d67ca89SAndroid Build Coastguard Workermake similar promises with respect to FORTIFY compiling to be zero-overhead in 106*8d67ca89SAndroid Build Coastguard Workersome cases, etc. Moreover, while this document specifically examines Bionic, 107*8d67ca89SAndroid Build Coastguard Workermany stdlibs will operate _very similarly_ to Bionic in their Clang FORTIFY 108*8d67ca89SAndroid Build Coastguard Workerimplementations. 109*8d67ca89SAndroid Build Coastguard Worker 110*8d67ca89SAndroid Build Coastguard Worker**In general, when reading the below, be prepared for exceptions, subtlety, and 111*8d67ca89SAndroid Build Coastguard Workercorner cases. The individual function breakdowns below try to not offer 112*8d67ca89SAndroid Build Coastguard Workerredundant information. Each one focuses on different aspects of FORTIFY.** 113*8d67ca89SAndroid Build Coastguard Worker 114*8d67ca89SAndroid Build Coastguard Worker### Terminology 115*8d67ca89SAndroid Build Coastguard Worker 116*8d67ca89SAndroid Build Coastguard WorkerBecause FORTIFY should be mostly transparent to developers, there are inherent 117*8d67ca89SAndroid Build Coastguard Workernaming collisions here: `memcpy(x, y, z)` turns into fundamentally different 118*8d67ca89SAndroid Build Coastguard Workergenerated code depending on the value of `_FORTIFY_SOURCE`. Further, said 119*8d67ca89SAndroid Build Coastguard Worker`memcpy` call with `_FORTIFY_SOURCE` enabled needs to be able to refer to the 120*8d67ca89SAndroid Build Coastguard Worker`memcpy` that would have been called, had `_FORTIFY_SOURCE` been disabled. 121*8d67ca89SAndroid Build Coastguard WorkerHence, the following convention is followed in the subsections below for all 122*8d67ca89SAndroid Build Coastguard Workerprose (namely, multiline code blocks are exempted from this): 123*8d67ca89SAndroid Build Coastguard Worker 124*8d67ca89SAndroid Build Coastguard Worker- Standard library function names preceded by `__builtin_` refer to the use of 125*8d67ca89SAndroid Build Coastguard Worker the function with `_FORTIFY_SOURCE` disabled. 126*8d67ca89SAndroid Build Coastguard Worker- Standard library function names without a prefix refer to the use of the 127*8d67ca89SAndroid Build Coastguard Worker function with `_FORTIFY_SOURCE` enabled. 128*8d67ca89SAndroid Build Coastguard Worker 129*8d67ca89SAndroid Build Coastguard WorkerThis convention also applies in `clang`. `__builtin_memcpy` will always call 130*8d67ca89SAndroid Build Coastguard Worker`memcpy` as though `_FORTIFY_SOURCE` were disabled. 131*8d67ca89SAndroid Build Coastguard Worker 132*8d67ca89SAndroid Build Coastguard Worker## Breakdown of `mempcpy` 133*8d67ca89SAndroid Build Coastguard Worker 134*8d67ca89SAndroid Build Coastguard WorkerThe [FORTIFY'ed version of `mempcpy`] is a full, featureful example of a 135*8d67ca89SAndroid Build Coastguard WorkerFORTIFY'ed function from Bionic. From the user's perspective, it supports a few 136*8d67ca89SAndroid Build Coastguard Workerthings: 137*8d67ca89SAndroid Build Coastguard Worker- Producing a compile-time error if the number of bytes to copy trivially 138*8d67ca89SAndroid Build Coastguard Worker exceeds the number of bytes available at the destination pointer. 139*8d67ca89SAndroid Build Coastguard Worker- If the `mempcpy` has the potential to write to more bytes than what is 140*8d67ca89SAndroid Build Coastguard Worker available at the destination, a run-time check is inserted to crash the 141*8d67ca89SAndroid Build Coastguard Worker program if more bytes are written than what is allowed. 142*8d67ca89SAndroid Build Coastguard Worker- Compiling away to be zero overhead when none of the buffer sizes can be 143*8d67ca89SAndroid Build Coastguard Worker determined at compile-time[^1]. 144*8d67ca89SAndroid Build Coastguard Worker 145*8d67ca89SAndroid Build Coastguard WorkerThe declaration in Bionic's headers for `__builtin_mempcpy` is: 146*8d67ca89SAndroid Build Coastguard Worker```c 147*8d67ca89SAndroid Build Coastguard Workervoid* mempcpy(void* __dst, const void* __src, size_t __n) __INTRODUCED_IN(23); 148*8d67ca89SAndroid Build Coastguard Worker``` 149*8d67ca89SAndroid Build Coastguard Worker 150*8d67ca89SAndroid Build Coastguard WorkerWhich is annotated with nothing special, so it will be ignored. 151*8d67ca89SAndroid Build Coastguard Worker 152*8d67ca89SAndroid Build Coastguard WorkerThe [source for `mempcpy`] in Bionic's headers for is: 153*8d67ca89SAndroid Build Coastguard Worker```c 154*8d67ca89SAndroid Build Coastguard Worker__BIONIC_FORTIFY_INLINE 155*8d67ca89SAndroid Build Coastguard Workervoid* mempcpy(void* const dst __pass_object_size0, const void* src, size_t copy_amount) 156*8d67ca89SAndroid Build Coastguard Worker __overloadable 157*8d67ca89SAndroid Build Coastguard Worker __clang_error_if(__bos_unevaluated_lt(__bos0(dst), copy_amount), 158*8d67ca89SAndroid Build Coastguard Worker "'mempcpy' called with size bigger than buffer") { 159*8d67ca89SAndroid Build Coastguard Worker#if __BIONIC_FORTIFY_RUNTIME_CHECKS_ENABLED 160*8d67ca89SAndroid Build Coastguard Worker size_t bos_dst = __bos0(dst); 161*8d67ca89SAndroid Build Coastguard Worker if (!__bos_trivially_ge(bos_dst, copy_amount)) { 162*8d67ca89SAndroid Build Coastguard Worker return __builtin___mempcpy_chk(dst, src, copy_amount, bos_dst); 163*8d67ca89SAndroid Build Coastguard Worker } 164*8d67ca89SAndroid Build Coastguard Worker#endif 165*8d67ca89SAndroid Build Coastguard Worker return __builtin_mempcpy(dst, src, copy_amount); 166*8d67ca89SAndroid Build Coastguard Worker} 167*8d67ca89SAndroid Build Coastguard Worker``` 168*8d67ca89SAndroid Build Coastguard Worker 169*8d67ca89SAndroid Build Coastguard WorkerExpanding some of the important macros here, this function expands to roughly: 170*8d67ca89SAndroid Build Coastguard Worker```c 171*8d67ca89SAndroid Build Coastguard Workerstatic 172*8d67ca89SAndroid Build Coastguard Worker__inline__ 173*8d67ca89SAndroid Build Coastguard Worker__attribute__((no_stack_protector)) 174*8d67ca89SAndroid Build Coastguard Worker__attribute__((always_inline)) 175*8d67ca89SAndroid Build Coastguard Workervoid* mempcpy( 176*8d67ca89SAndroid Build Coastguard Worker void* const dst __attribute__((pass_object_size(0))), 177*8d67ca89SAndroid Build Coastguard Worker const void* src, 178*8d67ca89SAndroid Build Coastguard Worker size_t copy_amount) 179*8d67ca89SAndroid Build Coastguard Worker __attribute__((overloadable)) 180*8d67ca89SAndroid Build Coastguard Worker __attribute__((diagnose_if( 181*8d67ca89SAndroid Build Coastguard Worker __builtin_object_size(dst, 0) != -1 && __builtin_object_size(dst, 0) <= copy_amount), 182*8d67ca89SAndroid Build Coastguard Worker "'mempcpy' called with size bigger than buffer"))) { 183*8d67ca89SAndroid Build Coastguard Worker#if __BIONIC_FORTIFY_RUNTIME_CHECKS_ENABLED 184*8d67ca89SAndroid Build Coastguard Worker size_t bos_dst = __builtin_object_size(dst, 0); 185*8d67ca89SAndroid Build Coastguard Worker if (!(__bos_trivially_ge(bos_dst, copy_amount))) { 186*8d67ca89SAndroid Build Coastguard Worker return __builtin___mempcpy_chk(dst, src, copy_amount, bos_dst); 187*8d67ca89SAndroid Build Coastguard Worker } 188*8d67ca89SAndroid Build Coastguard Worker#endif 189*8d67ca89SAndroid Build Coastguard Worker return __builtin_mempcpy(dst, src, copy_amount); 190*8d67ca89SAndroid Build Coastguard Worker} 191*8d67ca89SAndroid Build Coastguard Worker``` 192*8d67ca89SAndroid Build Coastguard Worker 193*8d67ca89SAndroid Build Coastguard WorkerSo let's walk through this step by step, to see how FORTIFY does what it says on 194*8d67ca89SAndroid Build Coastguard Workerthe tin here. 195*8d67ca89SAndroid Build Coastguard Worker 196*8d67ca89SAndroid Build Coastguard Worker[^1]: "Zero overhead" in a way [similar to C++11's `std::unique_ptr`]: this will 197*8d67ca89SAndroid Build Coastguard Workerturn into a direct call `__builtin_mempcpy` (or an optimized form thereof) with 198*8d67ca89SAndroid Build Coastguard Workerno other surrounding checks at runtime. However, the additional complexity may 199*8d67ca89SAndroid Build Coastguard Workerhinder optimizations that are performed before the optimizer can prove that the 200*8d67ca89SAndroid Build Coastguard Worker`if (...) { ... }` can be optimized out. Depending on how late this happens, 201*8d67ca89SAndroid Build Coastguard Workerthe additional complexity may skew inlining costs, hide opportunities for e.g., 202*8d67ca89SAndroid Build Coastguard Worker`memcpy` coalescing, etc etc. 203*8d67ca89SAndroid Build Coastguard Worker 204*8d67ca89SAndroid Build Coastguard Worker### How does Clang select `mempcpy`? 205*8d67ca89SAndroid Build Coastguard Worker 206*8d67ca89SAndroid Build Coastguard WorkerFirst, it's critical to notice that `mempcpy` is marked `overloadable`. This 207*8d67ca89SAndroid Build Coastguard Workerfunction is a `static inline __attribute__((always_inline))` overload of 208*8d67ca89SAndroid Build Coastguard Worker`__builtin_mempcpy`: 209*8d67ca89SAndroid Build Coastguard Worker- `__attribute__((overloadable))` allows us to perform overloading in C. 210*8d67ca89SAndroid Build Coastguard Worker- `__attribute__((overloadable))` mangles all calls to functions marked with 211*8d67ca89SAndroid Build Coastguard Worker `__attribute__((overloadable))`. 212*8d67ca89SAndroid Build Coastguard Worker- `__attribute__((overloadable))` allows exactly one function signature with a 213*8d67ca89SAndroid Build Coastguard Worker given name to not be marked with `__attribute__((overloadable))`. Calls to 214*8d67ca89SAndroid Build Coastguard Worker this overload will not be mangled. 215*8d67ca89SAndroid Build Coastguard Worker 216*8d67ca89SAndroid Build Coastguard WorkerSecond, one might note that this `mempcpy` implementation has the same C-level 217*8d67ca89SAndroid Build Coastguard Workersignature as `__builtin_mempcpy`. `pass_object_size` is a Clang attribute that 218*8d67ca89SAndroid Build Coastguard Workeris generally needed by FORTIFY, but it carries the side-effect that functions 219*8d67ca89SAndroid Build Coastguard Workermay be overloaded simply on the presence (or lack of presence) of 220*8d67ca89SAndroid Build Coastguard Worker`pass_object_size` attributes. Given two overloads of a function that only 221*8d67ca89SAndroid Build Coastguard Workerdiffer on the presence of `pass_object_size` attributes, the candidate with 222*8d67ca89SAndroid Build Coastguard Worker`pass_object_size` attributes is preferred. 223*8d67ca89SAndroid Build Coastguard Worker 224*8d67ca89SAndroid Build Coastguard WorkerFinally, the prior paragraph gets thrown out if one tries to take the address of 225*8d67ca89SAndroid Build Coastguard Worker`mempcpy`. It is impossible to take the address of a function with one or more 226*8d67ca89SAndroid Build Coastguard Workerparameters that are annotated with `pass_object_size`. Hence, 227*8d67ca89SAndroid Build Coastguard Worker`&__builtin_mempcpy == &mempcpy`. Further, because this is an issue of overload 228*8d67ca89SAndroid Build Coastguard Workerresolution, `(&mempcpy)(x, y, z);` is functionally identical to 229*8d67ca89SAndroid Build Coastguard Worker`__builtin_mempcpy(x, y, z);`. 230*8d67ca89SAndroid Build Coastguard Worker 231*8d67ca89SAndroid Build Coastguard WorkerAll of this accomplishes the following: 232*8d67ca89SAndroid Build Coastguard Worker- Direct calls to `mempcpy` should call the FORTIFY-protected `mempcpy`. 233*8d67ca89SAndroid Build Coastguard Worker- Indirect calls to `&mempcpy` should call `__builtin_mempcpy`. 234*8d67ca89SAndroid Build Coastguard Worker 235*8d67ca89SAndroid Build Coastguard Worker### How does Clang offer compile-time diagnostics? 236*8d67ca89SAndroid Build Coastguard Worker 237*8d67ca89SAndroid Build Coastguard WorkerOnce one is convinced that the FORTIFY-enabled overload of `mempcpy` will be 238*8d67ca89SAndroid Build Coastguard Workerselected for direct calls, Clang's `diagnose_if` and `__builtin_object_size` do 239*8d67ca89SAndroid Build Coastguard Workerall of the work from there. 240*8d67ca89SAndroid Build Coastguard Worker 241*8d67ca89SAndroid Build Coastguard WorkerSubtleties here primarily fall out of the discussion in the above section about 242*8d67ca89SAndroid Build Coastguard Worker`&__builtin_mempcpy == &mempcpy`: 243*8d67ca89SAndroid Build Coastguard Worker```c 244*8d67ca89SAndroid Build Coastguard Worker#define _FORTIFY_SOURCE 2 245*8d67ca89SAndroid Build Coastguard Worker#include <string.h> 246*8d67ca89SAndroid Build Coastguard Workervoid example_code() { 247*8d67ca89SAndroid Build Coastguard Worker char buf[4]; // ...Assume sizeof(char) == 1. 248*8d67ca89SAndroid Build Coastguard Worker const char input_buf[] = "Hello, World"; 249*8d67ca89SAndroid Build Coastguard Worker mempcpy(buf, input_buf, 4); // Valid, no diagnostic issued. 250*8d67ca89SAndroid Build Coastguard Worker 251*8d67ca89SAndroid Build Coastguard Worker mempcpy(buf, input_buf, 5); // Emits a compile-time error since sizeof(buf) < 5. 252*8d67ca89SAndroid Build Coastguard Worker __builtin_mempcpy(buf, input_buf, 5); // No compile-time error. 253*8d67ca89SAndroid Build Coastguard Worker (&mempcpy)(buf, input_buf, 5); // No compile-time error, since __builtin_mempcpy is selected. 254*8d67ca89SAndroid Build Coastguard Worker} 255*8d67ca89SAndroid Build Coastguard Worker``` 256*8d67ca89SAndroid Build Coastguard Worker 257*8d67ca89SAndroid Build Coastguard WorkerOtherwise, the rest of this subsection is dedicated to preliminary discussion 258*8d67ca89SAndroid Build Coastguard Workerabout `__builtin_object_size`. 259*8d67ca89SAndroid Build Coastguard Worker 260*8d67ca89SAndroid Build Coastguard WorkerClang's frontend can do one of two things with `__builtin_object_size(p, n)`: 261*8d67ca89SAndroid Build Coastguard Worker- Evaluate it as a constant. 262*8d67ca89SAndroid Build Coastguard Worker - This can either mean declaring that the number of bytes at `p` is definitely 263*8d67ca89SAndroid Build Coastguard Worker impossible to know, so the default value is used, or the number of bytes at 264*8d67ca89SAndroid Build Coastguard Worker `p` can be known without optimizations. 265*8d67ca89SAndroid Build Coastguard Worker- Declare that the expression cannot form a constant, and lower it to 266*8d67ca89SAndroid Build Coastguard Worker `@llvm.objectsize`, which is discussed in depth later. 267*8d67ca89SAndroid Build Coastguard Worker 268*8d67ca89SAndroid Build Coastguard WorkerIn the examples above, since `diagnose_if` is evaluated with context from the 269*8d67ca89SAndroid Build Coastguard Workercaller, Clang should be able to trivially determine that `buf` refers to a 270*8d67ca89SAndroid Build Coastguard Worker`char` array with 4 elements. 271*8d67ca89SAndroid Build Coastguard Worker 272*8d67ca89SAndroid Build Coastguard WorkerThe primary consequence of the above is that diagnostics can only be emitted if 273*8d67ca89SAndroid Build Coastguard Workerno optimizations are required to detect a broken code pattern. To be specific, 274*8d67ca89SAndroid Build Coastguard Workerclang's constexpr evaluator must be able to determine the logical object that 275*8d67ca89SAndroid Build Coastguard Workerany given pointer points to in order to fold `__builtin_object_size` to a 276*8d67ca89SAndroid Build Coastguard Workerconstant, non-default answer: 277*8d67ca89SAndroid Build Coastguard Worker 278*8d67ca89SAndroid Build Coastguard Worker```c 279*8d67ca89SAndroid Build Coastguard Worker#define _FORTIFY_SOURCE 2 280*8d67ca89SAndroid Build Coastguard Worker#include <string.h> 281*8d67ca89SAndroid Build Coastguard Workervoid example_code() { 282*8d67ca89SAndroid Build Coastguard Worker char buf[4]; // ...Assume sizeof(char) == 1. 283*8d67ca89SAndroid Build Coastguard Worker const char input_buf[] = "Hello, World"; 284*8d67ca89SAndroid Build Coastguard Worker mempcpy(buf, input_buf, 4); // Valid, no diagnostic issued. 285*8d67ca89SAndroid Build Coastguard Worker mempcpy(buf, input_buf, 5); // Emits a compile-time error since sizeof(buf) < 5. 286*8d67ca89SAndroid Build Coastguard Worker char *buf_ptr = buf; 287*8d67ca89SAndroid Build Coastguard Worker mempcpy(buf_ptr, input_buf, 5); // No compile-time error; `buf_ptr`'s target can't be determined. 288*8d67ca89SAndroid Build Coastguard Worker} 289*8d67ca89SAndroid Build Coastguard Worker``` 290*8d67ca89SAndroid Build Coastguard Worker 291*8d67ca89SAndroid Build Coastguard Worker### How does Clang insert run-time checks? 292*8d67ca89SAndroid Build Coastguard Worker 293*8d67ca89SAndroid Build Coastguard WorkerThis section expands on the following statement: FORTIFY has zero runtime cost 294*8d67ca89SAndroid Build Coastguard Workerin instances where there is no chance of catching a bug at run-time. Otherwise, 295*8d67ca89SAndroid Build Coastguard Workerit introduces a tiny additional run-time cost to ensure that functions aren't 296*8d67ca89SAndroid Build Coastguard Workermisused. 297*8d67ca89SAndroid Build Coastguard Worker 298*8d67ca89SAndroid Build Coastguard WorkerIn prior sections, the following was established: 299*8d67ca89SAndroid Build Coastguard Worker- `overloadable` and `pass_object_size` prompt Clang to always select this 300*8d67ca89SAndroid Build Coastguard Worker overload of `mempcpy` over `__builtin_mempcpy` for direct calls. 301*8d67ca89SAndroid Build Coastguard Worker- If a call to `mempcpy` was trivially broken, Clang would produce a 302*8d67ca89SAndroid Build Coastguard Worker compile-time error, rather than producing a binary. 303*8d67ca89SAndroid Build Coastguard Worker 304*8d67ca89SAndroid Build Coastguard WorkerHence, the case we're interested in here is one where Clang's frontend selected 305*8d67ca89SAndroid Build Coastguard Workera FORTIFY'ed function's implementation for a function call, but was unable to 306*8d67ca89SAndroid Build Coastguard Workerfind anything seriously wrong with said function call. Since the frontend is 307*8d67ca89SAndroid Build Coastguard Workerpowerless to detect bugs at this point, our focus shifts to the mechanisms that 308*8d67ca89SAndroid Build Coastguard WorkerLLVM uses to support FORTIFY. 309*8d67ca89SAndroid Build Coastguard Worker 310*8d67ca89SAndroid Build Coastguard WorkerGoing back to Bionic's `mempcpy` implementation, we have the following (ignoring 311*8d67ca89SAndroid Build Coastguard Workerdiagnose_if and assuming run-time checks are enabled): 312*8d67ca89SAndroid Build Coastguard Worker```c 313*8d67ca89SAndroid Build Coastguard Workerstatic 314*8d67ca89SAndroid Build Coastguard Worker__inline__ 315*8d67ca89SAndroid Build Coastguard Worker__attribute__((no_stack_protector)) 316*8d67ca89SAndroid Build Coastguard Worker__attribute__((always_inline)) 317*8d67ca89SAndroid Build Coastguard Workervoid* mempcpy( 318*8d67ca89SAndroid Build Coastguard Worker void* const dst __attribute__((pass_object_size(0))), 319*8d67ca89SAndroid Build Coastguard Worker const void* src, 320*8d67ca89SAndroid Build Coastguard Worker size_t copy_amount) 321*8d67ca89SAndroid Build Coastguard Worker __attribute__((overloadable)) { 322*8d67ca89SAndroid Build Coastguard Worker size_t bos_dst = __builtin_object_size(dst, 0); 323*8d67ca89SAndroid Build Coastguard Worker if (bos_dst != -1 && 324*8d67ca89SAndroid Build Coastguard Worker !(__builtin_constant_p(copy_amount) && bos_dst >= copy_amount)) { 325*8d67ca89SAndroid Build Coastguard Worker return __builtin___mempcpy_chk(dst, src, copy_amount, bos_dst); 326*8d67ca89SAndroid Build Coastguard Worker } 327*8d67ca89SAndroid Build Coastguard Worker return __builtin_mempcpy(dst, src, copy_amount); 328*8d67ca89SAndroid Build Coastguard Worker} 329*8d67ca89SAndroid Build Coastguard Worker``` 330*8d67ca89SAndroid Build Coastguard Worker 331*8d67ca89SAndroid Build Coastguard WorkerIn other words, we have a `static`, `always_inline` function which: 332*8d67ca89SAndroid Build Coastguard Worker- If `__builtin_object_size(dst, 0)` cannot be determined (in which case, it 333*8d67ca89SAndroid Build Coastguard Worker returns -1), calls `__builtin_mempcpy`. 334*8d67ca89SAndroid Build Coastguard Worker- Otherwise, if `copy_amount` can be folded to a constant, and if 335*8d67ca89SAndroid Build Coastguard Worker `__builtin_object_size(dst, 0) >= copy_amount`, calls `__builtin_mempcpy`. 336*8d67ca89SAndroid Build Coastguard Worker- Otherwise, calls `__builtin___mempcpy_chk`. 337*8d67ca89SAndroid Build Coastguard Worker 338*8d67ca89SAndroid Build Coastguard Worker 339*8d67ca89SAndroid Build Coastguard WorkerHow can this be "zero overhead"? Let's focus on the following part of the 340*8d67ca89SAndroid Build Coastguard Workerfunction: 341*8d67ca89SAndroid Build Coastguard Worker 342*8d67ca89SAndroid Build Coastguard Worker```c 343*8d67ca89SAndroid Build Coastguard Worker size_t bos_dst = __builtin_object_size(dst, 0); 344*8d67ca89SAndroid Build Coastguard Worker if (bos_dst != -1 && 345*8d67ca89SAndroid Build Coastguard Worker !(__builtin_constant_p(copy_amount) && bos_dst >= copy_amount)) { 346*8d67ca89SAndroid Build Coastguard Worker``` 347*8d67ca89SAndroid Build Coastguard Worker 348*8d67ca89SAndroid Build Coastguard WorkerIf Clang's frontend cannot determine a value for `__builtin_object_size`, Clang 349*8d67ca89SAndroid Build Coastguard Workerlowers it to LLVM's `@llvm.objectsize` intrinsic. The `@llvm.objectsize` 350*8d67ca89SAndroid Build Coastguard Workerinvocation corresponding to `__builtin_object_size(p, 0)` is guaranteed to 351*8d67ca89SAndroid Build Coastguard Workeralways fold to a constant value by the time LLVM emits machine code. 352*8d67ca89SAndroid Build Coastguard Worker 353*8d67ca89SAndroid Build Coastguard WorkerHence, `bos_dst` is guaranteed to be a constant; if it's -1, the above branch 354*8d67ca89SAndroid Build Coastguard Workercan be eliminated entirely, since it folds to `if (false && ...)`. Further, the 355*8d67ca89SAndroid Build Coastguard WorkerRHS of the `&&` in this branch has us call `__builtin_mempcpy` if `copy_amount` 356*8d67ca89SAndroid Build Coastguard Workeris a known value less than `bos_dst` (yet another constant value). Therefore, 357*8d67ca89SAndroid Build Coastguard Workerthe entire condition is always knowable when LLVM is done with LLVM IR-level 358*8d67ca89SAndroid Build Coastguard Workeroptimizations, so no condition is ever emitted to machine code in practice. 359*8d67ca89SAndroid Build Coastguard Worker 360*8d67ca89SAndroid Build Coastguard Worker#### Why is "zero overhead" in quotes? Why is `unique_ptr` relevant? 361*8d67ca89SAndroid Build Coastguard Worker 362*8d67ca89SAndroid Build Coastguard Worker`__builtin_object_size` and `__builtin_constant_p` are forced to be constants 363*8d67ca89SAndroid Build Coastguard Workerafter most optimizations take place. Until LLVM replaces both of these with 364*8d67ca89SAndroid Build Coastguard Workerconstants and optimizes them out, we have additional branches and function calls 365*8d67ca89SAndroid Build Coastguard Workerin our IR. This can have negative effects, such as distorting inlining costs and 366*8d67ca89SAndroid Build Coastguard Workerinhibiting optimizations that are conservative around branches in control-flow. 367*8d67ca89SAndroid Build Coastguard Worker 368*8d67ca89SAndroid Build Coastguard WorkerSo FORTIFY is free in these cases _in isolation of any of the code around it_. 369*8d67ca89SAndroid Build Coastguard WorkerDue to its implementation, it may impact the optimizations that occur on code 370*8d67ca89SAndroid Build Coastguard Workeraround the literal call to the FORTIFY-hardened libc function. 371*8d67ca89SAndroid Build Coastguard Worker 372*8d67ca89SAndroid Build Coastguard Worker`unique_ptr` was just the first thing that came to the author's mind for "the 373*8d67ca89SAndroid Build Coastguard Workertype should be zero cost with any level of optimization enabled, but edge-cases 374*8d67ca89SAndroid Build Coastguard Workermight make it only-mostly-free to use." 375*8d67ca89SAndroid Build Coastguard Worker 376*8d67ca89SAndroid Build Coastguard Worker### How is checking actually performed? 377*8d67ca89SAndroid Build Coastguard Worker 378*8d67ca89SAndroid Build Coastguard WorkerIn cases where checking can be performed (e.g., where we call 379*8d67ca89SAndroid Build Coastguard Worker`__builtin___mempcpy_chk(dst, src, copy_amount, bos_dst);`), Bionic provides [an 380*8d67ca89SAndroid Build Coastguard Workerimplementation for `__mempcpy_chk`]. This is: 381*8d67ca89SAndroid Build Coastguard Worker 382*8d67ca89SAndroid Build Coastguard Worker```c 383*8d67ca89SAndroid Build Coastguard Workerextern "C" void* __mempcpy_chk(void* dst, const void* src, size_t count, size_t dst_len) { 384*8d67ca89SAndroid Build Coastguard Worker __check_count("mempcpy", "count", count); 385*8d67ca89SAndroid Build Coastguard Worker __check_buffer_access("mempcpy", "write into", count, dst_len); 386*8d67ca89SAndroid Build Coastguard Worker return mempcpy(dst, src, count); 387*8d67ca89SAndroid Build Coastguard Worker} 388*8d67ca89SAndroid Build Coastguard Worker``` 389*8d67ca89SAndroid Build Coastguard WorkerThis function itself boils down to a few small branches which abort the program 390*8d67ca89SAndroid Build Coastguard Workerif they fail, and a direct call to `__builtin_mempcpy`. 391*8d67ca89SAndroid Build Coastguard Worker 392*8d67ca89SAndroid Build Coastguard Worker### Wrapping up 393*8d67ca89SAndroid Build Coastguard Worker 394*8d67ca89SAndroid Build Coastguard WorkerIn the above breakdown, it was shown how Clang and Bionic work together to: 395*8d67ca89SAndroid Build Coastguard Worker- represent FORTIFY-hardened overloads of functions, 396*8d67ca89SAndroid Build Coastguard Worker- report misuses of stdlib functions at compile-time, and 397*8d67ca89SAndroid Build Coastguard Worker- insert run-time checks for uses of functions that might be incorrect, but only 398*8d67ca89SAndroid Build Coastguard Worker if we have the potential of proving the incorrectness of these. 399*8d67ca89SAndroid Build Coastguard Worker 400*8d67ca89SAndroid Build Coastguard Worker## Breakdown of open 401*8d67ca89SAndroid Build Coastguard Worker 402*8d67ca89SAndroid Build Coastguard WorkerIn Bionic, the [FORTIFY'ed implementation of `open`] is quite large. Much like 403*8d67ca89SAndroid Build Coastguard Worker`mempcpy`, the `__builtin_open` declaration is simple: 404*8d67ca89SAndroid Build Coastguard Worker 405*8d67ca89SAndroid Build Coastguard Worker```c 406*8d67ca89SAndroid Build Coastguard Workerint open(const char* __path, int __flags, ...); 407*8d67ca89SAndroid Build Coastguard Worker``` 408*8d67ca89SAndroid Build Coastguard Worker 409*8d67ca89SAndroid Build Coastguard WorkerWith some macros expanded, the FORTIFY-hardened header implementation is: 410*8d67ca89SAndroid Build Coastguard Worker```c 411*8d67ca89SAndroid Build Coastguard Workerint __open_2(const char*, int); 412*8d67ca89SAndroid Build Coastguard Workerint __open_real(const char*, int, ...) __asm__(open); 413*8d67ca89SAndroid Build Coastguard Worker 414*8d67ca89SAndroid Build Coastguard Worker#define __open_modes_useful(flags) (((flags) & O_CREAT) || ((flags) & O_TMPFILE) == O_TMPFILE) 415*8d67ca89SAndroid Build Coastguard Worker 416*8d67ca89SAndroid Build Coastguard Workerstatic 417*8d67ca89SAndroid Build Coastguard Workerint open(const char* pathname, int flags, mode_t modes, ...) __overloadable 418*8d67ca89SAndroid Build Coastguard Worker __attribute__((diagnose_if(1, "error", "too many arguments"))); 419*8d67ca89SAndroid Build Coastguard Worker 420*8d67ca89SAndroid Build Coastguard Workerstatic 421*8d67ca89SAndroid Build Coastguard Worker__inline__ 422*8d67ca89SAndroid Build Coastguard Worker__attribute__((no_stack_protector)) 423*8d67ca89SAndroid Build Coastguard Worker__attribute__((always_inline)) 424*8d67ca89SAndroid Build Coastguard Workerint open(const char* const __attribute__((pass_object_size(1))) pathname, int flags) 425*8d67ca89SAndroid Build Coastguard Worker __attribute__((overloadable)) 426*8d67ca89SAndroid Build Coastguard Worker __attribute__((diagnose_if( 427*8d67ca89SAndroid Build Coastguard Worker __open_modes_useful(flags), 428*8d67ca89SAndroid Build Coastguard Worker "error", 429*8d67ca89SAndroid Build Coastguard Worker "'open' called with O_CREAT or O_TMPFILE, but missing mode"))) { 430*8d67ca89SAndroid Build Coastguard Worker#if __ANDROID_API__ >= 17 && __BIONIC_FORTIFY_RUNTIME_CHECKS_ENABLED 431*8d67ca89SAndroid Build Coastguard Worker return __open_2(pathname, flags); 432*8d67ca89SAndroid Build Coastguard Worker#else 433*8d67ca89SAndroid Build Coastguard Worker return __open_real(pathname, flags); 434*8d67ca89SAndroid Build Coastguard Worker#endif 435*8d67ca89SAndroid Build Coastguard Worker} 436*8d67ca89SAndroid Build Coastguard Workerstatic 437*8d67ca89SAndroid Build Coastguard Worker__inline__ 438*8d67ca89SAndroid Build Coastguard Worker__attribute__((no_stack_protector)) 439*8d67ca89SAndroid Build Coastguard Worker__attribute__((always_inline)) 440*8d67ca89SAndroid Build Coastguard Workerint open(const char* const __attribute__((pass_object_size(1))) pathname, int flags, mode_t modes) 441*8d67ca89SAndroid Build Coastguard Worker __attribute__((overloadable)) 442*8d67ca89SAndroid Build Coastguard Worker __clang_warning_if(!__open_modes_useful(flags) && modes, 443*8d67ca89SAndroid Build Coastguard Worker "'open' has superfluous mode bits; missing O_CREAT?") { 444*8d67ca89SAndroid Build Coastguard Worker return __open_real(pathname, flags, modes); 445*8d67ca89SAndroid Build Coastguard Worker} 446*8d67ca89SAndroid Build Coastguard Worker``` 447*8d67ca89SAndroid Build Coastguard Worker 448*8d67ca89SAndroid Build Coastguard WorkerWhich may be a lot to take in. 449*8d67ca89SAndroid Build Coastguard Worker 450*8d67ca89SAndroid Build Coastguard WorkerBefore diving too deeply, please note that the remainder of these subsections 451*8d67ca89SAndroid Build Coastguard Workerassume that the programmer didn't make any egregious typos. Moreover, there's no 452*8d67ca89SAndroid Build Coastguard Workerreal way that Bionic tries to prevent calls to `open` like 453*8d67ca89SAndroid Build Coastguard Worker`open("foo", 0, "how do you convert a const char[N] to mode_t?");`. The only 454*8d67ca89SAndroid Build Coastguard Workerreal C-compatible solution the author can think of is "stamp out many overloads 455*8d67ca89SAndroid Build Coastguard Workerto catch sort-of-common instances of this very uncommon typo." This isn't great. 456*8d67ca89SAndroid Build Coastguard Worker 457*8d67ca89SAndroid Build Coastguard WorkerMore directly, no effort is made below to recognize calls that, due to 458*8d67ca89SAndroid Build Coastguard Workerincompatible argument types, cannot go to any `open` implementation other than 459*8d67ca89SAndroid Build Coastguard Worker`__builtin_open`, since it's recognized right here. :) 460*8d67ca89SAndroid Build Coastguard Worker 461*8d67ca89SAndroid Build Coastguard Worker### Implementation breakdown 462*8d67ca89SAndroid Build Coastguard Worker 463*8d67ca89SAndroid Build Coastguard WorkerThis `open` implementation does a few things: 464*8d67ca89SAndroid Build Coastguard Worker- Turns calls to `open` with too many arguments into a compile-time error. 465*8d67ca89SAndroid Build Coastguard Worker- Diagnoses calls to `open` with missing modes at compile-time and run-time 466*8d67ca89SAndroid Build Coastguard Worker (both cases turn into errors). 467*8d67ca89SAndroid Build Coastguard Worker- Emits warnings on calls to `open` with useless mode bits, unless the mode bits 468*8d67ca89SAndroid Build Coastguard Worker are all 0. 469*8d67ca89SAndroid Build Coastguard Worker 470*8d67ca89SAndroid Build Coastguard WorkerOne common bit of code not explained below is the `__open_real` declaration above: 471*8d67ca89SAndroid Build Coastguard Worker```c 472*8d67ca89SAndroid Build Coastguard Workerint __open_real(const char*, int, ...) __asm__(open); 473*8d67ca89SAndroid Build Coastguard Worker``` 474*8d67ca89SAndroid Build Coastguard Worker 475*8d67ca89SAndroid Build Coastguard WorkerThis exists as a way for us to call `__builtin_open` without needing clang to 476*8d67ca89SAndroid Build Coastguard Workerhave a pre-defined `__builtin_open` function. 477*8d67ca89SAndroid Build Coastguard Worker 478*8d67ca89SAndroid Build Coastguard Worker#### Compile-time error on too many arguments 479*8d67ca89SAndroid Build Coastguard Worker 480*8d67ca89SAndroid Build Coastguard Worker```c 481*8d67ca89SAndroid Build Coastguard Workerstatic 482*8d67ca89SAndroid Build Coastguard Workerint open(const char* pathname, int flags, mode_t modes, ...) __overloadable 483*8d67ca89SAndroid Build Coastguard Worker __attribute__((diagnose_if(1, "error", "too many arguments"))); 484*8d67ca89SAndroid Build Coastguard Worker``` 485*8d67ca89SAndroid Build Coastguard Worker 486*8d67ca89SAndroid Build Coastguard WorkerWhich matches most calls to open that supply too many arguments, since 487*8d67ca89SAndroid Build Coastguard Worker`int(const char *, int, ...)` matches less strongly than 488*8d67ca89SAndroid Build Coastguard Worker`int(const char *, int, mode_t, ...)` for calls where the 3rd arg can be 489*8d67ca89SAndroid Build Coastguard Workerconverted to `mode_t` without too much effort. Because of the `diagnose_if` 490*8d67ca89SAndroid Build Coastguard Workerattribute, all of these calls turn into compile-time errors. 491*8d67ca89SAndroid Build Coastguard Worker 492*8d67ca89SAndroid Build Coastguard Worker#### Compile-time or run-time error on missing arguments 493*8d67ca89SAndroid Build Coastguard WorkerThe following overload handles all two-argument calls to `open`. 494*8d67ca89SAndroid Build Coastguard Worker```c 495*8d67ca89SAndroid Build Coastguard Workerstatic 496*8d67ca89SAndroid Build Coastguard Worker__inline__ 497*8d67ca89SAndroid Build Coastguard Worker__attribute__((no_stack_protector)) 498*8d67ca89SAndroid Build Coastguard Worker__attribute__((always_inline)) 499*8d67ca89SAndroid Build Coastguard Workerint open(const char* const __attribute__((pass_object_size(1))) pathname, int flags) 500*8d67ca89SAndroid Build Coastguard Worker __attribute__((overloadable)) 501*8d67ca89SAndroid Build Coastguard Worker __attribute__((diagnose_if( 502*8d67ca89SAndroid Build Coastguard Worker __open_modes_useful(flags), 503*8d67ca89SAndroid Build Coastguard Worker "error", 504*8d67ca89SAndroid Build Coastguard Worker "'open' called with O_CREAT or O_TMPFILE, but missing mode"))) { 505*8d67ca89SAndroid Build Coastguard Worker#if __ANDROID_API__ >= 17 && __BIONIC_FORTIFY_RUNTIME_CHECKS_ENABLED 506*8d67ca89SAndroid Build Coastguard Worker return __open_2(pathname, flags); 507*8d67ca89SAndroid Build Coastguard Worker#else 508*8d67ca89SAndroid Build Coastguard Worker return __open_real(pathname, flags); 509*8d67ca89SAndroid Build Coastguard Worker#endif 510*8d67ca89SAndroid Build Coastguard Worker} 511*8d67ca89SAndroid Build Coastguard Worker``` 512*8d67ca89SAndroid Build Coastguard Worker 513*8d67ca89SAndroid Build Coastguard WorkerLike `mempcpy`, `diagnose_if` handles emitting a compile-time error if the call 514*8d67ca89SAndroid Build Coastguard Workerto `open` is broken in a way that's visible to Clang's frontend. This 515*8d67ca89SAndroid Build Coastguard Workeressentially boils down to "`open` is being called with a `flags` value that 516*8d67ca89SAndroid Build Coastguard Workerrequires mode bits to be set." 517*8d67ca89SAndroid Build Coastguard Worker 518*8d67ca89SAndroid Build Coastguard WorkerIf that fails to catch a bug, we [unconditionally call `__open_2`], which 519*8d67ca89SAndroid Build Coastguard Workerperforms a run-time check: 520*8d67ca89SAndroid Build Coastguard Worker```c 521*8d67ca89SAndroid Build Coastguard Workerint __open_2(const char* pathname, int flags) { 522*8d67ca89SAndroid Build Coastguard Worker if (needs_mode(flags)) __fortify_fatal("open: called with O_CREAT/O_TMPFILE but no mode"); 523*8d67ca89SAndroid Build Coastguard Worker return FDTRACK_CREATE_NAME("open", __openat(AT_FDCWD, pathname, force_O_LARGEFILE(flags), 0)); 524*8d67ca89SAndroid Build Coastguard Worker} 525*8d67ca89SAndroid Build Coastguard Worker``` 526*8d67ca89SAndroid Build Coastguard Worker 527*8d67ca89SAndroid Build Coastguard Worker#### Compile-time warning if modes are pointless 528*8d67ca89SAndroid Build Coastguard Worker 529*8d67ca89SAndroid Build Coastguard WorkerFinally, we have the following `open` call: 530*8d67ca89SAndroid Build Coastguard Worker```c 531*8d67ca89SAndroid Build Coastguard Workerstatic 532*8d67ca89SAndroid Build Coastguard Worker__inline__ 533*8d67ca89SAndroid Build Coastguard Worker__attribute__((no_stack_protector)) 534*8d67ca89SAndroid Build Coastguard Worker__attribute__((always_inline)) 535*8d67ca89SAndroid Build Coastguard Workerint open(const char* const __attribute__((pass_object_size(1))) pathname, int flags, mode_t modes) 536*8d67ca89SAndroid Build Coastguard Worker __attribute__((overloadable)) 537*8d67ca89SAndroid Build Coastguard Worker __clang_warning_if(!__open_modes_useful(flags) && modes, 538*8d67ca89SAndroid Build Coastguard Worker "'open' has superfluous mode bits; missing O_CREAT?") { 539*8d67ca89SAndroid Build Coastguard Worker return __open_real(pathname, flags, modes); 540*8d67ca89SAndroid Build Coastguard Worker} 541*8d67ca89SAndroid Build Coastguard Worker``` 542*8d67ca89SAndroid Build Coastguard Worker 543*8d67ca89SAndroid Build Coastguard WorkerThis simply issues a warning if Clang's frontend can determine that `flags` 544*8d67ca89SAndroid Build Coastguard Workerisn't necessary. Due to conventions in existing code, a `modes` value of `0` is 545*8d67ca89SAndroid Build Coastguard Workernot diagnosed. 546*8d67ca89SAndroid Build Coastguard Worker 547*8d67ca89SAndroid Build Coastguard Worker#### What about `&open`? 548*8d67ca89SAndroid Build Coastguard WorkerOne yet-unaddressed aspect of the above is how `&open` works. This is thankfully 549*8d67ca89SAndroid Build Coastguard Workera short answer: 550*8d67ca89SAndroid Build Coastguard Worker- It happens that `open` takes a parameter of type `const char*`. 551*8d67ca89SAndroid Build Coastguard Worker- It happens that `pass_object_size` -- an attribute only applicable to 552*8d67ca89SAndroid Build Coastguard Worker parameters of type `T*` -- makes it impossible to take the address of a 553*8d67ca89SAndroid Build Coastguard Worker function. 554*8d67ca89SAndroid Build Coastguard Worker 555*8d67ca89SAndroid Build Coastguard WorkerSince clang doesn't support a "this function should never have its address 556*8d67ca89SAndroid Build Coastguard Workertaken," attribute, Bionic uses the next best thing: `pass_object_size`. :) 557*8d67ca89SAndroid Build Coastguard Worker 558*8d67ca89SAndroid Build Coastguard Worker## Breakdown of poll 559*8d67ca89SAndroid Build Coastguard Worker 560*8d67ca89SAndroid Build Coastguard Worker(Preemptively: at the time of writing, Clang has no literal `__builtin_poll` 561*8d67ca89SAndroid Build Coastguard Workerbuiltin. `__builtin_poll` is referenced below to remain consistent with the 562*8d67ca89SAndroid Build Coastguard Workerconvention established in the Terminology section.) 563*8d67ca89SAndroid Build Coastguard Worker 564*8d67ca89SAndroid Build Coastguard WorkerBionic's `poll` implementation is closest to `mempcpy` above, though it has a 565*8d67ca89SAndroid Build Coastguard Workerfew interesting aspects worth examining. 566*8d67ca89SAndroid Build Coastguard Worker 567*8d67ca89SAndroid Build Coastguard WorkerThe [full header implementation of `poll`] is, with some macros expanded: 568*8d67ca89SAndroid Build Coastguard Worker```c 569*8d67ca89SAndroid Build Coastguard Worker#define __bos_fd_count_trivially_safe(bos_val, fds, fd_count) \ 570*8d67ca89SAndroid Build Coastguard Worker ((bos_val) == -1) || \ 571*8d67ca89SAndroid Build Coastguard Worker (__builtin_constant_p(fd_count) && \ 572*8d67ca89SAndroid Build Coastguard Worker (bos_val) >= sizeof(*fds) * (fd_count))) 573*8d67ca89SAndroid Build Coastguard Worker 574*8d67ca89SAndroid Build Coastguard Workerstatic 575*8d67ca89SAndroid Build Coastguard Worker__inline__ 576*8d67ca89SAndroid Build Coastguard Worker__attribute__((no_stack_protector)) 577*8d67ca89SAndroid Build Coastguard Worker__attribute__((always_inline)) 578*8d67ca89SAndroid Build Coastguard Workerint poll(struct pollfd* const fds __attribute__((pass_object_size(1))), nfds_t fd_count, int timeout) 579*8d67ca89SAndroid Build Coastguard Worker __attribute__((overloadable)) 580*8d67ca89SAndroid Build Coastguard Worker __attriubte__((diagnose_if( 581*8d67ca89SAndroid Build Coastguard Worker __builtin_object_size(fds, 1) != -1 && __builtin_object_size(fds, 1) < sizeof(*fds) * fd_count, 582*8d67ca89SAndroid Build Coastguard Worker "error", 583*8d67ca89SAndroid Build Coastguard Worker "in call to 'poll', fd_count is larger than the given buffer"))) { 584*8d67ca89SAndroid Build Coastguard Worker size_t bos_fds = __builtin_object_size(fds, 1); 585*8d67ca89SAndroid Build Coastguard Worker if (!__bos_fd_count_trivially_safe(bos_fds, fds, fd_count)) { 586*8d67ca89SAndroid Build Coastguard Worker return __poll_chk(fds, fd_count, timeout, bos_fds); 587*8d67ca89SAndroid Build Coastguard Worker } 588*8d67ca89SAndroid Build Coastguard Worker return (&poll)(fds, fd_count, timeout); 589*8d67ca89SAndroid Build Coastguard Worker} 590*8d67ca89SAndroid Build Coastguard Worker``` 591*8d67ca89SAndroid Build Coastguard Worker 592*8d67ca89SAndroid Build Coastguard WorkerTo get the commonality with `mempcpy` and `open` out of the way: 593*8d67ca89SAndroid Build Coastguard Worker- This function is an overload with `__builtin_poll`. 594*8d67ca89SAndroid Build Coastguard Worker- The signature is the same, modulo the presence of a `pass_object_size` 595*8d67ca89SAndroid Build Coastguard Worker attribute. Hence, for direct calls, overload resolution will always prefer it 596*8d67ca89SAndroid Build Coastguard Worker over `__builtin_poll`. Taking the address of `poll` is forbidden, so all 597*8d67ca89SAndroid Build Coastguard Worker references to `&poll` actually reference `__builtin_poll`. 598*8d67ca89SAndroid Build Coastguard Worker- When `fds` is too small to hold `fd_count` `pollfd`s, Clang will emit a 599*8d67ca89SAndroid Build Coastguard Worker compile-time error if possible using `diagnose_if`. 600*8d67ca89SAndroid Build Coastguard Worker- If this can't be observed until run-time, `__poll_chk` verifies this. 601*8d67ca89SAndroid Build Coastguard Worker- When `fds` is a constant according to `__builtin_constant_p`, this always 602*8d67ca89SAndroid Build Coastguard Worker compiles into `__poll_chk` for always-broken calls to `poll`, or 603*8d67ca89SAndroid Build Coastguard Worker `__builtin_poll` for always-safe calls to `poll`. 604*8d67ca89SAndroid Build Coastguard Worker 605*8d67ca89SAndroid Build Coastguard WorkerThe critical bits to highlight here are on this line: 606*8d67ca89SAndroid Build Coastguard Worker```c 607*8d67ca89SAndroid Build Coastguard Workerint poll(struct pollfd* const fds __attribute__((pass_object_size(1))), nfds_t fd_count, int timeout) 608*8d67ca89SAndroid Build Coastguard Worker``` 609*8d67ca89SAndroid Build Coastguard Worker 610*8d67ca89SAndroid Build Coastguard WorkerAnd this line: 611*8d67ca89SAndroid Build Coastguard Worker```c 612*8d67ca89SAndroid Build Coastguard Worker return (&poll)(fds, fd_count, timeout); 613*8d67ca89SAndroid Build Coastguard Worker``` 614*8d67ca89SAndroid Build Coastguard Worker 615*8d67ca89SAndroid Build Coastguard WorkerStarting with the simplest, we call `__builtin_poll` with `(&poll)(...);`. As 616*8d67ca89SAndroid Build Coastguard Workerreferenced above, taking the address of an overloaded function where all but one 617*8d67ca89SAndroid Build Coastguard Workeroverload has a `pass_object_size` attribute on one or more parameters always 618*8d67ca89SAndroid Build Coastguard Workerresolves to the function without any `pass_object_size` attributes. 619*8d67ca89SAndroid Build Coastguard Worker 620*8d67ca89SAndroid Build Coastguard WorkerThe other line deserves a section. The subtlety of it is almost entirely in the 621*8d67ca89SAndroid Build Coastguard Workeruse of `pass_object_size(1)` instead of `pass_object_size(0)`. on the `fds` 622*8d67ca89SAndroid Build Coastguard Workerparameter, and the corresponding use of `__builtin_object_size(fds, 1);` in the 623*8d67ca89SAndroid Build Coastguard Workerbody of `poll`. 624*8d67ca89SAndroid Build Coastguard Worker 625*8d67ca89SAndroid Build Coastguard Worker### Subtleties of __builtin_object_size(p, N) 626*8d67ca89SAndroid Build Coastguard Worker 627*8d67ca89SAndroid Build Coastguard WorkerEarlier in this document, it was said that a full description of each 628*8d67ca89SAndroid Build Coastguard Workerattribute/builtin necessary to power FORTIFY was out of scope. This is... only 629*8d67ca89SAndroid Build Coastguard Workersomewhat the case when we talk about `__builtin_object_size` and 630*8d67ca89SAndroid Build Coastguard Worker`pass_object_size`, especially when their second argument is `1`. 631*8d67ca89SAndroid Build Coastguard Worker 632*8d67ca89SAndroid Build Coastguard Worker#### tl;dr 633*8d67ca89SAndroid Build Coastguard Worker`__builtin_object_size(p, N)` and `pass_object_size(N)`, where `(N & 1) == 1`, 634*8d67ca89SAndroid Build Coastguard Workercan only be accurately determined by Clang. LLVM's `@llvm.objectsize` intrinsic 635*8d67ca89SAndroid Build Coastguard Workerignores the value of `N & 1`, since handling `(N & 1) == 1` accurately requires 636*8d67ca89SAndroid Build Coastguard Workerdata that's currently entirely inaccessible to LLVM, and that is difficult to 637*8d67ca89SAndroid Build Coastguard Workerpreserve through LLVM's optimization passes. 638*8d67ca89SAndroid Build Coastguard Worker 639*8d67ca89SAndroid Build Coastguard Worker`pass_object_size`'s "lifting" of the evaluation of 640*8d67ca89SAndroid Build Coastguard Worker`__builtin_object_size(p, N)` to the caller is critical, since it allows Clang 641*8d67ca89SAndroid Build Coastguard Workerfull visibility into the expression passed to e.g., `poll(&foo->bar, baz, qux)`. 642*8d67ca89SAndroid Build Coastguard WorkerIt's not a perfect solution, but it allows `N == 1` to be fully accurate in at 643*8d67ca89SAndroid Build Coastguard Workerleast some cases. 644*8d67ca89SAndroid Build Coastguard Worker 645*8d67ca89SAndroid Build Coastguard Worker#### Background 646*8d67ca89SAndroid Build Coastguard WorkerClang's implementation of `__builtin_object_size` aims to be compatible with 647*8d67ca89SAndroid Build Coastguard WorkerGCC's, which has [a decent bit of documentation]. Put simply, 648*8d67ca89SAndroid Build Coastguard Worker`__builtin_object_size(p, N)` is intended to evaluate at compile-time how many 649*8d67ca89SAndroid Build Coastguard Workerbytes can be accessed after `p` in a well-defined way. Straightforward examples 650*8d67ca89SAndroid Build Coastguard Workerof this are: 651*8d67ca89SAndroid Build Coastguard Worker```c 652*8d67ca89SAndroid Build Coastguard Workerchar buf[8]; 653*8d67ca89SAndroid Build Coastguard Workerassert(__builtin_object_size(buf, N) == 8); 654*8d67ca89SAndroid Build Coastguard Workerassert(__builtin_object_size(buf + 1, N) == 7); 655*8d67ca89SAndroid Build Coastguard Worker``` 656*8d67ca89SAndroid Build Coastguard Worker 657*8d67ca89SAndroid Build Coastguard WorkerThis should hold for all values of N that are valid to pass to 658*8d67ca89SAndroid Build Coastguard Worker`__builtin_object_size`. The `N` value of `__builtin_object_size` is a mask of 659*8d67ca89SAndroid Build Coastguard Workersettings. 660*8d67ca89SAndroid Build Coastguard Worker 661*8d67ca89SAndroid Build Coastguard Worker##### (N & 2) == ? 662*8d67ca89SAndroid Build Coastguard Worker 663*8d67ca89SAndroid Build Coastguard WorkerThis is mostly for completeness sake; in Bionic's FORTIFY implementation, N is 664*8d67ca89SAndroid Build Coastguard Workeralways either 0 or 1. 665*8d67ca89SAndroid Build Coastguard Worker 666*8d67ca89SAndroid Build Coastguard WorkerIf there are multiple possible values of `p` in a call to 667*8d67ca89SAndroid Build Coastguard Worker`__builtin_object_size(p, N)`, the second bit in `N` determines the behavior of 668*8d67ca89SAndroid Build Coastguard Workerthe compiler. If `(N & 2) == 0`, `__builtin_object_size` should return the 669*8d67ca89SAndroid Build Coastguard Workergreatest possible size for each possible value of `p`. Otherwise, it should 670*8d67ca89SAndroid Build Coastguard Workerreturn the least possible value. For example: 671*8d67ca89SAndroid Build Coastguard Worker 672*8d67ca89SAndroid Build Coastguard Worker```c 673*8d67ca89SAndroid Build Coastguard Workerchar smol_buf[7]; 674*8d67ca89SAndroid Build Coastguard Workerchar buf[8]; 675*8d67ca89SAndroid Build Coastguard Workerchar *p = rand() ? smol_buf : buf; 676*8d67ca89SAndroid Build Coastguard Workerassert(__builtin_object_size(p, 0) == 8); 677*8d67ca89SAndroid Build Coastguard Workerassert(__builtin_object_size(p, 2) == 7); 678*8d67ca89SAndroid Build Coastguard Worker``` 679*8d67ca89SAndroid Build Coastguard Worker 680*8d67ca89SAndroid Build Coastguard Worker##### (N & 1) == 0 681*8d67ca89SAndroid Build Coastguard Worker 682*8d67ca89SAndroid Build Coastguard Worker`__builtin_object_size(p, 0)` is more or less as simple as the example in the 683*8d67ca89SAndroid Build Coastguard WorkerBackground section directly above. When Clang attempts to evaluate 684*8d67ca89SAndroid Build Coastguard Worker`__builtin_object_size(p, 0);` and when LLVM tries to determine the result of a 685*8d67ca89SAndroid Build Coastguard Workercorresponding `@llvm.objectsize` call to, they search for the storage underlying 686*8d67ca89SAndroid Build Coastguard Workerthe pointer in question. If that can be determined, Clang or LLVM can provide an 687*8d67ca89SAndroid Build Coastguard Workeranswer; otherwise, they cannot. 688*8d67ca89SAndroid Build Coastguard Worker 689*8d67ca89SAndroid Build Coastguard Worker##### (N & 1) == 1, and the true magic of pass_object_size 690*8d67ca89SAndroid Build Coastguard Worker 691*8d67ca89SAndroid Build Coastguard Worker`__builtin_object_size(p, 1)` has a less uniform implementation between LLVM and 692*8d67ca89SAndroid Build Coastguard WorkerClang. According to GCC's documentation, "If the least significant bit [of 693*8d67ca89SAndroid Build Coastguard Worker__builtin_object_size's second argument] is clear, objects are whole variables, 694*8d67ca89SAndroid Build Coastguard Workerif it is set, a closest surrounding subobject is considered the object a pointer 695*8d67ca89SAndroid Build Coastguard Workerpoints to." 696*8d67ca89SAndroid Build Coastguard Worker 697*8d67ca89SAndroid Build Coastguard WorkerThe "closest surrounding subobject," means that `(N & 1) == 1` depends on type 698*8d67ca89SAndroid Build Coastguard Workerinformation in order to operate in many cases. Consider the following examples: 699*8d67ca89SAndroid Build Coastguard Worker```c 700*8d67ca89SAndroid Build Coastguard Workerstruct Foo { 701*8d67ca89SAndroid Build Coastguard Worker int a; 702*8d67ca89SAndroid Build Coastguard Worker int b; 703*8d67ca89SAndroid Build Coastguard Worker}; 704*8d67ca89SAndroid Build Coastguard Worker 705*8d67ca89SAndroid Build Coastguard Workerstruct Foo foo; 706*8d67ca89SAndroid Build Coastguard Workerassert(__builtin_object_size(&foo, 0) == sizeof(foo)); 707*8d67ca89SAndroid Build Coastguard Workerassert(__builtin_object_size(&foo, 1) == sizeof(foo)); 708*8d67ca89SAndroid Build Coastguard Workerassert(__builtin_object_size(&foo->a, 0) == sizeof(foo)); 709*8d67ca89SAndroid Build Coastguard Workerassert(__builtin_object_size(&foo->a, 1) == sizeof(int)); 710*8d67ca89SAndroid Build Coastguard Worker 711*8d67ca89SAndroid Build Coastguard Workerstruct Foo foos[2]; 712*8d67ca89SAndroid Build Coastguard Workerassert(__builtin_object_size(&foos[0], 0) == 2 * sizeof(foo)); 713*8d67ca89SAndroid Build Coastguard Workerassert(__builtin_object_size(&foos[0], 1) == sizeof(foo)); 714*8d67ca89SAndroid Build Coastguard Workerassert(__builtin_object_size(&foos[0]->a, 0) == 2 * sizeof(foo)); 715*8d67ca89SAndroid Build Coastguard Workerassert(__builtin_object_size(&foos[0]->a, 1) == sizeof(int)); 716*8d67ca89SAndroid Build Coastguard Worker``` 717*8d67ca89SAndroid Build Coastguard Worker 718*8d67ca89SAndroid Build Coastguard Worker...And perhaps somewhat surprisingly: 719*8d67ca89SAndroid Build Coastguard Worker```c 720*8d67ca89SAndroid Build Coastguard Workervoid example(struct Foo *foo) { 721*8d67ca89SAndroid Build Coastguard Worker // (As a reminder, `-1` is "I don't know" when `(N & 2) == 0`.) 722*8d67ca89SAndroid Build Coastguard Worker assert(__builtin_object_size(foo, 0) == -1); 723*8d67ca89SAndroid Build Coastguard Worker assert(__builtin_object_size(foo, 1) == -1); 724*8d67ca89SAndroid Build Coastguard Worker assert(__builtin_object_size(foo->a, 0) == -1); 725*8d67ca89SAndroid Build Coastguard Worker assert(__builtin_object_size(foo->a, 1) == sizeof(int)); 726*8d67ca89SAndroid Build Coastguard Worker} 727*8d67ca89SAndroid Build Coastguard Worker``` 728*8d67ca89SAndroid Build Coastguard Worker 729*8d67ca89SAndroid Build Coastguard WorkerIn Clang, [this type-aware requirement poses problems for us]: Clang's frontend 730*8d67ca89SAndroid Build Coastguard Workerknows everything we could possibly want about the types of variables, but 731*8d67ca89SAndroid Build Coastguard Workeroptimizations are only performed by LLVM. LLVM has no reliable source for C or 732*8d67ca89SAndroid Build Coastguard WorkerC++ data types, so calls to `__builtin_object_size(p, N)` that cannot be 733*8d67ca89SAndroid Build Coastguard Workerresolved by clang are lowered to the equivalent of 734*8d67ca89SAndroid Build Coastguard Worker`__builtin_object_size(p, N & ~1)` in LLVM IR. 735*8d67ca89SAndroid Build Coastguard Worker 736*8d67ca89SAndroid Build Coastguard WorkerMoreover, Clang's frontend is the best-equipped part of the compiler to 737*8d67ca89SAndroid Build Coastguard Workeraccurately determine the answer for `__builtin_object_size(p, N)`, given we know 738*8d67ca89SAndroid Build Coastguard Workerwhat `p` is. LLVM is the best-equipped part of the compiler to determine the 739*8d67ca89SAndroid Build Coastguard Workervalue of `p`. This ordering issue is unfortunate. 740*8d67ca89SAndroid Build Coastguard Worker 741*8d67ca89SAndroid Build Coastguard WorkerThis is where `pass_object_size(N)` comes in. To summarize [the docs for 742*8d67ca89SAndroid Build Coastguard Worker`pass_object_size`], it evaluates `__builtin_object_size(p, N)` within the 743*8d67ca89SAndroid Build Coastguard Workercontext of the caller of the function annotated with `pass_object_size`, and 744*8d67ca89SAndroid Build Coastguard Workerpasses the value of that into the callee as an invisible parameter. All calls to 745*8d67ca89SAndroid Build Coastguard Worker`__builtin_object_size(parameter, N)` are substituted with references to this 746*8d67ca89SAndroid Build Coastguard Workerinvisible parameter. 747*8d67ca89SAndroid Build Coastguard Worker 748*8d67ca89SAndroid Build Coastguard WorkerPutting this plainly, Clang's frontend struggles to evaluate the following: 749*8d67ca89SAndroid Build Coastguard Worker```c 750*8d67ca89SAndroid Build Coastguard Workerint foo(void *p) { 751*8d67ca89SAndroid Build Coastguard Worker return __builtin_object_size(p, 1); 752*8d67ca89SAndroid Build Coastguard Worker} 753*8d67ca89SAndroid Build Coastguard Worker 754*8d67ca89SAndroid Build Coastguard Workervoid bar() { 755*8d67ca89SAndroid Build Coastguard Worker struct { int i, j } k; 756*8d67ca89SAndroid Build Coastguard Worker // The frontend can't figure this interprocedural objectsize out, so it gets lowered to 757*8d67ca89SAndroid Build Coastguard Worker // LLVM, which determines that the answer here is sizeof(k). 758*8d67ca89SAndroid Build Coastguard Worker int baz = foo(&k.i); 759*8d67ca89SAndroid Build Coastguard Worker} 760*8d67ca89SAndroid Build Coastguard Worker``` 761*8d67ca89SAndroid Build Coastguard Worker 762*8d67ca89SAndroid Build Coastguard WorkerHowever, with the magic of `pass_object_size`, we get one level of inlining to 763*8d67ca89SAndroid Build Coastguard Workerlook through: 764*8d67ca89SAndroid Build Coastguard Worker```c 765*8d67ca89SAndroid Build Coastguard Workerint foo(void *const __attribute__((pass_object_size(1))) p) { 766*8d67ca89SAndroid Build Coastguard Worker return __builtin_object_size(p, 1); 767*8d67ca89SAndroid Build Coastguard Worker} 768*8d67ca89SAndroid Build Coastguard Worker 769*8d67ca89SAndroid Build Coastguard Workervoid bar() { 770*8d67ca89SAndroid Build Coastguard Worker struct { int i, j } k; 771*8d67ca89SAndroid Build Coastguard Worker // Due to pass_object_size, this is equivalent to: 772*8d67ca89SAndroid Build Coastguard Worker // int baz = foo(&k.i, __builtin_object_size(&k.i, 1)); 773*8d67ca89SAndroid Build Coastguard Worker // ...and `int foo(void *)` is actually equivalent to: 774*8d67ca89SAndroid Build Coastguard Worker // int foo(void *const, size_t size) { 775*8d67ca89SAndroid Build Coastguard Worker // return size; 776*8d67ca89SAndroid Build Coastguard Worker // } 777*8d67ca89SAndroid Build Coastguard Worker int baz = foo(&k.i); 778*8d67ca89SAndroid Build Coastguard Worker} 779*8d67ca89SAndroid Build Coastguard Worker``` 780*8d67ca89SAndroid Build Coastguard Worker 781*8d67ca89SAndroid Build Coastguard WorkerSo we can obtain an accurate result in this case. 782*8d67ca89SAndroid Build Coastguard Worker 783*8d67ca89SAndroid Build Coastguard Worker##### What about pass_object_size(0)? 784*8d67ca89SAndroid Build Coastguard WorkerIt's sort of tangential, but if you find yourself wondering about the utility of 785*8d67ca89SAndroid Build Coastguard Worker`pass_object_size(0)` ... it's somewhat split. `pass_object_size(0)` in Bionic's 786*8d67ca89SAndroid Build Coastguard WorkerFORTIFY exists mostly for visual consistency, simplicity, and as a useful way to 787*8d67ca89SAndroid Build Coastguard Workerhave e.g., `&mempcpy` == `&__builtin_mempcpy`. 788*8d67ca89SAndroid Build Coastguard Worker 789*8d67ca89SAndroid Build Coastguard WorkerOutside of these fringe benefits, all of the functions with 790*8d67ca89SAndroid Build Coastguard Worker`pass_object_size(0)` on parameters are marked with `always_inline`, so 791*8d67ca89SAndroid Build Coastguard Worker"lifting" the `__builtin_object_size` call isn't ultimately very helpful. In 792*8d67ca89SAndroid Build Coastguard Workertheory, users can always have something like: 793*8d67ca89SAndroid Build Coastguard Worker 794*8d67ca89SAndroid Build Coastguard Worker```c 795*8d67ca89SAndroid Build Coastguard Worker// In some_header.h 796*8d67ca89SAndroid Build Coastguard Worker// This function does cool and interesting things with the `__builtin_object_size` of its parameter, 797*8d67ca89SAndroid Build Coastguard Worker// and is able to work with that as though the function were defined inline. 798*8d67ca89SAndroid Build Coastguard Workervoid out_of_line_function(void *__attribute__((pass_object_size(0)))); 799*8d67ca89SAndroid Build Coastguard Worker``` 800*8d67ca89SAndroid Build Coastguard Worker 801*8d67ca89SAndroid Build Coastguard WorkerThough the author isn't aware of uses like this in practice, beyond a few folks 802*8d67ca89SAndroid Build Coastguard Workeron LLVM's mailing list seeming interested in trying it someday. 803*8d67ca89SAndroid Build Coastguard Worker 804*8d67ca89SAndroid Build Coastguard Worker#### Wrapping up 805*8d67ca89SAndroid Build Coastguard WorkerIn the (long) section above, two things were covered: 806*8d67ca89SAndroid Build Coastguard Worker- The use of `(&poll)(...);` is a convenient shorthand for calling 807*8d67ca89SAndroid Build Coastguard Worker `__builtin_poll`. 808*8d67ca89SAndroid Build Coastguard Worker- `__builtin_object_size(p, N)` with `(N & 1) == 1` is not easy for Clang to 809*8d67ca89SAndroid Build Coastguard Worker answer accurately, since it relies on type info only available in the 810*8d67ca89SAndroid Build Coastguard Worker frontend, and it sometimes relies on optimizations only available in the 811*8d67ca89SAndroid Build Coastguard Worker middle-end. `pass_object_size` helps mitigate this. 812*8d67ca89SAndroid Build Coastguard Worker 813*8d67ca89SAndroid Build Coastguard Worker## Miscellaneous Notes 814*8d67ca89SAndroid Build Coastguard WorkerThe above should be a roughly comprehensive view of how FORTIFY works in the 815*8d67ca89SAndroid Build Coastguard Workerreal world. The main thing it fails to mention is the use of [the `diagnose_as_builtin` attribute] in Clang. 816*8d67ca89SAndroid Build Coastguard Worker 817*8d67ca89SAndroid Build Coastguard WorkerAs time has moved on, Clang has increasingly gained support for emitting 818*8d67ca89SAndroid Build Coastguard Workerwarnings that were previously emitted by FORTIFY machinery. 819*8d67ca89SAndroid Build Coastguard Worker`diagnose_as_builtin` allows us to remove the `diagnose_if`s from some of the 820*8d67ca89SAndroid Build Coastguard Worker`static inline` overloads of stdlib functions above, so Clang may diagnose them 821*8d67ca89SAndroid Build Coastguard Workerinstead. 822*8d67ca89SAndroid Build Coastguard Worker 823*8d67ca89SAndroid Build Coastguard WorkerClang's built-in diagnostics are often better than `diagnose_if` diagnostics, 824*8d67ca89SAndroid Build Coastguard Workersince Clang can format its diagnostics to include e.g., information about the 825*8d67ca89SAndroid Build Coastguard Workersizes of buffers in a suspect call to a function. `diagnose_if` can only have 826*8d67ca89SAndroid Build Coastguard Workerthe compiler output constant strings. 827*8d67ca89SAndroid Build Coastguard Worker 828*8d67ca89SAndroid Build Coastguard Worker[ChromeOS' Glibc patch]: https://chromium.googlesource.com/chromiumos/overlays/chromiumos-overlay/+/90fa9b27731db10a6010c7f7c25b24028145b091/sys-libs/glibc/files/local/glibc-2.33/0007-glibc-add-clang-style-FORTIFY.patch 829*8d67ca89SAndroid Build Coastguard Worker[FORTIFY'ed implementation of `open`]: https://android.googlesource.com/platform/bionic/+/refs/heads/android12-release/libc/include/bits/fortify/fcntl.h#41 830*8d67ca89SAndroid Build Coastguard Worker[FORTIFY'ed version of `mempcpy`]: https://android.googlesource.com/platform/bionic/+/refs/heads/android12-release/libc/include/bits/fortify/string.h#45 831*8d67ca89SAndroid Build Coastguard Worker[a decent bit of documentation]: https://gcc.gnu.org/onlinedocs/gcc/Object-Size-Checking.html 832*8d67ca89SAndroid Build Coastguard Worker[an implementation for `__mempcpy_chk`]: https://android.googlesource.com/platform/bionic/+/refs/heads/android12-release/libc/bionic/fortify.cpp#501 833*8d67ca89SAndroid Build Coastguard Worker[full header implementation of `poll`]: https://android.googlesource.com/platform/bionic/+/refs/heads/android12-release/libc/include/bits/fortify/poll.h#43 834*8d67ca89SAndroid Build Coastguard Worker[incompatible with stricter versions of FORTIFY checking]: https://godbolt.org/z/fGfEYxfnf 835*8d67ca89SAndroid Build Coastguard Worker[similar to C++11's `std::unique_ptr`]: https://stackoverflow.com/questions/58339165/why-can-a-t-be-passed-in-register-but-a-unique-ptrt-cannot 836*8d67ca89SAndroid Build Coastguard Worker[source for `mempcpy`]: https://android.googlesource.com/platform/bionic/+/refs/heads/android12-release/libc/include/string.h#55 837*8d67ca89SAndroid Build Coastguard Worker[the `diagnose_as_builtin` attribute]: https://releases.llvm.org/14.0.0/tools/clang/docs/AttributeReference.html#diagnose-as-builtin 838*8d67ca89SAndroid Build Coastguard Worker[the docs for `pass_object_size`]: https://releases.llvm.org/14.0.0/tools/clang/docs/AttributeReference.html#pass-object-size-pass-dynamic-object-size 839*8d67ca89SAndroid Build Coastguard Worker[this type-aware requirement poses problems for us]: https://github.com/llvm/llvm-project/issues/55742 840*8d67ca89SAndroid Build Coastguard Worker[unconditionally call `__open_2`]: https://android.googlesource.com/platform/bionic/+/refs/heads/android12-release/libc/bionic/open.cpp#70 841