include: ssp: fortify <wchar.h>

This includes all of the w*() equivalents to str*()/mem*() implemented
in more or less the same way.  For these ones, we'll just use
header-only implementations from the start to stop further cluttering
the libc symbol table.

Reviewed by:	markj
Sponsored by:	Klara, Inc.
Sponsored by:	Stormshield
Differential Revision:	https://reviews.freebsd.org/D45682
This commit is contained in:
Kyle Evans 2024-07-13 00:16:11 -05:00
parent d0b7445904
commit b53d7aa88f
24 changed files with 2319 additions and 14 deletions

View File

@ -1,4 +1,4 @@
INCS= poll.h ssp.h stdio.h stdlib.h string.h strings.h unistd.h
INCS= poll.h ssp.h stdio.h stdlib.h string.h strings.h unistd.h wchar.h
INCSDIR= ${INCLUDEDIR}/ssp
.include <bsd.prog.mk>

229
include/ssp/wchar.h Normal file
View File

@ -0,0 +1,229 @@
/*-
* 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.
*/
#ifndef _SSP_WCHAR_H_
#define _SSP_WCHAR_H_
#include <ssp/ssp.h>
#if __SSP_FORTIFY_LEVEL > 0
static inline int
__ssp_wchar_overlap(const void *leftp, const void *rightp, size_t len)
{
if (len > SIZE_MAX / sizeof(wchar_t))
return (1);
return (__ssp_overlap(leftp, rightp, len * sizeof(wchar_t)));
}
/*
* __ssp_wbos for w*() calls where the size parameters are in sizeof(wchar_t)
* units, so the result needs to be scaled appropriately.
*/
__ssp_inline size_t
__ssp_wbos(void *ptr)
{
const size_t ptrsize = __ssp_bos(ptr);
if (ptrsize == (size_t)-1)
return (ptrsize);
return (ptrsize / sizeof(wchar_t));
}
__BEGIN_DECLS
__ssp_redirect_raw_impl(wchar_t *, wmemcpy, wmemcpy,
(wchar_t *__restrict buf, const wchar_t *__restrict src, size_t len))
{
const size_t slen = __ssp_wbos(buf);
if (len > slen)
__chk_fail();
if (__ssp_wchar_overlap(src, buf, len))
__chk_fail();
return (__ssp_real(wmemcpy)(buf, src, len));
}
__ssp_redirect_raw_impl(wchar_t *, wmempcpy, wmempcpy,
(wchar_t *__restrict buf, const wchar_t *__restrict src, size_t len))
{
const size_t slen = __ssp_wbos(buf);
if (len > slen)
__chk_fail();
if (__ssp_wchar_overlap(src, buf, len))
__chk_fail();
return (__ssp_real(wmempcpy)(buf, src, len));
}
__ssp_redirect_raw_impl(wchar_t *, wmemmove, wmemmove,
(wchar_t *buf, const wchar_t *src, size_t len))
{
const size_t slen = __ssp_wbos(buf);
if (len > slen)
__chk_fail();
return (__ssp_real(wmemmove)(buf, src, len));
}
__ssp_redirect_raw_impl(wchar_t *, wmemset, wmemset,
(wchar_t *buf, wchar_t c, size_t len))
{
const size_t slen = __ssp_wbos(buf);
if (len > slen)
__chk_fail();
return (__ssp_real(wmemset)(buf, c, len));
}
__ssp_redirect_raw_impl(wchar_t *, wcpcpy, wcpcpy,
(wchar_t *__restrict buf, const wchar_t *__restrict src))
{
const size_t slen = __ssp_wbos(buf);
const size_t len = wcslen(src);
if (len >= slen)
__chk_fail();
if (__ssp_wchar_overlap(buf, src, len))
__chk_fail();
(void)__ssp_real(wmemcpy)(buf, src, len + 1);
return (buf + len);
}
__ssp_redirect_raw_impl(wchar_t *, wcpncpy, wcpncpy,
(wchar_t *__restrict buf, const wchar_t *__restrict src, size_t len))
{
const size_t slen = __ssp_wbos(buf);
if (len > slen)
__chk_fail();
if (__ssp_wchar_overlap(buf, src, len))
__chk_fail();
return (__ssp_real(wcpncpy)(buf, src, len));
}
__ssp_redirect_raw_impl(wchar_t *, wcscat, wcscat,
(wchar_t *__restrict buf, const wchar_t *__restrict src))
{
size_t slen = __ssp_wbos(buf);
wchar_t *cp;
cp = buf;
while (*cp != L'\0') {
cp++;
if (slen-- == 0)
__chk_fail();
}
while (*src != L'\0') {
if (slen-- == 0)
__chk_fail();
*cp++ = *src++;
}
if (slen-- == 0)
__chk_fail();
*cp = '\0';
return (buf);
}
__ssp_redirect_raw_impl(wchar_t *, wcscpy, wcscpy,
(wchar_t *__restrict buf, const wchar_t *__restrict src))
{
const size_t slen = __ssp_wbos(buf);
size_t len = wcslen(src) + 1;
if (len > slen)
__chk_fail();
if (__ssp_wchar_overlap(buf, src, len))
__chk_fail();
return (__ssp_real(wmemcpy)(buf, src, len));
}
__ssp_redirect_raw_impl(wchar_t *, wcsncat, wcsncat,
(wchar_t *__restrict buf, const wchar_t *__restrict src, size_t len))
{
const size_t slen = __ssp_wbos(buf);
if (len == 0)
return (buf);
if (len > slen)
__chk_fail();
if (__ssp_wchar_overlap(buf, src, len))
__chk_fail();
return (__ssp_real(wcsncat)(buf, src, len));
}
__ssp_redirect_raw_impl(size_t, wcslcat, wcslcat,
(wchar_t *__restrict buf, const wchar_t *__restrict src, size_t len))
{
const size_t slen = __ssp_wbos(buf);
if (len > slen)
__chk_fail();
if (__ssp_wchar_overlap(buf, src, len))
__chk_fail();
return (__ssp_real(wcslcat)(buf, src, len));
}
__ssp_redirect_raw_impl(wchar_t *, wcsncpy, wcsncpy,
(wchar_t *__restrict buf, const wchar_t *__restrict src, size_t len))
{
const size_t slen = __ssp_wbos(buf);
if (len > slen)
__chk_fail();
if (__ssp_wchar_overlap(buf, src, len))
__chk_fail();
return (__ssp_real(wcsncpy)(buf, src, len));
}
__ssp_redirect_raw_impl(size_t, wcslcpy, wcslcpy,
(wchar_t *__restrict buf, const wchar_t *__restrict src, size_t len))
{
const size_t slen = __ssp_wbos(buf);
if (len > slen)
__chk_fail();
if (__ssp_wchar_overlap(buf, src, len))
__chk_fail();
return (__ssp_real(wcslcpy)(buf, src, len));
}
__END_DECLS
#endif /* __SSP_FORTIFY_LEVEL > 0 */
#endif /* _SSP_WCHAR_H_ */

