[v7,2/4] Introduce _FORTIFY_SOURCE=3

Message ID 20201230064348.376092-3-siddhesh@sourceware.org
State Committed
Headers
Series _FORTIFY_SOURCE=3 |

Commit Message

Siddhesh Poyarekar Dec. 30, 2020, 6:43 a.m. UTC
  Introduce a new _FORTIFY_SOURCE level of 3 to enable additional
fortifications that may have a noticeable performance impact, allowing
more fortification coverage at the cost of some performance.

With llvm 9.0 or later, this will replace the use of
__builtin_object_size with __builtin_dynamic_object_size.

__builtin_dynamic_object_size
-----------------------------

__builtin_dynamic_object_size is an LLVM builtin that is similar to
__builtin_object_size.  In addition to what __builtin_object_size
does, i.e. replace the builtin call with a constant object size,
__builtin_dynamic_object_size will replace the call site with an
expression that evaluates to the object size, thus expanding its
applicability.  In practice, __builtin_dynamic_object_size evaluates
these expressions through malloc/calloc calls that it can associate
with the object being evaluated.

A simple motivating example is below; -D_FORTIFY_SOURCE=2 would miss
this and emit memcpy, but -D_FORTIFY_SOURCE=3 with the help of
__builtin_dynamic_object_size is able to emit __memcpy_chk with the
allocation size expression passed into the function:

void *copy_obj (const void *src, size_t alloc, size_t copysize)
{
  void *obj = malloc (alloc);
  memcpy (obj, src, copysize);
  return obj;
}

Limitations
-----------

If the object was allocated elsewhere that the compiler cannot see, or
if it was allocated in the function with a function that the compiler
does not recognize as an allocator then __builtin_dynamic_object_size
also returns -1.

Further, the expression used to compute object size may be non-trivial
and may potentially incur a noticeable performance impact.  These
fortifications are hence enabled at a new _FORTIFY_SOURCE level to
allow developers to make a choice on the tradeoff according to their
environment.
---
 include/features.h | 5 +++++
 misc/sys/cdefs.h   | 9 +++++++++
 2 files changed, 14 insertions(+)
  

Comments

Adhemerval Zanella Dec. 31, 2020, 10:47 a.m. UTC | #1
On 30/12/2020 03:43, Siddhesh Poyarekar wrote:
> Introduce a new _FORTIFY_SOURCE level of 3 to enable additional
> fortifications that may have a noticeable performance impact, allowing
> more fortification coverage at the cost of some performance.
> 
> With llvm 9.0 or later, this will replace the use of
> __builtin_object_size with __builtin_dynamic_object_size.
> 
> __builtin_dynamic_object_size
> -----------------------------
> 
> __builtin_dynamic_object_size is an LLVM builtin that is similar to
> __builtin_object_size.  In addition to what __builtin_object_size
> does, i.e. replace the builtin call with a constant object size,
> __builtin_dynamic_object_size will replace the call site with an
> expression that evaluates to the object size, thus expanding its
> applicability.  In practice, __builtin_dynamic_object_size evaluates
> these expressions through malloc/calloc calls that it can associate
> with the object being evaluated.
> 
> A simple motivating example is below; -D_FORTIFY_SOURCE=2 would miss
> this and emit memcpy, but -D_FORTIFY_SOURCE=3 with the help of
> __builtin_dynamic_object_size is able to emit __memcpy_chk with the
> allocation size expression passed into the function:
> 
> void *copy_obj (const void *src, size_t alloc, size_t copysize)
> {
>   void *obj = malloc (alloc);
>   memcpy (obj, src, copysize);
>   return obj;
> }
> 
> Limitations
> -----------
> 
> If the object was allocated elsewhere that the compiler cannot see, or
> if it was allocated in the function with a function that the compiler
> does not recognize as an allocator then __builtin_dynamic_object_size
> also returns -1.
> 
> Further, the expression used to compute object size may be non-trivial
> and may potentially incur a noticeable performance impact.  These
> fortifications are hence enabled at a new _FORTIFY_SOURCE level to
> allow developers to make a choice on the tradeoff according to their
> environment.

LGTM, thanks.

Reviewed-by: Adhemerval Zanella  <adhemerval.zanella@linaro.org>

