gcc: Object Size Checking
1
1 6.56 Object Size Checking Built-in Functions
1 ============================================
1
1 GCC implements a limited buffer overflow protection mechanism that can
1 prevent some buffer overflow attacks by determining the sizes of objects
1 into which data is about to be written and preventing the writes when
1 the size isn't sufficient. The built-in functions described below yield
1 the best results when used together and when optimization is enabled.
1 For example, to detect object sizes across function boundaries or to
1 follow pointer assignments through non-trivial control flow they rely on
1 various optimization passes enabled with '-O2'. However, to a limited
1 extent, they can be used without optimization as well.
1
1 -- Built-in Function: size_t __builtin_object_size (const void * PTR,
1 int TYPE)
1 is a built-in construct that returns a constant number of bytes
1 from PTR to the end of the object PTR pointer points to (if known
1 at compile time). '__builtin_object_size' never evaluates its
1 arguments for side effects. If there are any side effects in them,
1 it returns '(size_t) -1' for TYPE 0 or 1 and '(size_t) 0' for TYPE
1 2 or 3. If there are multiple objects PTR can point to and all of
1 them are known at compile time, the returned number is the maximum
1 of remaining byte counts in those objects if TYPE & 2 is 0 and
1 minimum if nonzero. If it is not possible to determine which
1 objects PTR points to at compile time, '__builtin_object_size'
1 should return '(size_t) -1' for TYPE 0 or 1 and '(size_t) 0' for
1 TYPE 2 or 3.
1
1 TYPE is an integer constant from 0 to 3. If the least significant
1 bit is clear, objects are whole variables, if it is set, a closest
1 surrounding subobject is considered the object a pointer points to.
1 The second bit determines if maximum or minimum of remaining bytes
1 is computed.
1
1 struct V { char buf1[10]; int b; char buf2[10]; } var;
1 char *p = &var.buf1[1], *q = &var.b;
1
1 /* Here the object p points to is var. */
1 assert (__builtin_object_size (p, 0) == sizeof (var) - 1);
1 /* The subobject p points to is var.buf1. */
1 assert (__builtin_object_size (p, 1) == sizeof (var.buf1) - 1);
1 /* The object q points to is var. */
1 assert (__builtin_object_size (q, 0)
1 == (char *) (&var + 1) - (char *) &var.b);
1 /* The subobject q points to is var.b. */
1 assert (__builtin_object_size (q, 1) == sizeof (var.b));
1
1 There are built-in functions added for many common string operation
1 functions, e.g., for 'memcpy' '__builtin___memcpy_chk' built-in is
1 provided. This built-in has an additional last argument, which is the
1 number of bytes remaining in the object the DEST argument points to or
1 '(size_t) -1' if the size is not known.
1
1 The built-in functions are optimized into the normal string functions
1 like 'memcpy' if the last argument is '(size_t) -1' or if it is known at
1 compile time that the destination object will not be overflowed. If the
1 compiler can determine at compile time that the object will always be
1 overflowed, it issues a warning.
1
1 The intended use can be e.g.
1
1 #undef memcpy
1 #define bos0(dest) __builtin_object_size (dest, 0)
1 #define memcpy(dest, src, n) \
1 __builtin___memcpy_chk (dest, src, n, bos0 (dest))
1
1 char *volatile p;
1 char buf[10];
1 /* It is unknown what object p points to, so this is optimized
1 into plain memcpy - no checking is possible. */
1 memcpy (p, "abcde", n);
1 /* Destination is known and length too. It is known at compile
1 time there will be no overflow. */
1 memcpy (&buf[5], "abcde", 5);
1 /* Destination is known, but the length is not known at compile time.
1 This will result in __memcpy_chk call that can check for overflow
1 at run time. */
1 memcpy (&buf[5], "abcde", n);
1 /* Destination is known and it is known at compile time there will
1 be overflow. There will be a warning and __memcpy_chk call that
1 will abort the program at run time. */
1 memcpy (&buf[6], "abcde", 5);
1
1 Such built-in functions are provided for 'memcpy', 'mempcpy',
1 'memmove', 'memset', 'strcpy', 'stpcpy', 'strncpy', 'strcat' and
1 'strncat'.
1
1 There are also checking built-in functions for formatted output
1 functions.
1 int __builtin___sprintf_chk (char *s, int flag, size_t os, const char *fmt, ...);
1 int __builtin___snprintf_chk (char *s, size_t maxlen, int flag, size_t os,
1 const char *fmt, ...);
1 int __builtin___vsprintf_chk (char *s, int flag, size_t os, const char *fmt,
1 va_list ap);
1 int __builtin___vsnprintf_chk (char *s, size_t maxlen, int flag, size_t os,
1 const char *fmt, va_list ap);
1
1 The added FLAG argument is passed unchanged to '__sprintf_chk' etc.
1 functions and can contain implementation specific flags on what
1 additional security measures the checking function might take, such as
1 handling '%n' differently.
1
1 The OS argument is the object size S points to, like in the other
1 built-in functions. There is a small difference in the behavior though,
1 if OS is '(size_t) -1', the built-in functions are optimized into the
1 non-checking functions only if FLAG is 0, otherwise the checking
1 function is called with OS argument set to '(size_t) -1'.
1
1 In addition to this, there are checking built-in functions
1 '__builtin___printf_chk', '__builtin___vprintf_chk',
1 '__builtin___fprintf_chk' and '__builtin___vfprintf_chk'. These have
1 just one additional argument, FLAG, right before format string FMT. If
1 the compiler is able to optimize them to 'fputc' etc. functions, it
1 does, otherwise the checking function is called and the FLAG argument
1 passed to it.
1