xref: /freebsd/lib/libc/tests/secure/generate-fortify-tests.lua (revision b0334450aa527ccbac7a3c37d1ba75ef96c7be91)
1020d003cSKyle Evans#!/usr/libexec/flua
2020d003cSKyle Evans--
3020d003cSKyle Evans-- SPDX-License-Identifier: BSD-2-Clause
4020d003cSKyle Evans--
5020d003cSKyle Evans-- Copyright (c) 2024, Klara, Inc.
6020d003cSKyle Evans--
7020d003cSKyle Evans-- Redistribution and use in source and binary forms, with or without
8020d003cSKyle Evans-- modification, are permitted provided that the following conditions
9020d003cSKyle Evans-- are met:
10020d003cSKyle Evans-- 1. Redistributions of source code must retain the above copyright
11020d003cSKyle Evans--    notice, this list of conditions and the following disclaimer.
12020d003cSKyle Evans-- 2. Redistributions in binary form must reproduce the above copyright
13020d003cSKyle Evans--    notice, this list of conditions and the following disclaimer in the
14020d003cSKyle Evans--    documentation and/or other materials provided with the distribution.
15020d003cSKyle Evans--
16020d003cSKyle Evans-- THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17020d003cSKyle Evans-- ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18020d003cSKyle Evans-- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19020d003cSKyle Evans-- ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20020d003cSKyle Evans-- FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21020d003cSKyle Evans-- DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22020d003cSKyle Evans-- OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23020d003cSKyle Evans-- HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24020d003cSKyle Evans-- LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25020d003cSKyle Evans-- OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26020d003cSKyle Evans-- SUCH DAMAGE.
27020d003cSKyle Evans--
28020d003cSKyle Evans
29020d003cSKyle Evans-- THEORY OF OPERATION
30020d003cSKyle Evans--
31020d003cSKyle Evans-- generate-fortify-tests.lua is intended to test fortified functions as found
32020d003cSKyle Evans-- mostly in the various headers in /usr/include/ssp.  Each fortified function
33020d003cSKyle Evans-- gets three basic tests:
34020d003cSKyle Evans--
35020d003cSKyle Evans--   1. Write just before the end of the buffer,
36020d003cSKyle Evans--   2. Write right at the end of the buffer,
37020d003cSKyle Evans--   3. Write just after the end of the buffer.
38020d003cSKyle Evans--
39020d003cSKyle Evans-- Each test is actually generated twice: once with a buffer on the stack, and
40020d003cSKyle Evans-- again with a buffer on the heap, to confirm that __builtin_object_size(3) can
41020d003cSKyle Evans-- deduce the buffer size in both scenarios.  The tests work by setting up the
42020d003cSKyle Evans-- stack with our buffer (and some padding on either side to avoid tripping any
43020d003cSKyle Evans-- other stack or memory protection), doing any initialization as described by
44020d003cSKyle Evans-- the test definition, then calling the fortified function with the buffer as
45020d003cSKyle Evans-- outlined by the test definition.
46020d003cSKyle Evans--
47020d003cSKyle Evans-- For the 'before' and 'at' the end tests, we're ensuring that valid writes
48020d003cSKyle Evans-- that are on the verge of being invalid aren't accidentally being detected as
49020d003cSKyle Evans-- invalid.
50020d003cSKyle Evans--
51020d003cSKyle Evans-- The 'after' test is the one that actually tests the functional benefit of
52020d003cSKyle Evans-- _FORTIFY_SOURCE by violating a boundary that should trigger an abort.  As
53020d003cSKyle Evans-- such, this test differs more from the other two in that it has to fork() off
54020d003cSKyle Evans-- the fortified function call so that we can monitor for a SIGABRT and
55020d003cSKyle Evans-- pass/fail the test at function end appropriately.
56020d003cSKyle Evans
57020d003cSKyle Evans-- Some tests, like the FD_*() macros, may define these differently.  For
58020d003cSKyle Evans-- instance, for fd sets we're varying the index we pass and not using arbitrary
59020d003cSKyle Evans-- buffers.  Other tests that don't use the length in any way may physically
60020d003cSKyle Evans-- vary the buffer size for each test case when we'd typically vary the length
61020d003cSKyle Evans-- we're requesting a write for.
62020d003cSKyle Evans
63020d003cSKyle Evanslocal includes = {
64020d003cSKyle Evans	"sys/param.h",
6522178cb2SKyle Evans	"sys/jail.h",
66062d9380SKyle Evans	"sys/random.h",
67020d003cSKyle Evans	"sys/resource.h",
682aba0eeaSKyle Evans	"sys/select.h",
691f155d48SKyle Evans	"sys/socket.h",
70020d003cSKyle Evans	"sys/time.h",
711ace24b3SKyle Evans	"sys/uio.h",
72020d003cSKyle Evans	"sys/wait.h",
73020d003cSKyle Evans	"dirent.h",
74020d003cSKyle Evans	"errno.h",
75020d003cSKyle Evans	"fcntl.h",
76020d003cSKyle Evans	"limits.h",
7788276dfbSKyle Evans	"poll.h",
78020d003cSKyle Evans	"signal.h",
79020d003cSKyle Evans	"stdio.h",
80020d003cSKyle Evans	"stdlib.h",
81020d003cSKyle Evans	"string.h",
82020d003cSKyle Evans	"strings.h",
83020d003cSKyle Evans	"sysexits.h",
84020d003cSKyle Evans	"unistd.h",
85b53d7aa8SKyle Evans	"wchar.h",
86020d003cSKyle Evans	"atf-c.h",
87020d003cSKyle Evans}
88020d003cSKyle Evans
89020d003cSKyle Evanslocal tests_added = {}
90020d003cSKyle Evans
9122178cb2SKyle Evans-- Configuration for tests that want the host/domainname
9222178cb2SKyle Evanslocal hostname = "host.example.com"
9322178cb2SKyle Evanslocal domainname = "example.com"
9422178cb2SKyle Evans
95020d003cSKyle Evans-- Some of these will need to be excluded because clang sees the wrong size when
96020d003cSKyle Evans-- an array is embedded inside a struct, we'll get something that looks more
97020d003cSKyle Evans-- like __builtin_object_size(ptr, 0) than it does the correct
98020d003cSKyle Evans-- __builtin_object_size(ptr, 1) (i.e., includes the padding after).  This is
99020d003cSKyle Evans-- almost certainly a bug in llvm.
100020d003cSKyle Evanslocal function excludes_stack_overflow(disposition, is_heap)
101020d003cSKyle Evans	return (not is_heap) and disposition > 0
102020d003cSKyle Evansend
103020d003cSKyle Evans
10488276dfbSKyle Evanslocal poll_init = [[
10588276dfbSKyle Evans	for (size_t i = 0; i < howmany(__bufsz, sizeof(struct pollfd)); i++) {
10688276dfbSKyle Evans		__stack.__buf[i].fd = -1;
10788276dfbSKyle Evans	}
10888276dfbSKyle Evans]]
10988276dfbSKyle Evans
110020d003cSKyle Evanslocal printf_stackvars = "\tchar srcvar[__len + 10];\n"
111020d003cSKyle Evanslocal printf_init = [[
112020d003cSKyle Evans	memset(srcvar, 'A', sizeof(srcvar) - 1);
113020d003cSKyle Evans	srcvar[sizeof(srcvar) - 1] = '\0';
114020d003cSKyle Evans]]
115020d003cSKyle Evans
1161ace24b3SKyle Evanslocal readv_stackvars = "\tstruct iovec iov[1];\n"
1171ace24b3SKyle Evanslocal readv_init = [[
1181ace24b3SKyle Evans	iov[0].iov_base = __stack.__buf;
1191ace24b3SKyle Evans	iov[0].iov_len = __len;
1201ace24b3SKyle Evans
1211ace24b3SKyle Evans	replace_stdin();
1221ace24b3SKyle Evans]]
1231ace24b3SKyle Evans
1241f155d48SKyle Evanslocal socket_stackvars = "\tint sock[2] = { -1, -1 };\n"
1251f155d48SKyle Evanslocal recvfrom_sockaddr_stackvars = socket_stackvars .. [[
1261f155d48SKyle Evans	char data[16];
1271f155d48SKyle Evans	socklen_t socklen;
1281f155d48SKyle Evans]]
1291f155d48SKyle Evanslocal recvmsg_stackvars = socket_stackvars .. "\tstruct msghdr msg;\n"
1301f155d48SKyle Evanslocal socket_init = [[
1311f155d48SKyle Evans	new_socket(sock);
1321f155d48SKyle Evans]]
1331f155d48SKyle Evanslocal socket_socklen_init = socket_init .. [[
1341f155d48SKyle Evans	socklen = __len;
1351f155d48SKyle Evans]]
1361f155d48SKyle Evans
137cf8e5289SKyle Evanslocal stdio_init = [[
138cf8e5289SKyle Evans	replace_stdin();
139cf8e5289SKyle Evans]]
140cf8e5289SKyle Evans
141020d003cSKyle Evanslocal string_stackvars = "\tchar src[__len];\n"
142020d003cSKyle Evanslocal string_init = [[
143020d003cSKyle Evans	memset(__stack.__buf, 0, __len);
144020d003cSKyle Evans	memset(src, 'A', __len - 1);
145020d003cSKyle Evans	src[__len - 1] = '\0';
146020d003cSKyle Evans]]
147020d003cSKyle Evans
148b53d7aa8SKyle Evanslocal wstring_stackvars = "\twchar_t src[__len];\n"
149b53d7aa8SKyle Evanslocal wstring_init = [[
150b53d7aa8SKyle Evans	wmemset(__stack.__buf, 0, __len);
151b53d7aa8SKyle Evans	wmemset(src, 'A', __len - 1);
152b53d7aa8SKyle Evans	src[__len - 1] = '\0';
153b53d7aa8SKyle Evans]]
154b53d7aa8SKyle Evans
155020d003cSKyle Evans-- Each test entry describes how to test a given function.  We need to know how
156020d003cSKyle Evans-- to construct the buffer, we need to know the argument set we're dealing with,
157020d003cSKyle Evans-- and we need to know what we're passing to each argument.  We could be passing
158020d003cSKyle Evans-- fixed values, or we could be passing the __buf under test.
159020d003cSKyle Evans--
160020d003cSKyle Evans-- definition:
161020d003cSKyle Evans--   func: name of the function under test to call
162020d003cSKyle Evans--   bufsize: size of buffer to generate, defaults to 42
163020d003cSKyle Evans--   buftype: type of buffer to generate, defaults to unsigned char[]
164020d003cSKyle Evans--   arguments: __buf, __len, or the name of a variable placed on the stack
165020d003cSKyle Evans--   exclude: a function(disposition, is_heap) that returns true if this combo
166020d003cSKyle Evans--     should be excluded.
167020d003cSKyle Evans--   stackvars: extra variables to be placed on the stack, should be a string
168020d003cSKyle Evans--     optionally formatted with tabs and newlines
169020d003cSKyle Evans--   init: extra code to inject just before the function call for initialization
170020d003cSKyle Evans--     of the buffer or any of the above-added stackvars; also a string
171020d003cSKyle Evans--   uses_len: bool-ish, necessary if arguments doesn't include either __idx or
172020d003cSKyle Evans--     or __len so that the test generator doesn't try to vary the size of the
173020d003cSKyle Evans--     buffer instead of just manipulating __idx/__len to try and induce an
174020d003cSKyle Evans--     overflow.
175020d003cSKyle Evans--
176020d003cSKyle Evans-- Most tests will just use the default bufsize/buftype, but under some
177020d003cSKyle Evans-- circumstances it's useful to use a different type (e.g., for alignment
178020d003cSKyle Evans-- requirements).
179020d003cSKyle Evanslocal all_tests = {
180062d9380SKyle Evans	random = {
181062d9380SKyle Evans		-- <sys/random.h>
182062d9380SKyle Evans		{
183062d9380SKyle Evans			func = "getrandom",
184062d9380SKyle Evans			arguments = {
185062d9380SKyle Evans				"__buf",
186062d9380SKyle Evans				"__len",
187062d9380SKyle Evans				"0",
188062d9380SKyle Evans			},
189062d9380SKyle Evans			exclude = excludes_stack_overflow,
190062d9380SKyle Evans		},
191062d9380SKyle Evans	},
1922aba0eeaSKyle Evans	select = {
1932aba0eeaSKyle Evans		-- <sys/select.h>
1942aba0eeaSKyle Evans		{
1952aba0eeaSKyle Evans			func = "FD_SET",
1962aba0eeaSKyle Evans			bufsize = "FD_SETSIZE",
1972aba0eeaSKyle Evans			buftype = "fd_set",
1982aba0eeaSKyle Evans			arguments = {
1992aba0eeaSKyle Evans				"__idx",
2002aba0eeaSKyle Evans				"__buf",
2012aba0eeaSKyle Evans			},
2022aba0eeaSKyle Evans		},
2032aba0eeaSKyle Evans		{
2042aba0eeaSKyle Evans			func = "FD_CLR",
2052aba0eeaSKyle Evans			bufsize = "FD_SETSIZE",
2062aba0eeaSKyle Evans			buftype = "fd_set",
2072aba0eeaSKyle Evans			arguments = {
2082aba0eeaSKyle Evans				"__idx",
2092aba0eeaSKyle Evans				"__buf",
2102aba0eeaSKyle Evans			},
2112aba0eeaSKyle Evans		},
2122aba0eeaSKyle Evans		{
2132aba0eeaSKyle Evans			func = "FD_ISSET",
2142aba0eeaSKyle Evans			bufsize = "FD_SETSIZE",
2152aba0eeaSKyle Evans			buftype = "fd_set",
2162aba0eeaSKyle Evans			arguments = {
2172aba0eeaSKyle Evans				"__idx",
2182aba0eeaSKyle Evans				"__buf",
2192aba0eeaSKyle Evans			},
2202aba0eeaSKyle Evans		},
2212aba0eeaSKyle Evans	},
2221f155d48SKyle Evans	socket = {
2231f155d48SKyle Evans		-- <sys/socket.h>
2241f155d48SKyle Evans		{
2251f155d48SKyle Evans			func = "getpeername",
2261f155d48SKyle Evans			buftype = "struct sockaddr",
2271f155d48SKyle Evans			bufsize = "sizeof(struct sockaddr)",
2281f155d48SKyle Evans			arguments = {
2291f155d48SKyle Evans				"sock[0]",
2301f155d48SKyle Evans				"__buf",
2311f155d48SKyle Evans				"&socklen",
2321f155d48SKyle Evans			},
2331f155d48SKyle Evans			exclude = excludes_stack_overflow,
2341f155d48SKyle Evans			stackvars = socket_stackvars .. "\tsocklen_t socklen;",
2351f155d48SKyle Evans			init = socket_socklen_init,
2361f155d48SKyle Evans			uses_len = true,
2371f155d48SKyle Evans		},
2381f155d48SKyle Evans		{
2391f155d48SKyle Evans			func = "getsockname",
2401f155d48SKyle Evans			buftype = "struct sockaddr",
2411f155d48SKyle Evans			bufsize = "sizeof(struct sockaddr)",
2421f155d48SKyle Evans			arguments = {
2431f155d48SKyle Evans				"sock[0]",
2441f155d48SKyle Evans				"__buf",
2451f155d48SKyle Evans				"&socklen",
2461f155d48SKyle Evans			},
2471f155d48SKyle Evans			exclude = excludes_stack_overflow,
2481f155d48SKyle Evans			stackvars = socket_stackvars .. "\tsocklen_t socklen;",
2491f155d48SKyle Evans			init = socket_socklen_init,
2501f155d48SKyle Evans			uses_len = true,
2511f155d48SKyle Evans		},
2521f155d48SKyle Evans		{
2531f155d48SKyle Evans			func = "recv",
2541f155d48SKyle Evans			arguments = {
2551f155d48SKyle Evans				"sock[0]",
2561f155d48SKyle Evans				"__buf",
2571f155d48SKyle Evans				"__len",
2581f155d48SKyle Evans				"0",
2591f155d48SKyle Evans			},
2601f155d48SKyle Evans			exclude = excludes_stack_overflow,
2611f155d48SKyle Evans			stackvars = socket_stackvars,
2621f155d48SKyle Evans			init = socket_init,
2631f155d48SKyle Evans		},
2641f155d48SKyle Evans		{
2651f155d48SKyle Evans			func = "recvfrom",
2661f155d48SKyle Evans			arguments = {
2671f155d48SKyle Evans				"sock[0]",
2681f155d48SKyle Evans				"__buf",
2691f155d48SKyle Evans				"__len",
2701f155d48SKyle Evans				"0",
2711f155d48SKyle Evans				"NULL",
2721f155d48SKyle Evans				"NULL",
2731f155d48SKyle Evans			},
2741f155d48SKyle Evans			exclude = excludes_stack_overflow,
2751f155d48SKyle Evans			stackvars = socket_stackvars,
2761f155d48SKyle Evans			init = socket_init,
2771f155d48SKyle Evans		},
2781f155d48SKyle Evans		{
2791f155d48SKyle Evans			func = "recvfrom",
2801f155d48SKyle Evans			variant = "sockaddr",
2811f155d48SKyle Evans			buftype = "struct sockaddr",
2821f155d48SKyle Evans			bufsize = "sizeof(struct sockaddr)",
2831f155d48SKyle Evans			arguments = {
2841f155d48SKyle Evans				"sock[0]",
2851f155d48SKyle Evans				"data",
2861f155d48SKyle Evans				"sizeof(data)",
2871f155d48SKyle Evans				"0",
2881f155d48SKyle Evans				"__buf",
2891f155d48SKyle Evans				"&socklen",
2901f155d48SKyle Evans			},
2911f155d48SKyle Evans			exclude = excludes_stack_overflow,
2921f155d48SKyle Evans			stackvars = recvfrom_sockaddr_stackvars,
2931f155d48SKyle Evans			init = socket_socklen_init,
2941f155d48SKyle Evans			uses_len = true,
2951f155d48SKyle Evans		},
2961f155d48SKyle Evans		{
2971f155d48SKyle Evans			func = "recvmsg",
2981f155d48SKyle Evans			variant = "msg_name",
2991f155d48SKyle Evans			buftype = "struct sockaddr",
3001f155d48SKyle Evans			bufsize = "sizeof(struct sockaddr)",
3011f155d48SKyle Evans			arguments = {
3021f155d48SKyle Evans				"sock[0]",
3031f155d48SKyle Evans				"&msg",
3041f155d48SKyle Evans				"0",
3051f155d48SKyle Evans			},
3061f155d48SKyle Evans			exclude = excludes_stack_overflow,
3071f155d48SKyle Evans			stackvars = recvmsg_stackvars,
3081f155d48SKyle Evans			init = [[
3091f155d48SKyle Evans	memset(&msg, 0, sizeof(msg));
3101f155d48SKyle Evans	msg.msg_name = BUF;
3111f155d48SKyle Evans	msg.msg_namelen = __len;
3121f155d48SKyle Evans]],
3131f155d48SKyle Evans			uses_len = true,
3141f155d48SKyle Evans		},
3151f155d48SKyle Evans		{
3161f155d48SKyle Evans			func = "recvmsg",
3171f155d48SKyle Evans			variant = "msg_iov",
3181f155d48SKyle Evans			arguments = {
3191f155d48SKyle Evans				"sock[0]",
3201f155d48SKyle Evans				"&msg",
3211f155d48SKyle Evans				"0",
3221f155d48SKyle Evans			},
3231f155d48SKyle Evans			exclude = excludes_stack_overflow,
3241f155d48SKyle Evans			stackvars = recvmsg_stackvars .. "\tstruct iovec iov[2];\n",
3251f155d48SKyle Evans			init = [[
3261f155d48SKyle Evans	memset(&msg, 0, sizeof(msg));
3271f155d48SKyle Evans	memset(&iov[0], 0, sizeof(iov));
3281f155d48SKyle Evans
3291f155d48SKyle Evans	/*
3301f155d48SKyle Evans	 * We position the buffer second just so that we can confirm that the
3311f155d48SKyle Evans	 * fortification bits are traversing the iovec correctly.
3321f155d48SKyle Evans	 */
3331f155d48SKyle Evans	iov[1].iov_base = BUF;
3341f155d48SKyle Evans	iov[1].iov_len = __len;
3351f155d48SKyle Evans
3361f155d48SKyle Evans	msg.msg_iov = &iov[0];
3371f155d48SKyle Evans	msg.msg_iovlen = nitems(iov);
3381f155d48SKyle Evans]],
3391f155d48SKyle Evans			uses_len = true,
3401f155d48SKyle Evans		},
3411f155d48SKyle Evans		{
3421f155d48SKyle Evans			func = "recvmsg",
3431f155d48SKyle Evans			variant = "msg_control",
3441f155d48SKyle Evans			bufsize = "CMSG_SPACE(sizeof(int))",
3451f155d48SKyle Evans			arguments = {
3461f155d48SKyle Evans				"sock[0]",
3471f155d48SKyle Evans				"&msg",
3481f155d48SKyle Evans				"0",
3491f155d48SKyle Evans			},
3501f155d48SKyle Evans			exclude = excludes_stack_overflow,
3511f155d48SKyle Evans			stackvars = recvmsg_stackvars,
3521f155d48SKyle Evans			init = [[
3531f155d48SKyle Evans	memset(&msg, 0, sizeof(msg));
3541f155d48SKyle Evans
3551f155d48SKyle Evans	msg.msg_control = BUF;
3561f155d48SKyle Evans	msg.msg_controllen = __len;
3571f155d48SKyle Evans]],
3581f155d48SKyle Evans			uses_len = true,
3591f155d48SKyle Evans		},
3601f155d48SKyle Evans		{
3611f155d48SKyle Evans			func = "recvmmsg",
3621f155d48SKyle Evans			variant = "msgvec",
3631f155d48SKyle Evans			buftype = "struct mmsghdr[]",
3641f155d48SKyle Evans			bufsize = "2",
3651f155d48SKyle Evans			arguments = {
3661f155d48SKyle Evans				"sock[0]",
3671f155d48SKyle Evans				"__buf",
3681f155d48SKyle Evans				"__len",
3691f155d48SKyle Evans				"0",
3701f155d48SKyle Evans				"NULL",
3711f155d48SKyle Evans			},
3721f155d48SKyle Evans			stackvars = socket_stackvars,
3731f155d48SKyle Evans		},
3741f155d48SKyle Evans		{
3751f155d48SKyle Evans			-- We'll assume that recvmsg is covering msghdr
3761f155d48SKyle Evans			-- validation thoroughly enough, we'll just try tossing
3771f155d48SKyle Evans			-- an error in the second element of a msgvec to try and
3781f155d48SKyle Evans			-- make sure that each one is being validated.
3791f155d48SKyle Evans			func = "recvmmsg",
3801f155d48SKyle Evans			variant = "msghdr",
3811f155d48SKyle Evans			arguments = {
3821f155d48SKyle Evans				"sock[0]",
3831f155d48SKyle Evans				"&msgvec[0]",
3841f155d48SKyle Evans				"nitems(msgvec)",
3851f155d48SKyle Evans				"0",
3861f155d48SKyle Evans				"NULL",
3871f155d48SKyle Evans			},
3881f155d48SKyle Evans			exclude = excludes_stack_overflow,
3891f155d48SKyle Evans			stackvars = socket_stackvars .. "\tstruct mmsghdr msgvec[2];\n",
3901f155d48SKyle Evans			init = [[
3911f155d48SKyle Evans	memset(&msgvec[0], 0, sizeof(msgvec));
3921f155d48SKyle Evans
3931f155d48SKyle Evans	/*
3941f155d48SKyle Evans	 * Same as above, make sure fortification isn't ignoring n > 1 elements
3951f155d48SKyle Evans	 * of the msgvec.
3961f155d48SKyle Evans	 */
3971f155d48SKyle Evans	msgvec[1].msg_hdr.msg_control = BUF;
3981f155d48SKyle Evans	msgvec[1].msg_hdr.msg_controllen = __len;
3991f155d48SKyle Evans]],
4001f155d48SKyle Evans			uses_len = true,
4011f155d48SKyle Evans		},
4021f155d48SKyle Evans	},
4031ace24b3SKyle Evans	uio = {
4041ace24b3SKyle Evans		-- <sys/uio.h>
4051ace24b3SKyle Evans		{
4061ace24b3SKyle Evans			func = "readv",
4071ace24b3SKyle Evans			buftype = "struct iovec[]",
4081ace24b3SKyle Evans			bufsize = 2,
4091ace24b3SKyle Evans			arguments = {
4101ace24b3SKyle Evans				"STDIN_FILENO",
4111ace24b3SKyle Evans				"__buf",
4121ace24b3SKyle Evans				"__len",
4131ace24b3SKyle Evans			},
4141ace24b3SKyle Evans		},
4151ace24b3SKyle Evans		{
4161ace24b3SKyle Evans			func = "readv",
4171ace24b3SKyle Evans			variant = "iov",
4181ace24b3SKyle Evans			arguments = {
4191ace24b3SKyle Evans				"STDIN_FILENO",
4201ace24b3SKyle Evans				"iov",
4211ace24b3SKyle Evans				"nitems(iov)",
4221ace24b3SKyle Evans			},
4231ace24b3SKyle Evans			exclude = excludes_stack_overflow,
4241ace24b3SKyle Evans			stackvars = readv_stackvars,
4251ace24b3SKyle Evans			init = readv_init,
4261ace24b3SKyle Evans			uses_len = true,
4271ace24b3SKyle Evans		},
4281ace24b3SKyle Evans		{
4291ace24b3SKyle Evans			func = "preadv",
4301ace24b3SKyle Evans			buftype = "struct iovec[]",
4311ace24b3SKyle Evans			bufsize = 2,
4321ace24b3SKyle Evans			arguments = {
4331ace24b3SKyle Evans				"STDIN_FILENO",
4341ace24b3SKyle Evans				"__buf",
4351ace24b3SKyle Evans				"__len",
4361ace24b3SKyle Evans				"0",
4371ace24b3SKyle Evans			},
4381ace24b3SKyle Evans		},
4391ace24b3SKyle Evans		{
4401ace24b3SKyle Evans			func = "preadv",
4411ace24b3SKyle Evans			variant = "iov",
4421ace24b3SKyle Evans			arguments = {
4431ace24b3SKyle Evans				"STDIN_FILENO",
4441ace24b3SKyle Evans				"iov",
4451ace24b3SKyle Evans				"nitems(iov)",
4461ace24b3SKyle Evans				"0",
4471ace24b3SKyle Evans			},
4481ace24b3SKyle Evans			exclude = excludes_stack_overflow,
4491ace24b3SKyle Evans			stackvars = readv_stackvars,
4501ace24b3SKyle Evans			init = readv_init,
4511ace24b3SKyle Evans			uses_len = true,
4521ace24b3SKyle Evans		},
4531ace24b3SKyle Evans	},
45488276dfbSKyle Evans	poll = {
45588276dfbSKyle Evans		-- <poll.h>
45688276dfbSKyle Evans		{
45788276dfbSKyle Evans			func = "poll",
45888276dfbSKyle Evans			bufsize = "4",
45988276dfbSKyle Evans			buftype = "struct pollfd[]",
46088276dfbSKyle Evans			arguments = {
46188276dfbSKyle Evans				"__buf",
46288276dfbSKyle Evans				"__len",
46388276dfbSKyle Evans				"0",
46488276dfbSKyle Evans			},
46588276dfbSKyle Evans			init = poll_init,
46688276dfbSKyle Evans		},
46788276dfbSKyle Evans		{
46888276dfbSKyle Evans			func = "ppoll",
46988276dfbSKyle Evans			bufsize = "4",
47088276dfbSKyle Evans			buftype = "struct pollfd[]",
47188276dfbSKyle Evans			arguments = {
47288276dfbSKyle Evans				"__buf",
47388276dfbSKyle Evans				"__len",
47488276dfbSKyle Evans				"&tv",
47588276dfbSKyle Evans				"NULL",
47688276dfbSKyle Evans			},
47788276dfbSKyle Evans			stackvars = "\tstruct timespec tv = { 0 };\n",
47888276dfbSKyle Evans			init = poll_init,
47988276dfbSKyle Evans		},
48088276dfbSKyle Evans	},
481*b0334450SRicardo Branco	signal = {
482*b0334450SRicardo Branco		-- <signal.h>
483*b0334450SRicardo Branco		{
484*b0334450SRicardo Branco			func = "sig2str",
485*b0334450SRicardo Branco			bufsize = "SIG2STR_MAX",
486*b0334450SRicardo Branco			arguments = {
487*b0334450SRicardo Branco				"1",
488*b0334450SRicardo Branco				"__buf",
489*b0334450SRicardo Branco			},
490*b0334450SRicardo Branco			exclude = excludes_stack_overflow,
491*b0334450SRicardo Branco		},
492*b0334450SRicardo Branco	},
493020d003cSKyle Evans	stdio = {
494020d003cSKyle Evans		-- <stdio.h>
495020d003cSKyle Evans		{
496cf8e5289SKyle Evans			func = "ctermid",
497cf8e5289SKyle Evans			bufsize = "L_ctermid",
498cf8e5289SKyle Evans			arguments = {
499cf8e5289SKyle Evans				"__buf",
500cf8e5289SKyle Evans			},
501cf8e5289SKyle Evans			exclude = excludes_stack_overflow,
502cf8e5289SKyle Evans		},
503cf8e5289SKyle Evans		{
504cf8e5289SKyle Evans			func = "ctermid_r",
505cf8e5289SKyle Evans			bufsize = "L_ctermid",
506cf8e5289SKyle Evans			arguments = {
507cf8e5289SKyle Evans				"__buf",
508cf8e5289SKyle Evans			},
509cf8e5289SKyle Evans			exclude = excludes_stack_overflow,
510cf8e5289SKyle Evans		},
511cf8e5289SKyle Evans		{
512cf8e5289SKyle Evans			func = "fread",
513cf8e5289SKyle Evans			arguments = {
514cf8e5289SKyle Evans				"__buf",
515cf8e5289SKyle Evans				"__len",
516cf8e5289SKyle Evans				"1",
517cf8e5289SKyle Evans				"stdin",
518cf8e5289SKyle Evans			},
519cf8e5289SKyle Evans			exclude = excludes_stack_overflow,
520cf8e5289SKyle Evans			init = stdio_init,
521cf8e5289SKyle Evans		},
522cf8e5289SKyle Evans		{
523cf8e5289SKyle Evans			func = "fread_unlocked",
524cf8e5289SKyle Evans			arguments = {
525cf8e5289SKyle Evans				"__buf",
526cf8e5289SKyle Evans				"__len",
527cf8e5289SKyle Evans				"1",
528cf8e5289SKyle Evans				"stdin",
529cf8e5289SKyle Evans			},
530cf8e5289SKyle Evans			exclude = excludes_stack_overflow,
531cf8e5289SKyle Evans			init = stdio_init,
532cf8e5289SKyle Evans		},
533cf8e5289SKyle Evans		{
534cf8e5289SKyle Evans			func = "gets_s",
535cf8e5289SKyle Evans			arguments = {
536cf8e5289SKyle Evans				"__buf",
537cf8e5289SKyle Evans				"__len",
538cf8e5289SKyle Evans			},
539cf8e5289SKyle Evans			exclude = excludes_stack_overflow,
540cf8e5289SKyle Evans			init = stdio_init,
541cf8e5289SKyle Evans		},
542cf8e5289SKyle Evans		{
543020d003cSKyle Evans			func = "sprintf",
544020d003cSKyle Evans			arguments = {
545020d003cSKyle Evans				"__buf",
546020d003cSKyle Evans				"\"%.*s\"",
547020d003cSKyle Evans				"(int)__len - 1",	-- - 1 for NUL terminator
548020d003cSKyle Evans				"srcvar",
549020d003cSKyle Evans			},
550020d003cSKyle Evans			exclude = excludes_stack_overflow,
551020d003cSKyle Evans			stackvars = printf_stackvars,
552020d003cSKyle Evans			init = printf_init,
553020d003cSKyle Evans		},
554020d003cSKyle Evans		{
555020d003cSKyle Evans			func = "snprintf",
556020d003cSKyle Evans			arguments = {
557020d003cSKyle Evans				"__buf",
558020d003cSKyle Evans				"__len",
559020d003cSKyle Evans				"\"%.*s\"",
560020d003cSKyle Evans				"(int)__len - 1",	-- - 1 for NUL terminator
561020d003cSKyle Evans				"srcvar",
562020d003cSKyle Evans			},
563020d003cSKyle Evans			exclude = excludes_stack_overflow,
564020d003cSKyle Evans			stackvars = printf_stackvars,
565020d003cSKyle Evans			init = printf_init,
566020d003cSKyle Evans		},
567cf8e5289SKyle Evans		{
568cf8e5289SKyle Evans			func = "tmpnam",
569cf8e5289SKyle Evans			bufsize = "L_tmpnam",
570cf8e5289SKyle Evans			arguments = {
571cf8e5289SKyle Evans				"__buf",
572cf8e5289SKyle Evans			},
573cf8e5289SKyle Evans			exclude = excludes_stack_overflow,
574cf8e5289SKyle Evans		},
575cf8e5289SKyle Evans		{
576cf8e5289SKyle Evans			func = "fgets",
577cf8e5289SKyle Evans			arguments = {
578cf8e5289SKyle Evans				"__buf",
579cf8e5289SKyle Evans				"__len",
580cf8e5289SKyle Evans				"fp",
581cf8e5289SKyle Evans			},
582cf8e5289SKyle Evans			exclude = excludes_stack_overflow,
583cf8e5289SKyle Evans			stackvars = "\tFILE *fp;\n",
584cf8e5289SKyle Evans			init = [[
585cf8e5289SKyle Evans	fp = new_fp(__len);
586cf8e5289SKyle Evans]],
587cf8e5289SKyle Evans		},
588020d003cSKyle Evans	},
589d0b74459SKyle Evans	stdlib = {
590d0b74459SKyle Evans		-- <stdlib.h>
591d0b74459SKyle Evans		{
592d0b74459SKyle Evans			func = "arc4random_buf",
593d0b74459SKyle Evans			arguments = {
594d0b74459SKyle Evans				"__buf",
595d0b74459SKyle Evans				"__len",
596d0b74459SKyle Evans			},
597d0b74459SKyle Evans			exclude = excludes_stack_overflow,
598d0b74459SKyle Evans		},
599d0b74459SKyle Evans		{
600873420caSDag-Erling Smørgrav			func = "getenv_r",
601873420caSDag-Erling Smørgrav			arguments = {
602873420caSDag-Erling Smørgrav				"\"PATH\"",
603873420caSDag-Erling Smørgrav				"__buf",
604873420caSDag-Erling Smørgrav				"__len",
605873420caSDag-Erling Smørgrav			},
606873420caSDag-Erling Smørgrav			exclude = excludes_stack_overflow,
607873420caSDag-Erling Smørgrav		},
608873420caSDag-Erling Smørgrav		{
609d0b74459SKyle Evans			func = "realpath",
610d0b74459SKyle Evans			bufsize = "PATH_MAX",
611d0b74459SKyle Evans			arguments = {
612d0b74459SKyle Evans				"\".\"",
613d0b74459SKyle Evans				"__buf",
614d0b74459SKyle Evans			},
615d0b74459SKyle Evans			exclude = excludes_stack_overflow,
616d0b74459SKyle Evans		},
617d0b74459SKyle Evans	},
618020d003cSKyle Evans	string = {
619020d003cSKyle Evans		-- <string.h>
620020d003cSKyle Evans		{
621020d003cSKyle Evans			func = "memcpy",
622020d003cSKyle Evans			arguments = {
623020d003cSKyle Evans				"__buf",
624020d003cSKyle Evans				"src",
625020d003cSKyle Evans				"__len",
626020d003cSKyle Evans			},
627020d003cSKyle Evans			exclude = excludes_stack_overflow,
628020d003cSKyle Evans			stackvars = "\tchar src[__len + 10];\n",
629020d003cSKyle Evans		},
630020d003cSKyle Evans		{
631cf8e5289SKyle Evans			func = "mempcpy",
632cf8e5289SKyle Evans			arguments = {
633cf8e5289SKyle Evans				"__buf",
634cf8e5289SKyle Evans				"src",
635cf8e5289SKyle Evans				"__len",
636cf8e5289SKyle Evans			},
637cf8e5289SKyle Evans			exclude = excludes_stack_overflow,
638cf8e5289SKyle Evans			stackvars = "\tchar src[__len + 10];\n",
639cf8e5289SKyle Evans		},
640cf8e5289SKyle Evans		{
641020d003cSKyle Evans			func = "memmove",
642020d003cSKyle Evans			arguments = {
643020d003cSKyle Evans				"__buf",
644020d003cSKyle Evans				"src",
645020d003cSKyle Evans				"__len",
646020d003cSKyle Evans			},
647020d003cSKyle Evans			exclude = excludes_stack_overflow,
648020d003cSKyle Evans			stackvars = "\tchar src[__len + 10];\n",
649020d003cSKyle Evans		},
650020d003cSKyle Evans		{
651020d003cSKyle Evans			func = "memset",
652020d003cSKyle Evans			arguments = {
653020d003cSKyle Evans				"__buf",
654020d003cSKyle Evans				"0",
655020d003cSKyle Evans				"__len",
656020d003cSKyle Evans			},
657020d003cSKyle Evans			exclude = excludes_stack_overflow,
658020d003cSKyle Evans		},
659020d003cSKyle Evans		{
6608983acc8SRobert Clausecker			func = "memset_explicit",
6618983acc8SRobert Clausecker			arguments = {
6628983acc8SRobert Clausecker				"__buf",
6638983acc8SRobert Clausecker				"0",
6648983acc8SRobert Clausecker				"__len",
6658983acc8SRobert Clausecker			},
6668983acc8SRobert Clausecker			exclude = excludes_stack_overflow,
6678983acc8SRobert Clausecker		},
6688983acc8SRobert Clausecker		{
669020d003cSKyle Evans			func = "stpcpy",
670020d003cSKyle Evans			arguments = {
671020d003cSKyle Evans				"__buf",
672020d003cSKyle Evans				"src",
673020d003cSKyle Evans			},
674020d003cSKyle Evans			exclude = excludes_stack_overflow,
675020d003cSKyle Evans			stackvars = string_stackvars,
676020d003cSKyle Evans			init = string_init,
677020d003cSKyle Evans			uses_len = true,
678020d003cSKyle Evans		},
679020d003cSKyle Evans		{
680020d003cSKyle Evans			func = "stpncpy",
681020d003cSKyle Evans			arguments = {
682020d003cSKyle Evans				"__buf",
683020d003cSKyle Evans				"src",
684020d003cSKyle Evans				"__len",
685020d003cSKyle Evans			},
686020d003cSKyle Evans			exclude = excludes_stack_overflow,
687020d003cSKyle Evans			stackvars = string_stackvars,
688020d003cSKyle Evans			init = string_init,
689020d003cSKyle Evans		},
690020d003cSKyle Evans		{
691020d003cSKyle Evans			func = "strcat",
692020d003cSKyle Evans			arguments = {
693020d003cSKyle Evans				"__buf",
694020d003cSKyle Evans				"src",
695020d003cSKyle Evans			},
696020d003cSKyle Evans			exclude = excludes_stack_overflow,
697020d003cSKyle Evans			stackvars = string_stackvars,
698020d003cSKyle Evans			init = string_init,
699020d003cSKyle Evans			uses_len = true,
700020d003cSKyle Evans		},
701020d003cSKyle Evans		{
702cf8e5289SKyle Evans			func = "strlcat",
703cf8e5289SKyle Evans			arguments = {
704cf8e5289SKyle Evans				"__buf",
705cf8e5289SKyle Evans				"src",
706cf8e5289SKyle Evans				"__len",
707cf8e5289SKyle Evans			},
708cf8e5289SKyle Evans			exclude = excludes_stack_overflow,
709cf8e5289SKyle Evans			stackvars = string_stackvars,
710cf8e5289SKyle Evans			init = string_init,
711cf8e5289SKyle Evans		},
712cf8e5289SKyle Evans		{
713020d003cSKyle Evans			func = "strncat",
714020d003cSKyle Evans			arguments = {
715020d003cSKyle Evans				"__buf",
716020d003cSKyle Evans				"src",
717020d003cSKyle Evans				"__len",
718020d003cSKyle Evans			},
719020d003cSKyle Evans			exclude = excludes_stack_overflow,
720020d003cSKyle Evans			stackvars = string_stackvars,
721020d003cSKyle Evans			init = string_init,
722020d003cSKyle Evans		},
723020d003cSKyle Evans		{
724020d003cSKyle Evans			func = "strcpy",
725020d003cSKyle Evans			arguments = {
726020d003cSKyle Evans				"__buf",
727020d003cSKyle Evans				"src",
728020d003cSKyle Evans			},
729020d003cSKyle Evans			exclude = excludes_stack_overflow,
730020d003cSKyle Evans			stackvars = string_stackvars,
731020d003cSKyle Evans			init = string_init,
732020d003cSKyle Evans			uses_len = true,
733020d003cSKyle Evans		},
734020d003cSKyle Evans		{
735cf8e5289SKyle Evans			func = "strlcpy",
736cf8e5289SKyle Evans			arguments = {
737cf8e5289SKyle Evans				"__buf",
738cf8e5289SKyle Evans				"src",
739cf8e5289SKyle Evans				"__len",
740cf8e5289SKyle Evans			},
741cf8e5289SKyle Evans			exclude = excludes_stack_overflow,
742cf8e5289SKyle Evans			stackvars = string_stackvars,
743cf8e5289SKyle Evans			init = string_init,
744cf8e5289SKyle Evans		},
745cf8e5289SKyle Evans		{
746020d003cSKyle Evans			func = "strncpy",
747020d003cSKyle Evans			arguments = {
748020d003cSKyle Evans				"__buf",
749020d003cSKyle Evans				"src",
750020d003cSKyle Evans				"__len",
751020d003cSKyle Evans			},
752020d003cSKyle Evans			exclude = excludes_stack_overflow,
753020d003cSKyle Evans			stackvars = string_stackvars,
754020d003cSKyle Evans			init = string_init,
755020d003cSKyle Evans		},
756020d003cSKyle Evans	},
757020d003cSKyle Evans	strings = {
758020d003cSKyle Evans		-- <strings.h>
759020d003cSKyle Evans		{
760020d003cSKyle Evans			func = "bcopy",
761020d003cSKyle Evans			arguments = {
762020d003cSKyle Evans				"src",
763020d003cSKyle Evans				"__buf",
764020d003cSKyle Evans				"__len",
765020d003cSKyle Evans			},
766020d003cSKyle Evans			exclude = excludes_stack_overflow,
767020d003cSKyle Evans			stackvars = "\tchar src[__len + 10];\n",
768020d003cSKyle Evans		},
769020d003cSKyle Evans		{
770020d003cSKyle Evans			func = "bzero",
771020d003cSKyle Evans			arguments = {
772020d003cSKyle Evans				"__buf",
773020d003cSKyle Evans				"__len",
774020d003cSKyle Evans			},
775020d003cSKyle Evans			exclude = excludes_stack_overflow,
776020d003cSKyle Evans		},
777cf8e5289SKyle Evans		{
778cf8e5289SKyle Evans			func = "explicit_bzero",
779cf8e5289SKyle Evans			arguments = {
780cf8e5289SKyle Evans				"__buf",
781cf8e5289SKyle Evans				"__len",
782cf8e5289SKyle Evans			},
783cf8e5289SKyle Evans			exclude = excludes_stack_overflow,
784cf8e5289SKyle Evans		},
785020d003cSKyle Evans	},
786020d003cSKyle Evans	unistd = {
787020d003cSKyle Evans		-- <unistd.h>
788020d003cSKyle Evans		{
789020d003cSKyle Evans			func = "getcwd",
790020d003cSKyle Evans			bufsize = "8",
791020d003cSKyle Evans			arguments = {
792020d003cSKyle Evans				"__buf",
793020d003cSKyle Evans				"__len",
794020d003cSKyle Evans			},
795020d003cSKyle Evans			exclude = excludes_stack_overflow,
796020d003cSKyle Evans		},
797020d003cSKyle Evans		{
798cf8e5289SKyle Evans			func = "getgrouplist",
799cf8e5289SKyle Evans			bufsize = "4",
800cf8e5289SKyle Evans			buftype = "gid_t[]",
801cf8e5289SKyle Evans			arguments = {
802cf8e5289SKyle Evans				"\"root\"",
803cf8e5289SKyle Evans				"0",
804cf8e5289SKyle Evans				"__buf",
805cf8e5289SKyle Evans				"&intlen",
806cf8e5289SKyle Evans			},
807cf8e5289SKyle Evans			exclude = excludes_stack_overflow,
808cf8e5289SKyle Evans			stackvars = "\tint intlen = (int)__len;\n",
809cf8e5289SKyle Evans			uses_len = true,
810cf8e5289SKyle Evans		},
811cf8e5289SKyle Evans		{
812cf8e5289SKyle Evans			func = "getgroups",
813cf8e5289SKyle Evans			bufsize = "4",
814cf8e5289SKyle Evans			buftype = "gid_t[]",
815cf8e5289SKyle Evans			arguments = {
816cf8e5289SKyle Evans				"__len",
817cf8e5289SKyle Evans				"__buf",
818cf8e5289SKyle Evans			},
819cf8e5289SKyle Evans			exclude = excludes_stack_overflow,
820cf8e5289SKyle Evans		},
821cf8e5289SKyle Evans		{
822cf8e5289SKyle Evans			func = "getloginclass",
823cf8e5289SKyle Evans			arguments = {
824cf8e5289SKyle Evans				"__buf",
825cf8e5289SKyle Evans				"__len",
826cf8e5289SKyle Evans			},
827cf8e5289SKyle Evans			exclude = excludes_stack_overflow,
828cf8e5289SKyle Evans		},
829cf8e5289SKyle Evans		{
830cf8e5289SKyle Evans			func = "pread",
831cf8e5289SKyle Evans			bufsize = "41",
832cf8e5289SKyle Evans			arguments = {
833cf8e5289SKyle Evans				"fd",
834cf8e5289SKyle Evans				"__buf",
835cf8e5289SKyle Evans				"__len",
836cf8e5289SKyle Evans				"0",
837cf8e5289SKyle Evans			},
838cf8e5289SKyle Evans			exclude = excludes_stack_overflow,
839cf8e5289SKyle Evans			stackvars = "\tint fd;\n",
840cf8e5289SKyle Evans			init = [[
841cf8e5289SKyle Evans	fd = new_tmpfile();	/* Cannot fail */
842cf8e5289SKyle Evans]],
843cf8e5289SKyle Evans		},
844cf8e5289SKyle Evans		{
845020d003cSKyle Evans			func = "read",
846020d003cSKyle Evans			bufsize = "41",
847020d003cSKyle Evans			arguments = {
848020d003cSKyle Evans				"fd",
849020d003cSKyle Evans				"__buf",
850020d003cSKyle Evans				"__len",
851020d003cSKyle Evans			},
852020d003cSKyle Evans			exclude = excludes_stack_overflow,
853020d003cSKyle Evans			stackvars = "\tint fd;\n",
854020d003cSKyle Evans			init = [[
855020d003cSKyle Evans	fd = new_tmpfile();	/* Cannot fail */
856020d003cSKyle Evans]],
857020d003cSKyle Evans		},
858020d003cSKyle Evans		{
859020d003cSKyle Evans			func = "readlink",
860020d003cSKyle Evans			arguments = {
861020d003cSKyle Evans				"path",
862020d003cSKyle Evans				"__buf",
863020d003cSKyle Evans				"__len",
864020d003cSKyle Evans			},
865020d003cSKyle Evans			exclude = excludes_stack_overflow,
866020d003cSKyle Evans			stackvars = "\tconst char *path;\n",
867020d003cSKyle Evans			init = [[
868020d003cSKyle Evans	path = new_symlink(__len);		/* Cannot fail */
869020d003cSKyle Evans]],
870020d003cSKyle Evans		},
871cf8e5289SKyle Evans		{
872cf8e5289SKyle Evans			func = "readlinkat",
873cf8e5289SKyle Evans			arguments = {
874cf8e5289SKyle Evans				"AT_FDCWD",
875cf8e5289SKyle Evans				"path",
876cf8e5289SKyle Evans				"__buf",
877cf8e5289SKyle Evans				"__len",
878cf8e5289SKyle Evans			},
879cf8e5289SKyle Evans			exclude = excludes_stack_overflow,
880cf8e5289SKyle Evans			stackvars = "\tconst char *path;\n",
881cf8e5289SKyle Evans			init = [[
882cf8e5289SKyle Evans	path = new_symlink(__len);		/* Cannot fail */
883cf8e5289SKyle Evans]],
884cf8e5289SKyle Evans		},
885cf8e5289SKyle Evans		{
886cf8e5289SKyle Evans			func = "getdomainname",
88722178cb2SKyle Evans			bufsize = #domainname + 1,
888cf8e5289SKyle Evans			arguments = {
889cf8e5289SKyle Evans				"__buf",
890cf8e5289SKyle Evans				"__len",
891cf8e5289SKyle Evans			},
89222178cb2SKyle Evans			need_root = true,
893cf8e5289SKyle Evans			exclude = excludes_stack_overflow,
89422178cb2SKyle Evans			early_init = "	dhost_jail();",
895cf8e5289SKyle Evans		},
896cf8e5289SKyle Evans		{
897cf8e5289SKyle Evans			func = "getentropy",
898cf8e5289SKyle Evans			arguments = {
899cf8e5289SKyle Evans				"__buf",
900cf8e5289SKyle Evans				"__len",
901cf8e5289SKyle Evans			},
902cf8e5289SKyle Evans			exclude = excludes_stack_overflow,
903cf8e5289SKyle Evans		},
904cf8e5289SKyle Evans		{
905cf8e5289SKyle Evans			func = "gethostname",
90622178cb2SKyle Evans			bufsize = #hostname + 1,
907cf8e5289SKyle Evans			arguments = {
908cf8e5289SKyle Evans				"__buf",
909cf8e5289SKyle Evans				"__len",
910cf8e5289SKyle Evans			},
91122178cb2SKyle Evans			need_root = true,
912cf8e5289SKyle Evans			exclude = excludes_stack_overflow,
91322178cb2SKyle Evans			early_init = "	dhost_jail();",
914cf8e5289SKyle Evans		},
915cf8e5289SKyle Evans		{
916cf8e5289SKyle Evans			func = "getlogin_r",
917cf8e5289SKyle Evans			bufsize = "MAXLOGNAME + 1",
918cf8e5289SKyle Evans			arguments = {
919cf8e5289SKyle Evans				"__buf",
920cf8e5289SKyle Evans				"__len",
921cf8e5289SKyle Evans			},
922cf8e5289SKyle Evans			exclude = excludes_stack_overflow,
923cf8e5289SKyle Evans		},
924cf8e5289SKyle Evans		{
925cf8e5289SKyle Evans			func = "ttyname_r",
926cf8e5289SKyle Evans			arguments = {
927cf8e5289SKyle Evans				"fd",
928cf8e5289SKyle Evans				"__buf",
929cf8e5289SKyle Evans				"__len",
930cf8e5289SKyle Evans			},
931cf8e5289SKyle Evans			exclude = excludes_stack_overflow,
932cf8e5289SKyle Evans			stackvars = "\tint fd;\n",
933cf8e5289SKyle Evans			early_init = [[
934cf8e5289SKyle Evans	fd = STDIN_FILENO;
935cf8e5289SKyle Evans	if (!isatty(fd))
936cf8e5289SKyle Evans		atf_tc_skip("stdin is not an fd");
937cf8e5289SKyle Evans]]
938cf8e5289SKyle Evans		},
939020d003cSKyle Evans	},
940b53d7aa8SKyle Evans	wchar = {
941b53d7aa8SKyle Evans		-- <wchar.h>
942b53d7aa8SKyle Evans		{
943b53d7aa8SKyle Evans			func = "wmemcpy",
944b53d7aa8SKyle Evans			buftype = "wchar_t[]",
945b53d7aa8SKyle Evans			arguments = {
946b53d7aa8SKyle Evans				"__buf",
947b53d7aa8SKyle Evans				"src",
948b53d7aa8SKyle Evans				"__len",
949b53d7aa8SKyle Evans			},
950b53d7aa8SKyle Evans			exclude = excludes_stack_overflow,
951b53d7aa8SKyle Evans			stackvars = "\twchar_t src[__len + 10];\n",
952b53d7aa8SKyle Evans		},
953b53d7aa8SKyle Evans		{
954b53d7aa8SKyle Evans			func = "wmempcpy",
955b53d7aa8SKyle Evans			buftype = "wchar_t[]",
956b53d7aa8SKyle Evans			arguments = {
957b53d7aa8SKyle Evans				"__buf",
958b53d7aa8SKyle Evans				"src",
959b53d7aa8SKyle Evans				"__len",
960b53d7aa8SKyle Evans			},
961b53d7aa8SKyle Evans			exclude = excludes_stack_overflow,
962b53d7aa8SKyle Evans			stackvars = "\twchar_t src[__len + 10];\n",
963b53d7aa8SKyle Evans		},
964b53d7aa8SKyle Evans		{
965b53d7aa8SKyle Evans			func = "wmemmove",
966b53d7aa8SKyle Evans			buftype = "wchar_t[]",
967b53d7aa8SKyle Evans			arguments = {
968b53d7aa8SKyle Evans				"__buf",
969b53d7aa8SKyle Evans				"src",
970b53d7aa8SKyle Evans				"__len",
971b53d7aa8SKyle Evans			},
972b53d7aa8SKyle Evans			exclude = excludes_stack_overflow,
973b53d7aa8SKyle Evans			stackvars = "\twchar_t src[__len + 10];\n",
974b53d7aa8SKyle Evans		},
975b53d7aa8SKyle Evans		{
976b53d7aa8SKyle Evans			func = "wmemset",
977b53d7aa8SKyle Evans			buftype = "wchar_t[]",
978b53d7aa8SKyle Evans			arguments = {
979b53d7aa8SKyle Evans				"__buf",
980b53d7aa8SKyle Evans				"L'0'",
981b53d7aa8SKyle Evans				"__len",
982b53d7aa8SKyle Evans			},
983b53d7aa8SKyle Evans			exclude = excludes_stack_overflow,
984b53d7aa8SKyle Evans		},
985b53d7aa8SKyle Evans		{
986b53d7aa8SKyle Evans			func = "wcpcpy",
987b53d7aa8SKyle Evans			buftype = "wchar_t[]",
988b53d7aa8SKyle Evans			arguments = {
989b53d7aa8SKyle Evans				"__buf",
990b53d7aa8SKyle Evans				"src",
991b53d7aa8SKyle Evans			},
992b53d7aa8SKyle Evans			exclude = excludes_stack_overflow,
993b53d7aa8SKyle Evans			stackvars = wstring_stackvars,
994b53d7aa8SKyle Evans			init = wstring_init,
995b53d7aa8SKyle Evans			uses_len = true,
996b53d7aa8SKyle Evans		},
997b53d7aa8SKyle Evans		{
998b53d7aa8SKyle Evans			func = "wcpncpy",
999b53d7aa8SKyle Evans			buftype = "wchar_t[]",
1000b53d7aa8SKyle Evans			arguments = {
1001b53d7aa8SKyle Evans				"__buf",
1002b53d7aa8SKyle Evans				"src",
1003b53d7aa8SKyle Evans				"__len",
1004b53d7aa8SKyle Evans			},
1005b53d7aa8SKyle Evans			exclude = excludes_stack_overflow,
1006b53d7aa8SKyle Evans			stackvars = wstring_stackvars,
1007b53d7aa8SKyle Evans			init = wstring_init,
1008b53d7aa8SKyle Evans		},
1009b53d7aa8SKyle Evans		{
1010b53d7aa8SKyle Evans			func = "wcscat",
1011b53d7aa8SKyle Evans			buftype = "wchar_t[]",
1012b53d7aa8SKyle Evans			arguments = {
1013b53d7aa8SKyle Evans				"__buf",
1014b53d7aa8SKyle Evans				"src",
1015b53d7aa8SKyle Evans			},
1016b53d7aa8SKyle Evans			exclude = excludes_stack_overflow,
1017b53d7aa8SKyle Evans			stackvars = wstring_stackvars,
1018b53d7aa8SKyle Evans			init = wstring_init,
1019b53d7aa8SKyle Evans			uses_len = true,
1020b53d7aa8SKyle Evans		},
1021b53d7aa8SKyle Evans		{
1022b53d7aa8SKyle Evans			func = "wcslcat",
1023b53d7aa8SKyle Evans			buftype = "wchar_t[]",
1024b53d7aa8SKyle Evans			arguments = {
1025b53d7aa8SKyle Evans				"__buf",
1026b53d7aa8SKyle Evans				"src",
1027b53d7aa8SKyle Evans				"__len",
1028b53d7aa8SKyle Evans			},
1029b53d7aa8SKyle Evans			exclude = excludes_stack_overflow,
1030b53d7aa8SKyle Evans			stackvars = wstring_stackvars,
1031b53d7aa8SKyle Evans			init = wstring_init,
1032b53d7aa8SKyle Evans		},
1033b53d7aa8SKyle Evans		{
1034b53d7aa8SKyle Evans			func = "wcsncat",
1035b53d7aa8SKyle Evans			buftype = "wchar_t[]",
1036b53d7aa8SKyle Evans			arguments = {
1037b53d7aa8SKyle Evans				"__buf",
1038b53d7aa8SKyle Evans				"src",
1039b53d7aa8SKyle Evans				"__len",
1040b53d7aa8SKyle Evans			},
1041b53d7aa8SKyle Evans			exclude = excludes_stack_overflow,
1042b53d7aa8SKyle Evans			stackvars = wstring_stackvars,
1043b53d7aa8SKyle Evans			init = wstring_init,
1044b53d7aa8SKyle Evans		},
1045b53d7aa8SKyle Evans		{
1046b53d7aa8SKyle Evans			func = "wcscpy",
1047b53d7aa8SKyle Evans			buftype = "wchar_t[]",
1048b53d7aa8SKyle Evans			arguments = {
1049b53d7aa8SKyle Evans				"__buf",
1050b53d7aa8SKyle Evans				"src",
1051b53d7aa8SKyle Evans			},
1052b53d7aa8SKyle Evans			exclude = excludes_stack_overflow,
1053b53d7aa8SKyle Evans			stackvars = wstring_stackvars,
1054b53d7aa8SKyle Evans			init = wstring_init,
1055b53d7aa8SKyle Evans			uses_len = true,
1056b53d7aa8SKyle Evans		},
1057b53d7aa8SKyle Evans		{
1058b53d7aa8SKyle Evans			func = "wcslcpy",
1059b53d7aa8SKyle Evans			buftype = "wchar_t[]",
1060b53d7aa8SKyle Evans			arguments = {
1061b53d7aa8SKyle Evans				"__buf",
1062b53d7aa8SKyle Evans				"src",
1063b53d7aa8SKyle Evans				"__len",
1064b53d7aa8SKyle Evans			},
1065b53d7aa8SKyle Evans			exclude = excludes_stack_overflow,
1066b53d7aa8SKyle Evans			stackvars = wstring_stackvars,
1067b53d7aa8SKyle Evans			init = wstring_init,
1068b53d7aa8SKyle Evans		},
1069b53d7aa8SKyle Evans		{
1070b53d7aa8SKyle Evans			func = "wcsncpy",
1071b53d7aa8SKyle Evans			buftype = "wchar_t[]",
1072b53d7aa8SKyle Evans			arguments = {
1073b53d7aa8SKyle Evans				"__buf",
1074b53d7aa8SKyle Evans				"src",
1075b53d7aa8SKyle Evans				"__len",
1076b53d7aa8SKyle Evans			},
1077b53d7aa8SKyle Evans			exclude = excludes_stack_overflow,
1078b53d7aa8SKyle Evans			stackvars = wstring_stackvars,
1079b53d7aa8SKyle Evans			init = wstring_init,
1080b53d7aa8SKyle Evans		},
1081b53d7aa8SKyle Evans	},
1082020d003cSKyle Evans}
1083020d003cSKyle Evans
108409cdbf04SKyle Evanslocal function write_test_boilerplate(fh, name, body, def)
108509cdbf04SKyle Evans	fh:write("ATF_TC(" .. name .. ");\n")
108609cdbf04SKyle Evans	fh:write("ATF_TC_HEAD(" .. name .. ", tc)\n")
108709cdbf04SKyle Evans	fh:write("{\n")
108809cdbf04SKyle Evans	if def.need_root then
108909cdbf04SKyle Evans		fh:write("	atf_tc_set_md_var(tc, \"require.user\", \"root\");\n")
109009cdbf04SKyle Evans	end
109109cdbf04SKyle Evans	fh:write("}\n")
109209cdbf04SKyle Evans
1093020d003cSKyle Evans	fh:write("ATF_TC_BODY(" .. name .. ", tc)\n")
1094020d003cSKyle Evans	fh:write("{\n" .. body .. "\n}\n\n")
1095020d003cSKyle Evans	return name
1096020d003cSKyle Evansend
1097020d003cSKyle Evans
1098020d003cSKyle Evanslocal function generate_test_name(func, variant, disposition, heap)
1099020d003cSKyle Evans	local basename = func
1100020d003cSKyle Evans	if variant then
1101020d003cSKyle Evans		basename = basename .. "_" .. variant
1102020d003cSKyle Evans	end
1103020d003cSKyle Evans	if heap then
1104020d003cSKyle Evans		basename = basename .. "_heap"
1105020d003cSKyle Evans	end
1106020d003cSKyle Evans	if disposition < 0 then
1107020d003cSKyle Evans		return basename .. "_before_end"
1108020d003cSKyle Evans	elseif disposition == 0 then
1109020d003cSKyle Evans		return basename .. "_end"
1110020d003cSKyle Evans	else
1111020d003cSKyle Evans		return basename .. "_after_end"
1112020d003cSKyle Evans	end
1113020d003cSKyle Evansend
1114020d003cSKyle Evans
1115020d003cSKyle Evanslocal function array_type(buftype)
1116020d003cSKyle Evans	if not buftype:match("%[%]") then
1117020d003cSKyle Evans		return nil
1118020d003cSKyle Evans	end
1119020d003cSKyle Evans
1120020d003cSKyle Evans	return buftype:gsub("%[%]", "")
1121020d003cSKyle Evansend
1122020d003cSKyle Evans
1123020d003cSKyle Evanslocal function configurable(def, idx)
1124020d003cSKyle Evans	local cfgitem = def[idx]
1125020d003cSKyle Evans
1126020d003cSKyle Evans	if not cfgitem then
1127020d003cSKyle Evans		return nil
1128020d003cSKyle Evans	end
1129020d003cSKyle Evans
1130020d003cSKyle Evans	if type(cfgitem) == "function" then
1131020d003cSKyle Evans		return cfgitem()
1132020d003cSKyle Evans	end
1133020d003cSKyle Evans
1134020d003cSKyle Evans	return cfgitem
1135020d003cSKyle Evansend
1136020d003cSKyle Evans
1137020d003cSKyle Evanslocal function generate_stackframe(buftype, bufsize, disposition, heap, def)
113885242b59SKyle Evans	local function len_offset(inverted)
1139020d003cSKyle Evans		-- Tests that don't use __len in their arguments may use an
1140020d003cSKyle Evans		-- inverted sense because we can't just specify a length that
1141020d003cSKyle Evans		-- would induce an access just after the end.  Instead, we have
1142020d003cSKyle Evans		-- to manipulate the buffer size to be too short so that the
1143020d003cSKyle Evans		-- function under test would write one too many.
1144020d003cSKyle Evans		if disposition < 0 then
1145020d003cSKyle Evans			return ((inverted and " + ") or " - ") .. "1"
1146020d003cSKyle Evans		elseif disposition == 0 then
1147020d003cSKyle Evans			return ""
1148020d003cSKyle Evans		else
1149020d003cSKyle Evans			return ((inverted and " - ") or " + ") .. "1"
1150020d003cSKyle Evans		end
1151020d003cSKyle Evans	end
1152020d003cSKyle Evans
115385242b59SKyle Evans	local function test_uses_len()
1154020d003cSKyle Evans		if def.uses_len then
1155020d003cSKyle Evans			return true
1156020d003cSKyle Evans		end
1157020d003cSKyle Evans
1158020d003cSKyle Evans		for _, arg in ipairs(def.arguments) do
1159020d003cSKyle Evans			if arg:match("__len") or arg:match("__idx") then
1160020d003cSKyle Evans				return true
1161020d003cSKyle Evans			end
1162020d003cSKyle Evans		end
1163020d003cSKyle Evans
1164020d003cSKyle Evans		return false
1165020d003cSKyle Evans	end
1166020d003cSKyle Evans
1167020d003cSKyle Evans
1168020d003cSKyle Evans	-- This is perhaps a little convoluted, but we toss the buffer into a
1169020d003cSKyle Evans	-- struct on the stack to guarantee that we have at least one valid
1170020d003cSKyle Evans	-- byte on either side of the buffer -- a measure to make sure that
1171020d003cSKyle Evans	-- we're tripping _FORTIFY_SOURCE specifically in the buffer + 1 case,
1172020d003cSKyle Evans	-- rather than some other stack or memory protection.
1173020d003cSKyle Evans	local vars = "\tstruct {\n"
1174020d003cSKyle Evans	vars = vars .. "\t\tuint8_t padding_l;\n"
1175020d003cSKyle Evans
117685242b59SKyle Evans	local uses_len = test_uses_len()
117785242b59SKyle Evans	local bufsize_offset = len_offset(not uses_len)
1178020d003cSKyle Evans	local buftype_elem = array_type(buftype)
1179020d003cSKyle Evans	local size_expr = bufsize
1180020d003cSKyle Evans
1181020d003cSKyle Evans	if not uses_len then
1182020d003cSKyle Evans		-- If the length isn't in use, we have to vary the buffer size
1183020d003cSKyle Evans		-- since the fortified function likely has some internal size
1184020d003cSKyle Evans		-- constraint that it's supposed to be checking.
1185020d003cSKyle Evans		size_expr = size_expr .. bufsize_offset
1186020d003cSKyle Evans	end
1187020d003cSKyle Evans
1188020d003cSKyle Evans	if not heap and buftype_elem then
1189020d003cSKyle Evans		-- Array type: size goes after identifier
1190020d003cSKyle Evans		vars = vars .. "\t\t" .. buftype_elem ..
1191020d003cSKyle Evans		    " __buf[" .. size_expr .. "];\n"
1192020d003cSKyle Evans	else
1193020d003cSKyle Evans		local basic_type = buftype_elem or buftype
1194020d003cSKyle Evans
1195020d003cSKyle Evans		-- Heap tests obviously just put a pointer on the stack that
1196020d003cSKyle Evans		-- points to our new allocation, but we leave it in the padded
1197020d003cSKyle Evans		-- struct just to simplify our generator.
1198020d003cSKyle Evans		if heap then
1199020d003cSKyle Evans			basic_type = basic_type .. " *"
1200020d003cSKyle Evans		end
1201020d003cSKyle Evans		vars = vars .. "\t\t" .. basic_type .. " __buf;\n"
1202020d003cSKyle Evans	end
1203020d003cSKyle Evans
1204020d003cSKyle Evans	-- padding_r is our just-past-the-end padding that we use to make sure
1205020d003cSKyle Evans	-- that there's a valid portion after the buffer that isn't being
1206020d003cSKyle Evans	-- included in our function calls.  If we didn't have it, then we'd have
1207020d003cSKyle Evans	-- a hard time feeling confident that an abort on the just-after tests
1208020d003cSKyle Evans	-- isn't maybe from some other memory or stack protection.
1209020d003cSKyle Evans	vars = vars .. "\t\tuint8_t padding_r;\n"
1210020d003cSKyle Evans	vars = vars .. "\t} __stack;\n"
1211020d003cSKyle Evans
1212020d003cSKyle Evans	-- Not all tests will use __bufsz, but some do for, e.g., clearing
1213020d003cSKyle Evans	-- memory..
1214020d003cSKyle Evans	vars = vars .. "\tconst size_t __bufsz __unused = "
1215020d003cSKyle Evans	if heap then
1216020d003cSKyle Evans		local scalar = 1
1217020d003cSKyle Evans		if buftype_elem then
1218020d003cSKyle Evans			scalar = size_expr
1219020d003cSKyle Evans		end
1220020d003cSKyle Evans
1221020d003cSKyle Evans		vars = vars .. "sizeof(*__stack.__buf) * (" .. scalar .. ");\n"
1222020d003cSKyle Evans	else
1223020d003cSKyle Evans		vars = vars .. "sizeof(__stack.__buf);\n"
1224020d003cSKyle Evans	end
1225020d003cSKyle Evans
1226020d003cSKyle Evans	vars = vars .. "\tconst size_t __len = " .. bufsize ..
1227020d003cSKyle Evans	    bufsize_offset .. ";\n"
1228020d003cSKyle Evans	vars = vars .. "\tconst size_t __idx __unused = __len - 1;\n"
1229020d003cSKyle Evans
1230020d003cSKyle Evans	-- For overflow testing, we need to fork() because we're expecting the
1231020d003cSKyle Evans	-- test to ultimately abort()/_exit().  Then we can collect the exit
1232020d003cSKyle Evans	-- status and report appropriately.
1233020d003cSKyle Evans	if disposition > 0 then
1234020d003cSKyle Evans		vars = vars .. "\tpid_t __child;\n"
1235020d003cSKyle Evans		vars = vars .. "\tint __status;\n"
1236020d003cSKyle Evans	end
1237020d003cSKyle Evans
1238020d003cSKyle Evans	-- Any other stackvars defined by the test get placed after everything
1239020d003cSKyle Evans	-- else.
1240020d003cSKyle Evans	vars = vars .. (configurable(def, "stackvars") or "")
1241020d003cSKyle Evans
1242020d003cSKyle Evans	return vars
1243020d003cSKyle Evansend
1244020d003cSKyle Evans
1245020d003cSKyle Evanslocal function write_test(fh, func, disposition, heap, def)
1246020d003cSKyle Evans	local testname = generate_test_name(func, def.variant, disposition, heap)
1247020d003cSKyle Evans	local buftype = def.buftype or "unsigned char[]"
1248020d003cSKyle Evans	local bufsize = def.bufsize or 42
1249020d003cSKyle Evans	local body = ""
1250020d003cSKyle Evans
1251020d003cSKyle Evans	if def.exclude and def.exclude(disposition, heap) then
1252020d003cSKyle Evans		return
1253020d003cSKyle Evans	end
1254020d003cSKyle Evans
125585242b59SKyle Evans	local function need_addr()
1256020d003cSKyle Evans		return not (buftype:match("%[%]") or buftype:match("%*"))
1257020d003cSKyle Evans	end
1258020d003cSKyle Evans
1259020d003cSKyle Evans	if heap then
1260020d003cSKyle Evans		body = body .. "#define BUF __stack.__buf\n"
1261020d003cSKyle Evans	else
1262020d003cSKyle Evans		body = body .. "#define BUF &__stack.__buf\n"
1263020d003cSKyle Evans	end
1264020d003cSKyle Evans
1265020d003cSKyle Evans	-- Setup the buffer
1266020d003cSKyle Evans	body = body .. generate_stackframe(buftype, bufsize, disposition, heap, def) ..
1267020d003cSKyle Evans	    "\n"
1268020d003cSKyle Evans
1269020d003cSKyle Evans	-- Any early initialization goes before we would fork for the just-after
1270020d003cSKyle Evans	-- tests, because they may want to skip the test based on some criteria
1271020d003cSKyle Evans	-- and we can't propagate that up very easily once we're forked.
1272020d003cSKyle Evans	local early_init = configurable(def, "early_init")
1273020d003cSKyle Evans	body = body .. (early_init or "")
1274020d003cSKyle Evans	if early_init then
1275020d003cSKyle Evans		body = body .. "\n"
1276020d003cSKyle Evans	end
1277020d003cSKyle Evans
1278020d003cSKyle Evans	-- Fork off, iff we're testing some access past the end of the buffer.
1279020d003cSKyle Evans	if disposition > 0 then
1280020d003cSKyle Evans		body = body .. [[
1281020d003cSKyle Evans	__child = fork();
1282020d003cSKyle Evans	ATF_REQUIRE(__child >= 0);
1283020d003cSKyle Evans	if (__child > 0)
1284020d003cSKyle Evans		goto monitor;
1285020d003cSKyle Evans
1286020d003cSKyle Evans	/* Child */
1287020d003cSKyle Evans	disable_coredumps();
1288020d003cSKyle Evans]]
1289020d003cSKyle Evans	end
1290020d003cSKyle Evans
1291020d003cSKyle Evans	local bufvar = "__stack.__buf"
1292020d003cSKyle Evans	if heap then
1293020d003cSKyle Evans		-- Buffer needs to be initialized because it's a heap allocation.
1294020d003cSKyle Evans		body = body .. "\t" .. bufvar .. " = malloc(__bufsz);\n"
1295020d003cSKyle Evans	end
1296020d003cSKyle Evans
1297020d003cSKyle Evans	-- Non-early init happens just after the fork in the child, not the
1298020d003cSKyle Evans	-- monitor.  This is used to setup any other buffers we may need, for
1299020d003cSKyle Evans	-- instance.
1300020d003cSKyle Evans	local extra_init = configurable(def, "init")
1301020d003cSKyle Evans	body = body .. (extra_init or "")
1302020d003cSKyle Evans
1303020d003cSKyle Evans	if heap or extra_init then
1304020d003cSKyle Evans		body = body .. "\n"
1305020d003cSKyle Evans	end
1306020d003cSKyle Evans
1307020d003cSKyle Evans	-- Setup the function call with arguments as described in the test
1308020d003cSKyle Evans	-- definition.
1309020d003cSKyle Evans	body = body .. "\t" .. func .. "("
1310020d003cSKyle Evans
1311020d003cSKyle Evans	for idx, arg in ipairs(def.arguments) do
1312020d003cSKyle Evans		if idx > 1 then
1313020d003cSKyle Evans			body = body .. ", "
1314020d003cSKyle Evans		end
1315020d003cSKyle Evans
1316020d003cSKyle Evans		if arg == "__buf" then
131785242b59SKyle Evans			if not heap and need_addr() then
1318020d003cSKyle Evans				body = body .. "&"
1319020d003cSKyle Evans			end
1320020d003cSKyle Evans
1321020d003cSKyle Evans			body = body .. bufvar
1322020d003cSKyle Evans		else
1323020d003cSKyle Evans			local argname = arg
1324020d003cSKyle Evans
1325020d003cSKyle Evans			if def.value_of then
1326020d003cSKyle Evans				argname = argname or def.value_of(arg)
1327020d003cSKyle Evans			end
1328020d003cSKyle Evans
1329020d003cSKyle Evans			body = body .. argname
1330020d003cSKyle Evans		end
1331020d003cSKyle Evans	end
1332020d003cSKyle Evans
1333020d003cSKyle Evans	body = body .. ");\n"
1334020d003cSKyle Evans
1335020d003cSKyle Evans	-- Monitor stuff follows, for OOB access.
1336020d003cSKyle Evans	if disposition <= 0 then
1337020d003cSKyle Evans		goto skip
1338020d003cSKyle Evans	end
1339020d003cSKyle Evans
1340020d003cSKyle Evans	body = body .. [[
1341020d003cSKyle Evans	_exit(EX_SOFTWARE);	/* Should have aborted. */
1342020d003cSKyle Evans
1343020d003cSKyle Evansmonitor:
1344020d003cSKyle Evans	while (waitpid(__child, &__status, 0) != __child) {
1345020d003cSKyle Evans		ATF_REQUIRE_EQ(EINTR, errno);
1346020d003cSKyle Evans	}
1347020d003cSKyle Evans
1348020d003cSKyle Evans	if (!WIFSIGNALED(__status)) {
1349020d003cSKyle Evans		switch (WEXITSTATUS(__status)) {
1350020d003cSKyle Evans		case EX_SOFTWARE:
1351020d003cSKyle Evans			atf_tc_fail("FORTIFY_SOURCE failed to abort");
1352020d003cSKyle Evans			break;
1353020d003cSKyle Evans		case EX_OSERR:
1354020d003cSKyle Evans			atf_tc_fail("setrlimit(2) failed");
1355020d003cSKyle Evans			break;
1356020d003cSKyle Evans		default:
1357020d003cSKyle Evans			atf_tc_fail("child exited with status %d",
1358020d003cSKyle Evans			    WEXITSTATUS(__status));
1359020d003cSKyle Evans		}
1360020d003cSKyle Evans	} else {
1361020d003cSKyle Evans		ATF_REQUIRE_EQ(SIGABRT, WTERMSIG(__status));
1362020d003cSKyle Evans	}
1363020d003cSKyle Evans]]
1364020d003cSKyle Evans
1365020d003cSKyle Evans::skip::
1366020d003cSKyle Evans	body = body .. "#undef BUF\n"
136709cdbf04SKyle Evans	return write_test_boilerplate(fh, testname, body, def)
1368020d003cSKyle Evansend
1369020d003cSKyle Evans
1370020d003cSKyle Evans-- main()
1371020d003cSKyle Evanslocal tests
1372020d003cSKyle Evanslocal tcat = assert(arg[1], "usage: generate-fortify-tests.lua <category>")
1373020d003cSKyle Evansfor k, defs in pairs(all_tests) do
1374020d003cSKyle Evans	if k == tcat then
1375020d003cSKyle Evans		tests = defs
1376020d003cSKyle Evans		break
1377020d003cSKyle Evans	end
1378020d003cSKyle Evansend
1379020d003cSKyle Evans
1380020d003cSKyle Evansassert(tests, "category " .. tcat .. " not found")
1381020d003cSKyle Evans
1382020d003cSKyle Evanslocal fh = io.stdout
1383020d003cSKyle Evansfh:write("/* @" .. "generated" .. " by `generate-fortify-tests.lua \"" ..
1384020d003cSKyle Evans    tcat .. "\"` */\n\n")
1385020d003cSKyle Evansfh:write("#define	_FORTIFY_SOURCE	2\n")
1386020d003cSKyle Evansfh:write("#define	TMPFILE_SIZE	(1024 * 32)\n")
1387020d003cSKyle Evans
1388020d003cSKyle Evansfh:write("\n")
1389020d003cSKyle Evansfor _, inc in ipairs(includes) do
1390020d003cSKyle Evans	fh:write("#include <" .. inc .. ">\n")
1391020d003cSKyle Evansend
1392020d003cSKyle Evans
1393020d003cSKyle Evansfh:write([[
1394020d003cSKyle Evans
1395cf8e5289SKyle Evansstatic FILE * __unused
1396cf8e5289SKyle Evansnew_fp(size_t __len)
1397cf8e5289SKyle Evans{
1398cf8e5289SKyle Evans	static char fpbuf[LINE_MAX];
1399cf8e5289SKyle Evans	FILE *fp;
1400cf8e5289SKyle Evans
1401cf8e5289SKyle Evans	ATF_REQUIRE(__len <= sizeof(fpbuf));
1402cf8e5289SKyle Evans
1403cf8e5289SKyle Evans	memset(fpbuf, 'A', sizeof(fpbuf) - 1);
1404cf8e5289SKyle Evans	fpbuf[sizeof(fpbuf) - 1] = '\0';
1405cf8e5289SKyle Evans
1406cf8e5289SKyle Evans	fp = fmemopen(fpbuf, sizeof(fpbuf), "rb");
1407cf8e5289SKyle Evans	ATF_REQUIRE(fp != NULL);
1408cf8e5289SKyle Evans
1409cf8e5289SKyle Evans	return (fp);
1410cf8e5289SKyle Evans}
1411cf8e5289SKyle Evans
1412020d003cSKyle Evans/*
1413020d003cSKyle Evans * Create a new symlink to use for readlink(2) style tests, we'll just use a
1414020d003cSKyle Evans * random target name to have something interesting to look at.
1415020d003cSKyle Evans */
1416020d003cSKyle Evansstatic const char * __unused
1417020d003cSKyle Evansnew_symlink(size_t __len)
1418020d003cSKyle Evans{
1419020d003cSKyle Evans	static const char linkname[] = "link";
1420020d003cSKyle Evans	char target[MAXNAMLEN];
1421020d003cSKyle Evans	int error;
1422020d003cSKyle Evans
1423020d003cSKyle Evans	ATF_REQUIRE(__len <= sizeof(target));
1424020d003cSKyle Evans
1425020d003cSKyle Evans	arc4random_buf(target, sizeof(target));
1426020d003cSKyle Evans
1427020d003cSKyle Evans	error = unlink(linkname);
1428020d003cSKyle Evans	ATF_REQUIRE(error == 0 || errno == ENOENT);
1429020d003cSKyle Evans
1430020d003cSKyle Evans	error = symlink(target, linkname);
1431020d003cSKyle Evans	ATF_REQUIRE(error == 0);
1432020d003cSKyle Evans
1433020d003cSKyle Evans	return (linkname);
1434020d003cSKyle Evans}
1435020d003cSKyle Evans
1436020d003cSKyle Evans/*
14371f155d48SKyle Evans * For our purposes, first descriptor will be the reader; we'll send both
14381f155d48SKyle Evans * raw data and a control message over it so that the result can be used for
14391f155d48SKyle Evans * any of our recv*() tests.
14401f155d48SKyle Evans */
14411f155d48SKyle Evansstatic void __unused
14421f155d48SKyle Evansnew_socket(int sock[2])
14431f155d48SKyle Evans{
14441f155d48SKyle Evans	unsigned char ctrl[CMSG_SPACE(sizeof(int))] = { 0 };
14451f155d48SKyle Evans	static char sockbuf[256];
14461f155d48SKyle Evans	ssize_t rv;
14471f155d48SKyle Evans	size_t total = 0;
14481f155d48SKyle Evans	struct msghdr hdr = { 0 };
14491f155d48SKyle Evans	struct cmsghdr *cmsg;
14501f155d48SKyle Evans	int error, fd;
14511f155d48SKyle Evans
14521f155d48SKyle Evans	error = socketpair(AF_UNIX, SOCK_STREAM, 0, sock);
14531f155d48SKyle Evans	ATF_REQUIRE(error == 0);
14541f155d48SKyle Evans
14551f155d48SKyle Evans	while (total != sizeof(sockbuf)) {
14561f155d48SKyle Evans		rv = send(sock[1], &sockbuf[total], sizeof(sockbuf) - total, 0);
14571f155d48SKyle Evans
14581f155d48SKyle Evans		ATF_REQUIRE_MSG(rv > 0,
14591f155d48SKyle Evans		    "expected bytes sent, got %zd with %zu left (size %zu, total %zu)",
14601f155d48SKyle Evans		    rv, sizeof(sockbuf) - total, sizeof(sockbuf), total);
14611f155d48SKyle Evans		ATF_REQUIRE_MSG(total + (size_t)rv <= sizeof(sockbuf),
14621f155d48SKyle Evans		    "%zd exceeds total %zu", rv, sizeof(sockbuf));
14631f155d48SKyle Evans		total += rv;
14641f155d48SKyle Evans	}
14651f155d48SKyle Evans
14661f155d48SKyle Evans	hdr.msg_control = ctrl;
14671f155d48SKyle Evans	hdr.msg_controllen = sizeof(ctrl);
14681f155d48SKyle Evans
14691f155d48SKyle Evans	cmsg = CMSG_FIRSTHDR(&hdr);
14701f155d48SKyle Evans	cmsg->cmsg_level = SOL_SOCKET;
14711f155d48SKyle Evans	cmsg->cmsg_type = SCM_RIGHTS;
14721f155d48SKyle Evans	cmsg->cmsg_len = CMSG_LEN(sizeof(fd));
14731f155d48SKyle Evans	fd = STDIN_FILENO;
14741f155d48SKyle Evans	memcpy(CMSG_DATA(cmsg), &fd, sizeof(fd));
14751f155d48SKyle Evans
14761f155d48SKyle Evans	error = sendmsg(sock[1], &hdr, 0);
14771f155d48SKyle Evans	ATF_REQUIRE(error != -1);
14781f155d48SKyle Evans}
14791f155d48SKyle Evans
14801f155d48SKyle Evans/*
1481020d003cSKyle Evans * Constructs a tmpfile that we can use for testing read(2) and friends.
1482020d003cSKyle Evans */
1483020d003cSKyle Evansstatic int __unused
1484020d003cSKyle Evansnew_tmpfile(void)
1485020d003cSKyle Evans{
1486020d003cSKyle Evans	char buf[1024];
1487020d003cSKyle Evans	ssize_t rv;
1488020d003cSKyle Evans	size_t written;
1489020d003cSKyle Evans	int fd;
1490020d003cSKyle Evans
1491020d003cSKyle Evans	fd = open("tmpfile", O_RDWR | O_CREAT | O_TRUNC, 0644);
1492020d003cSKyle Evans	ATF_REQUIRE(fd >= 0);
1493020d003cSKyle Evans
1494020d003cSKyle Evans	written = 0;
1495020d003cSKyle Evans	while (written < TMPFILE_SIZE) {
1496020d003cSKyle Evans		rv = write(fd, buf, sizeof(buf));
1497020d003cSKyle Evans		ATF_REQUIRE(rv > 0);
1498020d003cSKyle Evans
1499020d003cSKyle Evans		written += rv;
1500020d003cSKyle Evans	}
1501020d003cSKyle Evans
1502020d003cSKyle Evans	ATF_REQUIRE_EQ(0, lseek(fd, 0, SEEK_SET));
1503020d003cSKyle Evans	return (fd);
1504020d003cSKyle Evans}
1505020d003cSKyle Evans
1506020d003cSKyle Evansstatic void
1507020d003cSKyle Evansdisable_coredumps(void)
1508020d003cSKyle Evans{
1509020d003cSKyle Evans	struct rlimit rl = { 0 };
1510020d003cSKyle Evans
1511020d003cSKyle Evans	if (setrlimit(RLIMIT_CORE, &rl) == -1)
1512020d003cSKyle Evans		_exit(EX_OSERR);
1513020d003cSKyle Evans}
1514020d003cSKyle Evans
1515cf8e5289SKyle Evans/*
1516cf8e5289SKyle Evans * Replaces stdin with a file that we can actually read from, for tests where
1517cf8e5289SKyle Evans * we want a FILE * or fd that we can get data from.
1518cf8e5289SKyle Evans */
1519cf8e5289SKyle Evansstatic void __unused
1520cf8e5289SKyle Evansreplace_stdin(void)
1521cf8e5289SKyle Evans{
1522cf8e5289SKyle Evans	int fd;
1523cf8e5289SKyle Evans
1524cf8e5289SKyle Evans	fd = new_tmpfile();
1525cf8e5289SKyle Evans
1526cf8e5289SKyle Evans	(void)dup2(fd, STDIN_FILENO);
1527cf8e5289SKyle Evans	if (fd != STDIN_FILENO)
1528cf8e5289SKyle Evans		close(fd);
1529cf8e5289SKyle Evans}
1530cf8e5289SKyle Evans
1531020d003cSKyle Evans]])
1532020d003cSKyle Evans
153322178cb2SKyle Evansif tcat == "unistd" then
153422178cb2SKyle Evans	fh:write("#define	JAIL_HOSTNAME	\"" .. hostname .. "\"\n")
153522178cb2SKyle Evans	fh:write("#define	JAIL_DOMAINNAME	\"" .. domainname .. "\"\n")
153622178cb2SKyle Evans	fh:write([[
153722178cb2SKyle Evansstatic void
153822178cb2SKyle Evansdhost_jail(void)
153922178cb2SKyle Evans{
154022178cb2SKyle Evans	struct iovec iov[4];
154122178cb2SKyle Evans	int jid;
154222178cb2SKyle Evans
154322178cb2SKyle Evans	iov[0].iov_base = __DECONST(char *, "host.hostname");
154422178cb2SKyle Evans	iov[0].iov_len = sizeof("host.hostname");
154522178cb2SKyle Evans	iov[1].iov_base = __DECONST(char *, JAIL_HOSTNAME);
154622178cb2SKyle Evans	iov[1].iov_len = sizeof(JAIL_HOSTNAME);
154722178cb2SKyle Evans	iov[2].iov_base = __DECONST(char *, "host.domainname");
154822178cb2SKyle Evans	iov[2].iov_len = sizeof("host.domainname");
154922178cb2SKyle Evans	iov[3].iov_base = __DECONST(char *, JAIL_DOMAINNAME);
155022178cb2SKyle Evans	iov[3].iov_len = sizeof(JAIL_DOMAINNAME);
155122178cb2SKyle Evans
155222178cb2SKyle Evans	jid = jail_set(iov, nitems(iov), JAIL_CREATE | JAIL_ATTACH);
155322178cb2SKyle Evans	ATF_REQUIRE_MSG(jid > 0, "Jail creation failed: %s", strerror(errno));
155422178cb2SKyle Evans}
155522178cb2SKyle Evans
155622178cb2SKyle Evans]])
155722178cb2SKyle Evansend
155822178cb2SKyle Evans
1559020d003cSKyle Evansfor _, def in pairs(tests) do
1560020d003cSKyle Evans	local func = def.func
1561020d003cSKyle Evans	local function write_tests(heap)
1562020d003cSKyle Evans		-- Dispositions here are relative to the buffer size prescribed
1563020d003cSKyle Evans		-- by the test definition.
1564020d003cSKyle Evans		local dispositions = def.dispositions or { -1, 0, 1 }
1565020d003cSKyle Evans
1566020d003cSKyle Evans		for _, disposition in ipairs(dispositions) do
1567020d003cSKyle Evans			tests_added[#tests_added + 1] = write_test(fh, func, disposition, heap, def)
1568020d003cSKyle Evans		end
1569020d003cSKyle Evans	end
1570020d003cSKyle Evans
1571020d003cSKyle Evans	write_tests(false)
1572020d003cSKyle Evans	write_tests(true)
1573020d003cSKyle Evansend
1574020d003cSKyle Evans
1575020d003cSKyle Evansfh:write("ATF_TP_ADD_TCS(tp)\n")
1576020d003cSKyle Evansfh:write("{\n")
1577020d003cSKyle Evansfor idx = 1, #tests_added do
1578020d003cSKyle Evans	fh:write("\tATF_TP_ADD_TC(tp, " .. tests_added[idx] .. ");\n")
1579020d003cSKyle Evansend
1580020d003cSKyle Evansfh:write("\treturn (atf_no_error());\n")
1581020d003cSKyle Evansfh:write("}\n")
1582