Support gcc FORTIFY_SOURCE features for nuttx libc

This function will use gcc's function
__builtin_dynamic_object_size and __builtin_object_size

Its function is to obtain the size of the object through compilation,
so as to judge whether there are out-of-bounds operations in commonly used functions.
It should be noted that the option -O2 and above is required to enable this function

Signed-off-by: anjiahao <1090959677@qq.com>
This commit is contained in:
anjiahao 2023-05-23 06:46:19 +08:00 committed by Xiang Xiao
parent 880d78f903
commit d5981375a6
10 changed files with 483 additions and 0 deletions

12
Kconfig
View File

@ -597,6 +597,18 @@ endmenu # Customize Header Files
menu "Debug Options"
config FORTIFY_SOURCE
int "Fortify Source"
default 0
range 0 3
---help---
Detect overflows of buffers in common string and memory functions
where the compiler can determine and validate the buffer sizes.
0 does not have any checks.
1 will only check for out-of-bounds at compile time.
2 will only perform out-of-bounds checks on stack variables.
3 On the basis of 2, add an out-of-bounds check for dynamically allocated variables.
config NDEBUG
bool "Define NDEBUG globally"
default !DEBUG_ASSERTIONS

View File

@ -87,6 +87,38 @@
# define CONFIG_HAVE_BUILTIN_FFSLL 1
# endif
# if CONFIG_FORTIFY_SOURCE > 0
# if !defined(__OPTIMIZE__) || (__OPTIMIZE__) <= 0
# warning requires compiling with optimization (-O2 or higher)
# endif
# if CONFIG_FORTIFY_SOURCE == 3
# if __GNUC__ < 12 || (defined(__clang__) && __clang_major__ < 12)
# error compiler version less than 12 does not support dynamic object size
# endif
# define fortify_size(__o, type) __builtin_dynamic_object_size(__o, type)
# else
# define fortify_size(__o, type) __builtin_object_size(__o, type)
# endif
# define fortify_assert(condition) do \
{ \
if (!(condition)) \
{ \
__builtin_trap(); \
} \
} \
while (0)
# define fortify_va_arg_pack __builtin_va_arg_pack
# define fortify_str(s) #s
# define fortify_real(p,fn) __typeof__(fn) __real_##fn __asm__(fortify_str(p) #fn)
# define fortify_function(fn) fortify_real(__USER_LABEL_PREFIX__, fn); \
extern __inline__ \
__attribute__((__always_inline__, \
__gnu_inline__, __artificial__))
# endif
/* Pre-processor */
# define CONFIG_CPP_HAVE_VARARGS 1 /* Supports variable argument macros */

View File

@ -244,6 +244,67 @@ int pclose(FILE *stream);
FILE *popen(FAR const char *command, FAR const char *mode) popen_like;
#endif
#if CONFIG_FORTIFY_SOURCE > 0
fortify_function(fgets) FAR char *fgets(FAR char *s, int n, FAR FILE *stream)
{
fortify_assert((size_t)n <= fortify_size(s, 0));
return __real_fgets(s, n, stream);
}
fortify_function(fread) size_t fread(FAR void *ptr, size_t size,
size_t n_items, FAR FILE *stream)
{
fortify_assert(n_items == 0 || (n_items * size) / n_items == size);
fortify_assert(n_items * size <= fortify_size(ptr, 0));
return __real_fread(ptr, size, n_items, stream);
}
fortify_function(fwrite) size_t fwrite(FAR const void *ptr, size_t size,
size_t n_items, FAR FILE *stream)
{
fortify_assert(n_items == 0 || (n_items * size) / n_items == size);
fortify_assert(n_items * size <= fortify_size(ptr, 0));
return __real_fwrite(ptr, size, n_items, stream);
}
fortify_function(vsnprintf) int vsnprintf(FAR char *buf, size_t size,
FAR const IPTR char *format,
va_list ap)
{
fortify_assert(size <= fortify_size(buf, 0));
return __real_vsnprintf(buf, size, format, ap);
}
fortify_function(vsprintf) int vsprintf(FAR char *dest,
FAR const IPTR char *src,
va_list ap)
{
int ret;
ret = __real_vsprintf(dest, src, ap);
fortify_assert(ret == -1 || (size_t)ret <= fortify_size(dest, 0));
return ret;
}
fortify_function(snprintf) int snprintf(FAR char *buf, size_t size,
FAR const IPTR char *format, ...)
{
fortify_assert(size <= fortify_size(buf, 0));
return __real_snprintf(buf, size, format, fortify_va_arg_pack());
}
fortify_function(sprintf) int sprintf(FAR char *buf,
FAR const IPTR char *fmt,
...)
{
int ret;
ret = __real_sprintf(buf, fmt, fortify_va_arg_pack());
fortify_assert(ret == -1 || (size_t)ret <= fortify_size(buf, 0));
return ret;
}
#endif
#undef EXTERN
#if defined(__cplusplus)
}

