git: cf8e5289a110 - main - include: ssp: round out fortification of current set of headers
Date: Sat, 13 Jul 2024 05:23:00 UTC
The branch main has been updated by kevans: URL: https://cgit.FreeBSD.org/src/commit/?id=cf8e5289a110954600f135024d1515a77d0ae34d commit cf8e5289a110954600f135024d1515a77d0ae34d Author: Kyle Evans <kevans@FreeBSD.org> AuthorDate: 2024-07-13 05:16:10 +0000 Commit: Kyle Evans <kevans@FreeBSD.org> CommitDate: 2024-07-13 05:16:24 +0000 include: ssp: round out fortification of current set of headers ssp/ssp.h needed some improvements: - `len` isn't always a size_t, it may need casted - In some cases we may want to use a len that isn't specified as a parameter (e.g., L_ctermid), so __ssp_redirect() should be more flexible. - In other cases we may want additional checking, so pull all of the declaration bits out of __ssp_redirect_raw() so that some functions can implement the body themselves. strlcat/strlcpy should be the last of the fortified functions that get their own __*_chk symbols, and these cases are only done to be consistent with the rest of the str*() set. Reviewed by: markj Sponsored by: Klara, Inc. Sponsored by: Stormshield Differential Revision: https://reviews.freebsd.org/D45679 --- include/ssp/ssp.h | 16 +- include/ssp/stdio.h | 18 + include/ssp/string.h | 22 + include/ssp/strings.h | 5 + include/ssp/unistd.h | 36 +- include/stdio.h | 37 +- include/string.h | 29 +- include/strings.h | 11 +- lib/libc/amd64/string/strlcat.c | 2 + lib/libc/gen/ctermid.c | 5 +- lib/libc/gen/getdomainname.c | 3 +- lib/libc/gen/getentropy.c | 3 +- lib/libc/gen/getgrouplist.c | 3 +- lib/libc/gen/gethostname.c | 3 +- lib/libc/gen/getlogin.c | 3 +- lib/libc/gen/ttyname.c | 3 +- lib/libc/secure/Makefile.inc | 4 +- lib/libc/secure/Symbol.map | 2 + lib/libc/secure/strlcat_chk.c | 70 + lib/libc/secure/strlcpy_chk.c | 43 + lib/libc/stdio/fread.c | 4 +- lib/libc/stdio/gets_s.c | 3 +- lib/libc/stdio/tmpnam.c | 3 +- lib/libc/string/mempcpy.c | 4 +- lib/libc/string/strerror.c | 4 +- lib/libc/string/strlcat.c | 2 + lib/libc/string/strlcpy.c | 2 + lib/libc/string/strncpy.c | 2 + lib/libc/tests/secure/fortify_stdio_test.c | 1024 +++++++++++++- lib/libc/tests/secure/fortify_string_test.c | 478 +++++++ lib/libc/tests/secure/fortify_strings_test.c | 165 +++ lib/libc/tests/secure/fortify_unistd_test.c | 1592 +++++++++++++++++++++- lib/libc/tests/secure/generate-fortify-tests.lua | 271 ++++ lib/libutil/tests/trimdomain-nodomain_test.c | 4 +- lib/libutil/tests/trimdomain_test.c | 4 +- sys/libkern/explicit_bzero.c | 3 +- sys/sys/libkern.h | 6 + 37 files changed, 3745 insertions(+), 144 deletions(-) diff --git a/include/ssp/ssp.h b/include/ssp/ssp.h index de109da4959e..6ebc23288391 100644 --- 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) #include <machine/_stdint.h> diff --git a/include/ssp/stdio.h b/include/ssp/stdio.h index 4bca1de7d4f9..f7a390f315a4 100644 --- a/include/ssp/stdio.h +++ b/include/ssp/stdio.h @@ -37,6 +37,24 @@ #include <ssp/ssp.h> __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 index ceb4ba2a2174..b9f2dceb1df5 100644 --- a/include/ssp/string.h +++ b/include/ssp/string.h @@ -45,7 +45,9 @@ char *__stpncpy_chk(char *, const char *, size_t, size_t); 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_icheck2_restrict(stpcpy, char *, const char *) __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(src, 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 @@ __END_DECLS #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 index 51b11a14ee87..79b70eba1c5c 100644 --- 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 index bcd3664116cc..7e9d72343dde 100644 --- a/include/ssp/unistd.h +++ b/include/ssp/unistd.h @@ -43,14 +43,46 @@ __BEGIN_DECLS #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 index ea53816cf1d4..b0190d25eb4f 100644 --- a/include/stdio.h +++ b/include/stdio.h @@ -238,6 +238,21 @@ __END_DECLS #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 <ssp/stdio.h> +#endif + __BEGIN_DECLS #ifdef _XLOCALE_H_ #include <xlocale/_stdio.h> @@ -252,7 +267,7 @@ int ferror(FILE *); 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 @@ void rewind(FILE *); 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 ungetc(int, FILE *); 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 @@ int vsscanf(const char * __restrict, const char * __restrict, __va_list) __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 @@ extern int __isthreaded; __END_DECLS __NULLABILITY_PRAGMA_POP -#if !defined(_STANDALONE) && defined(_FORTIFY_SOURCE) && _FORTIFY_SOURCE > 0 -#include <ssp/stdio.h> -#endif #endif /* !_STDIO_H_ */ diff --git a/include/string.h b/include/string.h index ce605117daa6..c9d3e1add1a1 100644 --- a/include/string.h +++ b/include/string.h @@ -49,6 +49,10 @@ typedef __size_t size_t; #define _SIZE_T_DECLARED #endif +#if !defined(_STANDALONE) && defined(_FORTIFY_SOURCE) && _FORTIFY_SOURCE > 0 +#include <ssp/string.h> +#endif + __BEGIN_DECLS #if __XSI_VISIBLE >= 600 void *memccpy(void * __restrict, const void * __restrict, int, size_t); @@ -58,23 +62,23 @@ void *memchr(const void *, int, size_t) __pure; 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 @@ int strverscmp(const char *, const char *) __pure; #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 @@ char *strerror(int); 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 @@ typedef __mode_t mode_t; 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 @@ errno_t memset_s(void *, rsize_t, int, rsize_t); #endif /* __EXT1_VISIBLE */ __END_DECLS -#if !defined(_STANDALONE) && defined(_FORTIFY_SOURCE) && _FORTIFY_SOURCE > 0 -#include <ssp/string.h> -#endif #endif /* _STRING_H_ */ diff --git a/include/strings.h b/include/strings.h index 511f7c03cb3c..889f43bd2311 100644 --- a/include/strings.h +++ b/include/strings.h @@ -37,11 +37,15 @@ typedef __size_t size_t; #define _SIZE_T_DECLARED #endif +#if !defined(_STANDALONE) && defined(_FORTIFY_SOURCE) && _FORTIFY_SOURCE > 0 +#include <ssp/strings.h> +#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 @@ int strncasecmp(const char *, const char *, size_t) __pure; #endif __END_DECLS -#if !defined(_STANDALONE) && defined(_FORTIFY_SOURCE) && _FORTIFY_SOURCE > 0 -#include <ssp/strings.h> -#endif #endif /* _STRINGS_H_ */ diff --git a/lib/libc/amd64/string/strlcat.c b/lib/libc/amd64/string/strlcat.c index 0c1e1c5d05f7..94fdc0963dc3 100644 --- a/lib/libc/amd64/string/strlcat.c +++ b/lib/libc/amd64/string/strlcat.c @@ -8,6 +8,8 @@ #include <string.h> +#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 index 9265d402930c..fb117b3c8ded 100644 --- a/lib/libc/gen/ctermid.c +++ b/lib/libc/gen/ctermid.c @@ -34,11 +34,12 @@ #include <paths.h> #include <stdio.h> #include <string.h> +#include <ssp/ssp.h> #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 @@ ctermid(char *s) } 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 index a9527b36a247..c0be7465f967 100644 --- a/lib/libc/gen/getdomainname.c +++ b/lib/libc/gen/getdomainname.c @@ -33,9 +33,10 @@ #include <sys/sysctl.h> #include <unistd.h> +#include <ssp/ssp.h> 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 index 38cd515e74d7..40b84af65f83 100644 --- a/lib/libc/gen/getentropy.c +++ b/lib/libc/gen/getentropy.c @@ -35,6 +35,7 @@ #include <stdbool.h> #include <stdlib.h> #include <unistd.h> +#include <ssp/ssp.h> #include "libc_private.h" @@ -105,7 +106,7 @@ getentropy_fallback(void *buf, size_t buflen) } 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 index 1c29b249f8c4..5bd06bc5121f 100644 --- a/lib/libc/gen/getgrouplist.c +++ b/lib/libc/gen/getgrouplist.c @@ -37,11 +37,12 @@ #include <grp.h> #include <string.h> #include <unistd.h> +#include <ssp/ssp.h> 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 index 36e988c91ecc..66d401fad846 100644 --- a/lib/libc/gen/gethostname.c +++ b/lib/libc/gen/gethostname.c @@ -34,9 +34,10 @@ #include <errno.h> #include <unistd.h> +#include <ssp/ssp.h> 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 index 55ed83795f7d..f8a3fb079067 100644 --- a/lib/libc/gen/getlogin.c +++ b/lib/libc/gen/getlogin.c @@ -37,6 +37,7 @@ #include <unistd.h> #include "namespace.h" #include <pthread.h> +#include <ssp/ssp.h> #include "un-namespace.h" #include "libc_private.h" @@ -54,7 +55,7 @@ getlogin(void) } 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 index 268b2e0f7b65..f1e2f401fe5d 100644 --- a/lib/libc/gen/ttyname.c +++ b/lib/libc/gen/ttyname.c @@ -42,6 +42,7 @@ #include <paths.h> #include <errno.h> #include "reentrant.h" +#include <ssp/ssp.h> #include "un-namespace.h" #include "libc_private.h" @@ -53,7 +54,7 @@ static thread_key_t ttyname_key; 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 index 28289127c7a6..5d10612e67a8 100644 --- 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 index 0d854039955f..1f12fe059367 100644 --- a/lib/libc/secure/Symbol.map +++ b/lib/libc/secure/Symbol.map @@ -15,7 +15,9 @@ FBSD_1.8 { __stpncpy_chk; __strcat_chk; __strcpy_chk; + __strlcat_chk; __strncat_chk; + __strlcpy_chk; __strncpy_chk; __vsnprintf_chk; __vsprintf_chk; diff --git a/lib/libc/secure/strlcat_chk.c b/lib/libc/secure/strlcat_chk.c new file mode 100644 index 000000000000..26448bd37af0 --- /dev/null +++ b/lib/libc/secure/strlcat_chk.c @@ -0,0 +1,70 @@ +/* $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 <Todd.Miller@courtesan.com> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <stdio.h> +#include <string.h> + +#include <ssp/string.h> + +/* + * 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 + * will be copied. Always NUL terminates (unless dsize <= strlen(dst)). + * Returns strlen(src) + MIN(dsize, strlen(initial dst)). + * If retval >= dsize, truncation occurred. + */ +size_t +__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') { + dst++; + } + + dlen = dst - odst; + n = dsize - dlen; + + if (n-- == 0) + return (dlen + strlen(src)); + while (*src != '\0') { + if (n != 0) { + if (dbufsize-- == 0) + __chk_fail(); + *dst++ = *src; + n--; + } + + src++; + } + + if (dbufsize-- == 0) + __chk_fail(); + *dst = '\0'; + return (dlen + (src - osrc)); /* count does not include NUL */ +} diff --git a/lib/libc/secure/strlcpy_chk.c b/lib/libc/secure/strlcpy_chk.c new file mode 100644 index 000000000000..8c11ee3e07eb --- /dev/null +++ b/lib/libc/secure/strlcpy_chk.c @@ -0,0 +1,43 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2024, Klara, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/types.h> +#include <string.h> + +#include <ssp/string.h> +#undef strlcpy + +size_t +__strlcpy_chk(char * __restrict dst, const char * __restrict src, size_t dsize, + size_t dbufsize) +{ + + if (dsize > dbufsize) + __chk_fail(); + + return (strlcpy(dst, src, dsize)); +} diff --git a/lib/libc/stdio/fread.c b/lib/libc/stdio/fread.c index bf943fdd1d0d..65d9ecf94366 100644 --- a/lib/libc/stdio/fread.c +++ b/lib/libc/stdio/fread.c @@ -37,6 +37,7 @@ #include <stdint.h> #include <stdio.h> #include <string.h> +#include <ssp/ssp.h> #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 index 9a8cf34916fb..41e379507483 100644 --- a/lib/libc/stdio/gets_s.c +++ b/lib/libc/stdio/gets_s.c @@ -39,6 +39,7 @@ #include <unistd.h> #include <stdint.h> #include <stdio.h> +#include <ssp/ssp.h> #include "un-namespace.h" #include "libc_private.h" #include "local.h" @@ -77,7 +78,7 @@ _gets_s(char *buf, rsize_t n) /* 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 index d7c436928cd7..fab4253e2834 100644 --- a/lib/libc/stdio/tmpnam.c +++ b/lib/libc/stdio/tmpnam.c @@ -36,6 +36,7 @@ #include <stdio.h> #include <unistd.h> +#include <ssp/ssp.h> __warn_references(tmpnam, "warning: tmpnam() possibly used unsafely; consider using mkstemp()"); @@ -43,7 +44,7 @@ __warn_references(tmpnam, 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 index 619371632922..86e44cdebb85 100644 --- a/lib/libc/string/mempcpy.c +++ b/lib/libc/string/mempcpy.c @@ -29,9 +29,11 @@ */ #include <string.h> +#include <ssp/ssp.h> 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 index ecad55caa673..922bb0284497 100644 --- a/lib/libc/string/strerror.c +++ b/lib/libc/string/strerror.c @@ -38,6 +38,8 @@ #include <string.h> #include <stdio.h> +#include <ssp/ssp.h> + #include "errlst.h" #include "../locale/xlocale_private.h" #include "libc_private.h" @@ -114,7 +116,7 @@ __strerror_rl(int errnum, char *strerrbuf, size_t buflen, locale_t locale) } 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 index bdb302def7b0..fc18fad179db 100644 --- a/lib/libc/string/strlcat.c +++ b/lib/libc/string/strlcat.c @@ -19,6 +19,8 @@ #include <sys/types.h> #include <string.h> +#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 index 58a42e321f6a..79f7ab19cdfd 100644 --- a/lib/libc/string/strlcpy.c +++ b/lib/libc/string/strlcpy.c @@ -19,6 +19,8 @@ #include <sys/types.h> #include <string.h> +#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 index b1df82a2dbf8..67240a855196 100644 --- a/lib/libc/string/strncpy.c +++ b/lib/libc/string/strncpy.c @@ -34,6 +34,8 @@ #include <string.h> +#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 index 20ecdab89a8b..fe0f14acd988 100644 --- a/lib/libc/tests/secure/fortify_stdio_test.c +++ b/lib/libc/tests/secure/fortify_stdio_test.c @@ -20,6 +20,23 @@ #include <unistd.h> #include <atf-c.h> +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 @@ new_tmpfile(void) 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; *** 3922 LINES SKIPPED ***