> ---
>  include/features.h | 5 +++++
>  misc/sys/cdefs.h   | 9 +++++++++
>  2 files changed, 14 insertions(+)
> 
> diff --git a/include/features.h b/include/features.h
> index 540230b90b..066eb0eecd 100644
> --- a/include/features.h
> +++ b/include/features.h
> @@ -397,6 +397,11 @@
>  #  warning _FORTIFY_SOURCE requires compiling with optimization (-O)
>  # elif !__GNUC_PREREQ (4, 1)
>  #  warning _FORTIFY_SOURCE requires GCC 4.1 or later
> +# elif _FORTIFY_SOURCE > 2 && __glibc_clang_prereq (9, 0)
> +#  if _FORTIFY_SOURCE > 3
> +#   warning _FORTIFY_SOURCE > 3 is treated like 3 on this platform
> +#  endif
> +#  define __USE_FORTIFY_LEVEL 3
>  # elif _FORTIFY_SOURCE > 1
>  #  if _FORTIFY_SOURCE > 2
>  #   warning _FORTIFY_SOURCE > 2 is treated like 2 on this platform
> diff --git a/misc/sys/cdefs.h b/misc/sys/cdefs.h
> index a06f1cfd91..5fb6e309be 100644
> --- a/misc/sys/cdefs.h
> +++ b/misc/sys/cdefs.h
> @@ -127,6 +127,15 @@
>  #define __bos(ptr) __builtin_object_size (ptr, __USE_FORTIFY_LEVEL > 1)
>  #define __bos0(ptr) __builtin_object_size (ptr, 0)
>  
> +/* Use __builtin_dynamic_object_size at _FORTIFY_SOURCE=3 when available.  */
> +#if __USE_FORTIFY_LEVEL == 3 && __glibc_clang_prereq (9, 0)
> +# define __glibc_objsize0(__o) __builtin_dynamic_object_size (__o, 0)
> +# define __glibc_objsize(__o) __builtin_dynamic_object_size (__o, 1)
> +#else
> +# define __glibc_objsize0(__o) __bos0 (__o)
> +# define __glibc_objsize(__o) __bos (__o)
> +#endif
> +
>  #if __GNUC_PREREQ (4,3)
>  # define __warnattr(msg) __attribute__((__warning__ (msg)))
>  # define __errordecl(name, msg) \
>
  

Patch

diff --git a/include/features.h b/include/features.h
index 540230b90b..066eb0eecd 100644
--- a/include/features.h
+++ b/include/features.h
@@ -397,6 +397,11 @@ 
 #  warning _FORTIFY_SOURCE requires compiling with optimization (-O)
 # elif !__GNUC_PREREQ (4, 1)
 #  warning _FORTIFY_SOURCE requires GCC 4.1 or later
+# elif _FORTIFY_SOURCE > 2 && __glibc_clang_prereq (9, 0)
+#  if _FORTIFY_SOURCE > 3
+#   warning _FORTIFY_SOURCE > 3 is treated like 3 on this platform
+#  endif
+#  define __USE_FORTIFY_LEVEL 3
 # elif _FORTIFY_SOURCE > 1
 #  if _FORTIFY_SOURCE > 2
 #   warning _FORTIFY_SOURCE > 2 is treated like 2 on this platform
diff --git a/misc/sys/cdefs.h b/misc/sys/cdefs.h
index a06f1cfd91..5fb6e309be 100644
--- a/misc/sys/cdefs.h
+++ b/misc/sys/cdefs.h
@@ -127,6 +127,15 @@ 
 #define __bos(ptr) __builtin_object_size (ptr, __USE_FORTIFY_LEVEL > 1)
 #define __bos0(ptr) __builtin_object_size (ptr, 0)
 
+/* Use __builtin_dynamic_object_size at _FORTIFY_SOURCE=3 when available.  */
+#if __USE_FORTIFY_LEVEL == 3 && __glibc_clang_prereq (9, 0)
+# define __glibc_objsize0(__o) __builtin_dynamic_object_size (__o, 0)
+# define __glibc_objsize(__o) __builtin_dynamic_object_size (__o, 1)
+#else
+# define __glibc_objsize0(__o) __bos0 (__o)
+# define __glibc_objsize(__o) __bos (__o)
+#endif
+
 #if __GNUC_PREREQ (4,3)
 # define __warnattr(msg) __attribute__((__warning__ (msg)))
 # define __errordecl(name, msg) \