View File

@ -108,6 +108,14 @@ typedef struct __sFILE FILE;
#endif
struct tm;
__BEGIN_DECLS
size_t wcslen(const wchar_t *) __pure;
__END_DECLS
#if !defined(_STANDALONE) && defined(_FORTIFY_SOURCE) && _FORTIFY_SOURCE > 0
#include <ssp/wchar.h>
#endif
__BEGIN_DECLS
wint_t btowc(int);
wint_t fgetwc(FILE *);
@ -146,7 +154,6 @@ wchar_t *wcscpy(wchar_t * __restrict, const wchar_t * __restrict);
size_t wcscspn(const wchar_t *, const wchar_t *) __pure;
size_t wcsftime(wchar_t * __restrict, size_t, const wchar_t * __restrict,
const struct tm * __restrict);
size_t wcslen(const wchar_t *) __pure;
wchar_t *wcsncat(wchar_t * __restrict, const wchar_t * __restrict,
size_t);
int wcsncmp(const wchar_t *, const wchar_t *, size_t) __pure;

View File

@ -32,9 +32,10 @@
*/
#include <wchar.h>
#include <ssp/ssp.h>
wchar_t *
wcpcpy(wchar_t * __restrict to, const wchar_t * __restrict from)
__ssp_real(wcpcpy)(wchar_t * __restrict to, const wchar_t * __restrict from)
{
for (; (*to = *from); ++from, ++to);

View File

@ -27,9 +27,11 @@
*/
#include <wchar.h>
#include <ssp/ssp.h>
wchar_t *
wcpncpy(wchar_t * __restrict dst, const wchar_t * __restrict src, size_t n)
__ssp_real(wcpncpy)(wchar_t * __restrict dst, const wchar_t * __restrict src,
size_t n)
{
for (; n--; dst++, src++) {

View File

@ -35,9 +35,10 @@ __RCSID("$NetBSD: wcscat.c,v 1.1 2000/12/23 23:14:36 itojun Exp $");
#endif /* LIBC_SCCS and not lint */
#endif
#include <wchar.h>
#include <ssp/ssp.h>
wchar_t *
wcscat(wchar_t * __restrict s1, const wchar_t * __restrict s2)
__ssp_real(wcscat)(wchar_t * __restrict s1, const wchar_t * __restrict s2)
{
wchar_t *cp;

View File

@ -35,9 +35,10 @@ __RCSID("$NetBSD: wcscpy.c,v 1.1 2000/12/23 23:14:36 itojun Exp $");
#endif /* LIBC_SCCS and not lint */
#endif
#include <wchar.h>
#include <ssp/ssp.h>
wchar_t *
wcscpy(wchar_t * __restrict s1, const wchar_t * __restrict s2)
__ssp_real(wcscpy)(wchar_t * __restrict s1, const wchar_t * __restrict s2)
{
wchar_t *cp;

View File

@ -37,6 +37,7 @@ __RCSID("$NetBSD: wcslcat.c,v 1.1 2000/12/23 23:14:36 itojun Exp $");
#endif
#include <sys/types.h>
#include <wchar.h>
#include <ssp/ssp.h>
/*
* Appends src to string dst of size siz (unlike wcsncat, siz is the
@ -46,7 +47,7 @@ __RCSID("$NetBSD: wcslcat.c,v 1.1 2000/12/23 23:14:36 itojun Exp $");
* truncation occurred.
*/
size_t
wcslcat(wchar_t *dst, const wchar_t *src, size_t siz)
__ssp_real(wcslcat)(wchar_t *dst, const wchar_t *src, size_t siz)
{
wchar_t *d = dst;
const wchar_t *s = src;

View File

@ -37,6 +37,7 @@ __RCSID("$NetBSD: wcslcpy.c,v 1.1 2000/12/23 23:14:36 itojun Exp $");
#endif
#include <sys/types.h>
#include <wchar.h>
#include <ssp/ssp.h>
/*
* Copy src to string dst of size siz. At most siz-1 characters
@ -44,7 +45,7 @@ __RCSID("$NetBSD: wcslcpy.c,v 1.1 2000/12/23 23:14:36 itojun Exp $");
* Returns wcslen(src); if retval >= siz, truncation occurred.
*/
size_t
wcslcpy(wchar_t *dst, const wchar_t *src, size_t siz)
__ssp_real(wcslcpy)(wchar_t *dst, const wchar_t *src, size_t siz)
{
wchar_t *d = dst;
const wchar_t *s = src;

View File

@ -35,9 +35,11 @@ __RCSID("$NetBSD: wcsncat.c,v 1.1 2000/12/23 23:14:36 itojun Exp $");
#endif /* LIBC_SCCS and not lint */
#endif
#include <wchar.h>
#include <ssp/ssp.h>
wchar_t *
wcsncat(wchar_t * __restrict s1, const wchar_t * __restrict s2, size_t n)
__ssp_real(wcsncat)(wchar_t * __restrict s1, const wchar_t * __restrict s2,
size_t n)
{
wchar_t *p;
wchar_t *q;

View File

@ -33,13 +33,15 @@
*/
#include <wchar.h>
#include <ssp/ssp.h>
/*
* Copy src to dst, truncating or null-padding to always copy n bytes.
* Return dst.
*/
wchar_t *
wcsncpy(wchar_t * __restrict dst, const wchar_t * __restrict src, size_t n)
__ssp_real(wcsncpy)(wchar_t * __restrict dst, const wchar_t * __restrict src,
size_t n)
{
if (n != 0) {
wchar_t *d = dst;

View File

@ -36,9 +36,11 @@ __RCSID("$NetBSD: wmemcpy.c,v 1.1 2000/12/23 23:14:37 itojun Exp $");
#endif
#include <string.h>
#include <wchar.h>
#include <ssp/ssp.h>
wchar_t *
wmemcpy(wchar_t * __restrict d, const wchar_t * __restrict s, size_t n)
__ssp_real(wmemcpy)(wchar_t * __restrict d, const wchar_t * __restrict s,
size_t n)
{
return (wchar_t *)memcpy(d, s, n * sizeof(wchar_t));
}

View File

@ -36,9 +36,10 @@ __RCSID("$NetBSD: wmemmove.c,v 1.1 2000/12/23 23:14:37 itojun Exp $");
#endif
#include <string.h>
#include <wchar.h>
#include <ssp/ssp.h>
wchar_t *
wmemmove(wchar_t *d, const wchar_t *s, size_t n)
__ssp_real(wmemmove)(wchar_t *d, const wchar_t *s, size_t n)
{
return (wchar_t *)memmove(d, s, n * sizeof(wchar_t));
}

View File

@ -30,9 +30,11 @@
#include <string.h>
#include <wchar.h>
#include <ssp/ssp.h>
wchar_t *
wmempcpy(wchar_t *__restrict dst, const wchar_t *__restrict src, size_t len)
__ssp_real(wmempcpy)(wchar_t *__restrict dst, const wchar_t *__restrict src,
size_t len)
{
return (wmemcpy(dst, src, len) + len);
}

View File

@ -35,9 +35,10 @@ __RCSID("$NetBSD: wmemset.c,v 1.1 2000/12/23 23:14:37 itojun Exp $");
#endif /* LIBC_SCCS and not lint */
#endif
#include <wchar.h>
#include <ssp/ssp.h>
wchar_t *
wmemset(wchar_t *s, wchar_t c, size_t n)
__ssp_real(wmemset)(wchar_t *s, wchar_t c, size_t n)
{
size_t i;
wchar_t *p;

View File

@ -8,6 +8,7 @@ FORTIFY_TCATS+= stdio
FORTIFY_TCATS+= string
FORTIFY_TCATS+= strings
FORTIFY_TCATS+= unistd
FORTIFY_TCATS+= wchar
# Manually run after updating the test generator.
generate-tests: .PHONY

View File

@ -19,6 +19,7 @@
#include <strings.h>
#include <sysexits.h>
#include <unistd.h>
#include <wchar.h>
#include <atf-c.h>
static FILE * __unused

View File

@ -19,6 +19,7 @@
#include <strings.h>
#include <sysexits.h>
#include <unistd.h>
#include <wchar.h>
#include <atf-c.h>
static FILE * __unused

View File

@ -19,6 +19,7 @@
#include <strings.h>
#include <sysexits.h>
#include <unistd.h>
#include <wchar.h>
#include <atf-c.h>
static FILE * __unused

View File

@ -19,6 +19,7 @@
#include <strings.h>
#include <sysexits.h>
#include <unistd.h>
#include <wchar.h>
#include <atf-c.h>
static FILE * __unused

View File

@ -19,6 +19,7 @@
#include <strings.h>
#include <sysexits.h>
#include <unistd.h>
#include <wchar.h>
#include <atf-c.h>
static FILE * __unused

View File

@ -19,6 +19,7 @@
#include <strings.h>
#include <sysexits.h>
#include <unistd.h>
#include <wchar.h>
#include <atf-c.h>
static FILE * __unused

File diff suppressed because it is too large Load Diff

View File

@ -77,6 +77,7 @@ local includes = {
"strings.h",
"sysexits.h",
"unistd.h",
"wchar.h",
"atf-c.h",
}
@ -114,6 +115,13 @@ local string_init = [[
src[__len - 1] = '\0';
]]
local wstring_stackvars = "\twchar_t src[__len];\n"
local wstring_init = [[
wmemset(__stack.__buf, 0, __len);
wmemset(src, 'A', __len - 1);
src[__len - 1] = '\0';
]]
-- Each test entry describes how to test a given function. We need to know how
-- to construct the buffer, we need to know the argument set we're dealing with,
-- and we need to know what we're passing to each argument. We could be passing
@ -606,6 +614,148 @@ local all_tests = {
]]
},
},
wchar = {
-- <wchar.h>
{
func = "wmemcpy",
buftype = "wchar_t[]",
arguments = {
"__buf",
"src",
"__len",
},
exclude = excludes_stack_overflow,
stackvars = "\twchar_t src[__len + 10];\n",
},
{
func = "wmempcpy",
buftype = "wchar_t[]",
arguments = {
"__buf",
"src",
"__len",
},
exclude = excludes_stack_overflow,
stackvars = "\twchar_t src[__len + 10];\n",
},
{
func = "wmemmove",
buftype = "wchar_t[]",
arguments = {
"__buf",
"src",
"__len",
},
exclude = excludes_stack_overflow,
stackvars = "\twchar_t src[__len + 10];\n",
},
{
func = "wmemset",
buftype = "wchar_t[]",
arguments = {
"__buf",
"L'0'",
"__len",
},
exclude = excludes_stack_overflow,
},
{
func = "wcpcpy",
buftype = "wchar_t[]",
arguments = {
"__buf",
"src",
},
exclude = excludes_stack_overflow,
stackvars = wstring_stackvars,
init = wstring_init,
uses_len = true,
},
{
func = "wcpncpy",
buftype = "wchar_t[]",
arguments = {
"__buf",
"src",
"__len",
},
exclude = excludes_stack_overflow,
stackvars = wstring_stackvars,
init = wstring_init,
},
{
func = "wcscat",
buftype = "wchar_t[]",
arguments = {
"__buf",
"src",
},
exclude = excludes_stack_overflow,
stackvars = wstring_stackvars,
init = wstring_init,
uses_len = true,
},
{
func = "wcslcat",
buftype = "wchar_t[]",
arguments = {
"__buf",
"src",
"__len",
},
exclude = excludes_stack_overflow,
stackvars = wstring_stackvars,
init = wstring_init,
},
{
func = "wcsncat",
buftype = "wchar_t[]",
arguments = {
"__buf",
"src",
"__len",
},
exclude = excludes_stack_overflow,
stackvars = wstring_stackvars,
init = wstring_init,
},
{
func = "wcscpy",
buftype = "wchar_t[]",
arguments = {
"__buf",
"src",
},
exclude = excludes_stack_overflow,
stackvars = wstring_stackvars,
init = wstring_init,
uses_len = true,
},
{
func = "wcslcpy",
buftype = "wchar_t[]",
arguments = {
"__buf",
"src",
"__len",
},
exclude = excludes_stack_overflow,
stackvars = wstring_stackvars,
init = wstring_init,
},
{
func = "wcsncpy",
buftype = "wchar_t[]",
arguments = {
"__buf",
"src",
"__len",
},
exclude = excludes_stack_overflow,
stackvars = wstring_stackvars,
init = wstring_init,
},
},
}
local function write_test_boilerplate(fh, name, body)