346 lines
16 KiB
Diff
346 lines
16 KiB
Diff
|
commit c82bdf033f93a710044e25f721340c26e89a3769
|
||
|
Author: Siddhesh Poyarekar <siddhesh@sourceware.org>
|
||
|
Date: Tue Oct 12 12:29:13 2021 +0530
|
||
|
|
||
|
Don't add access size hints to fortifiable functions
|
||
|
|
||
|
In the context of a function definition, the size hints imply that the
|
||
|
size of an object pointed to by one parameter is another parameter.
|
||
|
This doesn't make sense for the fortified versions of the functions
|
||
|
since that's the bit it's trying to validate.
|
||
|
|
||
|
This is harmless with __builtin_object_size since it has fairly simple
|
||
|
semantics when it comes to objects passed as function parameters.
|
||
|
With __builtin_dynamic_object_size we could (as my patchset for gcc[1]
|
||
|
already does) use the access attribute to determine the object size in
|
||
|
the general case but it misleads the fortified functions.
|
||
|
|
||
|
Basically the problem occurs when access attributes are present on
|
||
|
regular functions that have inline fortified definitions to generate
|
||
|
_chk variants; the attributes get inherited by these definitions,
|
||
|
causing problems when analyzing them. For example with poll(fds, nfds,
|
||
|
timeout), nfds is hinted using the __attr_access as being the size of
|
||
|
fds.
|
||
|
|
||
|
Now, when analyzing the inline function definition in bits/poll2.h, the
|
||
|
compiler sees that nfds is the size of fds and tries to use that
|
||
|
information in the function body. In _FORTIFY_SOURCE=3 case, where the
|
||
|
object size could be a non-constant expression, this information results
|
||
|
in the conclusion that nfds is the size of fds, which defeats the
|
||
|
purpose of the implementation because we're trying to check here if nfds
|
||
|
does indeed represent the size of fds. Hence for this case, it is best
|
||
|
to not have the access attribute.
|
||
|
|
||
|
With the attributes gone, the expression evaluation should get delayed
|
||
|
until the function is actually inlined into its destinations.
|
||
|
|
||
|
Disable the access attribute for fortified function inline functions
|
||
|
when building at _FORTIFY_SOURCE=3 to make this work better. The
|
||
|
access attributes remain for the _chk variants since they can be used
|
||
|
by the compiler to warn when the caller is passing invalid arguments.
|
||
|
|
||
|
[1] https://gcc.gnu.org/pipermail/gcc-patches/2021-October/581125.html
|
||
|
|
||
|
Signed-off-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
|
||
|
(cherry picked from commit e938c02748402c50f60ba0eb983273e7b52937d1)
|
||
|
|
||
|
diff --git a/io/bits/poll2.h b/io/bits/poll2.h
|
||
|
index a623678c09f9f04f..be74d020f2e0e434 100644
|
||
|
--- a/io/bits/poll2.h
|
||
|
+++ b/io/bits/poll2.h
|
||
|
@@ -33,7 +33,7 @@ extern int __REDIRECT (__poll_chk_warn, (struct pollfd *__fds, nfds_t __nfds,
|
||
|
__poll_chk)
|
||
|
__warnattr ("poll called with fds buffer too small file nfds entries");
|
||
|
|
||
|
-__fortify_function __attr_access ((__write_only__, 1, 2)) int
|
||
|
+__fortify_function __fortified_attr_access (__write_only__, 1, 2) int
|
||
|
poll (struct pollfd *__fds, nfds_t __nfds, int __timeout)
|
||
|
{
|
||
|
if (__glibc_objsize (__fds) != (__SIZE_TYPE__) -1)
|
||
|
@@ -64,7 +64,7 @@ extern int __REDIRECT (__ppoll_chk_warn, (struct pollfd *__fds, nfds_t __nfds,
|
||
|
__ppoll_chk)
|
||
|
__warnattr ("ppoll called with fds buffer too small file nfds entries");
|
||
|
|
||
|
-__fortify_function __attr_access ((__write_only__, 1, 2)) int
|
||
|
+__fortify_function __fortified_attr_access (__write_only__, 1, 2) int
|
||
|
ppoll (struct pollfd *__fds, nfds_t __nfds, const struct timespec *__timeout,
|
||
|
const __sigset_t *__ss)
|
||
|
{
|
||
|
diff --git a/io/sys/poll.h b/io/sys/poll.h
|
||
|
index e640efb2bce7ea67..751c7f5f72db8be2 100644
|
||
|
--- a/io/sys/poll.h
|
||
|
+++ b/io/sys/poll.h
|
||
|
@@ -52,7 +52,7 @@ __BEGIN_DECLS
|
||
|
This function is a cancellation point and therefore not marked with
|
||
|
__THROW. */
|
||
|
extern int poll (struct pollfd *__fds, nfds_t __nfds, int __timeout)
|
||
|
- __attr_access ((__write_only__, 1, 2));
|
||
|
+ __fortified_attr_access (__write_only__, 1, 2);
|
||
|
|
||
|
#ifdef __USE_GNU
|
||
|
/* Like poll, but before waiting the threads signal mask is replaced
|
||
|
@@ -64,7 +64,7 @@ extern int poll (struct pollfd *__fds, nfds_t __nfds, int __timeout)
|
||
|
extern int ppoll (struct pollfd *__fds, nfds_t __nfds,
|
||
|
const struct timespec *__timeout,
|
||
|
const __sigset_t *__ss)
|
||
|
- __attr_access ((__write_only__, 1, 2));
|
||
|
+ __fortified_attr_access (__write_only__, 1, 2);
|
||
|
|
||
|
# ifdef __USE_TIME_BITS64
|
||
|
# ifdef __REDIRECT
|
||
|
@@ -72,7 +72,7 @@ extern int __REDIRECT (ppoll, (struct pollfd *__fds, nfds_t __nfds,
|
||
|
const struct timespec *__timeout,
|
||
|
const __sigset_t *__ss),
|
||
|
__ppoll64)
|
||
|
- __attr_access ((__write_only__, 1, 2));
|
||
|
+ __fortified_attr_access (__write_only__, 1, 2);
|
||
|
# else
|
||
|
# define ppoll __ppoll64
|
||
|
# endif
|
||
|
diff --git a/libio/bits/stdio2.h b/libio/bits/stdio2.h
|
||
|
index 3f0cab1254b02c43..4f016a563857a137 100644
|
||
|
--- a/libio/bits/stdio2.h
|
||
|
+++ b/libio/bits/stdio2.h
|
||
|
@@ -258,7 +258,7 @@ extern char *__REDIRECT (__fgets_chk_warn,
|
||
|
__wur __warnattr ("fgets called with bigger size than length "
|
||
|
"of destination buffer");
|
||
|
|
||
|
-__fortify_function __wur __attr_access ((__write_only__, 1, 2)) char *
|
||
|
+__fortify_function __wur __fortified_attr_access (__write_only__, 1, 2) char *
|
||
|
fgets (char *__restrict __s, int __n, FILE *__restrict __stream)
|
||
|
{
|
||
|
if (__glibc_objsize (__s) != (size_t) -1)
|
||
|
@@ -320,7 +320,7 @@ extern char *__REDIRECT (__fgets_unlocked_chk_warn,
|
||
|
__wur __warnattr ("fgets_unlocked called with bigger size than length "
|
||
|
"of destination buffer");
|
||
|
|
||
|
-__fortify_function __wur __attr_access ((__write_only__, 1, 2)) char *
|
||
|
+__fortify_function __wur __fortified_attr_access (__write_only__, 1, 2) char *
|
||
|
fgets_unlocked (char *__restrict __s, int __n, FILE *__restrict __stream)
|
||
|
{
|
||
|
if (__glibc_objsize (__s) != (size_t) -1)
|
||
|
diff --git a/libio/stdio.h b/libio/stdio.h
|
||
|
index 497da016ffa2e230..abefe640e52d18d5 100644
|
||
|
--- a/libio/stdio.h
|
||
|
+++ b/libio/stdio.h
|
||
|
@@ -584,7 +584,7 @@ extern int putw (int __w, FILE *__stream);
|
||
|
This function is a possible cancellation point and therefore not
|
||
|
marked with __THROW. */
|
||
|
extern char *fgets (char *__restrict __s, int __n, FILE *__restrict __stream)
|
||
|
- __wur __attr_access ((__write_only__, 1, 2));
|
||
|
+ __wur __fortified_attr_access (__write_only__, 1, 2);
|
||
|
|
||
|
#if __GLIBC_USE (DEPRECATED_GETS)
|
||
|
/* Get a newline-terminated string from stdin, removing the newline.
|
||
|
@@ -608,7 +608,7 @@ extern char *gets (char *__s) __wur __attribute_deprecated__;
|
||
|
therefore not marked with __THROW. */
|
||
|
extern char *fgets_unlocked (char *__restrict __s, int __n,
|
||
|
FILE *__restrict __stream) __wur
|
||
|
- __attr_access ((__write_only__, 1, 2));
|
||
|
+ __fortified_attr_access (__write_only__, 1, 2);
|
||
|
#endif
|
||
|
|
||
|
|
||
|
diff --git a/misc/sys/cdefs.h b/misc/sys/cdefs.h
|
||
|
index e490fc1aebeadc3d..cd836441a9807d6a 100644
|
||
|
--- a/misc/sys/cdefs.h
|
||
|
+++ b/misc/sys/cdefs.h
|
||
|
@@ -603,12 +603,22 @@ _Static_assert (0, "IEEE 128-bits long double requires redirection on this platf
|
||
|
size-index is not provided:
|
||
|
access (access-mode, <ref-index> [, <size-index>]) */
|
||
|
# define __attr_access(x) __attribute__ ((__access__ x))
|
||
|
+/* For _FORTIFY_SOURCE == 3 we use __builtin_dynamic_object_size, which may
|
||
|
+ use the access attribute to get object sizes from function definition
|
||
|
+ arguments, so we can't use them on functions we fortify. Drop the object
|
||
|
+ size hints for such functions. */
|
||
|
+# if __USE_FORTIFY_LEVEL == 3
|
||
|
+# define __fortified_attr_access(a, o, s) __attribute__ ((__access__ (a, o)))
|
||
|
+# else
|
||
|
+# define __fortified_attr_access(a, o, s) __attr_access ((a, o, s))
|
||
|
+# endif
|
||
|
# if __GNUC_PREREQ (11, 0)
|
||
|
# define __attr_access_none(argno) __attribute__ ((__access__ (__none__, argno)))
|
||
|
# else
|
||
|
# define __attr_access_none(argno)
|
||
|
# endif
|
||
|
#else
|
||
|
+# define __fortified_attr_access(a, o, s)
|
||
|
# define __attr_access(x)
|
||
|
# define __attr_access_none(argno)
|
||
|
#endif
|
||
|
diff --git a/posix/unistd.h b/posix/unistd.h
|
||
|
index 8224c5fbc956306f..7a61ff5e868c3456 100644
|
||
|
--- a/posix/unistd.h
|
||
|
+++ b/posix/unistd.h
|
||
|
@@ -369,7 +369,7 @@ extern void closefrom (int __lowfd) __THROW;
|
||
|
This function is a cancellation point and therefore not marked with
|
||
|
__THROW. */
|
||
|
extern ssize_t read (int __fd, void *__buf, size_t __nbytes) __wur
|
||
|
- __attr_access ((__write_only__, 2, 3));
|
||
|
+ __fortified_attr_access (__write_only__, 2, 3);
|
||
|
|
||
|
/* Write N bytes of BUF to FD. Return the number written, or -1.
|
||
|
|
||
|
@@ -388,7 +388,7 @@ extern ssize_t write (int __fd, const void *__buf, size_t __n) __wur
|
||
|
__THROW. */
|
||
|
extern ssize_t pread (int __fd, void *__buf, size_t __nbytes,
|
||
|
__off_t __offset) __wur
|
||
|
- __attr_access ((__write_only__, 2, 3));
|
||
|
+ __fortified_attr_access (__write_only__, 2, 3);
|
||
|
|
||
|
/* Write N bytes of BUF to FD at the given position OFFSET without
|
||
|
changing the file pointer. Return the number written, or -1.
|
||
|
@@ -404,7 +404,7 @@ extern ssize_t pwrite (int __fd, const void *__buf, size_t __n,
|
||
|
extern ssize_t __REDIRECT (pread, (int __fd, void *__buf, size_t __nbytes,
|
||
|
__off64_t __offset),
|
||
|
pread64) __wur
|
||
|
- __attr_access ((__write_only__, 2, 3));
|
||
|
+ __fortified_attr_access (__write_only__, 2, 3);
|
||
|
extern ssize_t __REDIRECT (pwrite, (int __fd, const void *__buf,
|
||
|
size_t __nbytes, __off64_t __offset),
|
||
|
pwrite64) __wur
|
||
|
@@ -421,7 +421,7 @@ extern ssize_t __REDIRECT (pwrite, (int __fd, const void *__buf,
|
||
|
or 0 for EOF. */
|
||
|
extern ssize_t pread64 (int __fd, void *__buf, size_t __nbytes,
|
||
|
__off64_t __offset) __wur
|
||
|
- __attr_access ((__write_only__, 2, 3));
|
||
|
+ __fortified_attr_access (__write_only__, 2, 3);
|
||
|
/* Write N bytes of BUF to FD at the given position OFFSET without
|
||
|
changing the file pointer. Return the number written, or -1. */
|
||
|
extern ssize_t pwrite64 (int __fd, const void *__buf, size_t __n,
|
||
|
@@ -642,7 +642,7 @@ extern long int sysconf (int __name) __THROW;
|
||
|
#ifdef __USE_POSIX2
|
||
|
/* Get the value of the string-valued system variable NAME. */
|
||
|
extern size_t confstr (int __name, char *__buf, size_t __len) __THROW
|
||
|
- __attr_access ((__write_only__, 2, 3));
|
||
|
+ __fortified_attr_access (__write_only__, 2, 3);
|
||
|
#endif
|
||
|
|
||
|
|
||
|
@@ -709,7 +709,7 @@ extern __gid_t getegid (void) __THROW;
|
||
|
the calling process is in. Otherwise, fill in the group IDs
|
||
|
of its supplementary groups in LIST and return the number written. */
|
||
|
extern int getgroups (int __size, __gid_t __list[]) __THROW __wur
|
||
|
- __attr_access ((__write_only__, 2, 1));
|
||
|
+ __fortified_attr_access (__write_only__, 2, 1);
|
||
|
#ifdef __USE_GNU
|
||
|
/* Return nonzero iff the calling process is in group GID. */
|
||
|
extern int group_member (__gid_t __gid) __THROW;
|
||
|
@@ -801,7 +801,8 @@ extern char *ttyname (int __fd) __THROW;
|
||
|
/* Store at most BUFLEN characters of the pathname of the terminal FD is
|
||
|
open on in BUF. Return 0 on success, otherwise an error number. */
|
||
|
extern int ttyname_r (int __fd, char *__buf, size_t __buflen)
|
||
|
- __THROW __nonnull ((2)) __wur __attr_access ((__write_only__, 2, 3));
|
||
|
+ __THROW __nonnull ((2)) __wur
|
||
|
+ __fortified_attr_access (__write_only__, 2, 3);
|
||
|
|
||
|
/* Return 1 if FD is a valid descriptor associated
|
||
|
with a terminal, zero if not. */
|
||
|
@@ -836,7 +837,8 @@ extern int symlink (const char *__from, const char *__to)
|
||
|
Returns the number of characters read, or -1 for errors. */
|
||
|
extern ssize_t readlink (const char *__restrict __path,
|
||
|
char *__restrict __buf, size_t __len)
|
||
|
- __THROW __nonnull ((1, 2)) __wur __attr_access ((__write_only__, 2, 3));
|
||
|
+ __THROW __nonnull ((1, 2)) __wur
|
||
|
+ __fortified_attr_access (__write_only__, 2, 3);
|
||
|
|
||
|
#endif /* Use POSIX.1-2001. */
|
||
|
|
||
|
@@ -848,7 +850,8 @@ extern int symlinkat (const char *__from, int __tofd,
|
||
|
/* Like readlink but a relative PATH is interpreted relative to FD. */
|
||
|
extern ssize_t readlinkat (int __fd, const char *__restrict __path,
|
||
|
char *__restrict __buf, size_t __len)
|
||
|
- __THROW __nonnull ((2, 3)) __wur __attr_access ((__write_only__, 3, 4));
|
||
|
+ __THROW __nonnull ((2, 3)) __wur
|
||
|
+ __fortified_attr_access (__write_only__, 3, 4);
|
||
|
#endif
|
||
|
|
||
|
/* Remove the link NAME. */
|
||
|
@@ -884,7 +887,7 @@ extern char *getlogin (void);
|
||
|
This function is a possible cancellation point and therefore not
|
||
|
marked with __THROW. */
|
||
|
extern int getlogin_r (char *__name, size_t __name_len) __nonnull ((1))
|
||
|
- __attr_access ((__write_only__, 1, 2));
|
||
|
+ __fortified_attr_access (__write_only__, 1, 2);
|
||
|
#endif
|
||
|
|
||
|
#ifdef __USE_MISC
|
||
|
@@ -906,7 +909,7 @@ extern int setlogin (const char *__name) __THROW __nonnull ((1));
|
||
|
The result is null-terminated if LEN is large enough for the full
|
||
|
name and the terminator. */
|
||
|
extern int gethostname (char *__name, size_t __len) __THROW __nonnull ((1))
|
||
|
- __attr_access ((__write_only__, 1, 2));
|
||
|
+ __fortified_attr_access (__write_only__, 1, 2);
|
||
|
#endif
|
||
|
|
||
|
|
||
|
@@ -925,7 +928,8 @@ extern int sethostid (long int __id) __THROW __wur;
|
||
|
Called just like `gethostname' and `sethostname'.
|
||
|
The NIS domain name is usually the empty string when not using NIS. */
|
||
|
extern int getdomainname (char *__name, size_t __len)
|
||
|
- __THROW __nonnull ((1)) __wur __attr_access ((__write_only__, 1, 2));
|
||
|
+ __THROW __nonnull ((1)) __wur
|
||
|
+ __fortified_attr_access (__write_only__, 1, 2);
|
||
|
extern int setdomainname (const char *__name, size_t __len)
|
||
|
__THROW __nonnull ((1)) __wur __attr_access ((__read_only__, 1, 2));
|
||
|
|
||
|
diff --git a/stdlib/stdlib.h b/stdlib/stdlib.h
|
||
|
index 0481c1235514f6e7..74c00eee73e4009d 100644
|
||
|
--- a/stdlib/stdlib.h
|
||
|
+++ b/stdlib/stdlib.h
|
||
|
@@ -943,7 +943,8 @@ extern size_t mbstowcs (wchar_t *__restrict __pwcs,
|
||
|
extern size_t wcstombs (char *__restrict __s,
|
||
|
const wchar_t *__restrict __pwcs, size_t __n)
|
||
|
__THROW
|
||
|
- __attr_access ((__write_only__, 1, 3)) __attr_access ((__read_only__, 2));
|
||
|
+ __fortified_attr_access (__write_only__, 1, 3)
|
||
|
+ __attr_access ((__read_only__, 2));
|
||
|
|
||
|
#ifdef __USE_MISC
|
||
|
/* Determine whether the string value of RESPONSE matches the affirmation
|
||
|
@@ -997,7 +998,7 @@ extern char *ptsname (int __fd) __THROW __wur;
|
||
|
terminal associated with the master FD is open on in BUF.
|
||
|
Return 0 on success, otherwise an error number. */
|
||
|
extern int ptsname_r (int __fd, char *__buf, size_t __buflen)
|
||
|
- __THROW __nonnull ((2)) __attr_access ((__write_only__, 2, 3));
|
||
|
+ __THROW __nonnull ((2)) __fortified_attr_access (__write_only__, 2, 3);
|
||
|
|
||
|
/* Open a master pseudo terminal and return its file descriptor. */
|
||
|
extern int getpt (void);
|
||
|
diff --git a/string/bits/string_fortified.h b/string/bits/string_fortified.h
|
||
|
index 67ae2c6b50435368..5731274848260ad2 100644
|
||
|
--- a/string/bits/string_fortified.h
|
||
|
+++ b/string/bits/string_fortified.h
|
||
|
@@ -64,7 +64,7 @@ __NTH (memset (void *__dest, int __ch, size_t __len))
|
||
|
# include <bits/strings_fortified.h>
|
||
|
|
||
|
void __explicit_bzero_chk (void *__dest, size_t __len, size_t __destlen)
|
||
|
- __THROW __nonnull ((1)) __attr_access ((__write_only__, 1, 2));
|
||
|
+ __THROW __nonnull ((1)) __fortified_attr_access (__write_only__, 1, 2);
|
||
|
|
||
|
__fortify_function void
|
||
|
__NTH (explicit_bzero (void *__dest, size_t __len))
|
||
|
@@ -106,7 +106,8 @@ __NTH (stpncpy (char *__dest, const char *__src, size_t __n))
|
||
|
#else
|
||
|
extern char *__stpncpy_chk (char *__dest, const char *__src, size_t __n,
|
||
|
size_t __destlen) __THROW
|
||
|
- __attr_access ((__write_only__, 1, 3)) __attr_access ((__read_only__, 2));
|
||
|
+ __fortified_attr_access ((__write_only__, 1, 3))
|
||
|
+ __attr_access ((__read_only__, 2));
|
||
|
extern char *__REDIRECT_NTH (__stpncpy_alias, (char *__dest, const char *__src,
|
||
|
size_t __n), stpncpy);
|
||
|
|
||
|
diff --git a/string/string.h b/string/string.h
|
||
|
index 04e1b7067dc31d3c..8dcafb4ac4952853 100644
|
||
|
--- a/string/string.h
|
||
|
+++ b/string/string.h
|
||
|
@@ -448,7 +448,7 @@ extern char *strerror_l (int __errnum, locale_t __l) __THROW;
|
||
|
/* Set N bytes of S to 0. The compiler will not delete a call to this
|
||
|
function, even if S is dead after the call. */
|
||
|
extern void explicit_bzero (void *__s, size_t __n) __THROW __nonnull ((1))
|
||
|
- __attr_access ((__write_only__, 1, 2));
|
||
|
+ __fortified_attr_access (__write_only__, 1, 2);
|
||
|
|
||
|
/* Return the next DELIM-delimited token from *STRINGP,
|
||
|
terminating it with a '\0', and update *STRINGP to point past it. */
|