View File

@ -291,6 +291,29 @@ FAR const char *getprogname(void);
int __cxa_atexit(CODE void (*func)(FAR void *), FAR void *arg,
FAR void *dso_handle);
#if CONFIG_FORTIFY_SOURCE > 0
fortify_function(realpath) FAR char *realpath(FAR const char *path,
FAR char *resolved)
{
FAR char *ret = __real_realpath(path, resolved);
if (ret != NULL && resolved != NULL)
{
size_t len = 1;
FAR char *p;
p = ret;
while (*p++ != '\0')
{
len++;
}
fortify_assert(len <= fortify_size(resolved, 0));
}
return ret;
}
#endif
#undef EXTERN
#if defined(__cplusplus)
}

View File

@ -108,6 +108,107 @@ FAR void *memmem(FAR const void *haystack, size_t haystacklen,
void explicit_bzero(FAR void *s, size_t n);
int timingsafe_bcmp(FAR const void *b1, FAR const void *b2, size_t n);
#if CONFIG_FORTIFY_SOURCE > 0
fortify_function(strcat) FAR char *strcat(FAR char *dest,
FAR const char *src)
{
fortify_assert(strlen(dest) + strlen(src) + 1 <= fortify_size(dest, 0));
return __real_strcat(dest, src);
}
fortify_function(strlcat) size_t strlcat(FAR char *dst,
FAR const char *src,
size_t dsize)
{
fortify_assert(dsize <= fortify_size(dst, 0));
return __real_strlcat(dst, src, dsize);
}
fortify_function(strncat) FAR char *strncat(FAR char *dest,
FAR const char *src,
size_t n)
{
fortify_assert(n <= fortify_size(dest, 0));
return __real_strncat(dest, src, n);
}
fortify_function(strcpy) FAR char *strcpy(FAR char *dest,
FAR const char *src)
{
fortify_assert(strlen(src) + 1 <= fortify_size(dest, 0));
return __real_strcpy(dest, src);
}
fortify_function(stpcpy) FAR char *stpcpy(FAR char *dest,
FAR const char *src)
{
fortify_assert(strlen(src) + 1 <= fortify_size(dest, 0));
return __real_stpcpy(dest, src);
}
fortify_function(stpncpy) FAR char *stpncpy(FAR char *dest,
FAR const char *src,
size_t n)
{
fortify_assert(n <= fortify_size(dest, 0));
return __real_stpncpy(dest, src, n);
}
fortify_function(strlcpy) size_t strlcpy(FAR char *dst,
FAR const char *src,
size_t siz)
{
fortify_assert(siz <= fortify_size(dst, 0));
return __real_strlcpy(dst, src, siz);
}
fortify_function(strncpy) FAR char *strncpy(FAR char *dest,
FAR const char *src,
size_t n)
{
fortify_assert(n <= fortify_size(dest, 0));
return __real_strncpy(dest, src, n);
}
fortify_function(memmove) FAR void *memmove(FAR void *dest,
FAR const void *src,
size_t count)
{
fortify_assert(count <= fortify_size(dest, 0) &&
count <= fortify_size(src, 0));
return __real_memmove(dest, src, count);
}
fortify_function(memcpy) FAR void *memcpy(FAR void *dest,
FAR const void *src,
size_t n)
{
fortify_assert(n <= fortify_size(dest, 0) && n <= fortify_size(src, 0));
return __real_memcpy(dest, src, n);
}
fortify_function(memset) FAR void *memset(FAR void *s, int c, size_t n)
{
fortify_assert(n <= fortify_size(s, 0));
return __real_memset(s, c, n);
}
fortify_function(mempcpy) FAR void *mempcpy(FAR void *dest,
FAR const void *src,
size_t n)
{
fortify_assert(n <= fortify_size(dest, 0) && n <= fortify_size(src, 0));
return __real_mempcpy(dest, src, n);
}
fortify_function(explicit_bzero) void explicit_bzero(FAR void *s,
size_t n)
{
fortify_assert(n <= fortify_size(s, 0));
__real_explicit_bzero(s, n);
}
#endif
#undef EXTERN
#if defined(__cplusplus)
}

View File

@ -93,6 +93,14 @@ int strncasecmp(FAR const char *, FAR const char *, size_t);
void bzero(FAR void *s, size_t n);
#if CONFIG_FORTIFY_SOURCE > 0
fortify_function(bzero) void bzero(FAR void *s, size_t n)
{
fortify_assert(n <= fortify_size(s, 0));
return bzero(s, n);
}
#endif
#undef EXTERN
#if defined(__cplusplus)
}

View File

