diff --git a/include/ssp/ssp.h b/include/ssp/ssp.h --- a/include/ssp/ssp.h +++ b/include/ssp/ssp.h @@ -67,21 +67,25 @@ #define __ssp_bos0(ptr) __builtin_object_size(ptr, 0) #define __ssp_check(buf, len, bos) \ - if (bos(buf) != (size_t)-1 && len > bos(buf)) \ + if (bos(buf) != (size_t)-1 && (size_t)len > bos(buf)) \ __chk_fail() -#define __ssp_redirect_raw(rtype, fun, symbol, args, call, cond, bos) \ + +#define __ssp_redirect_raw_impl(rtype, fun, symbol, args) \ rtype __ssp_real_(fun) args __RENAME(symbol); \ __ssp_inline rtype fun args __RENAME(__ssp_protected_ ## fun); \ -__ssp_inline rtype fun args { \ +__ssp_inline rtype fun args + +#define __ssp_redirect_raw(rtype, fun, symbol, args, call, cond, bos, len) \ +__ssp_redirect_raw_impl(rtype, fun, symbol, args) { \ if (cond) \ - __ssp_check(__buf, __len, bos); \ + __ssp_check(__buf, len, bos); \ return __ssp_real_(fun) call; \ } #define __ssp_redirect(rtype, fun, args, call) \ - __ssp_redirect_raw(rtype, fun, fun, args, call, 1, __ssp_bos) + __ssp_redirect_raw(rtype, fun, fun, args, call, 1, __ssp_bos, __len) #define __ssp_redirect0(rtype, fun, args, call) \ - __ssp_redirect_raw(rtype, fun, fun, args, call, 1, __ssp_bos0) + __ssp_redirect_raw(rtype, fun, fun, args, call, 1, __ssp_bos0, __len) /* * Take caution when using __ssp_overlap! Don't use it in contexts where we diff --git a/include/ssp/stdio.h b/include/ssp/stdio.h --- a/include/ssp/stdio.h +++ b/include/ssp/stdio.h @@ -37,6 +37,24 @@ #include __BEGIN_DECLS +#if __SSP_FORTIFY_LEVEL > 0 +#if __POSIX_VISIBLE +__ssp_redirect_raw(char *, ctermid, ctermid, (char *__buf), (__buf), + __buf != NULL, __ssp_bos, L_ctermid); +#if __BSD_VISIBLE +__ssp_redirect_raw(char *, ctermid_r, ctermid_r, (char *__buf), (__buf), + __buf != NULL, __ssp_bos, L_ctermid); +#endif /* __BSD_VISIBLE */ +#endif /* __POSIX_VISIBLE */ +__ssp_redirect(size_t, fread, (void *__restrict __buf, size_t __len, + size_t __nmemb, FILE *__restrict __fp), (__buf, __len, __nmemb, __fp)); +__ssp_redirect(size_t, fread_unlocked, (void *__restrict __buf, size_t __len, + size_t __nmemb, FILE *__restrict __fp), (__buf, __len, __nmemb, __fp)); +__ssp_redirect(char *, gets_s, (char *__buf, rsize_t __len), (__buf, __len)); +__ssp_redirect_raw(char *, tmpnam, tmpnam, (char *__buf), (__buf), 1, + __ssp_bos, L_tmpnam); +#endif + int __sprintf_chk(char *__restrict, int, size_t, const char *__restrict, ...) __printflike(4, 5); int __vsprintf_chk(char *__restrict, int, size_t, const char *__restrict, diff --git a/include/ssp/string.h b/include/ssp/string.h --- a/include/ssp/string.h +++ b/include/ssp/string.h @@ -45,7 +45,9 @@ char *__strcat_chk(char *, const char *, size_t); char *__strcpy_chk(char *, const char *, size_t); char *__strncat_chk(char *, const char *, size_t, size_t); +size_t __strlcat_chk(char *, const char *, size_t, size_t); char *__strncpy_chk(char *, const char *, size_t, size_t); +size_t __strlcpy_chk(char *, const char *, size_t, size_t); __END_DECLS #if __SSP_FORTIFY_LEVEL > 0 @@ -110,8 +112,24 @@ __ssp_bos_icheck3_restrict(stpncpy, char *, const char *) __ssp_bos_icheck2_restrict(strcpy, char *, const char *) __ssp_bos_icheck2_restrict(strcat, char *, const char *) +__ssp_redirect0(int, strerror_r, (int __errnum, char *__buf, size_t __len), + (__errnum, __buf, __len)); __ssp_bos_icheck3_restrict(strncpy, char *, const char *) __ssp_bos_icheck3_restrict(strncat, char *, const char *) + +__ssp_redirect_raw_impl(void *, mempcpy, mempcpy, + (void *__restrict buf, const void *__restrict src, size_t len)) +{ + const size_t slen = __ssp_bos(buf); + + if (len > slen) + __chk_fail(); + + if (__ssp_overlap((const char *)src, (const char *)buf, len)) + __chk_fail(); + + return (__ssp_real(mempcpy)(buf, src, len)); +} __END_DECLS #define memcpy(dst, src, len) __ssp_bos_check3(memcpy, dst, src, len) @@ -122,7 +140,11 @@ #define stpncpy(dst, src, len) __ssp_bos_check3(stpncpy, dst, src, len) #define strcpy(dst, src) __ssp_bos_check2(strcpy, dst, src) #define strcat(dst, src) __ssp_bos_check2(strcat, dst, src) +#define strlcpy(dst, src, dstlen) \ + __strlcpy_chk(dst, src, dstlen, __ssp_bos(dst)) #define strncpy(dst, src, len) __ssp_bos_check3(strncpy, dst, src, len) +#define strlcat(dst, src, dstlen) \ + __strlcat_chk(dst, src, dstlen, __ssp_bos(dst)) #define strncat(dst, src, len) __ssp_bos_check3(strncat, dst, src, len) #endif /* __SSP_FORTIFY_LEVEL > 0 */ diff --git a/include/ssp/strings.h b/include/ssp/strings.h --- a/include/ssp/strings.h +++ b/include/ssp/strings.h @@ -63,5 +63,10 @@ #define bzero(dst, len) _ssp_bzero(__ssp_var(dstv), dst, __ssp_var(lenv), len) +__BEGIN_DECLS +__ssp_redirect(void, explicit_bzero, (void *__buf, size_t __len), + (__buf, __len)); +__END_DECLS + #endif /* __SSP_FORTIFY_LEVEL > 0 */ #endif /* _SSP_STRINGS_H_ */ diff --git a/include/ssp/unistd.h b/include/ssp/unistd.h --- a/include/ssp/unistd.h +++ b/include/ssp/unistd.h @@ -43,14 +43,46 @@ #define _FORTIFY_SOURCE_read read #endif -__ssp_redirect0(ssize_t, _FORTIFY_SOURCE_read, (int __fd, void *__buf, +__ssp_inline size_t +__ssp_gid_bos(const void *ptr) +{ + size_t ptrsize = __ssp_bos(ptr); + + if (ptrsize == (size_t)-1) + return (ptrsize); + + return (ptrsize / sizeof(gid_t)); +} + +__ssp_redirect_raw(int, getgrouplist, getgrouplist, + (const char *__name, gid_t __base, gid_t *__buf, int *__lenp), + (__name, __base, __buf, __lenp), 1, __ssp_gid_bos, *__lenp); + +__ssp_redirect_raw(int, getgroups, getgroups, (int __len, gid_t *__buf), + (__len, __buf), 1, __ssp_gid_bos, __len); + +__ssp_redirect(int, getloginclass, (char *__buf, size_t __len), + (__buf, __len)); + +__ssp_redirect(ssize_t, _FORTIFY_SOURCE_read, (int __fd, void *__buf, size_t __len), (__fd, __buf, __len)); +__ssp_redirect(ssize_t, pread, (int __fd, void *__buf, size_t __len, + off_t __offset), (__fd, __buf, __len, __offset)); __ssp_redirect(ssize_t, readlink, (const char *__restrict __path, \ char *__restrict __buf, size_t __len), (__path, __buf, __len)); +__ssp_redirect(ssize_t, readlinkat, (int __fd, const char *__restrict __path, + char *__restrict __buf, size_t __len), (__fd, __path, __buf, __len)); __ssp_redirect_raw(char *, getcwd, getcwd, (char *__buf, size_t __len), - (__buf, __len), __buf != 0, __ssp_bos); + (__buf, __len), __buf != 0, __ssp_bos, __len); + +__ssp_redirect(int, getdomainname, (char *__buf, int __len), (__buf, __len)); +__ssp_redirect(int, getentropy, (void *__buf, size_t __len), (__buf, __len)); +__ssp_redirect(int, gethostname, (char *__buf, size_t __len), (__buf, __len)); +__ssp_redirect(int, getlogin_r, (char *__buf, size_t __len), (__buf, __len)); +__ssp_redirect(int, ttyname_r, (int __fd, char *__buf, size_t __len), + (__fd, __buf, __len)); __END_DECLS diff --git a/include/stdio.h b/include/stdio.h --- a/include/stdio.h +++ b/include/stdio.h @@ -238,6 +238,21 @@ #define stdout __stdoutp #define stderr __stderrp +/* + * Functions defined in all versions of POSIX 1003.1. + */ +#if __BSD_VISIBLE || (__POSIX_VISIBLE && __POSIX_VISIBLE <= 199506) +#define L_cuserid 17 /* size for cuserid(3); MAXLOGNAME, legacy */ +#endif + +#if __POSIX_VISIBLE +#define L_ctermid 1024 /* size for ctermid(3); PATH_MAX */ +#endif /* __POSIX_VISIBLE */ + +#if !defined(_STANDALONE) && defined(_FORTIFY_SOURCE) && _FORTIFY_SOURCE > 0 +#include +#endif + __BEGIN_DECLS #ifdef _XLOCALE_H_ #include @@ -252,7 +267,7 @@ int fflush(FILE *); int fgetc(FILE *); int fgetpos(FILE * __restrict, fpos_t * __restrict); -char *fgets(char * __restrict, int, FILE * __restrict); +char *(fgets)(char * __restrict, int, FILE * __restrict); FILE *fopen(const char * __restrict, const char * __restrict); int fprintf(FILE * __restrict, const char * __restrict, ...); int fputc(int, FILE *); @@ -280,7 +295,7 @@ int scanf(const char * __restrict, ...); void setbuf(FILE * __restrict, char * __restrict); int setvbuf(FILE * __restrict, char * __restrict, int, size_t); -int sprintf(char * __restrict, const char * __restrict, ...); +int (sprintf)(char * __restrict, const char * __restrict, ...); int sscanf(const char * __restrict, const char * __restrict, ...); FILE *tmpfile(void); char *tmpnam(char *); @@ -288,13 +303,13 @@ int vfprintf(FILE * __restrict, const char * __restrict, __va_list); int vprintf(const char * __restrict, __va_list); -int vsprintf(char * __restrict, const char * __restrict, +int (vsprintf)(char * __restrict, const char * __restrict, __va_list); #if __ISO_C_VISIBLE >= 1999 || __POSIX_VISIBLE >= 199506 -int snprintf(char * __restrict, size_t, const char * __restrict, +int (snprintf)(char * __restrict, size_t, const char * __restrict, ...) __printflike(3, 4); -int vsnprintf(char * __restrict, size_t, const char * __restrict, +int (vsnprintf)(char * __restrict, size_t, const char * __restrict, __va_list) __printflike(3, 0); #endif #if __ISO_C_VISIBLE >= 1999 @@ -305,16 +320,7 @@ __scanflike(2, 0); #endif -/* - * Functions defined in all versions of POSIX 1003.1. - */ -#if __BSD_VISIBLE || (__POSIX_VISIBLE && __POSIX_VISIBLE <= 199506) -#define L_cuserid 17 /* size for cuserid(3); MAXLOGNAME, legacy */ -#endif - #if __POSIX_VISIBLE -#define L_ctermid 1024 /* size for ctermid(3); PATH_MAX */ - char *ctermid(char *); FILE *fdopen(int, const char *); int fileno(FILE *); @@ -530,7 +536,4 @@ __END_DECLS __NULLABILITY_PRAGMA_POP -#if !defined(_STANDALONE) && defined(_FORTIFY_SOURCE) && _FORTIFY_SOURCE > 0 -#include -#endif #endif /* !_STDIO_H_ */ diff --git a/include/string.h b/include/string.h --- a/include/string.h +++ b/include/string.h @@ -49,6 +49,10 @@ #define _SIZE_T_DECLARED #endif +#if !defined(_STANDALONE) && defined(_FORTIFY_SOURCE) && _FORTIFY_SOURCE > 0 +#include +#endif + __BEGIN_DECLS #if __XSI_VISIBLE >= 600 void *memccpy(void * __restrict, const void * __restrict, int, size_t); @@ -58,23 +62,23 @@ void *memrchr(const void *, int, size_t) __pure; #endif int memcmp(const void *, const void *, size_t) __pure; -void *memcpy(void * __restrict, const void * __restrict, size_t); +void *(memcpy)(void * __restrict, const void * __restrict, size_t); #if __BSD_VISIBLE void *memmem(const void *, size_t, const void *, size_t) __pure; #endif -void *memmove(void *, const void *, size_t); +void *(memmove)(void *, const void *, size_t); #if __BSD_VISIBLE void *mempcpy(void * __restrict, const void * __restrict, size_t); #endif -void *memset(void *, int, size_t); +void *(memset)(void *, int, size_t); #if __POSIX_VISIBLE >= 200809 -char *stpcpy(char * __restrict, const char * __restrict); -char *stpncpy(char * __restrict, const char * __restrict, size_t); +char *(stpcpy)(char * __restrict, const char * __restrict); +char *(stpncpy)(char * __restrict, const char * __restrict, size_t); #endif #if __BSD_VISIBLE char *strcasestr(const char *, const char *) __pure; #endif -char *strcat(char * __restrict, const char * __restrict); +char *(strcat)(char * __restrict, const char * __restrict); char *strchr(const char *, int) __pure; #if __BSD_VISIBLE char *strchrnul(const char*, int) __pure; @@ -82,7 +86,7 @@ #endif int strcmp(const char *, const char *) __pure; int strcoll(const char *, const char *); -char *strcpy(char * __restrict, const char * __restrict); +char *(strcpy)(char * __restrict, const char * __restrict); size_t strcspn(const char *, const char *) __pure; #if __POSIX_VISIBLE >= 200112 || __XSI_VISIBLE char *strdup(const char *) __malloc_like; @@ -92,8 +96,8 @@ int strerror_r(int, char *, size_t); #endif #if __BSD_VISIBLE -size_t strlcat(char * __restrict, const char * __restrict, size_t); -size_t strlcpy(char * __restrict, const char * __restrict, size_t); +size_t (strlcat)(char * __restrict, const char * __restrict, size_t); +size_t (strlcpy)(char * __restrict, const char * __restrict, size_t); #endif size_t strlen(const char *) __pure; #if __BSD_VISIBLE @@ -105,9 +109,9 @@ void strmode(mode_t, char *); #endif -char *strncat(char * __restrict, const char * __restrict, size_t); +char *(strncat)(char * __restrict, const char * __restrict, size_t); int strncmp(const char *, const char *, size_t) __pure; -char *strncpy(char * __restrict, const char * __restrict, size_t); +char *(strncpy)(char * __restrict, const char * __restrict, size_t); #if __POSIX_VISIBLE >= 200809 char *strndup(const char *, size_t) __malloc_like; size_t strnlen(const char *, size_t) __pure; @@ -168,7 +172,4 @@ #endif /* __EXT1_VISIBLE */ __END_DECLS -#if !defined(_STANDALONE) && defined(_FORTIFY_SOURCE) && _FORTIFY_SOURCE > 0 -#include -#endif #endif /* _STRING_H_ */ diff --git a/include/strings.h b/include/strings.h --- a/include/strings.h +++ b/include/strings.h @@ -37,11 +37,15 @@ #define _SIZE_T_DECLARED #endif +#if !defined(_STANDALONE) && defined(_FORTIFY_SOURCE) && _FORTIFY_SOURCE > 0 +#include +#endif + __BEGIN_DECLS #if __BSD_VISIBLE || __POSIX_VISIBLE <= 200112 int bcmp(const void *, const void *, size_t) __pure; /* LEGACY */ -void bcopy(const void *, void *, size_t); /* LEGACY */ -void bzero(void *, size_t); /* LEGACY */ +void (bcopy)(const void *, void *, size_t); /* LEGACY */ +void (bzero)(void *, size_t); /* LEGACY */ #endif #if __BSD_VISIBLE void explicit_bzero(void *, size_t); @@ -68,7 +72,4 @@ #endif __END_DECLS -#if !defined(_STANDALONE) && defined(_FORTIFY_SOURCE) && _FORTIFY_SOURCE > 0 -#include -#endif #endif /* _STRINGS_H_ */ diff --git a/lib/libc/amd64/string/strlcat.c b/lib/libc/amd64/string/strlcat.c --- a/lib/libc/amd64/string/strlcat.c +++ b/lib/libc/amd64/string/strlcat.c @@ -8,6 +8,8 @@ #include +#undef strlcat /* FORTIFY_SOURCE */ + void *__memchr(const void *, int, size_t); size_t __strlcpy(char *restrict, const char *restrict, size_t); diff --git a/lib/libc/gen/ctermid.c b/lib/libc/gen/ctermid.c --- a/lib/libc/gen/ctermid.c +++ b/lib/libc/gen/ctermid.c @@ -34,11 +34,12 @@ #include #include #include +#include #define LEN_PATH_DEV (sizeof(_PATH_DEV) - 1) char * -ctermid(char *s) +__ssp_real(ctermid)(char *s) { static char def[sizeof(_PATH_DEV) + SPECNAMELEN]; struct stat sb; @@ -62,7 +63,7 @@ } char * -ctermid_r(char *s) +__ssp_real(ctermid_r)(char *s) { return (s != NULL ? ctermid(s) : NULL); diff --git a/lib/libc/gen/getdomainname.c b/lib/libc/gen/getdomainname.c --- a/lib/libc/gen/getdomainname.c +++ b/lib/libc/gen/getdomainname.c @@ -33,9 +33,10 @@ #include #include +#include int -getdomainname(char *name, int namelen) +__ssp_real(getdomainname)(char *name, int namelen) { int mib[2]; size_t size; diff --git a/lib/libc/gen/getentropy.c b/lib/libc/gen/getentropy.c --- a/lib/libc/gen/getentropy.c +++ b/lib/libc/gen/getentropy.c @@ -35,6 +35,7 @@ #include #include #include +#include #include "libc_private.h" @@ -105,7 +106,7 @@ } int -getentropy(void *buf, size_t buflen) +__ssp_real(getentropy)(void *buf, size_t buflen) { ssize_t rd; bool have_getrandom; diff --git a/lib/libc/gen/getgrouplist.c b/lib/libc/gen/getgrouplist.c --- a/lib/libc/gen/getgrouplist.c +++ b/lib/libc/gen/getgrouplist.c @@ -37,11 +37,12 @@ #include #include #include +#include extern int __getgroupmembership(const char *, gid_t, gid_t *, int, int *); int -getgrouplist(const char *uname, gid_t agroup, gid_t *groups, int *grpcnt) +__ssp_real(getgrouplist)(const char *uname, gid_t agroup, gid_t *groups, int *grpcnt) { return __getgroupmembership(uname, agroup, groups, *grpcnt, grpcnt); } diff --git a/lib/libc/gen/gethostname.c b/lib/libc/gen/gethostname.c --- a/lib/libc/gen/gethostname.c +++ b/lib/libc/gen/gethostname.c @@ -34,9 +34,10 @@ #include #include +#include int -gethostname(char *name, size_t namelen) +__ssp_real(gethostname)(char *name, size_t namelen) { int mib[2]; diff --git a/lib/libc/gen/getlogin.c b/lib/libc/gen/getlogin.c --- a/lib/libc/gen/getlogin.c +++ b/lib/libc/gen/getlogin.c @@ -37,6 +37,7 @@ #include #include "namespace.h" #include +#include #include "un-namespace.h" #include "libc_private.h" @@ -54,7 +55,7 @@ } int -getlogin_r(char *logname, size_t namelen) +__ssp_real(getlogin_r)(char *logname, size_t namelen) { char tmpname[MAXLOGNAME]; int len; diff --git a/lib/libc/gen/ttyname.c b/lib/libc/gen/ttyname.c --- a/lib/libc/gen/ttyname.c +++ b/lib/libc/gen/ttyname.c @@ -42,6 +42,7 @@ #include #include #include "reentrant.h" +#include #include "un-namespace.h" #include "libc_private.h" @@ -53,7 +54,7 @@ static int ttyname_keycreated = 0; int -ttyname_r(int fd, char *buf, size_t len) +__ssp_real(ttyname_r)(int fd, char *buf, size_t len) { size_t used; diff --git a/lib/libc/secure/Makefile.inc b/lib/libc/secure/Makefile.inc --- a/lib/libc/secure/Makefile.inc +++ b/lib/libc/secure/Makefile.inc @@ -6,8 +6,8 @@ # _FORTIFY_SOURCE SRCS+= fgets_chk.c memcpy_chk.c memmove_chk.c memset_chk.c \ snprintf_chk.c sprintf_chk.c stpcpy_chk.c stpncpy_chk.c \ - strcat_chk.c strcpy_chk.c strncat_chk.c strncpy_chk.c \ - vsnprintf_chk.c vsprintf_chk.c + strcat_chk.c strcpy_chk.c strlcat_chk.c strncat_chk.c strlcpy_chk.c \ + strncpy_chk.c vsnprintf_chk.c vsprintf_chk.c CFLAGS.snprintf_chk.c+= -Wno-unused-parameter CFLAGS.sprintf_chk.c+= -Wno-unused-parameter diff --git a/lib/libc/secure/Symbol.map b/lib/libc/secure/Symbol.map --- a/lib/libc/secure/Symbol.map +++ b/lib/libc/secure/Symbol.map @@ -15,7 +15,9 @@ __stpncpy_chk; __strcat_chk; __strcpy_chk; + __strlcat_chk; __strncat_chk; + __strlcpy_chk; __strncpy_chk; __vsnprintf_chk; __vsprintf_chk; diff --git a/lib/libc/string/strlcat.c b/lib/libc/secure/strlcat_chk.c copy from lib/libc/string/strlcat.c copy to lib/libc/secure/strlcat_chk.c --- a/lib/libc/string/strlcat.c +++ b/lib/libc/secure/strlcat_chk.c @@ -1,6 +1,8 @@ /* $OpenBSD: strlcat.c,v 1.15 2015/03/02 21:41:08 millert Exp $ */ /* + * SPDX-License-Identifier: ISC + * * Copyright (c) 1998, 2015 Todd C. Miller * * Permission to use, copy, modify, and distribute this software for any @@ -16,9 +18,11 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include +#include #include +#include + /* * Appends src to string dst of size dsize (unlike strncat, dsize is the * full size of dst, not space left). At most dsize-1 characters @@ -27,29 +31,40 @@ * If retval >= dsize, truncation occurred. */ size_t -strlcat(char * __restrict dst, const char * __restrict src, size_t dsize) +__strlcat_chk(char * __restrict dst, const char * __restrict src, size_t dsize, + size_t dbufsize) { const char *odst = dst; const char *osrc = src; size_t n = dsize; size_t dlen; + if (dsize > dbufsize) + __chk_fail(); + /* Find the end of dst and adjust bytes left but don't go past end. */ - while (n-- != 0 && *dst != '\0') + while (n-- != 0 && *dst != '\0') { dst++; + } + dlen = dst - odst; n = dsize - dlen; if (n-- == 0) - return(dlen + strlen(src)); + return (dlen + strlen(src)); while (*src != '\0') { if (n != 0) { + if (dbufsize-- == 0) + __chk_fail(); *dst++ = *src; n--; } + src++; } - *dst = '\0'; - return(dlen + (src - osrc)); /* count does not include NUL */ + if (dbufsize-- == 0) + __chk_fail(); + *dst = '\0'; + return (dlen + (src - osrc)); /* count does not include NUL */ } diff --git a/include/ssp/unistd.h b/lib/libc/secure/strlcpy_chk.c copy from include/ssp/unistd.h copy to lib/libc/secure/strlcpy_chk.c --- a/include/ssp/unistd.h +++ b/lib/libc/secure/strlcpy_chk.c @@ -1,14 +1,7 @@ -/* $NetBSD: unistd.h,v 1.7 2015/06/25 18:41:03 joerg Exp $ */ - /*- - * * SPDX-License-Identifier: BSD-2-Clause * - * Copyright (c) 2006 The NetBSD Foundation, Inc. - * All rights reserved. - * - * This code is derived from software contributed to The NetBSD Foundation - * by Christos Zoulas. + * Copyright (c) 2024, Klara, Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -31,28 +24,20 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ -#ifndef _SSP_UNISTD_H_ -#define _SSP_UNISTD_H_ - -#include - -#if __SSP_FORTIFY_LEVEL > 0 -__BEGIN_DECLS - -#ifndef _FORTIFY_SOURCE_read -#define _FORTIFY_SOURCE_read read -#endif -__ssp_redirect0(ssize_t, _FORTIFY_SOURCE_read, (int __fd, void *__buf, - size_t __len), (__fd, __buf, __len)); +#include +#include -__ssp_redirect(ssize_t, readlink, (const char *__restrict __path, \ - char *__restrict __buf, size_t __len), (__path, __buf, __len)); +#include +#undef strlcpy -__ssp_redirect_raw(char *, getcwd, getcwd, (char *__buf, size_t __len), - (__buf, __len), __buf != 0, __ssp_bos); +size_t +__strlcpy_chk(char * __restrict dst, const char * __restrict src, size_t dsize, + size_t dbufsize) +{ -__END_DECLS + if (dsize > dbufsize) + __chk_fail(); -#endif /* __SSP_FORTIFY_LEVEL > 0 */ -#endif /* _SSP_UNISTD_H_ */ + return (strlcpy(dst, src, dsize)); +} diff --git a/lib/libc/stdio/fread.c b/lib/libc/stdio/fread.c --- a/lib/libc/stdio/fread.c +++ b/lib/libc/stdio/fread.c @@ -37,6 +37,7 @@ #include #include #include +#include #include "un-namespace.h" #include "local.h" #include "libc_private.h" @@ -46,7 +47,8 @@ */ size_t -fread(void * __restrict buf, size_t size, size_t count, FILE * __restrict fp) +__ssp_real(fread)(void * __restrict buf, size_t size, size_t count, + FILE * __restrict fp) { size_t ret; diff --git a/lib/libc/stdio/gets_s.c b/lib/libc/stdio/gets_s.c --- a/lib/libc/stdio/gets_s.c +++ b/lib/libc/stdio/gets_s.c @@ -39,6 +39,7 @@ #include #include #include +#include #include "un-namespace.h" #include "libc_private.h" #include "local.h" @@ -77,7 +78,7 @@ /* ISO/IEC 9899:2011 K.3.7.4.1 */ char * -gets_s(char *buf, rsize_t n) +__ssp_real(gets_s)(char *buf, rsize_t n) { char *ret; if (buf == NULL) { diff --git a/lib/libc/stdio/tmpnam.c b/lib/libc/stdio/tmpnam.c --- a/lib/libc/stdio/tmpnam.c +++ b/lib/libc/stdio/tmpnam.c @@ -36,6 +36,7 @@ #include #include +#include __warn_references(tmpnam, "warning: tmpnam() possibly used unsafely; consider using mkstemp()"); @@ -43,7 +44,7 @@ extern char *_mktemp(char *); char * -tmpnam(char *s) +__ssp_real(tmpnam)(char *s) { static u_long tmpcount; static char buf[L_tmpnam]; diff --git a/lib/libc/string/mempcpy.c b/lib/libc/string/mempcpy.c --- a/lib/libc/string/mempcpy.c +++ b/lib/libc/string/mempcpy.c @@ -29,9 +29,11 @@ */ #include +#include void * -mempcpy(void *__restrict dst, const void *__restrict src, size_t len) +__ssp_real(mempcpy)(void *__restrict dst, const void *__restrict src, + size_t len) { return ((char *)memcpy(dst, src, len) + len); } diff --git a/lib/libc/string/strerror.c b/lib/libc/string/strerror.c --- a/lib/libc/string/strerror.c +++ b/lib/libc/string/strerror.c @@ -38,6 +38,8 @@ #include #include +#include + #include "errlst.h" #include "../locale/xlocale_private.h" #include "libc_private.h" @@ -114,7 +116,7 @@ } int -strerror_r(int errnum, char *strerrbuf, size_t buflen) +__ssp_real(strerror_r)(int errnum, char *strerrbuf, size_t buflen) { return (__strerror_rl(errnum, strerrbuf, buflen, __get_locale())); } diff --git a/lib/libc/string/strlcat.c b/lib/libc/string/strlcat.c --- a/lib/libc/string/strlcat.c +++ b/lib/libc/string/strlcat.c @@ -19,6 +19,8 @@ #include #include +#undef strlcat /* FORTIFY_SOURCE */ + /* * Appends src to string dst of size dsize (unlike strncat, dsize is the * full size of dst, not space left). At most dsize-1 characters diff --git a/lib/libc/string/strlcpy.c b/lib/libc/string/strlcpy.c --- a/lib/libc/string/strlcpy.c +++ b/lib/libc/string/strlcpy.c @@ -19,6 +19,8 @@ #include #include +#undef strlcpy /* FORTIFY_SOURCE */ + /* * Copy string src to buffer dst of size dsize. At most dsize-1 * chars will be copied. Always NUL terminates (unless dsize == 0). diff --git a/lib/libc/string/strncpy.c b/lib/libc/string/strncpy.c --- a/lib/libc/string/strncpy.c +++ b/lib/libc/string/strncpy.c @@ -34,6 +34,8 @@ #include +#undef strncpy /* FORTIFY_SOURCE */ + /* * Copy src to dst, truncating or null-padding to always copy n bytes. * Return dst. diff --git a/lib/libc/tests/secure/fortify_stdio_test.c b/lib/libc/tests/secure/fortify_stdio_test.c --- a/lib/libc/tests/secure/fortify_stdio_test.c +++ b/lib/libc/tests/secure/fortify_stdio_test.c @@ -20,6 +20,23 @@ #include #include +static FILE * __unused +new_fp(size_t __len) +{ + static char fpbuf[LINE_MAX]; + FILE *fp; + + ATF_REQUIRE(__len <= sizeof(fpbuf)); + + memset(fpbuf, 'A', sizeof(fpbuf) - 1); + fpbuf[sizeof(fpbuf) - 1] = '\0'; + + fp = fmemopen(fpbuf, sizeof(fpbuf), "rb"); + ATF_REQUIRE(fp != NULL); + + return (fp); +} + /* * Create a new symlink to use for readlink(2) style tests, we'll just use a * random target name to have something interesting to look at. @@ -55,28 +72,700 @@ size_t written; int fd; - fd = open("tmpfile", O_RDWR | O_CREAT | O_TRUNC, 0644); - ATF_REQUIRE(fd >= 0); + fd = open("tmpfile", O_RDWR | O_CREAT | O_TRUNC, 0644); + ATF_REQUIRE(fd >= 0); + + written = 0; + while (written < TMPFILE_SIZE) { + rv = write(fd, buf, sizeof(buf)); + ATF_REQUIRE(rv > 0); + + written += rv; + } + + ATF_REQUIRE_EQ(0, lseek(fd, 0, SEEK_SET)); + return (fd); +} + +static void +disable_coredumps(void) +{ + struct rlimit rl = { 0 }; + + if (setrlimit(RLIMIT_CORE, &rl) == -1) + _exit(EX_OSERR); +} + +/* + * Replaces stdin with a file that we can actually read from, for tests where + * we want a FILE * or fd that we can get data from. + */ +static void __unused +replace_stdin(void) +{ + int fd; + + fd = new_tmpfile(); + + (void)dup2(fd, STDIN_FILENO); + if (fd != STDIN_FILENO) + close(fd); +} + +ATF_TC_WITHOUT_HEAD(ctermid_before_end); +ATF_TC_BODY(ctermid_before_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + unsigned char __buf[L_ctermid + 1]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = L_ctermid + 1; + const size_t __idx __unused = __len - 1; + + ctermid(__stack.__buf); +#undef BUF + +} + +ATF_TC_WITHOUT_HEAD(ctermid_end); +ATF_TC_BODY(ctermid_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + unsigned char __buf[L_ctermid]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = L_ctermid; + const size_t __idx __unused = __len - 1; + + ctermid(__stack.__buf); +#undef BUF + +} + +ATF_TC_WITHOUT_HEAD(ctermid_heap_before_end); +ATF_TC_BODY(ctermid_heap_before_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (L_ctermid + 1); + const size_t __len = L_ctermid + 1; + const size_t __idx __unused = __len - 1; + + __stack.__buf = malloc(__bufsz); + + ctermid(__stack.__buf); +#undef BUF + +} + +ATF_TC_WITHOUT_HEAD(ctermid_heap_end); +ATF_TC_BODY(ctermid_heap_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (L_ctermid); + const size_t __len = L_ctermid; + const size_t __idx __unused = __len - 1; + + __stack.__buf = malloc(__bufsz); + + ctermid(__stack.__buf); +#undef BUF + +} + +ATF_TC_WITHOUT_HEAD(ctermid_heap_after_end); +ATF_TC_BODY(ctermid_heap_after_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (L_ctermid - 1); + const size_t __len = L_ctermid - 1; + const size_t __idx __unused = __len - 1; + pid_t __child; + int __status; + + __child = fork(); + ATF_REQUIRE(__child >= 0); + if (__child > 0) + goto monitor; + + /* Child */ + disable_coredumps(); + __stack.__buf = malloc(__bufsz); + + ctermid(__stack.__buf); + _exit(EX_SOFTWARE); /* Should have aborted. */ + +monitor: + while (waitpid(__child, &__status, 0) != __child) { + ATF_REQUIRE_EQ(EINTR, errno); + } + + if (!WIFSIGNALED(__status)) { + switch (WEXITSTATUS(__status)) { + case EX_SOFTWARE: + atf_tc_fail("FORTIFY_SOURCE failed to abort"); + break; + case EX_OSERR: + atf_tc_fail("setrlimit(2) failed"); + break; + default: + atf_tc_fail("child exited with status %d", + WEXITSTATUS(__status)); + } + } else { + ATF_REQUIRE_EQ(SIGABRT, WTERMSIG(__status)); + } +#undef BUF + +} + +ATF_TC_WITHOUT_HEAD(ctermid_r_before_end); +ATF_TC_BODY(ctermid_r_before_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + unsigned char __buf[L_ctermid + 1]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = L_ctermid + 1; + const size_t __idx __unused = __len - 1; + + ctermid_r(__stack.__buf); +#undef BUF + +} + +ATF_TC_WITHOUT_HEAD(ctermid_r_end); +ATF_TC_BODY(ctermid_r_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + unsigned char __buf[L_ctermid]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = L_ctermid; + const size_t __idx __unused = __len - 1; + + ctermid_r(__stack.__buf); +#undef BUF + +} + +ATF_TC_WITHOUT_HEAD(ctermid_r_heap_before_end); +ATF_TC_BODY(ctermid_r_heap_before_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (L_ctermid + 1); + const size_t __len = L_ctermid + 1; + const size_t __idx __unused = __len - 1; + + __stack.__buf = malloc(__bufsz); + + ctermid_r(__stack.__buf); +#undef BUF + +} + +ATF_TC_WITHOUT_HEAD(ctermid_r_heap_end); +ATF_TC_BODY(ctermid_r_heap_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (L_ctermid); + const size_t __len = L_ctermid; + const size_t __idx __unused = __len - 1; + + __stack.__buf = malloc(__bufsz); + + ctermid_r(__stack.__buf); +#undef BUF + +} + +ATF_TC_WITHOUT_HEAD(ctermid_r_heap_after_end); +ATF_TC_BODY(ctermid_r_heap_after_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (L_ctermid - 1); + const size_t __len = L_ctermid - 1; + const size_t __idx __unused = __len - 1; + pid_t __child; + int __status; + + __child = fork(); + ATF_REQUIRE(__child >= 0); + if (__child > 0) + goto monitor; + + /* Child */ + disable_coredumps(); + __stack.__buf = malloc(__bufsz); + + ctermid_r(__stack.__buf); + _exit(EX_SOFTWARE); /* Should have aborted. */ + +monitor: + while (waitpid(__child, &__status, 0) != __child) { + ATF_REQUIRE_EQ(EINTR, errno); + } + + if (!WIFSIGNALED(__status)) { + switch (WEXITSTATUS(__status)) { + case EX_SOFTWARE: + atf_tc_fail("FORTIFY_SOURCE failed to abort"); + break; + case EX_OSERR: + atf_tc_fail("setrlimit(2) failed"); + break; + default: + atf_tc_fail("child exited with status %d", + WEXITSTATUS(__status)); + } + } else { + ATF_REQUIRE_EQ(SIGABRT, WTERMSIG(__status)); + } +#undef BUF + +} + +ATF_TC_WITHOUT_HEAD(fread_before_end); +ATF_TC_BODY(fread_before_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + unsigned char __buf[42]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 42 - 1; + const size_t __idx __unused = __len - 1; + + replace_stdin(); + + fread(__stack.__buf, __len, 1, stdin); +#undef BUF + +} + +ATF_TC_WITHOUT_HEAD(fread_end); +ATF_TC_BODY(fread_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + unsigned char __buf[42]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 42; + const size_t __idx __unused = __len - 1; + + replace_stdin(); + + fread(__stack.__buf, __len, 1, stdin); +#undef BUF + +} + +ATF_TC_WITHOUT_HEAD(fread_heap_before_end); +ATF_TC_BODY(fread_heap_before_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42 - 1; + const size_t __idx __unused = __len - 1; + + __stack.__buf = malloc(__bufsz); + replace_stdin(); + + fread(__stack.__buf, __len, 1, stdin); +#undef BUF + +} + +ATF_TC_WITHOUT_HEAD(fread_heap_end); +ATF_TC_BODY(fread_heap_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42; + const size_t __idx __unused = __len - 1; + + __stack.__buf = malloc(__bufsz); + replace_stdin(); + + fread(__stack.__buf, __len, 1, stdin); +#undef BUF + +} + +ATF_TC_WITHOUT_HEAD(fread_heap_after_end); +ATF_TC_BODY(fread_heap_after_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42 + 1; + const size_t __idx __unused = __len - 1; + pid_t __child; + int __status; + + __child = fork(); + ATF_REQUIRE(__child >= 0); + if (__child > 0) + goto monitor; + + /* Child */ + disable_coredumps(); + __stack.__buf = malloc(__bufsz); + replace_stdin(); + + fread(__stack.__buf, __len, 1, stdin); + _exit(EX_SOFTWARE); /* Should have aborted. */ + +monitor: + while (waitpid(__child, &__status, 0) != __child) { + ATF_REQUIRE_EQ(EINTR, errno); + } + + if (!WIFSIGNALED(__status)) { + switch (WEXITSTATUS(__status)) { + case EX_SOFTWARE: + atf_tc_fail("FORTIFY_SOURCE failed to abort"); + break; + case EX_OSERR: + atf_tc_fail("setrlimit(2) failed"); + break; + default: + atf_tc_fail("child exited with status %d", + WEXITSTATUS(__status)); + } + } else { + ATF_REQUIRE_EQ(SIGABRT, WTERMSIG(__status)); + } +#undef BUF + +} + +ATF_TC_WITHOUT_HEAD(fread_unlocked_before_end); +ATF_TC_BODY(fread_unlocked_before_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + unsigned char __buf[42]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 42 - 1; + const size_t __idx __unused = __len - 1; + + replace_stdin(); + + fread_unlocked(__stack.__buf, __len, 1, stdin); +#undef BUF + +} + +ATF_TC_WITHOUT_HEAD(fread_unlocked_end); +ATF_TC_BODY(fread_unlocked_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + unsigned char __buf[42]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 42; + const size_t __idx __unused = __len - 1; + + replace_stdin(); + + fread_unlocked(__stack.__buf, __len, 1, stdin); +#undef BUF + +} + +ATF_TC_WITHOUT_HEAD(fread_unlocked_heap_before_end); +ATF_TC_BODY(fread_unlocked_heap_before_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42 - 1; + const size_t __idx __unused = __len - 1; + + __stack.__buf = malloc(__bufsz); + replace_stdin(); + + fread_unlocked(__stack.__buf, __len, 1, stdin); +#undef BUF + +} + +ATF_TC_WITHOUT_HEAD(fread_unlocked_heap_end); +ATF_TC_BODY(fread_unlocked_heap_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42; + const size_t __idx __unused = __len - 1; + + __stack.__buf = malloc(__bufsz); + replace_stdin(); + + fread_unlocked(__stack.__buf, __len, 1, stdin); +#undef BUF + +} + +ATF_TC_WITHOUT_HEAD(fread_unlocked_heap_after_end); +ATF_TC_BODY(fread_unlocked_heap_after_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42 + 1; + const size_t __idx __unused = __len - 1; + pid_t __child; + int __status; + + __child = fork(); + ATF_REQUIRE(__child >= 0); + if (__child > 0) + goto monitor; + + /* Child */ + disable_coredumps(); + __stack.__buf = malloc(__bufsz); + replace_stdin(); + + fread_unlocked(__stack.__buf, __len, 1, stdin); + _exit(EX_SOFTWARE); /* Should have aborted. */ + +monitor: + while (waitpid(__child, &__status, 0) != __child) { + ATF_REQUIRE_EQ(EINTR, errno); + } + + if (!WIFSIGNALED(__status)) { + switch (WEXITSTATUS(__status)) { + case EX_SOFTWARE: + atf_tc_fail("FORTIFY_SOURCE failed to abort"); + break; + case EX_OSERR: + atf_tc_fail("setrlimit(2) failed"); + break; + default: + atf_tc_fail("child exited with status %d", + WEXITSTATUS(__status)); + } + } else { + ATF_REQUIRE_EQ(SIGABRT, WTERMSIG(__status)); + } +#undef BUF + +} + +ATF_TC_WITHOUT_HEAD(gets_s_before_end); +ATF_TC_BODY(gets_s_before_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + unsigned char __buf[42]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 42 - 1; + const size_t __idx __unused = __len - 1; + + replace_stdin(); + + gets_s(__stack.__buf, __len); +#undef BUF + +} + +ATF_TC_WITHOUT_HEAD(gets_s_end); +ATF_TC_BODY(gets_s_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + unsigned char __buf[42]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 42; + const size_t __idx __unused = __len - 1; + + replace_stdin(); + + gets_s(__stack.__buf, __len); +#undef BUF + +} + +ATF_TC_WITHOUT_HEAD(gets_s_heap_before_end); +ATF_TC_BODY(gets_s_heap_before_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42 - 1; + const size_t __idx __unused = __len - 1; + + __stack.__buf = malloc(__bufsz); + replace_stdin(); + + gets_s(__stack.__buf, __len); +#undef BUF + +} + +ATF_TC_WITHOUT_HEAD(gets_s_heap_end); +ATF_TC_BODY(gets_s_heap_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42; + const size_t __idx __unused = __len - 1; + + __stack.__buf = malloc(__bufsz); + replace_stdin(); + + gets_s(__stack.__buf, __len); +#undef BUF + +} + +ATF_TC_WITHOUT_HEAD(gets_s_heap_after_end); +ATF_TC_BODY(gets_s_heap_after_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42 + 1; + const size_t __idx __unused = __len - 1; + pid_t __child; + int __status; + + __child = fork(); + ATF_REQUIRE(__child >= 0); + if (__child > 0) + goto monitor; + + /* Child */ + disable_coredumps(); + __stack.__buf = malloc(__bufsz); + replace_stdin(); - written = 0; - while (written < TMPFILE_SIZE) { - rv = write(fd, buf, sizeof(buf)); - ATF_REQUIRE(rv > 0); + gets_s(__stack.__buf, __len); + _exit(EX_SOFTWARE); /* Should have aborted. */ - written += rv; +monitor: + while (waitpid(__child, &__status, 0) != __child) { + ATF_REQUIRE_EQ(EINTR, errno); } - ATF_REQUIRE_EQ(0, lseek(fd, 0, SEEK_SET)); - return (fd); -} - -static void -disable_coredumps(void) -{ - struct rlimit rl = { 0 }; + if (!WIFSIGNALED(__status)) { + switch (WEXITSTATUS(__status)) { + case EX_SOFTWARE: + atf_tc_fail("FORTIFY_SOURCE failed to abort"); + break; + case EX_OSERR: + atf_tc_fail("setrlimit(2) failed"); + break; + default: + atf_tc_fail("child exited with status %d", + WEXITSTATUS(__status)); + } + } else { + ATF_REQUIRE_EQ(SIGABRT, WTERMSIG(__status)); + } +#undef BUF - if (setrlimit(RLIMIT_CORE, &rl) == -1) - _exit(EX_OSERR); } ATF_TC_WITHOUT_HEAD(sprintf_before_end); @@ -367,8 +1056,299 @@ } +ATF_TC_WITHOUT_HEAD(tmpnam_before_end); +ATF_TC_BODY(tmpnam_before_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + unsigned char __buf[L_tmpnam + 1]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = L_tmpnam + 1; + const size_t __idx __unused = __len - 1; + + tmpnam(__stack.__buf); +#undef BUF + +} + +ATF_TC_WITHOUT_HEAD(tmpnam_end); +ATF_TC_BODY(tmpnam_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + unsigned char __buf[L_tmpnam]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = L_tmpnam; + const size_t __idx __unused = __len - 1; + + tmpnam(__stack.__buf); +#undef BUF + +} + +ATF_TC_WITHOUT_HEAD(tmpnam_heap_before_end); +ATF_TC_BODY(tmpnam_heap_before_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (L_tmpnam + 1); + const size_t __len = L_tmpnam + 1; + const size_t __idx __unused = __len - 1; + + __stack.__buf = malloc(__bufsz); + + tmpnam(__stack.__buf); +#undef BUF + +} + +ATF_TC_WITHOUT_HEAD(tmpnam_heap_end); +ATF_TC_BODY(tmpnam_heap_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (L_tmpnam); + const size_t __len = L_tmpnam; + const size_t __idx __unused = __len - 1; + + __stack.__buf = malloc(__bufsz); + + tmpnam(__stack.__buf); +#undef BUF + +} + +ATF_TC_WITHOUT_HEAD(tmpnam_heap_after_end); +ATF_TC_BODY(tmpnam_heap_after_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (L_tmpnam - 1); + const size_t __len = L_tmpnam - 1; + const size_t __idx __unused = __len - 1; + pid_t __child; + int __status; + + __child = fork(); + ATF_REQUIRE(__child >= 0); + if (__child > 0) + goto monitor; + + /* Child */ + disable_coredumps(); + __stack.__buf = malloc(__bufsz); + + tmpnam(__stack.__buf); + _exit(EX_SOFTWARE); /* Should have aborted. */ + +monitor: + while (waitpid(__child, &__status, 0) != __child) { + ATF_REQUIRE_EQ(EINTR, errno); + } + + if (!WIFSIGNALED(__status)) { + switch (WEXITSTATUS(__status)) { + case EX_SOFTWARE: + atf_tc_fail("FORTIFY_SOURCE failed to abort"); + break; + case EX_OSERR: + atf_tc_fail("setrlimit(2) failed"); + break; + default: + atf_tc_fail("child exited with status %d", + WEXITSTATUS(__status)); + } + } else { + ATF_REQUIRE_EQ(SIGABRT, WTERMSIG(__status)); + } +#undef BUF + +} + +ATF_TC_WITHOUT_HEAD(fgets_before_end); +ATF_TC_BODY(fgets_before_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + unsigned char __buf[42]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 42 - 1; + const size_t __idx __unused = __len - 1; + FILE *fp; + + fp = new_fp(__len); + + fgets(__stack.__buf, __len, fp); +#undef BUF + +} + +ATF_TC_WITHOUT_HEAD(fgets_end); +ATF_TC_BODY(fgets_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + unsigned char __buf[42]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 42; + const size_t __idx __unused = __len - 1; + FILE *fp; + + fp = new_fp(__len); + + fgets(__stack.__buf, __len, fp); +#undef BUF + +} + +ATF_TC_WITHOUT_HEAD(fgets_heap_before_end); +ATF_TC_BODY(fgets_heap_before_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42 - 1; + const size_t __idx __unused = __len - 1; + FILE *fp; + + __stack.__buf = malloc(__bufsz); + fp = new_fp(__len); + + fgets(__stack.__buf, __len, fp); +#undef BUF + +} + +ATF_TC_WITHOUT_HEAD(fgets_heap_end); +ATF_TC_BODY(fgets_heap_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42; + const size_t __idx __unused = __len - 1; + FILE *fp; + + __stack.__buf = malloc(__bufsz); + fp = new_fp(__len); + + fgets(__stack.__buf, __len, fp); +#undef BUF + +} + +ATF_TC_WITHOUT_HEAD(fgets_heap_after_end); +ATF_TC_BODY(fgets_heap_after_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42 + 1; + const size_t __idx __unused = __len - 1; + pid_t __child; + int __status; + FILE *fp; + + __child = fork(); + ATF_REQUIRE(__child >= 0); + if (__child > 0) + goto monitor; + + /* Child */ + disable_coredumps(); + __stack.__buf = malloc(__bufsz); + fp = new_fp(__len); + + fgets(__stack.__buf, __len, fp); + _exit(EX_SOFTWARE); /* Should have aborted. */ + +monitor: + while (waitpid(__child, &__status, 0) != __child) { + ATF_REQUIRE_EQ(EINTR, errno); + } + + if (!WIFSIGNALED(__status)) { + switch (WEXITSTATUS(__status)) { + case EX_SOFTWARE: + atf_tc_fail("FORTIFY_SOURCE failed to abort"); + break; + case EX_OSERR: + atf_tc_fail("setrlimit(2) failed"); + break; + default: + atf_tc_fail("child exited with status %d", + WEXITSTATUS(__status)); + } + } else { + ATF_REQUIRE_EQ(SIGABRT, WTERMSIG(__status)); + } +#undef BUF + +} + ATF_TP_ADD_TCS(tp) { + ATF_TP_ADD_TC(tp, ctermid_before_end); + ATF_TP_ADD_TC(tp, ctermid_end); + ATF_TP_ADD_TC(tp, ctermid_heap_before_end); + ATF_TP_ADD_TC(tp, ctermid_heap_end); + ATF_TP_ADD_TC(tp, ctermid_heap_after_end); + ATF_TP_ADD_TC(tp, ctermid_r_before_end); + ATF_TP_ADD_TC(tp, ctermid_r_end); + ATF_TP_ADD_TC(tp, ctermid_r_heap_before_end); + ATF_TP_ADD_TC(tp, ctermid_r_heap_end); + ATF_TP_ADD_TC(tp, ctermid_r_heap_after_end); + ATF_TP_ADD_TC(tp, fread_before_end); + ATF_TP_ADD_TC(tp, fread_end); + ATF_TP_ADD_TC(tp, fread_heap_before_end); + ATF_TP_ADD_TC(tp, fread_heap_end); + ATF_TP_ADD_TC(tp, fread_heap_after_end); + ATF_TP_ADD_TC(tp, fread_unlocked_before_end); + ATF_TP_ADD_TC(tp, fread_unlocked_end); + ATF_TP_ADD_TC(tp, fread_unlocked_heap_before_end); + ATF_TP_ADD_TC(tp, fread_unlocked_heap_end); + ATF_TP_ADD_TC(tp, fread_unlocked_heap_after_end); + ATF_TP_ADD_TC(tp, gets_s_before_end); + ATF_TP_ADD_TC(tp, gets_s_end); + ATF_TP_ADD_TC(tp, gets_s_heap_before_end); + ATF_TP_ADD_TC(tp, gets_s_heap_end); + ATF_TP_ADD_TC(tp, gets_s_heap_after_end); ATF_TP_ADD_TC(tp, sprintf_before_end); ATF_TP_ADD_TC(tp, sprintf_end); ATF_TP_ADD_TC(tp, sprintf_heap_before_end); @@ -379,5 +1359,15 @@ ATF_TP_ADD_TC(tp, snprintf_heap_before_end); ATF_TP_ADD_TC(tp, snprintf_heap_end); ATF_TP_ADD_TC(tp, snprintf_heap_after_end); + ATF_TP_ADD_TC(tp, tmpnam_before_end); + ATF_TP_ADD_TC(tp, tmpnam_end); + ATF_TP_ADD_TC(tp, tmpnam_heap_before_end); + ATF_TP_ADD_TC(tp, tmpnam_heap_end); + ATF_TP_ADD_TC(tp, tmpnam_heap_after_end); + ATF_TP_ADD_TC(tp, fgets_before_end); + ATF_TP_ADD_TC(tp, fgets_end); + ATF_TP_ADD_TC(tp, fgets_heap_before_end); + ATF_TP_ADD_TC(tp, fgets_heap_end); + ATF_TP_ADD_TC(tp, fgets_heap_after_end); return (atf_no_error()); } diff --git a/lib/libc/tests/secure/fortify_string_test.c b/lib/libc/tests/secure/fortify_string_test.c --- a/lib/libc/tests/secure/fortify_string_test.c +++ b/lib/libc/tests/secure/fortify_string_test.c @@ -20,6 +20,23 @@ #include #include +static FILE * __unused +new_fp(size_t __len) +{ + static char fpbuf[LINE_MAX]; + FILE *fp; + + ATF_REQUIRE(__len <= sizeof(fpbuf)); + + memset(fpbuf, 'A', sizeof(fpbuf) - 1); + fpbuf[sizeof(fpbuf) - 1] = '\0'; + + fp = fmemopen(fpbuf, sizeof(fpbuf), "rb"); + ATF_REQUIRE(fp != NULL); + + return (fp); +} + /* * Create a new symlink to use for readlink(2) style tests, we'll just use a * random target name to have something interesting to look at. @@ -79,6 +96,22 @@ _exit(EX_OSERR); } +/* + * Replaces stdin with a file that we can actually read from, for tests where + * we want a FILE * or fd that we can get data from. + */ +static void __unused +replace_stdin(void) +{ + int fd; + + fd = new_tmpfile(); + + (void)dup2(fd, STDIN_FILENO); + if (fd != STDIN_FILENO) + close(fd); +} + ATF_TC_WITHOUT_HEAD(memcpy_before_end); ATF_TC_BODY(memcpy_before_end, tc) { @@ -211,6 +244,138 @@ } +ATF_TC_WITHOUT_HEAD(mempcpy_before_end); +ATF_TC_BODY(mempcpy_before_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + unsigned char __buf[42]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 42 - 1; + const size_t __idx __unused = __len - 1; + char src[__len + 10]; + + mempcpy(__stack.__buf, src, __len); +#undef BUF + +} + +ATF_TC_WITHOUT_HEAD(mempcpy_end); +ATF_TC_BODY(mempcpy_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + unsigned char __buf[42]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 42; + const size_t __idx __unused = __len - 1; + char src[__len + 10]; + + mempcpy(__stack.__buf, src, __len); +#undef BUF + +} + +ATF_TC_WITHOUT_HEAD(mempcpy_heap_before_end); +ATF_TC_BODY(mempcpy_heap_before_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42 - 1; + const size_t __idx __unused = __len - 1; + char src[__len + 10]; + + __stack.__buf = malloc(__bufsz); + + mempcpy(__stack.__buf, src, __len); +#undef BUF + +} + +ATF_TC_WITHOUT_HEAD(mempcpy_heap_end); +ATF_TC_BODY(mempcpy_heap_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42; + const size_t __idx __unused = __len - 1; + char src[__len + 10]; + + __stack.__buf = malloc(__bufsz); + + mempcpy(__stack.__buf, src, __len); +#undef BUF + +} + +ATF_TC_WITHOUT_HEAD(mempcpy_heap_after_end); +ATF_TC_BODY(mempcpy_heap_after_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42 + 1; + const size_t __idx __unused = __len - 1; + pid_t __child; + int __status; + char src[__len + 10]; + + __child = fork(); + ATF_REQUIRE(__child >= 0); + if (__child > 0) + goto monitor; + + /* Child */ + disable_coredumps(); + __stack.__buf = malloc(__bufsz); + + mempcpy(__stack.__buf, src, __len); + _exit(EX_SOFTWARE); /* Should have aborted. */ + +monitor: + while (waitpid(__child, &__status, 0) != __child) { + ATF_REQUIRE_EQ(EINTR, errno); + } + + if (!WIFSIGNALED(__status)) { + switch (WEXITSTATUS(__status)) { + case EX_SOFTWARE: + atf_tc_fail("FORTIFY_SOURCE failed to abort"); + break; + case EX_OSERR: + atf_tc_fail("setrlimit(2) failed"); + break; + default: + atf_tc_fail("child exited with status %d", + WEXITSTATUS(__status)); + } + } else { + ATF_REQUIRE_EQ(SIGABRT, WTERMSIG(__status)); + } +#undef BUF + +} + ATF_TC_WITHOUT_HEAD(memmove_before_end); ATF_TC_BODY(memmove_before_end, tc) { @@ -917,6 +1082,155 @@ } +ATF_TC_WITHOUT_HEAD(strlcat_before_end); +ATF_TC_BODY(strlcat_before_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + unsigned char __buf[42]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 42 - 1; + const size_t __idx __unused = __len - 1; + char src[__len]; + + memset(__stack.__buf, 0, __len); + memset(src, 'A', __len - 1); + src[__len - 1] = '\0'; + + strlcat(__stack.__buf, src, __len); +#undef BUF + +} + +ATF_TC_WITHOUT_HEAD(strlcat_end); +ATF_TC_BODY(strlcat_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + unsigned char __buf[42]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 42; + const size_t __idx __unused = __len - 1; + char src[__len]; + + memset(__stack.__buf, 0, __len); + memset(src, 'A', __len - 1); + src[__len - 1] = '\0'; + + strlcat(__stack.__buf, src, __len); +#undef BUF + +} + +ATF_TC_WITHOUT_HEAD(strlcat_heap_before_end); +ATF_TC_BODY(strlcat_heap_before_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42 - 1; + const size_t __idx __unused = __len - 1; + char src[__len]; + + __stack.__buf = malloc(__bufsz); + memset(__stack.__buf, 0, __len); + memset(src, 'A', __len - 1); + src[__len - 1] = '\0'; + + strlcat(__stack.__buf, src, __len); +#undef BUF + +} + +ATF_TC_WITHOUT_HEAD(strlcat_heap_end); +ATF_TC_BODY(strlcat_heap_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42; + const size_t __idx __unused = __len - 1; + char src[__len]; + + __stack.__buf = malloc(__bufsz); + memset(__stack.__buf, 0, __len); + memset(src, 'A', __len - 1); + src[__len - 1] = '\0'; + + strlcat(__stack.__buf, src, __len); +#undef BUF + +} + +ATF_TC_WITHOUT_HEAD(strlcat_heap_after_end); +ATF_TC_BODY(strlcat_heap_after_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42 + 1; + const size_t __idx __unused = __len - 1; + pid_t __child; + int __status; + char src[__len]; + + __child = fork(); + ATF_REQUIRE(__child >= 0); + if (__child > 0) + goto monitor; + + /* Child */ + disable_coredumps(); + __stack.__buf = malloc(__bufsz); + memset(__stack.__buf, 0, __len); + memset(src, 'A', __len - 1); + src[__len - 1] = '\0'; + + strlcat(__stack.__buf, src, __len); + _exit(EX_SOFTWARE); /* Should have aborted. */ + +monitor: + while (waitpid(__child, &__status, 0) != __child) { + ATF_REQUIRE_EQ(EINTR, errno); + } + + if (!WIFSIGNALED(__status)) { + switch (WEXITSTATUS(__status)) { + case EX_SOFTWARE: + atf_tc_fail("FORTIFY_SOURCE failed to abort"); + break; + case EX_OSERR: + atf_tc_fail("setrlimit(2) failed"); + break; + default: + atf_tc_fail("child exited with status %d", + WEXITSTATUS(__status)); + } + } else { + ATF_REQUIRE_EQ(SIGABRT, WTERMSIG(__status)); + } +#undef BUF + +} + ATF_TC_WITHOUT_HEAD(strncat_before_end); ATF_TC_BODY(strncat_before_end, tc) { @@ -1215,6 +1529,155 @@ } +ATF_TC_WITHOUT_HEAD(strlcpy_before_end); +ATF_TC_BODY(strlcpy_before_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + unsigned char __buf[42]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 42 - 1; + const size_t __idx __unused = __len - 1; + char src[__len]; + + memset(__stack.__buf, 0, __len); + memset(src, 'A', __len - 1); + src[__len - 1] = '\0'; + + strlcpy(__stack.__buf, src, __len); +#undef BUF + +} + +ATF_TC_WITHOUT_HEAD(strlcpy_end); +ATF_TC_BODY(strlcpy_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + unsigned char __buf[42]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 42; + const size_t __idx __unused = __len - 1; + char src[__len]; + + memset(__stack.__buf, 0, __len); + memset(src, 'A', __len - 1); + src[__len - 1] = '\0'; + + strlcpy(__stack.__buf, src, __len); +#undef BUF + +} + +ATF_TC_WITHOUT_HEAD(strlcpy_heap_before_end); +ATF_TC_BODY(strlcpy_heap_before_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42 - 1; + const size_t __idx __unused = __len - 1; + char src[__len]; + + __stack.__buf = malloc(__bufsz); + memset(__stack.__buf, 0, __len); + memset(src, 'A', __len - 1); + src[__len - 1] = '\0'; + + strlcpy(__stack.__buf, src, __len); +#undef BUF + +} + +ATF_TC_WITHOUT_HEAD(strlcpy_heap_end); +ATF_TC_BODY(strlcpy_heap_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42; + const size_t __idx __unused = __len - 1; + char src[__len]; + + __stack.__buf = malloc(__bufsz); + memset(__stack.__buf, 0, __len); + memset(src, 'A', __len - 1); + src[__len - 1] = '\0'; + + strlcpy(__stack.__buf, src, __len); +#undef BUF + +} + +ATF_TC_WITHOUT_HEAD(strlcpy_heap_after_end); +ATF_TC_BODY(strlcpy_heap_after_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42 + 1; + const size_t __idx __unused = __len - 1; + pid_t __child; + int __status; + char src[__len]; + + __child = fork(); + ATF_REQUIRE(__child >= 0); + if (__child > 0) + goto monitor; + + /* Child */ + disable_coredumps(); + __stack.__buf = malloc(__bufsz); + memset(__stack.__buf, 0, __len); + memset(src, 'A', __len - 1); + src[__len - 1] = '\0'; + + strlcpy(__stack.__buf, src, __len); + _exit(EX_SOFTWARE); /* Should have aborted. */ + +monitor: + while (waitpid(__child, &__status, 0) != __child) { + ATF_REQUIRE_EQ(EINTR, errno); + } + + if (!WIFSIGNALED(__status)) { + switch (WEXITSTATUS(__status)) { + case EX_SOFTWARE: + atf_tc_fail("FORTIFY_SOURCE failed to abort"); + break; + case EX_OSERR: + atf_tc_fail("setrlimit(2) failed"); + break; + default: + atf_tc_fail("child exited with status %d", + WEXITSTATUS(__status)); + } + } else { + ATF_REQUIRE_EQ(SIGABRT, WTERMSIG(__status)); + } +#undef BUF + +} + ATF_TC_WITHOUT_HEAD(strncpy_before_end); ATF_TC_BODY(strncpy_before_end, tc) { @@ -1371,6 +1834,11 @@ ATF_TP_ADD_TC(tp, memcpy_heap_before_end); ATF_TP_ADD_TC(tp, memcpy_heap_end); ATF_TP_ADD_TC(tp, memcpy_heap_after_end); + ATF_TP_ADD_TC(tp, mempcpy_before_end); + ATF_TP_ADD_TC(tp, mempcpy_end); + ATF_TP_ADD_TC(tp, mempcpy_heap_before_end); + ATF_TP_ADD_TC(tp, mempcpy_heap_end); + ATF_TP_ADD_TC(tp, mempcpy_heap_after_end); ATF_TP_ADD_TC(tp, memmove_before_end); ATF_TP_ADD_TC(tp, memmove_end); ATF_TP_ADD_TC(tp, memmove_heap_before_end); @@ -1396,6 +1864,11 @@ ATF_TP_ADD_TC(tp, strcat_heap_before_end); ATF_TP_ADD_TC(tp, strcat_heap_end); ATF_TP_ADD_TC(tp, strcat_heap_after_end); + ATF_TP_ADD_TC(tp, strlcat_before_end); + ATF_TP_ADD_TC(tp, strlcat_end); + ATF_TP_ADD_TC(tp, strlcat_heap_before_end); + ATF_TP_ADD_TC(tp, strlcat_heap_end); + ATF_TP_ADD_TC(tp, strlcat_heap_after_end); ATF_TP_ADD_TC(tp, strncat_before_end); ATF_TP_ADD_TC(tp, strncat_end); ATF_TP_ADD_TC(tp, strncat_heap_before_end); @@ -1406,6 +1879,11 @@ ATF_TP_ADD_TC(tp, strcpy_heap_before_end); ATF_TP_ADD_TC(tp, strcpy_heap_end); ATF_TP_ADD_TC(tp, strcpy_heap_after_end); + ATF_TP_ADD_TC(tp, strlcpy_before_end); + ATF_TP_ADD_TC(tp, strlcpy_end); + ATF_TP_ADD_TC(tp, strlcpy_heap_before_end); + ATF_TP_ADD_TC(tp, strlcpy_heap_end); + ATF_TP_ADD_TC(tp, strlcpy_heap_after_end); ATF_TP_ADD_TC(tp, strncpy_before_end); ATF_TP_ADD_TC(tp, strncpy_end); ATF_TP_ADD_TC(tp, strncpy_heap_before_end); diff --git a/lib/libc/tests/secure/fortify_strings_test.c b/lib/libc/tests/secure/fortify_strings_test.c --- a/lib/libc/tests/secure/fortify_strings_test.c +++ b/lib/libc/tests/secure/fortify_strings_test.c @@ -20,6 +20,23 @@ #include #include +static FILE * __unused +new_fp(size_t __len) +{ + static char fpbuf[LINE_MAX]; + FILE *fp; + + ATF_REQUIRE(__len <= sizeof(fpbuf)); + + memset(fpbuf, 'A', sizeof(fpbuf) - 1); + fpbuf[sizeof(fpbuf) - 1] = '\0'; + + fp = fmemopen(fpbuf, sizeof(fpbuf), "rb"); + ATF_REQUIRE(fp != NULL); + + return (fp); +} + /* * Create a new symlink to use for readlink(2) style tests, we'll just use a * random target name to have something interesting to look at. @@ -79,6 +96,22 @@ _exit(EX_OSERR); } +/* + * Replaces stdin with a file that we can actually read from, for tests where + * we want a FILE * or fd that we can get data from. + */ +static void __unused +replace_stdin(void) +{ + int fd; + + fd = new_tmpfile(); + + (void)dup2(fd, STDIN_FILENO); + if (fd != STDIN_FILENO) + close(fd); +} + ATF_TC_WITHOUT_HEAD(bcopy_before_end); ATF_TC_BODY(bcopy_before_end, tc) { @@ -338,6 +371,133 @@ } +ATF_TC_WITHOUT_HEAD(explicit_bzero_before_end); +ATF_TC_BODY(explicit_bzero_before_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + unsigned char __buf[42]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 42 - 1; + const size_t __idx __unused = __len - 1; + + explicit_bzero(__stack.__buf, __len); +#undef BUF + +} + +ATF_TC_WITHOUT_HEAD(explicit_bzero_end); +ATF_TC_BODY(explicit_bzero_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + unsigned char __buf[42]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 42; + const size_t __idx __unused = __len - 1; + + explicit_bzero(__stack.__buf, __len); +#undef BUF + +} + +ATF_TC_WITHOUT_HEAD(explicit_bzero_heap_before_end); +ATF_TC_BODY(explicit_bzero_heap_before_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42 - 1; + const size_t __idx __unused = __len - 1; + + __stack.__buf = malloc(__bufsz); + + explicit_bzero(__stack.__buf, __len); +#undef BUF + +} + +ATF_TC_WITHOUT_HEAD(explicit_bzero_heap_end); +ATF_TC_BODY(explicit_bzero_heap_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42; + const size_t __idx __unused = __len - 1; + + __stack.__buf = malloc(__bufsz); + + explicit_bzero(__stack.__buf, __len); +#undef BUF + +} + +ATF_TC_WITHOUT_HEAD(explicit_bzero_heap_after_end); +ATF_TC_BODY(explicit_bzero_heap_after_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42 + 1; + const size_t __idx __unused = __len - 1; + pid_t __child; + int __status; + + __child = fork(); + ATF_REQUIRE(__child >= 0); + if (__child > 0) + goto monitor; + + /* Child */ + disable_coredumps(); + __stack.__buf = malloc(__bufsz); + + explicit_bzero(__stack.__buf, __len); + _exit(EX_SOFTWARE); /* Should have aborted. */ + +monitor: + while (waitpid(__child, &__status, 0) != __child) { + ATF_REQUIRE_EQ(EINTR, errno); + } + + if (!WIFSIGNALED(__status)) { + switch (WEXITSTATUS(__status)) { + case EX_SOFTWARE: + atf_tc_fail("FORTIFY_SOURCE failed to abort"); + break; + case EX_OSERR: + atf_tc_fail("setrlimit(2) failed"); + break; + default: + atf_tc_fail("child exited with status %d", + WEXITSTATUS(__status)); + } + } else { + ATF_REQUIRE_EQ(SIGABRT, WTERMSIG(__status)); + } +#undef BUF + +} + ATF_TP_ADD_TCS(tp) { ATF_TP_ADD_TC(tp, bcopy_before_end); @@ -350,5 +510,10 @@ ATF_TP_ADD_TC(tp, bzero_heap_before_end); ATF_TP_ADD_TC(tp, bzero_heap_end); ATF_TP_ADD_TC(tp, bzero_heap_after_end); + ATF_TP_ADD_TC(tp, explicit_bzero_before_end); + ATF_TP_ADD_TC(tp, explicit_bzero_end); + ATF_TP_ADD_TC(tp, explicit_bzero_heap_before_end); + ATF_TP_ADD_TC(tp, explicit_bzero_heap_end); + ATF_TP_ADD_TC(tp, explicit_bzero_heap_after_end); return (atf_no_error()); } diff --git a/lib/libc/tests/secure/fortify_unistd_test.c b/lib/libc/tests/secure/fortify_unistd_test.c --- a/lib/libc/tests/secure/fortify_unistd_test.c +++ b/lib/libc/tests/secure/fortify_unistd_test.c @@ -20,6 +20,23 @@ #include #include +static FILE * __unused +new_fp(size_t __len) +{ + static char fpbuf[LINE_MAX]; + FILE *fp; + + ATF_REQUIRE(__len <= sizeof(fpbuf)); + + memset(fpbuf, 'A', sizeof(fpbuf) - 1); + fpbuf[sizeof(fpbuf) - 1] = '\0'; + + fp = fmemopen(fpbuf, sizeof(fpbuf), "rb"); + ATF_REQUIRE(fp != NULL); + + return (fp); +} + /* * Create a new symlink to use for readlink(2) style tests, we'll just use a * random target name to have something interesting to look at. @@ -79,6 +96,22 @@ _exit(EX_OSERR); } +/* + * Replaces stdin with a file that we can actually read from, for tests where + * we want a FILE * or fd that we can get data from. + */ +static void __unused +replace_stdin(void) +{ + int fd; + + fd = new_tmpfile(); + + (void)dup2(fd, STDIN_FILENO); + if (fd != STDIN_FILENO) + close(fd); +} + ATF_TC_WITHOUT_HEAD(getcwd_before_end); ATF_TC_BODY(getcwd_before_end, tc) { @@ -206,107 +239,228 @@ } -ATF_TC_WITHOUT_HEAD(read_before_end); -ATF_TC_BODY(read_before_end, tc) +ATF_TC_WITHOUT_HEAD(getgrouplist_before_end); +ATF_TC_BODY(getgrouplist_before_end, tc) { #define BUF &__stack.__buf struct { uint8_t padding_l; - unsigned char __buf[41]; + gid_t __buf[4]; uint8_t padding_r; } __stack; const size_t __bufsz __unused = sizeof(__stack.__buf); - const size_t __len = 41 - 1; + const size_t __len = 4 - 1; const size_t __idx __unused = __len - 1; - int fd; + int intlen = (int)__len; - fd = new_tmpfile(); /* Cannot fail */ + getgrouplist("root", 0, __stack.__buf, &intlen); +#undef BUF - read(fd, __stack.__buf, __len); +} + +ATF_TC_WITHOUT_HEAD(getgrouplist_end); +ATF_TC_BODY(getgrouplist_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + gid_t __buf[4]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 4; + const size_t __idx __unused = __len - 1; + int intlen = (int)__len; + + getgrouplist("root", 0, __stack.__buf, &intlen); #undef BUF } -ATF_TC_WITHOUT_HEAD(read_end); -ATF_TC_BODY(read_end, tc) +ATF_TC_WITHOUT_HEAD(getgrouplist_heap_before_end); +ATF_TC_BODY(getgrouplist_heap_before_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + gid_t * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (4); + const size_t __len = 4 - 1; + const size_t __idx __unused = __len - 1; + int intlen = (int)__len; + + __stack.__buf = malloc(__bufsz); + + getgrouplist("root", 0, __stack.__buf, &intlen); +#undef BUF + +} + +ATF_TC_WITHOUT_HEAD(getgrouplist_heap_end); +ATF_TC_BODY(getgrouplist_heap_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + gid_t * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (4); + const size_t __len = 4; + const size_t __idx __unused = __len - 1; + int intlen = (int)__len; + + __stack.__buf = malloc(__bufsz); + + getgrouplist("root", 0, __stack.__buf, &intlen); +#undef BUF + +} + +ATF_TC_WITHOUT_HEAD(getgrouplist_heap_after_end); +ATF_TC_BODY(getgrouplist_heap_after_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + gid_t * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (4); + const size_t __len = 4 + 1; + const size_t __idx __unused = __len - 1; + pid_t __child; + int __status; + int intlen = (int)__len; + + __child = fork(); + ATF_REQUIRE(__child >= 0); + if (__child > 0) + goto monitor; + + /* Child */ + disable_coredumps(); + __stack.__buf = malloc(__bufsz); + + getgrouplist("root", 0, __stack.__buf, &intlen); + _exit(EX_SOFTWARE); /* Should have aborted. */ + +monitor: + while (waitpid(__child, &__status, 0) != __child) { + ATF_REQUIRE_EQ(EINTR, errno); + } + + if (!WIFSIGNALED(__status)) { + switch (WEXITSTATUS(__status)) { + case EX_SOFTWARE: + atf_tc_fail("FORTIFY_SOURCE failed to abort"); + break; + case EX_OSERR: + atf_tc_fail("setrlimit(2) failed"); + break; + default: + atf_tc_fail("child exited with status %d", + WEXITSTATUS(__status)); + } + } else { + ATF_REQUIRE_EQ(SIGABRT, WTERMSIG(__status)); + } +#undef BUF + +} + +ATF_TC_WITHOUT_HEAD(getgroups_before_end); +ATF_TC_BODY(getgroups_before_end, tc) { #define BUF &__stack.__buf struct { uint8_t padding_l; - unsigned char __buf[41]; + gid_t __buf[4]; uint8_t padding_r; } __stack; const size_t __bufsz __unused = sizeof(__stack.__buf); - const size_t __len = 41; + const size_t __len = 4 - 1; const size_t __idx __unused = __len - 1; - int fd; - fd = new_tmpfile(); /* Cannot fail */ + getgroups(__len, __stack.__buf); +#undef BUF - read(fd, __stack.__buf, __len); +} + +ATF_TC_WITHOUT_HEAD(getgroups_end); +ATF_TC_BODY(getgroups_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + gid_t __buf[4]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 4; + const size_t __idx __unused = __len - 1; + + getgroups(__len, __stack.__buf); #undef BUF } -ATF_TC_WITHOUT_HEAD(read_heap_before_end); -ATF_TC_BODY(read_heap_before_end, tc) +ATF_TC_WITHOUT_HEAD(getgroups_heap_before_end); +ATF_TC_BODY(getgroups_heap_before_end, tc) { #define BUF __stack.__buf struct { uint8_t padding_l; - unsigned char * __buf; + gid_t * __buf; uint8_t padding_r; } __stack; - const size_t __bufsz __unused = sizeof(*__stack.__buf) * (41); - const size_t __len = 41 - 1; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (4); + const size_t __len = 4 - 1; const size_t __idx __unused = __len - 1; - int fd; __stack.__buf = malloc(__bufsz); - fd = new_tmpfile(); /* Cannot fail */ - read(fd, __stack.__buf, __len); + getgroups(__len, __stack.__buf); #undef BUF } -ATF_TC_WITHOUT_HEAD(read_heap_end); -ATF_TC_BODY(read_heap_end, tc) +ATF_TC_WITHOUT_HEAD(getgroups_heap_end); +ATF_TC_BODY(getgroups_heap_end, tc) { #define BUF __stack.__buf struct { uint8_t padding_l; - unsigned char * __buf; + gid_t * __buf; uint8_t padding_r; } __stack; - const size_t __bufsz __unused = sizeof(*__stack.__buf) * (41); - const size_t __len = 41; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (4); + const size_t __len = 4; const size_t __idx __unused = __len - 1; - int fd; __stack.__buf = malloc(__bufsz); - fd = new_tmpfile(); /* Cannot fail */ - read(fd, __stack.__buf, __len); + getgroups(__len, __stack.__buf); #undef BUF } -ATF_TC_WITHOUT_HEAD(read_heap_after_end); -ATF_TC_BODY(read_heap_after_end, tc) +ATF_TC_WITHOUT_HEAD(getgroups_heap_after_end); +ATF_TC_BODY(getgroups_heap_after_end, tc) { #define BUF __stack.__buf struct { uint8_t padding_l; - unsigned char * __buf; + gid_t * __buf; uint8_t padding_r; } __stack; - const size_t __bufsz __unused = sizeof(*__stack.__buf) * (41); - const size_t __len = 41 + 1; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (4); + const size_t __len = 4 + 1; const size_t __idx __unused = __len - 1; pid_t __child; int __status; - int fd; __child = fork(); ATF_REQUIRE(__child >= 0); @@ -316,9 +470,8 @@ /* Child */ disable_coredumps(); __stack.__buf = malloc(__bufsz); - fd = new_tmpfile(); /* Cannot fail */ - read(fd, __stack.__buf, __len); + getgroups(__len, __stack.__buf); _exit(EX_SOFTWARE); /* Should have aborted. */ monitor: @@ -345,8 +498,8 @@ } -ATF_TC_WITHOUT_HEAD(readlink_before_end); -ATF_TC_BODY(readlink_before_end, tc) +ATF_TC_WITHOUT_HEAD(getloginclass_before_end); +ATF_TC_BODY(getloginclass_before_end, tc) { #define BUF &__stack.__buf struct { @@ -357,17 +510,14 @@ const size_t __bufsz __unused = sizeof(__stack.__buf); const size_t __len = 42 - 1; const size_t __idx __unused = __len - 1; - const char *path; - - path = new_symlink(__len); /* Cannot fail */ - readlink(path, __stack.__buf, __len); + getloginclass(__stack.__buf, __len); #undef BUF } -ATF_TC_WITHOUT_HEAD(readlink_end); -ATF_TC_BODY(readlink_end, tc) +ATF_TC_WITHOUT_HEAD(getloginclass_end); +ATF_TC_BODY(getloginclass_end, tc) { #define BUF &__stack.__buf struct { @@ -378,17 +528,14 @@ const size_t __bufsz __unused = sizeof(__stack.__buf); const size_t __len = 42; const size_t __idx __unused = __len - 1; - const char *path; - - path = new_symlink(__len); /* Cannot fail */ - readlink(path, __stack.__buf, __len); + getloginclass(__stack.__buf, __len); #undef BUF } -ATF_TC_WITHOUT_HEAD(readlink_heap_before_end); -ATF_TC_BODY(readlink_heap_before_end, tc) +ATF_TC_WITHOUT_HEAD(getloginclass_heap_before_end); +ATF_TC_BODY(getloginclass_heap_before_end, tc) { #define BUF __stack.__buf struct { @@ -399,18 +546,16 @@ const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); const size_t __len = 42 - 1; const size_t __idx __unused = __len - 1; - const char *path; __stack.__buf = malloc(__bufsz); - path = new_symlink(__len); /* Cannot fail */ - readlink(path, __stack.__buf, __len); + getloginclass(__stack.__buf, __len); #undef BUF } -ATF_TC_WITHOUT_HEAD(readlink_heap_end); -ATF_TC_BODY(readlink_heap_end, tc) +ATF_TC_WITHOUT_HEAD(getloginclass_heap_end); +ATF_TC_BODY(getloginclass_heap_end, tc) { #define BUF __stack.__buf struct { @@ -421,18 +566,16 @@ const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); const size_t __len = 42; const size_t __idx __unused = __len - 1; - const char *path; __stack.__buf = malloc(__bufsz); - path = new_symlink(__len); /* Cannot fail */ - readlink(path, __stack.__buf, __len); + getloginclass(__stack.__buf, __len); #undef BUF } -ATF_TC_WITHOUT_HEAD(readlink_heap_after_end); -ATF_TC_BODY(readlink_heap_after_end, tc) +ATF_TC_WITHOUT_HEAD(getloginclass_heap_after_end); +ATF_TC_BODY(getloginclass_heap_after_end, tc) { #define BUF __stack.__buf struct { @@ -445,7 +588,6 @@ const size_t __idx __unused = __len - 1; pid_t __child; int __status; - const char *path; __child = fork(); ATF_REQUIRE(__child >= 0); @@ -455,9 +597,1279 @@ /* Child */ disable_coredumps(); __stack.__buf = malloc(__bufsz); - path = new_symlink(__len); /* Cannot fail */ - readlink(path, __stack.__buf, __len); + getloginclass(__stack.__buf, __len); + _exit(EX_SOFTWARE); /* Should have aborted. */ + +monitor: + while (waitpid(__child, &__status, 0) != __child) { + ATF_REQUIRE_EQ(EINTR, errno); + } + + if (!WIFSIGNALED(__status)) { + switch (WEXITSTATUS(__status)) { + case EX_SOFTWARE: + atf_tc_fail("FORTIFY_SOURCE failed to abort"); + break; + case EX_OSERR: + atf_tc_fail("setrlimit(2) failed"); + break; + default: + atf_tc_fail("child exited with status %d", + WEXITSTATUS(__status)); + } + } else { + ATF_REQUIRE_EQ(SIGABRT, WTERMSIG(__status)); + } +#undef BUF + +} + +ATF_TC_WITHOUT_HEAD(pread_before_end); +ATF_TC_BODY(pread_before_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + unsigned char __buf[41]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 41 - 1; + const size_t __idx __unused = __len - 1; + int fd; + + fd = new_tmpfile(); /* Cannot fail */ + + pread(fd, __stack.__buf, __len, 0); +#undef BUF + +} + +ATF_TC_WITHOUT_HEAD(pread_end); +ATF_TC_BODY(pread_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + unsigned char __buf[41]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 41; + const size_t __idx __unused = __len - 1; + int fd; + + fd = new_tmpfile(); /* Cannot fail */ + + pread(fd, __stack.__buf, __len, 0); +#undef BUF + +} + +ATF_TC_WITHOUT_HEAD(pread_heap_before_end); +ATF_TC_BODY(pread_heap_before_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (41); + const size_t __len = 41 - 1; + const size_t __idx __unused = __len - 1; + int fd; + + __stack.__buf = malloc(__bufsz); + fd = new_tmpfile(); /* Cannot fail */ + + pread(fd, __stack.__buf, __len, 0); +#undef BUF + +} + +ATF_TC_WITHOUT_HEAD(pread_heap_end); +ATF_TC_BODY(pread_heap_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (41); + const size_t __len = 41; + const size_t __idx __unused = __len - 1; + int fd; + + __stack.__buf = malloc(__bufsz); + fd = new_tmpfile(); /* Cannot fail */ + + pread(fd, __stack.__buf, __len, 0); +#undef BUF + +} + +ATF_TC_WITHOUT_HEAD(pread_heap_after_end); +ATF_TC_BODY(pread_heap_after_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (41); + const size_t __len = 41 + 1; + const size_t __idx __unused = __len - 1; + pid_t __child; + int __status; + int fd; + + __child = fork(); + ATF_REQUIRE(__child >= 0); + if (__child > 0) + goto monitor; + + /* Child */ + disable_coredumps(); + __stack.__buf = malloc(__bufsz); + fd = new_tmpfile(); /* Cannot fail */ + + pread(fd, __stack.__buf, __len, 0); + _exit(EX_SOFTWARE); /* Should have aborted. */ + +monitor: + while (waitpid(__child, &__status, 0) != __child) { + ATF_REQUIRE_EQ(EINTR, errno); + } + + if (!WIFSIGNALED(__status)) { + switch (WEXITSTATUS(__status)) { + case EX_SOFTWARE: + atf_tc_fail("FORTIFY_SOURCE failed to abort"); + break; + case EX_OSERR: + atf_tc_fail("setrlimit(2) failed"); + break; + default: + atf_tc_fail("child exited with status %d", + WEXITSTATUS(__status)); + } + } else { + ATF_REQUIRE_EQ(SIGABRT, WTERMSIG(__status)); + } +#undef BUF + +} + +ATF_TC_WITHOUT_HEAD(read_before_end); +ATF_TC_BODY(read_before_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + unsigned char __buf[41]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 41 - 1; + const size_t __idx __unused = __len - 1; + int fd; + + fd = new_tmpfile(); /* Cannot fail */ + + read(fd, __stack.__buf, __len); +#undef BUF + +} + +ATF_TC_WITHOUT_HEAD(read_end); +ATF_TC_BODY(read_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + unsigned char __buf[41]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 41; + const size_t __idx __unused = __len - 1; + int fd; + + fd = new_tmpfile(); /* Cannot fail */ + + read(fd, __stack.__buf, __len); +#undef BUF + +} + +ATF_TC_WITHOUT_HEAD(read_heap_before_end); +ATF_TC_BODY(read_heap_before_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (41); + const size_t __len = 41 - 1; + const size_t __idx __unused = __len - 1; + int fd; + + __stack.__buf = malloc(__bufsz); + fd = new_tmpfile(); /* Cannot fail */ + + read(fd, __stack.__buf, __len); +#undef BUF + +} + +ATF_TC_WITHOUT_HEAD(read_heap_end); +ATF_TC_BODY(read_heap_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (41); + const size_t __len = 41; + const size_t __idx __unused = __len - 1; + int fd; + + __stack.__buf = malloc(__bufsz); + fd = new_tmpfile(); /* Cannot fail */ + + read(fd, __stack.__buf, __len); +#undef BUF + +} + +ATF_TC_WITHOUT_HEAD(read_heap_after_end); +ATF_TC_BODY(read_heap_after_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (41); + const size_t __len = 41 + 1; + const size_t __idx __unused = __len - 1; + pid_t __child; + int __status; + int fd; + + __child = fork(); + ATF_REQUIRE(__child >= 0); + if (__child > 0) + goto monitor; + + /* Child */ + disable_coredumps(); + __stack.__buf = malloc(__bufsz); + fd = new_tmpfile(); /* Cannot fail */ + + read(fd, __stack.__buf, __len); + _exit(EX_SOFTWARE); /* Should have aborted. */ + +monitor: + while (waitpid(__child, &__status, 0) != __child) { + ATF_REQUIRE_EQ(EINTR, errno); + } + + if (!WIFSIGNALED(__status)) { + switch (WEXITSTATUS(__status)) { + case EX_SOFTWARE: + atf_tc_fail("FORTIFY_SOURCE failed to abort"); + break; + case EX_OSERR: + atf_tc_fail("setrlimit(2) failed"); + break; + default: + atf_tc_fail("child exited with status %d", + WEXITSTATUS(__status)); + } + } else { + ATF_REQUIRE_EQ(SIGABRT, WTERMSIG(__status)); + } +#undef BUF + +} + +ATF_TC_WITHOUT_HEAD(readlink_before_end); +ATF_TC_BODY(readlink_before_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + unsigned char __buf[42]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 42 - 1; + const size_t __idx __unused = __len - 1; + const char *path; + + path = new_symlink(__len); /* Cannot fail */ + + readlink(path, __stack.__buf, __len); +#undef BUF + +} + +ATF_TC_WITHOUT_HEAD(readlink_end); +ATF_TC_BODY(readlink_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + unsigned char __buf[42]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 42; + const size_t __idx __unused = __len - 1; + const char *path; + + path = new_symlink(__len); /* Cannot fail */ + + readlink(path, __stack.__buf, __len); +#undef BUF + +} + +ATF_TC_WITHOUT_HEAD(readlink_heap_before_end); +ATF_TC_BODY(readlink_heap_before_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42 - 1; + const size_t __idx __unused = __len - 1; + const char *path; + + __stack.__buf = malloc(__bufsz); + path = new_symlink(__len); /* Cannot fail */ + + readlink(path, __stack.__buf, __len); +#undef BUF + +} + +ATF_TC_WITHOUT_HEAD(readlink_heap_end); +ATF_TC_BODY(readlink_heap_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42; + const size_t __idx __unused = __len - 1; + const char *path; + + __stack.__buf = malloc(__bufsz); + path = new_symlink(__len); /* Cannot fail */ + + readlink(path, __stack.__buf, __len); +#undef BUF + +} + +ATF_TC_WITHOUT_HEAD(readlink_heap_after_end); +ATF_TC_BODY(readlink_heap_after_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42 + 1; + const size_t __idx __unused = __len - 1; + pid_t __child; + int __status; + const char *path; + + __child = fork(); + ATF_REQUIRE(__child >= 0); + if (__child > 0) + goto monitor; + + /* Child */ + disable_coredumps(); + __stack.__buf = malloc(__bufsz); + path = new_symlink(__len); /* Cannot fail */ + + readlink(path, __stack.__buf, __len); + _exit(EX_SOFTWARE); /* Should have aborted. */ + +monitor: + while (waitpid(__child, &__status, 0) != __child) { + ATF_REQUIRE_EQ(EINTR, errno); + } + + if (!WIFSIGNALED(__status)) { + switch (WEXITSTATUS(__status)) { + case EX_SOFTWARE: + atf_tc_fail("FORTIFY_SOURCE failed to abort"); + break; + case EX_OSERR: + atf_tc_fail("setrlimit(2) failed"); + break; + default: + atf_tc_fail("child exited with status %d", + WEXITSTATUS(__status)); + } + } else { + ATF_REQUIRE_EQ(SIGABRT, WTERMSIG(__status)); + } +#undef BUF + +} + +ATF_TC_WITHOUT_HEAD(readlinkat_before_end); +ATF_TC_BODY(readlinkat_before_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + unsigned char __buf[42]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 42 - 1; + const size_t __idx __unused = __len - 1; + const char *path; + + path = new_symlink(__len); /* Cannot fail */ + + readlinkat(AT_FDCWD, path, __stack.__buf, __len); +#undef BUF + +} + +ATF_TC_WITHOUT_HEAD(readlinkat_end); +ATF_TC_BODY(readlinkat_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + unsigned char __buf[42]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 42; + const size_t __idx __unused = __len - 1; + const char *path; + + path = new_symlink(__len); /* Cannot fail */ + + readlinkat(AT_FDCWD, path, __stack.__buf, __len); +#undef BUF + +} + +ATF_TC_WITHOUT_HEAD(readlinkat_heap_before_end); +ATF_TC_BODY(readlinkat_heap_before_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42 - 1; + const size_t __idx __unused = __len - 1; + const char *path; + + __stack.__buf = malloc(__bufsz); + path = new_symlink(__len); /* Cannot fail */ + + readlinkat(AT_FDCWD, path, __stack.__buf, __len); +#undef BUF + +} + +ATF_TC_WITHOUT_HEAD(readlinkat_heap_end); +ATF_TC_BODY(readlinkat_heap_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42; + const size_t __idx __unused = __len - 1; + const char *path; + + __stack.__buf = malloc(__bufsz); + path = new_symlink(__len); /* Cannot fail */ + + readlinkat(AT_FDCWD, path, __stack.__buf, __len); +#undef BUF + +} + +ATF_TC_WITHOUT_HEAD(readlinkat_heap_after_end); +ATF_TC_BODY(readlinkat_heap_after_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42 + 1; + const size_t __idx __unused = __len - 1; + pid_t __child; + int __status; + const char *path; + + __child = fork(); + ATF_REQUIRE(__child >= 0); + if (__child > 0) + goto monitor; + + /* Child */ + disable_coredumps(); + __stack.__buf = malloc(__bufsz); + path = new_symlink(__len); /* Cannot fail */ + + readlinkat(AT_FDCWD, path, __stack.__buf, __len); + _exit(EX_SOFTWARE); /* Should have aborted. */ + +monitor: + while (waitpid(__child, &__status, 0) != __child) { + ATF_REQUIRE_EQ(EINTR, errno); + } + + if (!WIFSIGNALED(__status)) { + switch (WEXITSTATUS(__status)) { + case EX_SOFTWARE: + atf_tc_fail("FORTIFY_SOURCE failed to abort"); + break; + case EX_OSERR: + atf_tc_fail("setrlimit(2) failed"); + break; + default: + atf_tc_fail("child exited with status %d", + WEXITSTATUS(__status)); + } + } else { + ATF_REQUIRE_EQ(SIGABRT, WTERMSIG(__status)); + } +#undef BUF + +} + +ATF_TC_WITHOUT_HEAD(getdomainname_before_end); +ATF_TC_BODY(getdomainname_before_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + unsigned char __buf[4]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 4 - 1; + const size_t __idx __unused = __len - 1; + char sysdomain[256]; + + (void)getdomainname(sysdomain, __len); + if (strlen(sysdomain) <= __len) + atf_tc_skip("domain name too short for testing"); + + getdomainname(__stack.__buf, __len); +#undef BUF + +} + +ATF_TC_WITHOUT_HEAD(getdomainname_end); +ATF_TC_BODY(getdomainname_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + unsigned char __buf[4]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 4; + const size_t __idx __unused = __len - 1; + char sysdomain[256]; + + (void)getdomainname(sysdomain, __len); + if (strlen(sysdomain) <= __len) + atf_tc_skip("domain name too short for testing"); + + getdomainname(__stack.__buf, __len); +#undef BUF + +} + +ATF_TC_WITHOUT_HEAD(getdomainname_heap_before_end); +ATF_TC_BODY(getdomainname_heap_before_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (4); + const size_t __len = 4 - 1; + const size_t __idx __unused = __len - 1; + char sysdomain[256]; + + (void)getdomainname(sysdomain, __len); + if (strlen(sysdomain) <= __len) + atf_tc_skip("domain name too short for testing"); + + __stack.__buf = malloc(__bufsz); + + getdomainname(__stack.__buf, __len); +#undef BUF + +} + +ATF_TC_WITHOUT_HEAD(getdomainname_heap_end); +ATF_TC_BODY(getdomainname_heap_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (4); + const size_t __len = 4; + const size_t __idx __unused = __len - 1; + char sysdomain[256]; + + (void)getdomainname(sysdomain, __len); + if (strlen(sysdomain) <= __len) + atf_tc_skip("domain name too short for testing"); + + __stack.__buf = malloc(__bufsz); + + getdomainname(__stack.__buf, __len); +#undef BUF + +} + +ATF_TC_WITHOUT_HEAD(getdomainname_heap_after_end); +ATF_TC_BODY(getdomainname_heap_after_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (4); + const size_t __len = 4 + 1; + const size_t __idx __unused = __len - 1; + pid_t __child; + int __status; + char sysdomain[256]; + + (void)getdomainname(sysdomain, __len); + if (strlen(sysdomain) <= __len) + atf_tc_skip("domain name too short for testing"); + + __child = fork(); + ATF_REQUIRE(__child >= 0); + if (__child > 0) + goto monitor; + + /* Child */ + disable_coredumps(); + __stack.__buf = malloc(__bufsz); + + getdomainname(__stack.__buf, __len); + _exit(EX_SOFTWARE); /* Should have aborted. */ + +monitor: + while (waitpid(__child, &__status, 0) != __child) { + ATF_REQUIRE_EQ(EINTR, errno); + } + + if (!WIFSIGNALED(__status)) { + switch (WEXITSTATUS(__status)) { + case EX_SOFTWARE: + atf_tc_fail("FORTIFY_SOURCE failed to abort"); + break; + case EX_OSERR: + atf_tc_fail("setrlimit(2) failed"); + break; + default: + atf_tc_fail("child exited with status %d", + WEXITSTATUS(__status)); + } + } else { + ATF_REQUIRE_EQ(SIGABRT, WTERMSIG(__status)); + } +#undef BUF + +} + +ATF_TC_WITHOUT_HEAD(getentropy_before_end); +ATF_TC_BODY(getentropy_before_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + unsigned char __buf[42]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 42 - 1; + const size_t __idx __unused = __len - 1; + + getentropy(__stack.__buf, __len); +#undef BUF + +} + +ATF_TC_WITHOUT_HEAD(getentropy_end); +ATF_TC_BODY(getentropy_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + unsigned char __buf[42]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 42; + const size_t __idx __unused = __len - 1; + + getentropy(__stack.__buf, __len); +#undef BUF + +} + +ATF_TC_WITHOUT_HEAD(getentropy_heap_before_end); +ATF_TC_BODY(getentropy_heap_before_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42 - 1; + const size_t __idx __unused = __len - 1; + + __stack.__buf = malloc(__bufsz); + + getentropy(__stack.__buf, __len); +#undef BUF + +} + +ATF_TC_WITHOUT_HEAD(getentropy_heap_end); +ATF_TC_BODY(getentropy_heap_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42; + const size_t __idx __unused = __len - 1; + + __stack.__buf = malloc(__bufsz); + + getentropy(__stack.__buf, __len); +#undef BUF + +} + +ATF_TC_WITHOUT_HEAD(getentropy_heap_after_end); +ATF_TC_BODY(getentropy_heap_after_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42 + 1; + const size_t __idx __unused = __len - 1; + pid_t __child; + int __status; + + __child = fork(); + ATF_REQUIRE(__child >= 0); + if (__child > 0) + goto monitor; + + /* Child */ + disable_coredumps(); + __stack.__buf = malloc(__bufsz); + + getentropy(__stack.__buf, __len); + _exit(EX_SOFTWARE); /* Should have aborted. */ + +monitor: + while (waitpid(__child, &__status, 0) != __child) { + ATF_REQUIRE_EQ(EINTR, errno); + } + + if (!WIFSIGNALED(__status)) { + switch (WEXITSTATUS(__status)) { + case EX_SOFTWARE: + atf_tc_fail("FORTIFY_SOURCE failed to abort"); + break; + case EX_OSERR: + atf_tc_fail("setrlimit(2) failed"); + break; + default: + atf_tc_fail("child exited with status %d", + WEXITSTATUS(__status)); + } + } else { + ATF_REQUIRE_EQ(SIGABRT, WTERMSIG(__status)); + } +#undef BUF + +} + +ATF_TC_WITHOUT_HEAD(gethostname_before_end); +ATF_TC_BODY(gethostname_before_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + unsigned char __buf[4]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 4 - 1; + const size_t __idx __unused = __len - 1; + char syshost[256]; + int error; + + error = gethostname(syshost, __len); + if (error != 0 || strlen(syshost) <= __len) + atf_tc_skip("hostname too short for testing"); + + gethostname(__stack.__buf, __len); +#undef BUF + +} + +ATF_TC_WITHOUT_HEAD(gethostname_end); +ATF_TC_BODY(gethostname_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + unsigned char __buf[4]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 4; + const size_t __idx __unused = __len - 1; + char syshost[256]; + int error; + + error = gethostname(syshost, __len); + if (error != 0 || strlen(syshost) <= __len) + atf_tc_skip("hostname too short for testing"); + + gethostname(__stack.__buf, __len); +#undef BUF + +} + +ATF_TC_WITHOUT_HEAD(gethostname_heap_before_end); +ATF_TC_BODY(gethostname_heap_before_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (4); + const size_t __len = 4 - 1; + const size_t __idx __unused = __len - 1; + char syshost[256]; + int error; + + error = gethostname(syshost, __len); + if (error != 0 || strlen(syshost) <= __len) + atf_tc_skip("hostname too short for testing"); + + __stack.__buf = malloc(__bufsz); + + gethostname(__stack.__buf, __len); +#undef BUF + +} + +ATF_TC_WITHOUT_HEAD(gethostname_heap_end); +ATF_TC_BODY(gethostname_heap_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (4); + const size_t __len = 4; + const size_t __idx __unused = __len - 1; + char syshost[256]; + int error; + + error = gethostname(syshost, __len); + if (error != 0 || strlen(syshost) <= __len) + atf_tc_skip("hostname too short for testing"); + + __stack.__buf = malloc(__bufsz); + + gethostname(__stack.__buf, __len); +#undef BUF + +} + +ATF_TC_WITHOUT_HEAD(gethostname_heap_after_end); +ATF_TC_BODY(gethostname_heap_after_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (4); + const size_t __len = 4 + 1; + const size_t __idx __unused = __len - 1; + pid_t __child; + int __status; + char syshost[256]; + int error; + + error = gethostname(syshost, __len); + if (error != 0 || strlen(syshost) <= __len) + atf_tc_skip("hostname too short for testing"); + + __child = fork(); + ATF_REQUIRE(__child >= 0); + if (__child > 0) + goto monitor; + + /* Child */ + disable_coredumps(); + __stack.__buf = malloc(__bufsz); + + gethostname(__stack.__buf, __len); + _exit(EX_SOFTWARE); /* Should have aborted. */ + +monitor: + while (waitpid(__child, &__status, 0) != __child) { + ATF_REQUIRE_EQ(EINTR, errno); + } + + if (!WIFSIGNALED(__status)) { + switch (WEXITSTATUS(__status)) { + case EX_SOFTWARE: + atf_tc_fail("FORTIFY_SOURCE failed to abort"); + break; + case EX_OSERR: + atf_tc_fail("setrlimit(2) failed"); + break; + default: + atf_tc_fail("child exited with status %d", + WEXITSTATUS(__status)); + } + } else { + ATF_REQUIRE_EQ(SIGABRT, WTERMSIG(__status)); + } +#undef BUF + +} + +ATF_TC_WITHOUT_HEAD(getlogin_r_before_end); +ATF_TC_BODY(getlogin_r_before_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + unsigned char __buf[MAXLOGNAME + 1]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = MAXLOGNAME + 1 - 1; + const size_t __idx __unused = __len - 1; + + getlogin_r(__stack.__buf, __len); +#undef BUF + +} + +ATF_TC_WITHOUT_HEAD(getlogin_r_end); +ATF_TC_BODY(getlogin_r_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + unsigned char __buf[MAXLOGNAME + 1]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = MAXLOGNAME + 1; + const size_t __idx __unused = __len - 1; + + getlogin_r(__stack.__buf, __len); +#undef BUF + +} + +ATF_TC_WITHOUT_HEAD(getlogin_r_heap_before_end); +ATF_TC_BODY(getlogin_r_heap_before_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (MAXLOGNAME + 1); + const size_t __len = MAXLOGNAME + 1 - 1; + const size_t __idx __unused = __len - 1; + + __stack.__buf = malloc(__bufsz); + + getlogin_r(__stack.__buf, __len); +#undef BUF + +} + +ATF_TC_WITHOUT_HEAD(getlogin_r_heap_end); +ATF_TC_BODY(getlogin_r_heap_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (MAXLOGNAME + 1); + const size_t __len = MAXLOGNAME + 1; + const size_t __idx __unused = __len - 1; + + __stack.__buf = malloc(__bufsz); + + getlogin_r(__stack.__buf, __len); +#undef BUF + +} + +ATF_TC_WITHOUT_HEAD(getlogin_r_heap_after_end); +ATF_TC_BODY(getlogin_r_heap_after_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (MAXLOGNAME + 1); + const size_t __len = MAXLOGNAME + 1 + 1; + const size_t __idx __unused = __len - 1; + pid_t __child; + int __status; + + __child = fork(); + ATF_REQUIRE(__child >= 0); + if (__child > 0) + goto monitor; + + /* Child */ + disable_coredumps(); + __stack.__buf = malloc(__bufsz); + + getlogin_r(__stack.__buf, __len); + _exit(EX_SOFTWARE); /* Should have aborted. */ + +monitor: + while (waitpid(__child, &__status, 0) != __child) { + ATF_REQUIRE_EQ(EINTR, errno); + } + + if (!WIFSIGNALED(__status)) { + switch (WEXITSTATUS(__status)) { + case EX_SOFTWARE: + atf_tc_fail("FORTIFY_SOURCE failed to abort"); + break; + case EX_OSERR: + atf_tc_fail("setrlimit(2) failed"); + break; + default: + atf_tc_fail("child exited with status %d", + WEXITSTATUS(__status)); + } + } else { + ATF_REQUIRE_EQ(SIGABRT, WTERMSIG(__status)); + } +#undef BUF + +} + +ATF_TC_WITHOUT_HEAD(ttyname_r_before_end); +ATF_TC_BODY(ttyname_r_before_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + unsigned char __buf[42]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 42 - 1; + const size_t __idx __unused = __len - 1; + int fd; + + fd = STDIN_FILENO; + if (!isatty(fd)) + atf_tc_skip("stdin is not an fd"); + + ttyname_r(fd, __stack.__buf, __len); +#undef BUF + +} + +ATF_TC_WITHOUT_HEAD(ttyname_r_end); +ATF_TC_BODY(ttyname_r_end, tc) +{ +#define BUF &__stack.__buf + struct { + uint8_t padding_l; + unsigned char __buf[42]; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(__stack.__buf); + const size_t __len = 42; + const size_t __idx __unused = __len - 1; + int fd; + + fd = STDIN_FILENO; + if (!isatty(fd)) + atf_tc_skip("stdin is not an fd"); + + ttyname_r(fd, __stack.__buf, __len); +#undef BUF + +} + +ATF_TC_WITHOUT_HEAD(ttyname_r_heap_before_end); +ATF_TC_BODY(ttyname_r_heap_before_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42 - 1; + const size_t __idx __unused = __len - 1; + int fd; + + fd = STDIN_FILENO; + if (!isatty(fd)) + atf_tc_skip("stdin is not an fd"); + + __stack.__buf = malloc(__bufsz); + + ttyname_r(fd, __stack.__buf, __len); +#undef BUF + +} + +ATF_TC_WITHOUT_HEAD(ttyname_r_heap_end); +ATF_TC_BODY(ttyname_r_heap_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42; + const size_t __idx __unused = __len - 1; + int fd; + + fd = STDIN_FILENO; + if (!isatty(fd)) + atf_tc_skip("stdin is not an fd"); + + __stack.__buf = malloc(__bufsz); + + ttyname_r(fd, __stack.__buf, __len); +#undef BUF + +} + +ATF_TC_WITHOUT_HEAD(ttyname_r_heap_after_end); +ATF_TC_BODY(ttyname_r_heap_after_end, tc) +{ +#define BUF __stack.__buf + struct { + uint8_t padding_l; + unsigned char * __buf; + uint8_t padding_r; + } __stack; + const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42); + const size_t __len = 42 + 1; + const size_t __idx __unused = __len - 1; + pid_t __child; + int __status; + int fd; + + fd = STDIN_FILENO; + if (!isatty(fd)) + atf_tc_skip("stdin is not an fd"); + + __child = fork(); + ATF_REQUIRE(__child >= 0); + if (__child > 0) + goto monitor; + + /* Child */ + disable_coredumps(); + __stack.__buf = malloc(__bufsz); + + ttyname_r(fd, __stack.__buf, __len); _exit(EX_SOFTWARE); /* Should have aborted. */ monitor: @@ -491,6 +1903,26 @@ ATF_TP_ADD_TC(tp, getcwd_heap_before_end); ATF_TP_ADD_TC(tp, getcwd_heap_end); ATF_TP_ADD_TC(tp, getcwd_heap_after_end); + ATF_TP_ADD_TC(tp, getgrouplist_before_end); + ATF_TP_ADD_TC(tp, getgrouplist_end); + ATF_TP_ADD_TC(tp, getgrouplist_heap_before_end); + ATF_TP_ADD_TC(tp, getgrouplist_heap_end); + ATF_TP_ADD_TC(tp, getgrouplist_heap_after_end); + ATF_TP_ADD_TC(tp, getgroups_before_end); + ATF_TP_ADD_TC(tp, getgroups_end); + ATF_TP_ADD_TC(tp, getgroups_heap_before_end); + ATF_TP_ADD_TC(tp, getgroups_heap_end); + ATF_TP_ADD_TC(tp, getgroups_heap_after_end); + ATF_TP_ADD_TC(tp, getloginclass_before_end); + ATF_TP_ADD_TC(tp, getloginclass_end); + ATF_TP_ADD_TC(tp, getloginclass_heap_before_end); + ATF_TP_ADD_TC(tp, getloginclass_heap_end); + ATF_TP_ADD_TC(tp, getloginclass_heap_after_end); + ATF_TP_ADD_TC(tp, pread_before_end); + ATF_TP_ADD_TC(tp, pread_end); + ATF_TP_ADD_TC(tp, pread_heap_before_end); + ATF_TP_ADD_TC(tp, pread_heap_end); + ATF_TP_ADD_TC(tp, pread_heap_after_end); ATF_TP_ADD_TC(tp, read_before_end); ATF_TP_ADD_TC(tp, read_end); ATF_TP_ADD_TC(tp, read_heap_before_end); @@ -501,5 +1933,35 @@ ATF_TP_ADD_TC(tp, readlink_heap_before_end); ATF_TP_ADD_TC(tp, readlink_heap_end); ATF_TP_ADD_TC(tp, readlink_heap_after_end); + ATF_TP_ADD_TC(tp, readlinkat_before_end); + ATF_TP_ADD_TC(tp, readlinkat_end); + ATF_TP_ADD_TC(tp, readlinkat_heap_before_end); + ATF_TP_ADD_TC(tp, readlinkat_heap_end); + ATF_TP_ADD_TC(tp, readlinkat_heap_after_end); + ATF_TP_ADD_TC(tp, getdomainname_before_end); + ATF_TP_ADD_TC(tp, getdomainname_end); + ATF_TP_ADD_TC(tp, getdomainname_heap_before_end); + ATF_TP_ADD_TC(tp, getdomainname_heap_end); + ATF_TP_ADD_TC(tp, getdomainname_heap_after_end); + ATF_TP_ADD_TC(tp, getentropy_before_end); + ATF_TP_ADD_TC(tp, getentropy_end); + ATF_TP_ADD_TC(tp, getentropy_heap_before_end); + ATF_TP_ADD_TC(tp, getentropy_heap_end); + ATF_TP_ADD_TC(tp, getentropy_heap_after_end); + ATF_TP_ADD_TC(tp, gethostname_before_end); + ATF_TP_ADD_TC(tp, gethostname_end); + ATF_TP_ADD_TC(tp, gethostname_heap_before_end); + ATF_TP_ADD_TC(tp, gethostname_heap_end); + ATF_TP_ADD_TC(tp, gethostname_heap_after_end); + ATF_TP_ADD_TC(tp, getlogin_r_before_end); + ATF_TP_ADD_TC(tp, getlogin_r_end); + ATF_TP_ADD_TC(tp, getlogin_r_heap_before_end); + ATF_TP_ADD_TC(tp, getlogin_r_heap_end); + ATF_TP_ADD_TC(tp, getlogin_r_heap_after_end); + ATF_TP_ADD_TC(tp, ttyname_r_before_end); + ATF_TP_ADD_TC(tp, ttyname_r_end); + ATF_TP_ADD_TC(tp, ttyname_r_heap_before_end); + ATF_TP_ADD_TC(tp, ttyname_r_heap_end); + ATF_TP_ADD_TC(tp, ttyname_r_heap_after_end); return (atf_no_error()); } diff --git a/lib/libc/tests/secure/generate-fortify-tests.lua b/lib/libc/tests/secure/generate-fortify-tests.lua --- a/lib/libc/tests/secure/generate-fortify-tests.lua +++ b/lib/libc/tests/secure/generate-fortify-tests.lua @@ -96,6 +96,10 @@ srcvar[sizeof(srcvar) - 1] = '\0'; ]] +local stdio_init = [[ + replace_stdin(); +]] + local string_stackvars = "\tchar src[__len];\n" local string_init = [[ memset(__stack.__buf, 0, __len); @@ -130,6 +134,53 @@ local all_tests = { stdio = { -- + { + func = "ctermid", + bufsize = "L_ctermid", + arguments = { + "__buf", + }, + exclude = excludes_stack_overflow, + }, + { + func = "ctermid_r", + bufsize = "L_ctermid", + arguments = { + "__buf", + }, + exclude = excludes_stack_overflow, + }, + { + func = "fread", + arguments = { + "__buf", + "__len", + "1", + "stdin", + }, + exclude = excludes_stack_overflow, + init = stdio_init, + }, + { + func = "fread_unlocked", + arguments = { + "__buf", + "__len", + "1", + "stdin", + }, + exclude = excludes_stack_overflow, + init = stdio_init, + }, + { + func = "gets_s", + arguments = { + "__buf", + "__len", + }, + exclude = excludes_stack_overflow, + init = stdio_init, + }, { func = "sprintf", arguments = { @@ -155,6 +206,27 @@ stackvars = printf_stackvars, init = printf_init, }, + { + func = "tmpnam", + bufsize = "L_tmpnam", + arguments = { + "__buf", + }, + exclude = excludes_stack_overflow, + }, + { + func = "fgets", + arguments = { + "__buf", + "__len", + "fp", + }, + exclude = excludes_stack_overflow, + stackvars = "\tFILE *fp;\n", + init = [[ + fp = new_fp(__len); +]], + }, }, string = { -- @@ -168,6 +240,16 @@ exclude = excludes_stack_overflow, stackvars = "\tchar src[__len + 10];\n", }, + { + func = "mempcpy", + arguments = { + "__buf", + "src", + "__len", + }, + exclude = excludes_stack_overflow, + stackvars = "\tchar src[__len + 10];\n", + }, { func = "memmove", arguments = { @@ -220,6 +302,17 @@ init = string_init, uses_len = true, }, + { + func = "strlcat", + arguments = { + "__buf", + "src", + "__len", + }, + exclude = excludes_stack_overflow, + stackvars = string_stackvars, + init = string_init, + }, { func = "strncat", arguments = { @@ -242,6 +335,17 @@ init = string_init, uses_len = true, }, + { + func = "strlcpy", + arguments = { + "__buf", + "src", + "__len", + }, + exclude = excludes_stack_overflow, + stackvars = string_stackvars, + init = string_init, + }, { func = "strncpy", arguments = { @@ -274,6 +378,14 @@ }, exclude = excludes_stack_overflow, }, + { + func = "explicit_bzero", + arguments = { + "__buf", + "__len", + }, + exclude = excludes_stack_overflow, + }, }, unistd = { -- @@ -286,6 +398,53 @@ }, exclude = excludes_stack_overflow, }, + { + func = "getgrouplist", + bufsize = "4", + buftype = "gid_t[]", + arguments = { + "\"root\"", + "0", + "__buf", + "&intlen", + }, + exclude = excludes_stack_overflow, + stackvars = "\tint intlen = (int)__len;\n", + uses_len = true, + }, + { + func = "getgroups", + bufsize = "4", + buftype = "gid_t[]", + arguments = { + "__len", + "__buf", + }, + exclude = excludes_stack_overflow, + }, + { + func = "getloginclass", + arguments = { + "__buf", + "__len", + }, + exclude = excludes_stack_overflow, + }, + { + func = "pread", + bufsize = "41", + arguments = { + "fd", + "__buf", + "__len", + "0", + }, + exclude = excludes_stack_overflow, + stackvars = "\tint fd;\n", + init = [[ + fd = new_tmpfile(); /* Cannot fail */ +]], + }, { func = "read", bufsize = "41", @@ -313,6 +472,85 @@ path = new_symlink(__len); /* Cannot fail */ ]], }, + { + func = "readlinkat", + arguments = { + "AT_FDCWD", + "path", + "__buf", + "__len", + }, + exclude = excludes_stack_overflow, + stackvars = "\tconst char *path;\n", + init = [[ + path = new_symlink(__len); /* Cannot fail */ +]], + }, + { + func = "getdomainname", + bufsize = "4", + arguments = { + "__buf", + "__len", + }, + exclude = excludes_stack_overflow, + stackvars = "\tchar sysdomain[256];\n", + early_init = [[ + (void)getdomainname(sysdomain, __len); + if (strlen(sysdomain) <= __len) + atf_tc_skip("domain name too short for testing"); +]] + }, + { + func = "getentropy", + arguments = { + "__buf", + "__len", + }, + exclude = excludes_stack_overflow, + }, + { + func = "gethostname", + bufsize = "4", + arguments = { + "__buf", + "__len", + }, + exclude = excludes_stack_overflow, + stackvars = [[ + char syshost[256]; + int error; +]], + early_init = [[ + error = gethostname(syshost, __len); + if (error != 0 || strlen(syshost) <= __len) + atf_tc_skip("hostname too short for testing"); +]] + }, + { + func = "getlogin_r", + bufsize = "MAXLOGNAME + 1", + arguments = { + "__buf", + "__len", + }, + exclude = excludes_stack_overflow, + }, + { + func = "ttyname_r", + arguments = { + "fd", + "__buf", + "__len", + }, + exclude = excludes_stack_overflow, + stackvars = "\tint fd;\n", + early_init = [[ + fd = STDIN_FILENO; + if (!isatty(fd)) + atf_tc_skip("stdin is not an fd"); +]] + }, }, } @@ -620,6 +858,23 @@ fh:write([[ +static FILE * __unused +new_fp(size_t __len) +{ + static char fpbuf[LINE_MAX]; + FILE *fp; + + ATF_REQUIRE(__len <= sizeof(fpbuf)); + + memset(fpbuf, 'A', sizeof(fpbuf) - 1); + fpbuf[sizeof(fpbuf) - 1] = '\0'; + + fp = fmemopen(fpbuf, sizeof(fpbuf), "rb"); + ATF_REQUIRE(fp != NULL); + + return (fp); +} + /* * Create a new symlink to use for readlink(2) style tests, we'll just use a * random target name to have something interesting to look at. @@ -679,6 +934,22 @@ _exit(EX_OSERR); } +/* + * Replaces stdin with a file that we can actually read from, for tests where + * we want a FILE * or fd that we can get data from. + */ +static void __unused +replace_stdin(void) +{ + int fd; + + fd = new_tmpfile(); + + (void)dup2(fd, STDIN_FILENO); + if (fd != STDIN_FILENO) + close(fd); +} + ]]) for _, def in pairs(tests) do diff --git a/lib/libutil/tests/trimdomain-nodomain_test.c b/lib/libutil/tests/trimdomain-nodomain_test.c --- a/lib/libutil/tests/trimdomain-nodomain_test.c +++ b/lib/libutil/tests/trimdomain-nodomain_test.c @@ -45,7 +45,7 @@ * oddly configured systems. */ int -gethostname(char *name, size_t namelen) +__ssp_real(gethostname)(char *name, size_t namelen) { if (strlcpy(name, TESTFQDN, namelen) > namelen) { errno = ENAMETOOLONG; diff --git a/lib/libutil/tests/trimdomain_test.c b/lib/libutil/tests/trimdomain_test.c --- a/lib/libutil/tests/trimdomain_test.c +++ b/lib/libutil/tests/trimdomain_test.c @@ -45,7 +45,7 @@ * oddly configured systems. */ int -gethostname(char *name, size_t namelen) +__ssp_real(gethostname)(char *name, size_t namelen) { if (strlcpy(name, TESTFQDN, namelen) > namelen) { errno = ENAMETOOLONG; diff --git a/sys/libkern/explicit_bzero.c b/sys/libkern/explicit_bzero.c --- a/sys/libkern/explicit_bzero.c +++ b/sys/libkern/explicit_bzero.c @@ -9,6 +9,7 @@ #include #else #include +#include #endif /* _KERNEL */ __attribute__((weak)) void __explicit_bzero_hook(void *, size_t); @@ -19,7 +20,7 @@ } void -explicit_bzero(void *buf, size_t len) +__ssp_real(explicit_bzero)(void *buf, size_t len) { memset(buf, 0, len); __explicit_bzero_hook(buf, len); diff --git a/sys/sys/libkern.h b/sys/sys/libkern.h --- a/sys/sys/libkern.h +++ b/sys/sys/libkern.h @@ -337,4 +337,10 @@ #define FNM_IGNORECASE FNM_CASEFOLD #define FNM_FILE_NAME FNM_PATHNAME +#if __has_include() +#include /* __ssp_real */ +#else +#define __ssp_real(fun) fun +#endif + #endif /* !_SYS_LIBKERN_H_ */