[PATCH v5 1/2] string: _FORTIFY_SOURCE=3 using __builtin_dynamic_object_size
Siddhesh Poyarekar
siddhesh@sourceware.org
Wed Dec 16 15:24:09 GMT 2020
Introduce a new _FORTIFY_SOURCE level of 3 to enable additional
fortifications that may have a potential performance impact. At the
moment this level of fortification involves the use of the
__builtin_dynamic_object_size builtin whenever the compiler supports
it.
This change enhances fortified string functions to use
__builtin_dynamic_object_size under _FORTIFY_SOURCE=3 whenever the
compiler supports it.
__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.
Other Changes
-------------
The _FORTIFY_SOURCE macro soup in features.h now warns about
unsupported fortification levels. For example, it will warn about
_FORTIFY_SOURCE=3 and over for llvm older than 9.0 and for gcc and
_FORTIFY_SOURCE=4 will result in a warning on all compilers with an
indication of which level has been selected.
---
NEWS | 6 ++++++
include/features.h | 11 +++++++++++
include/string.h | 5 +++--
manual/creature.texi | 3 ++-
misc/sys/cdefs.h | 9 +++++++++
string/bits/string_fortified.h | 22 +++++++++++-----------
string/bits/strings_fortified.h | 4 ++--
7 files changed, 44 insertions(+), 16 deletions(-)
diff --git a/NEWS b/NEWS
index 0820984547..df46560878 100644
--- a/NEWS
+++ b/NEWS
@@ -28,6 +28,12 @@ Major new features:
The 32-bit RISC-V port requires at least Linux 5.4, GCC 7.1 and binutils
2.28.
+* A new fortification level _FORTIFY_SOURCE=3 is available. At this level,
+ glibc may use additional checks that may have an additional performance
+ overhead. At present these checks are available only on LLVM 9 and later.
+ The latest GCC available at this time (10.2) does not support this level of
+ fortification.
+
Deprecated and removed features, and other changes affecting compatibility:
* The mallinfo function is marked deprecated. Callers should call
diff --git a/include/features.h b/include/features.h
index f3e62d3362..d6b69b7d97 100644
--- a/include/features.h
+++ b/include/features.h
@@ -397,6 +397,17 @@
# 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 > 3 && __glibc_clang_prereq(9, 0)
+# warning _FORTIFY_SOURCE > 3 unsupported falling back to 3
+# define __USE_FORTIFY_LEVEL 3
+# elif _FORTIFY_SOURCE > 3
+# warning _FORTIFY_SOURCE > 3 unsupported falling back to 2
+# define __USE_FORTIFY_LEVEL 2
+# elif _FORTIFY_SOURCE > 2 && !__glibc_clang_prereq(9, 0)
+# warning _FORTIFY_SOURCE=3 requires LLVM 9.0 or later, falling back to 2
+# define __USE_FORTIFY_LEVEL 2
+# elif _FORTIFY_SOURCE > 2
+# define __USE_FORTIFY_LEVEL 3
# elif _FORTIFY_SOURCE > 1
# define __USE_FORTIFY_LEVEL 2
# else
diff --git a/include/string.h b/include/string.h
index 7d344d77d4..841ee05a1d 100644
--- a/include/string.h
+++ b/include/string.h
@@ -123,10 +123,11 @@ libc_hidden_proto (__strerror_l)
void __explicit_bzero_chk_internal (void *, size_t, size_t)
__THROW __nonnull ((1)) attribute_hidden;
# define explicit_bzero(buf, len) \
- __explicit_bzero_chk_internal (buf, len, __bos0 (buf))
+ __explicit_bzero_chk_internal (buf, len, __objsize0 (buf))
#elif !IS_IN (nonlib)
void __explicit_bzero_chk (void *, size_t, size_t) __THROW __nonnull ((1));
-# define explicit_bzero(buf, len) __explicit_bzero_chk (buf, len, __bos0 (buf))
+# define explicit_bzero(buf, len) __explicit_bzero_chk (buf, len, \
+ __objsize0 (buf))
#endif
libc_hidden_builtin_proto (memchr)
diff --git a/manual/creature.texi b/manual/creature.texi
index be5050468b..31208ccb2b 100644
--- a/manual/creature.texi
+++ b/manual/creature.texi
@@ -254,7 +254,8 @@ included.
@standards{GNU, (none)}
If this macro is defined to @math{1}, security hardening is added to
various library functions. If defined to @math{2}, even stricter
-checks are applied.
+checks are applied. If defined to @math{3}, @theglibc{} may also use
+checks that may have an additional performance overhead.
@end defvr
@defvr Macro _REENTRANT
diff --git a/misc/sys/cdefs.h b/misc/sys/cdefs.h
index a06f1cfd91..ca51a5c3ad 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 __objsize0(__o) __builtin_dynamic_object_size (__o, 0)
+# define __objsize(__o) __builtin_dynamic_object_size (__o, 1)
+#else
+# define __objsize0(__o) __bos0 (__o)
+# define __objsize(__o) __bos (__o)
+#endif
+
#if __GNUC_PREREQ (4,3)
# define __warnattr(msg) __attribute__((__warning__ (msg)))
# define __errordecl(name, msg) \
diff --git a/string/bits/string_fortified.h b/string/bits/string_fortified.h
index 4c1aeb45f1..c9f9197aef 100644
--- a/string/bits/string_fortified.h
+++ b/string/bits/string_fortified.h
@@ -26,13 +26,13 @@ __fortify_function void *
__NTH (memcpy (void *__restrict __dest, const void *__restrict __src,
size_t __len))
{
- return __builtin___memcpy_chk (__dest, __src, __len, __bos0 (__dest));
+ return __builtin___memcpy_chk (__dest, __src, __len, __objsize0 (__dest));
}
__fortify_function void *
__NTH (memmove (void *__dest, const void *__src, size_t __len))
{
- return __builtin___memmove_chk (__dest, __src, __len, __bos0 (__dest));
+ return __builtin___memmove_chk (__dest, __src, __len, __objsize0 (__dest));
}
#ifdef __USE_GNU
@@ -40,7 +40,7 @@ __fortify_function void *
__NTH (mempcpy (void *__restrict __dest, const void *__restrict __src,
size_t __len))
{
- return __builtin___mempcpy_chk (__dest, __src, __len, __bos0 (__dest));
+ return __builtin___mempcpy_chk (__dest, __src, __len, __objsize0 (__dest));
}
#endif
@@ -53,7 +53,7 @@ __NTH (mempcpy (void *__restrict __dest, const void *__restrict __src,
__fortify_function void *
__NTH (memset (void *__dest, int __ch, size_t __len))
{
- return __builtin___memset_chk (__dest, __ch, __len, __bos0 (__dest));
+ return __builtin___memset_chk (__dest, __ch, __len, __objsize0 (__dest));
}
#ifdef __USE_MISC
@@ -65,21 +65,21 @@ void __explicit_bzero_chk (void *__dest, size_t __len, size_t __destlen)
__fortify_function void
__NTH (explicit_bzero (void *__dest, size_t __len))
{
- __explicit_bzero_chk (__dest, __len, __bos0 (__dest));
+ __explicit_bzero_chk (__dest, __len, __objsize0 (__dest));
}
#endif
__fortify_function char *
__NTH (strcpy (char *__restrict __dest, const char *__restrict __src))
{
- return __builtin___strcpy_chk (__dest, __src, __bos (__dest));
+ return __builtin___strcpy_chk (__dest, __src, __objsize (__dest));
}
#ifdef __USE_GNU
__fortify_function char *
__NTH (stpcpy (char *__restrict __dest, const char *__restrict __src))
{
- return __builtin___stpcpy_chk (__dest, __src, __bos (__dest));
+ return __builtin___stpcpy_chk (__dest, __src, __objsize (__dest));
}
#endif
@@ -88,14 +88,14 @@ __fortify_function char *
__NTH (strncpy (char *__restrict __dest, const char *__restrict __src,
size_t __len))
{
- return __builtin___strncpy_chk (__dest, __src, __len, __bos (__dest));
+ return __builtin___strncpy_chk (__dest, __src, __len, __objsize (__dest));
}
#if __GNUC_PREREQ (4, 7) || __glibc_clang_prereq (2, 6)
__fortify_function char *
__NTH (stpncpy (char *__dest, const char *__src, size_t __n))
{
- return __builtin___stpncpy_chk (__dest, __src, __n, __bos (__dest));
+ return __builtin___stpncpy_chk (__dest, __src, __n, __objsize (__dest));
}
#else
extern char *__stpncpy_chk (char *__dest, const char *__src, size_t __n,
@@ -118,7 +118,7 @@ __NTH (stpncpy (char *__dest, const char *__src, size_t __n))
__fortify_function char *
__NTH (strcat (char *__restrict __dest, const char *__restrict __src))
{
- return __builtin___strcat_chk (__dest, __src, __bos (__dest));
+ return __builtin___strcat_chk (__dest, __src, __objsize (__dest));
}
@@ -126,7 +126,7 @@ __fortify_function char *
__NTH (strncat (char *__restrict __dest, const char *__restrict __src,
size_t __len))
{
- return __builtin___strncat_chk (__dest, __src, __len, __bos (__dest));
+ return __builtin___strncat_chk (__dest, __src, __len, __objsize (__dest));
}
#endif /* bits/string_fortified.h */
diff --git a/string/bits/strings_fortified.h b/string/bits/strings_fortified.h
index d4091f4f69..122199e036 100644
--- a/string/bits/strings_fortified.h
+++ b/string/bits/strings_fortified.h
@@ -22,13 +22,13 @@
__fortify_function void
__NTH (bcopy (const void *__src, void *__dest, size_t __len))
{
- (void) __builtin___memmove_chk (__dest, __src, __len, __bos0 (__dest));
+ (void) __builtin___memmove_chk (__dest, __src, __len, __objsize0 (__dest));
}
__fortify_function void
__NTH (bzero (void *__dest, size_t __len))
{
- (void) __builtin___memset_chk (__dest, '\0', __len, __bos0 (__dest));
+ (void) __builtin___memset_chk (__dest, '\0', __len, __objsize0 (__dest));
}
#endif
--
2.29.2
More information about the Libc-alpha
mailing list