@ -149,6 +149,23 @@ int poll_fdsetup(int fd, FAR struct pollfd *fds, bool setup);
void poll_default_cb(FAR struct pollfd *fds);
void poll_notify(FAR struct pollfd **afds, int nfds, pollevent_t eventset);
#if CONFIG_FORTIFY_SOURCE > 0
fortify_function(poll) int poll(FAR struct pollfd *fds,
nfds_t nfds, int timeout)
{
fortify_assert(nfds <= fortify_size(fds, 0) / sizeof(struct pollfd));
return __real_poll(fds, nfds, timeout);
}
fortify_function(ppoll) int ppoll(FAR struct pollfd *fds, nfds_t nfds,
FAR const struct timespec *timeout_ts,
FAR const sigset_t *sigmask)
{
fortify_assert(nfds <= fortify_size(fds, 0) / sizeof(struct pollfd));
return __real_ppoll(fds, nfds, timeout_ts, sigmask);
}
#endif
#undef EXTERN
#if defined(__cplusplus)
}

View File

@ -435,6 +435,40 @@ int getpeername(int sockfd, FAR struct sockaddr *addr,
ssize_t recvmsg(int sockfd, FAR struct msghdr *msg, int flags);
ssize_t sendmsg(int sockfd, FAR struct msghdr *msg, int flags);
#if CONFIG_FORTIFY_SOURCE > 0
fortify_function(send) ssize_t send(int sockfd, FAR const void *buf,
size_t len, int flags)
{
fortify_assert(len <= fortify_size(buf, 0));
return __real_send(sockfd, buf, len, flags);
}
fortify_function(sendto) ssize_t sendto(int sockfd, FAR const void *buf,
size_t len, int flags,
FAR const struct sockaddr *to,
socklen_t tolen)
{
fortify_assert(len <= fortify_size(buf, 0));
return __real_sendto(sockfd, buf, len, flags, to, tolen);
}
fortify_function(recv) ssize_t recv(int sockfd, FAR void *buf,
size_t len, int flags)
{
fortify_assert(len <= fortify_size(buf, 0));
return __real_recv(sockfd, buf, len, flags);
}
fortify_function(recvfrom) ssize_t recvfrom(int sockfd, FAR void *buf,
size_t len, int flags,
FAR struct sockaddr *from,
FAR socklen_t *fromlen)
{
fortify_assert(len <= fortify_size(buf, 0));
return __real_recvfrom(sockfd, buf, len, flags, from, fromlen);
}
#endif
#undef EXTERN
#if defined(__cplusplus)
}

View File

@ -434,6 +434,74 @@ int getentropy(FAR void *buffer, size_t length);
void sync(void);
#if CONFIG_FORTIFY_SOURCE > 0
fortify_function(getcwd) FAR char *getcwd(FAR char *buf,
size_t size)
{
fortify_assert(size <= fortify_size(buf, 0));
return __real_getcwd(buf, size);
}
fortify_function(gethostname) int gethostname(FAR char *name,
size_t namelen)
{
fortify_assert(namelen <= fortify_size(name, 0));
return __real_gethostname(name, namelen);
}
fortify_function(pread) ssize_t pread(int fd, FAR void *buf,
size_t nbytes, off_t offset)
{
fortify_assert(nbytes <= fortify_size(buf, 0));
return __real_pread(fd, buf, nbytes, offset);
}
fortify_function(read) ssize_t read(int fd, FAR void *buf,
size_t nbytes)
{
fortify_assert(nbytes <= fortify_size(buf, 0));
return __real_read(fd, buf, nbytes);
}
fortify_function(readlink) ssize_t readlink(FAR const char *path,
FAR char *buf,
size_t bufsize)
{
fortify_assert(bufsize <= fortify_size(buf, 0));
return __real_readlink(path, buf, bufsize);
}
fortify_function(readlinkat) ssize_t readlinkat(int dirfd,
FAR const char *path,
FAR char *buf,
size_t bufsize)
{
fortify_assert(bufsize <= fortify_size(buf, 0));
return __real_readlinkat(dirfd, path, buf, bufsize);
}
fortify_function(ttyname_r) int ttyname_r(int fd, FAR char *buf,
size_t buflen)
{
fortify_assert(buflen <= fortify_size(buf, 0));
return __real_ttyname_r(fd, buf, buflen);
}
fortify_function(pwrite) ssize_t pwrite(int fd, FAR const void *buf,
size_t nbytes, off_t offset)
{
fortify_assert(nbytes <= fortify_size(buf, 0));
return __real_pwrite(fd, buf, nbytes, offset);
}
fortify_function(write) ssize_t write(int fd, FAR const void *buf,
size_t nbytes)
{
fortify_assert(nbytes <= fortify_size(buf, 0));
return __real_write(fd, buf, nbytes);
}
#endif
#undef EXTERN
#if defined(__cplusplus)
}

View File

@ -218,6 +218,133 @@ FAR wchar_t *wmemset(FAR wchar_t *, wchar_t, size_t);
int wprintf(FAR const wchar_t *, ...);
int wscanf(FAR const wchar_t *, ...);
#if CONFIG_FORTIFY_SOURCE > 0
fortify_function(fgetws) FAR wchar_t *fgetws(FAR wchar_t *s, int n,
FAR FILE *stream)
{
fortify_assert((size_t)n <= fortify_size(s, 0) / sizeof(wchar_t));
return __real_fgetws(s, n, stream);
}
fortify_function(mbsnrtowcs) size_t mbsnrtowcs(FAR wchar_t *dst,
FAR const char **src,
size_t nms,
size_t len,
FAR mbstate_t *ps)
{
fortify_assert(len <= fortify_size(dst, 0) / sizeof(wchar_t));
return __real_mbsnrtowcs(dst, src, nms, len, ps);
}
fortify_function(mbsrtowcs) size_t mbsrtowcs(FAR wchar_t *dst,
FAR const char **src,
size_t len,
FAR mbstate_t *ps)
{
fortify_assert(len <= fortify_size(dst, 0) / sizeof(wchar_t));
return __real_mbsrtowcs(dst, src, len, ps);
}
fortify_function(wcrtomb) size_t wcrtomb(FAR char *s, wchar_t wc,
FAR mbstate_t *ps)
{
size_t ret = __real_wcrtomb(s, wc, ps);
fortify_assert(s == NULL || ret <= fortify_size(s, 0));
return ret;
}
fortify_function(wcscpy) FAR wchar_t *wcscpy(FAR wchar_t *dst,
FAR const wchar_t *src)
{
fortify_assert(wcslen(src) + 1 <= fortify_size(dst, 0) / sizeof(wchar_t));
return __real_wcscpy(dst, src);
}
fortify_function(wcslcpy) size_t wcslcpy(FAR wchar_t *dst,
FAR const wchar_t *src,
size_t siz)
{
fortify_assert(siz <= fortify_size(dst, 0) / sizeof(wchar_t));
return __real_wcslcpy(dst, src, siz);
}
fortify_function(wcscat) FAR wchar_t *wcscat(FAR wchar_t *dst,
FAR const wchar_t *src)
{
fortify_assert(wcslen(dst) + wcslen(src) + 1 <=
fortify_size(dst, 0) / sizeof(wchar_t));
return __real_wcscat(dst, src);
}
fortify_function(wcsncat) FAR wchar_t *wcsncat(FAR wchar_t *dst,
FAR const wchar_t *src,
size_t siz)
{
fortify_assert(siz <= fortify_size(dst, 0) / sizeof(wchar_t));
return __real_wcsncat(dst, src, siz);
}
fortify_function(wcslcat) size_t wcslcat(FAR wchar_t *dst,
FAR const wchar_t *src,
size_t siz)
{
fortify_assert(siz <= fortify_size(dst, 0) / sizeof(wchar_t));
return __real_wcslcat(dst, src, siz);
}
fortify_function(wcsncpy) FAR wchar_t *wcsncpy(FAR wchar_t *dst,
FAR const wchar_t *src,
size_t siz)
{
fortify_assert(siz <= fortify_size(dst, 0) / sizeof(wchar_t));
return __real_wcsncpy(dst, src, siz);
}
fortify_function(wcsnrtombs) size_t wcsnrtombs(FAR char *dst,
FAR const wchar_t **src,
size_t nwc, size_t len,
FAR mbstate_t *ps)
{
fortify_assert(len <= fortify_size(dst, 0));
return __real_wcsnrtombs(dst, src, nwc, len, ps);
}
fortify_function(wcsrtombs) size_t wcsrtombs(FAR char *dst,
FAR const wchar_t **src,
size_t len,
FAR mbstate_t *ps)
{
fortify_assert(len <= fortify_size(dst, 0));
return __real_wcsrtombs(dst, src, len, ps);
}
fortify_function(wmemcpy) FAR wchar_t *wmemcpy(FAR wchar_t *d,
FAR const wchar_t *s,
size_t n)
{
fortify_assert(n <= fortify_size(d, 0) / sizeof(wchar_t));
return __real_wmemcpy(d, s, n);
}
fortify_function(wmemmove) FAR wchar_t *wmemmove(FAR wchar_t *d,
FAR const wchar_t *s,
size_t n)
{
fortify_assert(n <= fortify_size(d, 0) / sizeof(wchar_t));
return __real_wmemmove(d, s, n);
}
fortify_function(wmemset) FAR wchar_t *wmemset(FAR wchar_t *s,
wchar_t c,
size_t n)
{
fortify_assert(n <= fortify_size(s, 0) / sizeof(wchar_t));
return __real_wmemset(s, c, n);
}
#endif
#undef EXTERN
#ifdef __cplusplus
}