xref: /freebsd/lib/libc/tests/secure/generate-fortify-tests.lua (revision 1f155d48f878495d31592c59cab82f975c210ad8)
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",
65062d9380SKyle Evans	"sys/random.h",
66020d003cSKyle Evans	"sys/resource.h",
672aba0eeaSKyle Evans	"sys/select.h",
68*1f155d48SKyle Evans	"sys/socket.h",
69020d003cSKyle Evans	"sys/time.h",
701ace24b3SKyle Evans	"sys/uio.h",
71020d003cSKyle Evans	"sys/wait.h",
72020d003cSKyle Evans	"dirent.h",
73020d003cSKyle Evans	"errno.h",
74020d003cSKyle Evans	"fcntl.h",
75020d003cSKyle Evans	"limits.h",
7688276dfbSKyle Evans	"poll.h",
77020d003cSKyle Evans	"signal.h",
78020d003cSKyle Evans	"stdio.h",
79020d003cSKyle Evans	"stdlib.h",
80020d003cSKyle Evans	"string.h",
81020d003cSKyle Evans	"strings.h",
82020d003cSKyle Evans	"sysexits.h",
83020d003cSKyle Evans	"unistd.h",
84b53d7aa8SKyle Evans	"wchar.h",
85020d003cSKyle Evans	"atf-c.h",
86020d003cSKyle Evans}
87020d003cSKyle Evans
88020d003cSKyle Evanslocal tests_added = {}
89020d003cSKyle Evans
90020d003cSKyle Evans-- Some of these will need to be excluded because clang sees the wrong size when
91020d003cSKyle Evans-- an array is embedded inside a struct, we'll get something that looks more
92020d003cSKyle Evans-- like __builtin_object_size(ptr, 0) than it does the correct
93020d003cSKyle Evans-- __builtin_object_size(ptr, 1) (i.e., includes the padding after).  This is
94020d003cSKyle Evans-- almost certainly a bug in llvm.
95020d003cSKyle Evanslocal function excludes_stack_overflow(disposition, is_heap)
96020d003cSKyle Evans	return (not is_heap) and disposition > 0
97020d003cSKyle Evansend
98020d003cSKyle Evans
9988276dfbSKyle Evanslocal poll_init = [[
10088276dfbSKyle Evans	for (size_t i = 0; i < howmany(__bufsz, sizeof(struct pollfd)); i++) {
10188276dfbSKyle Evans		__stack.__buf[i].fd = -1;
10288276dfbSKyle Evans	}
10388276dfbSKyle Evans]]
10488276dfbSKyle Evans
105020d003cSKyle Evanslocal printf_stackvars = "\tchar srcvar[__len + 10];\n"
106020d003cSKyle Evanslocal printf_init = [[
107020d003cSKyle Evans	memset(srcvar, 'A', sizeof(srcvar) - 1);
108020d003cSKyle Evans	srcvar[sizeof(srcvar) - 1] = '\0';
109020d003cSKyle Evans]]
110020d003cSKyle Evans
1111ace24b3SKyle Evanslocal readv_stackvars = "\tstruct iovec iov[1];\n"
1121ace24b3SKyle Evanslocal readv_init = [[
1131ace24b3SKyle Evans	iov[0].iov_base = __stack.__buf;
1141ace24b3SKyle Evans	iov[0].iov_len = __len;
1151ace24b3SKyle Evans
1161ace24b3SKyle Evans	replace_stdin();
1171ace24b3SKyle Evans]]
1181ace24b3SKyle Evans
119*1f155d48SKyle Evanslocal socket_stackvars = "\tint sock[2] = { -1, -1 };\n"
120*1f155d48SKyle Evanslocal recvfrom_sockaddr_stackvars = socket_stackvars .. [[
121*1f155d48SKyle Evans	char data[16];
122*1f155d48SKyle Evans	socklen_t socklen;
123*1f155d48SKyle Evans]]
124*1f155d48SKyle Evanslocal recvmsg_stackvars = socket_stackvars .. "\tstruct msghdr msg;\n"
125*1f155d48SKyle Evanslocal socket_init = [[
126*1f155d48SKyle Evans	new_socket(sock);
127*1f155d48SKyle Evans]]
128*1f155d48SKyle Evanslocal socket_socklen_init = socket_init .. [[
129*1f155d48SKyle Evans	socklen = __len;
130*1f155d48SKyle Evans]]
131*1f155d48SKyle Evans
132cf8e5289SKyle Evanslocal stdio_init = [[
133cf8e5289SKyle Evans	replace_stdin();
134cf8e5289SKyle Evans]]
135cf8e5289SKyle Evans
136020d003cSKyle Evanslocal string_stackvars = "\tchar src[__len];\n"
137020d003cSKyle Evanslocal string_init = [[
138020d003cSKyle Evans	memset(__stack.__buf, 0, __len);
139020d003cSKyle Evans	memset(src, 'A', __len - 1);
140020d003cSKyle Evans	src[__len - 1] = '\0';
141020d003cSKyle Evans]]
142020d003cSKyle Evans
143b53d7aa8SKyle Evanslocal wstring_stackvars = "\twchar_t src[__len];\n"
144b53d7aa8SKyle Evanslocal wstring_init = [[
145b53d7aa8SKyle Evans	wmemset(__stack.__buf, 0, __len);
146b53d7aa8SKyle Evans	wmemset(src, 'A', __len - 1);
147b53d7aa8SKyle Evans	src[__len - 1] = '\0';
148b53d7aa8SKyle Evans]]
149b53d7aa8SKyle Evans
150020d003cSKyle Evans-- Each test entry describes how to test a given function.  We need to know how
151020d003cSKyle Evans-- to construct the buffer, we need to know the argument set we're dealing with,
152020d003cSKyle Evans-- and we need to know what we're passing to each argument.  We could be passing
153020d003cSKyle Evans-- fixed values, or we could be passing the __buf under test.
154020d003cSKyle Evans--
155020d003cSKyle Evans-- definition:
156020d003cSKyle Evans--   func: name of the function under test to call
157020d003cSKyle Evans--   bufsize: size of buffer to generate, defaults to 42
158020d003cSKyle Evans--   buftype: type of buffer to generate, defaults to unsigned char[]
159020d003cSKyle Evans--   arguments: __buf, __len, or the name of a variable placed on the stack
160020d003cSKyle Evans--   exclude: a function(disposition, is_heap) that returns true if this combo
161020d003cSKyle Evans--     should be excluded.
162020d003cSKyle Evans--   stackvars: extra variables to be placed on the stack, should be a string
163020d003cSKyle Evans--     optionally formatted with tabs and newlines
164020d003cSKyle Evans--   init: extra code to inject just before the function call for initialization
165020d003cSKyle Evans--     of the buffer or any of the above-added stackvars; also a string
166020d003cSKyle Evans--   uses_len: bool-ish, necessary if arguments doesn't include either __idx or
167020d003cSKyle Evans--     or __len so that the test generator doesn't try to vary the size of the
168020d003cSKyle Evans--     buffer instead of just manipulating __idx/__len to try and induce an
169020d003cSKyle Evans--     overflow.
170020d003cSKyle Evans--
171020d003cSKyle Evans-- Most tests will just use the default bufsize/buftype, but under some
172020d003cSKyle Evans-- circumstances it's useful to use a different type (e.g., for alignment
173020d003cSKyle Evans-- requirements).
174020d003cSKyle Evanslocal all_tests = {
175062d9380SKyle Evans	random = {
176062d9380SKyle Evans		-- <sys/random.h>
177062d9380SKyle Evans		{
178062d9380SKyle Evans			func = "getrandom",
179062d9380SKyle Evans			arguments = {
180062d9380SKyle Evans				"__buf",
181062d9380SKyle Evans				"__len",
182062d9380SKyle Evans				"0",
183062d9380SKyle Evans			},
184062d9380SKyle Evans			exclude = excludes_stack_overflow,
185062d9380SKyle Evans		},
186062d9380SKyle Evans	},
1872aba0eeaSKyle Evans	select = {
1882aba0eeaSKyle Evans		-- <sys/select.h>
1892aba0eeaSKyle Evans		{
1902aba0eeaSKyle Evans			func = "FD_SET",
1912aba0eeaSKyle Evans			bufsize = "FD_SETSIZE",
1922aba0eeaSKyle Evans			buftype = "fd_set",
1932aba0eeaSKyle Evans			arguments = {
1942aba0eeaSKyle Evans				"__idx",
1952aba0eeaSKyle Evans				"__buf",
1962aba0eeaSKyle Evans			},
1972aba0eeaSKyle Evans		},
1982aba0eeaSKyle Evans		{
1992aba0eeaSKyle Evans			func = "FD_CLR",
2002aba0eeaSKyle Evans			bufsize = "FD_SETSIZE",
2012aba0eeaSKyle Evans			buftype = "fd_set",
2022aba0eeaSKyle Evans			arguments = {
2032aba0eeaSKyle Evans				"__idx",
2042aba0eeaSKyle Evans				"__buf",
2052aba0eeaSKyle Evans			},
2062aba0eeaSKyle Evans		},
2072aba0eeaSKyle Evans		{
2082aba0eeaSKyle Evans			func = "FD_ISSET",
2092aba0eeaSKyle Evans			bufsize = "FD_SETSIZE",
2102aba0eeaSKyle Evans			buftype = "fd_set",
2112aba0eeaSKyle Evans			arguments = {
2122aba0eeaSKyle Evans				"__idx",
2132aba0eeaSKyle Evans				"__buf",
2142aba0eeaSKyle Evans			},
2152aba0eeaSKyle Evans		},
2162aba0eeaSKyle Evans	},
217*1f155d48SKyle Evans	socket = {
218*1f155d48SKyle Evans		-- <sys/socket.h>
219*1f155d48SKyle Evans		{
220*1f155d48SKyle Evans			func = "getpeername",
221*1f155d48SKyle Evans			buftype = "struct sockaddr",
222*1f155d48SKyle Evans			bufsize = "sizeof(struct sockaddr)",
223*1f155d48SKyle Evans			arguments = {
224*1f155d48SKyle Evans				"sock[0]",
225*1f155d48SKyle Evans				"__buf",
226*1f155d48SKyle Evans				"&socklen",
227*1f155d48SKyle Evans			},
228*1f155d48SKyle Evans			exclude = excludes_stack_overflow,
229*1f155d48SKyle Evans			stackvars = socket_stackvars .. "\tsocklen_t socklen;",
230*1f155d48SKyle Evans			init = socket_socklen_init,
231*1f155d48SKyle Evans			uses_len = true,
232*1f155d48SKyle Evans		},
233*1f155d48SKyle Evans		{
234*1f155d48SKyle Evans			func = "getsockname",
235*1f155d48SKyle Evans			buftype = "struct sockaddr",
236*1f155d48SKyle Evans			bufsize = "sizeof(struct sockaddr)",
237*1f155d48SKyle Evans			arguments = {
238*1f155d48SKyle Evans				"sock[0]",
239*1f155d48SKyle Evans				"__buf",
240*1f155d48SKyle Evans				"&socklen",
241*1f155d48SKyle Evans			},
242*1f155d48SKyle Evans			exclude = excludes_stack_overflow,
243*1f155d48SKyle Evans			stackvars = socket_stackvars .. "\tsocklen_t socklen;",
244*1f155d48SKyle Evans			init = socket_socklen_init,
245*1f155d48SKyle Evans			uses_len = true,
246*1f155d48SKyle Evans		},
247*1f155d48SKyle Evans		{
248*1f155d48SKyle Evans			func = "recv",
249*1f155d48SKyle Evans			arguments = {
250*1f155d48SKyle Evans				"sock[0]",
251*1f155d48SKyle Evans				"__buf",
252*1f155d48SKyle Evans				"__len",
253*1f155d48SKyle Evans				"0",
254*1f155d48SKyle Evans			},
255*1f155d48SKyle Evans			exclude = excludes_stack_overflow,
256*1f155d48SKyle Evans			stackvars = socket_stackvars,
257*1f155d48SKyle Evans			init = socket_init,
258*1f155d48SKyle Evans		},
259*1f155d48SKyle Evans		{
260*1f155d48SKyle Evans			func = "recvfrom",
261*1f155d48SKyle Evans			arguments = {
262*1f155d48SKyle Evans				"sock[0]",
263*1f155d48SKyle Evans				"__buf",
264*1f155d48SKyle Evans				"__len",
265*1f155d48SKyle Evans				"0",
266*1f155d48SKyle Evans				"NULL",
267*1f155d48SKyle Evans				"NULL",
268*1f155d48SKyle Evans			},
269*1f155d48SKyle Evans			exclude = excludes_stack_overflow,
270*1f155d48SKyle Evans			stackvars = socket_stackvars,
271*1f155d48SKyle Evans			init = socket_init,
272*1f155d48SKyle Evans		},
273*1f155d48SKyle Evans		{
274*1f155d48SKyle Evans			func = "recvfrom",
275*1f155d48SKyle Evans			variant = "sockaddr",
276*1f155d48SKyle Evans			buftype = "struct sockaddr",
277*1f155d48SKyle Evans			bufsize = "sizeof(struct sockaddr)",
278*1f155d48SKyle Evans			arguments = {
279*1f155d48SKyle Evans				"sock[0]",
280*1f155d48SKyle Evans				"data",
281*1f155d48SKyle Evans				"sizeof(data)",
282*1f155d48SKyle Evans				"0",
283*1f155d48SKyle Evans				"__buf",
284*1f155d48SKyle Evans				"&socklen",
285*1f155d48SKyle Evans			},
286*1f155d48SKyle Evans			exclude = excludes_stack_overflow,
287*1f155d48SKyle Evans			stackvars = recvfrom_sockaddr_stackvars,
288*1f155d48SKyle Evans			init = socket_socklen_init,
289*1f155d48SKyle Evans			uses_len = true,
290*1f155d48SKyle Evans		},
291*1f155d48SKyle Evans		{
292*1f155d48SKyle Evans			func = "recvmsg",
293*1f155d48SKyle Evans			variant = "msg_name",
294*1f155d48SKyle Evans			buftype = "struct sockaddr",
295*1f155d48SKyle Evans			bufsize = "sizeof(struct sockaddr)",
296*1f155d48SKyle Evans			arguments = {
297*1f155d48SKyle Evans				"sock[0]",
298*1f155d48SKyle Evans				"&msg",
299*1f155d48SKyle Evans				"0",
300*1f155d48SKyle Evans			},
301*1f155d48SKyle Evans			exclude = excludes_stack_overflow,
302*1f155d48SKyle Evans			stackvars = recvmsg_stackvars,
303*1f155d48SKyle Evans			init = [[
304*1f155d48SKyle Evans	memset(&msg, 0, sizeof(msg));
305*1f155d48SKyle Evans	msg.msg_name = BUF;
306*1f155d48SKyle Evans	msg.msg_namelen = __len;
307*1f155d48SKyle Evans]],
308*1f155d48SKyle Evans			uses_len = true,
309*1f155d48SKyle Evans		},
310*1f155d48SKyle Evans		{
311*1f155d48SKyle Evans			func = "recvmsg",
312*1f155d48SKyle Evans			variant = "msg_iov",
313*1f155d48SKyle Evans			arguments = {
314*1f155d48SKyle Evans				"sock[0]",
315*1f155d48SKyle Evans				"&msg",
316*1f155d48SKyle Evans				"0",
317*1f155d48SKyle Evans			},
318*1f155d48SKyle Evans			exclude = excludes_stack_overflow,
319*1f155d48SKyle Evans			stackvars = recvmsg_stackvars .. "\tstruct iovec iov[2];\n",
320*1f155d48SKyle Evans			init = [[
321*1f155d48SKyle Evans	memset(&msg, 0, sizeof(msg));
322*1f155d48SKyle Evans	memset(&iov[0], 0, sizeof(iov));
323*1f155d48SKyle Evans
324*1f155d48SKyle Evans	/*
325*1f155d48SKyle Evans	 * We position the buffer second just so that we can confirm that the
326*1f155d48SKyle Evans	 * fortification bits are traversing the iovec correctly.
327*1f155d48SKyle Evans	 */
328*1f155d48SKyle Evans	iov[1].iov_base = BUF;
329*1f155d48SKyle Evans	iov[1].iov_len = __len;
330*1f155d48SKyle Evans
331*1f155d48SKyle Evans	msg.msg_iov = &iov[0];
332*1f155d48SKyle Evans	msg.msg_iovlen = nitems(iov);
333*1f155d48SKyle Evans]],
334*1f155d48SKyle Evans			uses_len = true,
335*1f155d48SKyle Evans		},
336*1f155d48SKyle Evans		{
337*1f155d48SKyle Evans			func = "recvmsg",
338*1f155d48SKyle Evans			variant = "msg_control",
339*1f155d48SKyle Evans			bufsize = "CMSG_SPACE(sizeof(int))",
340*1f155d48SKyle Evans			arguments = {
341*1f155d48SKyle Evans				"sock[0]",
342*1f155d48SKyle Evans				"&msg",
343*1f155d48SKyle Evans				"0",
344*1f155d48SKyle Evans			},
345*1f155d48SKyle Evans			exclude = excludes_stack_overflow,
346*1f155d48SKyle Evans			stackvars = recvmsg_stackvars,
347*1f155d48SKyle Evans			init = [[
348*1f155d48SKyle Evans	memset(&msg, 0, sizeof(msg));
349*1f155d48SKyle Evans
350*1f155d48SKyle Evans	msg.msg_control = BUF;
351*1f155d48SKyle Evans	msg.msg_controllen = __len;
352*1f155d48SKyle Evans]],
353*1f155d48SKyle Evans			uses_len = true,
354*1f155d48SKyle Evans		},
355*1f155d48SKyle Evans		{
356*1f155d48SKyle Evans			func = "recvmmsg",
357*1f155d48SKyle Evans			variant = "msgvec",
358*1f155d48SKyle Evans			buftype = "struct mmsghdr[]",
359*1f155d48SKyle Evans			bufsize = "2",
360*1f155d48SKyle Evans			arguments = {
361*1f155d48SKyle Evans				"sock[0]",
362*1f155d48SKyle Evans				"__buf",
363*1f155d48SKyle Evans				"__len",
364*1f155d48SKyle Evans				"0",
365*1f155d48SKyle Evans				"NULL",
366*1f155d48SKyle Evans			},
367*1f155d48SKyle Evans			stackvars = socket_stackvars,
368*1f155d48SKyle Evans		},
369*1f155d48SKyle Evans		{
370*1f155d48SKyle Evans			-- We'll assume that recvmsg is covering msghdr
371*1f155d48SKyle Evans			-- validation thoroughly enough, we'll just try tossing
372*1f155d48SKyle Evans			-- an error in the second element of a msgvec to try and
373*1f155d48SKyle Evans			-- make sure that each one is being validated.
374*1f155d48SKyle Evans			func = "recvmmsg",
375*1f155d48SKyle Evans			variant = "msghdr",
376*1f155d48SKyle Evans			arguments = {
377*1f155d48SKyle Evans				"sock[0]",
378*1f155d48SKyle Evans				"&msgvec[0]",
379*1f155d48SKyle Evans				"nitems(msgvec)",
380*1f155d48SKyle Evans				"0",
381*1f155d48SKyle Evans				"NULL",
382*1f155d48SKyle Evans			},
383*1f155d48SKyle Evans			exclude = excludes_stack_overflow,
384*1f155d48SKyle Evans			stackvars = socket_stackvars .. "\tstruct mmsghdr msgvec[2];\n",
385*1f155d48SKyle Evans			init = [[
386*1f155d48SKyle Evans	memset(&msgvec[0], 0, sizeof(msgvec));
387*1f155d48SKyle Evans
388*1f155d48SKyle Evans	/*
389*1f155d48SKyle Evans	 * Same as above, make sure fortification isn't ignoring n > 1 elements
390*1f155d48SKyle Evans	 * of the msgvec.
391*1f155d48SKyle Evans	 */
392*1f155d48SKyle Evans	msgvec[1].msg_hdr.msg_control = BUF;
393*1f155d48SKyle Evans	msgvec[1].msg_hdr.msg_controllen = __len;
394*1f155d48SKyle Evans]],
395*1f155d48SKyle Evans			uses_len = true,
396*1f155d48SKyle Evans		},
397*1f155d48SKyle Evans	},
3981ace24b3SKyle Evans	uio = {
3991ace24b3SKyle Evans		-- <sys/uio.h>
4001ace24b3SKyle Evans		{
4011ace24b3SKyle Evans			func = "readv",
4021ace24b3SKyle Evans			buftype = "struct iovec[]",
4031ace24b3SKyle Evans			bufsize = 2,
4041ace24b3SKyle Evans			arguments = {
4051ace24b3SKyle Evans				"STDIN_FILENO",
4061ace24b3SKyle Evans				"__buf",
4071ace24b3SKyle Evans				"__len",
4081ace24b3SKyle Evans			},
4091ace24b3SKyle Evans		},
4101ace24b3SKyle Evans		{
4111ace24b3SKyle Evans			func = "readv",
4121ace24b3SKyle Evans			variant = "iov",
4131ace24b3SKyle Evans			arguments = {
4141ace24b3SKyle Evans				"STDIN_FILENO",
4151ace24b3SKyle Evans				"iov",
4161ace24b3SKyle Evans				"nitems(iov)",
4171ace24b3SKyle Evans			},
4181ace24b3SKyle Evans			exclude = excludes_stack_overflow,
4191ace24b3SKyle Evans			stackvars = readv_stackvars,
4201ace24b3SKyle Evans			init = readv_init,
4211ace24b3SKyle Evans			uses_len = true,
4221ace24b3SKyle Evans		},
4231ace24b3SKyle Evans		{
4241ace24b3SKyle Evans			func = "preadv",
4251ace24b3SKyle Evans			buftype = "struct iovec[]",
4261ace24b3SKyle Evans			bufsize = 2,
4271ace24b3SKyle Evans			arguments = {
4281ace24b3SKyle Evans				"STDIN_FILENO",
4291ace24b3SKyle Evans				"__buf",
4301ace24b3SKyle Evans				"__len",
4311ace24b3SKyle Evans				"0",
4321ace24b3SKyle Evans			},
4331ace24b3SKyle Evans		},
4341ace24b3SKyle Evans		{
4351ace24b3SKyle Evans			func = "preadv",
4361ace24b3SKyle Evans			variant = "iov",
4371ace24b3SKyle Evans			arguments = {
4381ace24b3SKyle Evans				"STDIN_FILENO",
4391ace24b3SKyle Evans				"iov",
4401ace24b3SKyle Evans				"nitems(iov)",
4411ace24b3SKyle Evans				"0",
4421ace24b3SKyle Evans			},
4431ace24b3SKyle Evans			exclude = excludes_stack_overflow,
4441ace24b3SKyle Evans			stackvars = readv_stackvars,
4451ace24b3SKyle Evans			init = readv_init,
4461ace24b3SKyle Evans			uses_len = true,
4471ace24b3SKyle Evans		},
4481ace24b3SKyle Evans	},
44988276dfbSKyle Evans	poll = {
45088276dfbSKyle Evans		-- <poll.h>
45188276dfbSKyle Evans		{
45288276dfbSKyle Evans			func = "poll",
45388276dfbSKyle Evans			bufsize = "4",
45488276dfbSKyle Evans			buftype = "struct pollfd[]",
45588276dfbSKyle Evans			arguments = {
45688276dfbSKyle Evans				"__buf",
45788276dfbSKyle Evans				"__len",
45888276dfbSKyle Evans				"0",
45988276dfbSKyle Evans			},
46088276dfbSKyle Evans			init = poll_init,
46188276dfbSKyle Evans		},
46288276dfbSKyle Evans		{
46388276dfbSKyle Evans			func = "ppoll",
46488276dfbSKyle Evans			bufsize = "4",
46588276dfbSKyle Evans			buftype = "struct pollfd[]",
46688276dfbSKyle Evans			arguments = {
46788276dfbSKyle Evans				"__buf",
46888276dfbSKyle Evans				"__len",
46988276dfbSKyle Evans				"&tv",
47088276dfbSKyle Evans				"NULL",
47188276dfbSKyle Evans			},
47288276dfbSKyle Evans			stackvars = "\tstruct timespec tv = { 0 };\n",
47388276dfbSKyle Evans			init = poll_init,
47488276dfbSKyle Evans		},
47588276dfbSKyle Evans	},
476020d003cSKyle Evans	stdio = {
477020d003cSKyle Evans		-- <stdio.h>
478020d003cSKyle Evans		{
479cf8e5289SKyle Evans			func = "ctermid",
480cf8e5289SKyle Evans			bufsize = "L_ctermid",
481cf8e5289SKyle Evans			arguments = {
482cf8e5289SKyle Evans				"__buf",
483cf8e5289SKyle Evans			},
484cf8e5289SKyle Evans			exclude = excludes_stack_overflow,
485cf8e5289SKyle Evans		},
486cf8e5289SKyle Evans		{
487cf8e5289SKyle Evans			func = "ctermid_r",
488cf8e5289SKyle Evans			bufsize = "L_ctermid",
489cf8e5289SKyle Evans			arguments = {
490cf8e5289SKyle Evans				"__buf",
491cf8e5289SKyle Evans			},
492cf8e5289SKyle Evans			exclude = excludes_stack_overflow,
493cf8e5289SKyle Evans		},
494cf8e5289SKyle Evans		{
495cf8e5289SKyle Evans			func = "fread",
496cf8e5289SKyle Evans			arguments = {
497cf8e5289SKyle Evans				"__buf",
498cf8e5289SKyle Evans				"__len",
499cf8e5289SKyle Evans				"1",
500cf8e5289SKyle Evans				"stdin",
501cf8e5289SKyle Evans			},
502cf8e5289SKyle Evans			exclude = excludes_stack_overflow,
503cf8e5289SKyle Evans			init = stdio_init,
504cf8e5289SKyle Evans		},
505cf8e5289SKyle Evans		{
506cf8e5289SKyle Evans			func = "fread_unlocked",
507cf8e5289SKyle Evans			arguments = {
508cf8e5289SKyle Evans				"__buf",
509cf8e5289SKyle Evans				"__len",
510cf8e5289SKyle Evans				"1",
511cf8e5289SKyle Evans				"stdin",
512cf8e5289SKyle Evans			},
513cf8e5289SKyle Evans			exclude = excludes_stack_overflow,
514cf8e5289SKyle Evans			init = stdio_init,
515cf8e5289SKyle Evans		},
516cf8e5289SKyle Evans		{
517cf8e5289SKyle Evans			func = "gets_s",
518cf8e5289SKyle Evans			arguments = {
519cf8e5289SKyle Evans				"__buf",
520cf8e5289SKyle Evans				"__len",
521cf8e5289SKyle Evans			},
522cf8e5289SKyle Evans			exclude = excludes_stack_overflow,
523cf8e5289SKyle Evans			init = stdio_init,
524cf8e5289SKyle Evans		},
525cf8e5289SKyle Evans		{
526020d003cSKyle Evans			func = "sprintf",
527020d003cSKyle Evans			arguments = {
528020d003cSKyle Evans				"__buf",
529020d003cSKyle Evans				"\"%.*s\"",
530020d003cSKyle Evans				"(int)__len - 1",	-- - 1 for NUL terminator
531020d003cSKyle Evans				"srcvar",
532020d003cSKyle Evans			},
533020d003cSKyle Evans			exclude = excludes_stack_overflow,
534020d003cSKyle Evans			stackvars = printf_stackvars,
535020d003cSKyle Evans			init = printf_init,
536020d003cSKyle Evans		},
537020d003cSKyle Evans		{
538020d003cSKyle Evans			func = "snprintf",
539020d003cSKyle Evans			arguments = {
540020d003cSKyle Evans				"__buf",
541020d003cSKyle Evans				"__len",
542020d003cSKyle Evans				"\"%.*s\"",
543020d003cSKyle Evans				"(int)__len - 1",	-- - 1 for NUL terminator
544020d003cSKyle Evans				"srcvar",
545020d003cSKyle Evans			},
546020d003cSKyle Evans			exclude = excludes_stack_overflow,
547020d003cSKyle Evans			stackvars = printf_stackvars,
548020d003cSKyle Evans			init = printf_init,
549020d003cSKyle Evans		},
550cf8e5289SKyle Evans		{
551cf8e5289SKyle Evans			func = "tmpnam",
552cf8e5289SKyle Evans			bufsize = "L_tmpnam",
553cf8e5289SKyle Evans			arguments = {
554cf8e5289SKyle Evans				"__buf",
555cf8e5289SKyle Evans			},
556cf8e5289SKyle Evans			exclude = excludes_stack_overflow,
557cf8e5289SKyle Evans		},
558cf8e5289SKyle Evans		{
559cf8e5289SKyle Evans			func = "fgets",
560cf8e5289SKyle Evans			arguments = {
561cf8e5289SKyle Evans				"__buf",
562cf8e5289SKyle Evans				"__len",
563cf8e5289SKyle Evans				"fp",
564cf8e5289SKyle Evans			},
565cf8e5289SKyle Evans			exclude = excludes_stack_overflow,
566cf8e5289SKyle Evans			stackvars = "\tFILE *fp;\n",
567cf8e5289SKyle Evans			init = [[
568cf8e5289SKyle Evans	fp = new_fp(__len);
569cf8e5289SKyle Evans]],
570cf8e5289SKyle Evans		},
571020d003cSKyle Evans	},
572d0b74459SKyle Evans	stdlib = {
573d0b74459SKyle Evans		-- <stdlib.h>
574d0b74459SKyle Evans		{
575d0b74459SKyle Evans			func = "arc4random_buf",
576d0b74459SKyle Evans			arguments = {
577d0b74459SKyle Evans				"__buf",
578d0b74459SKyle Evans				"__len",
579d0b74459SKyle Evans			},
580d0b74459SKyle Evans			exclude = excludes_stack_overflow,
581d0b74459SKyle Evans		},
582d0b74459SKyle Evans		{
583d0b74459SKyle Evans			func = "realpath",
584d0b74459SKyle Evans			bufsize = "PATH_MAX",
585d0b74459SKyle Evans			arguments = {
586d0b74459SKyle Evans				"\".\"",
587d0b74459SKyle Evans				"__buf",
588d0b74459SKyle Evans			},
589d0b74459SKyle Evans			exclude = excludes_stack_overflow,
590d0b74459SKyle Evans		},
591d0b74459SKyle Evans	},
592020d003cSKyle Evans	string = {
593020d003cSKyle Evans		-- <string.h>
594020d003cSKyle Evans		{
595020d003cSKyle Evans			func = "memcpy",
596020d003cSKyle Evans			arguments = {
597020d003cSKyle Evans				"__buf",
598020d003cSKyle Evans				"src",
599020d003cSKyle Evans				"__len",
600020d003cSKyle Evans			},
601020d003cSKyle Evans			exclude = excludes_stack_overflow,
602020d003cSKyle Evans			stackvars = "\tchar src[__len + 10];\n",
603020d003cSKyle Evans		},
604020d003cSKyle Evans		{
605cf8e5289SKyle Evans			func = "mempcpy",
606cf8e5289SKyle Evans			arguments = {
607cf8e5289SKyle Evans				"__buf",
608cf8e5289SKyle Evans				"src",
609cf8e5289SKyle Evans				"__len",
610cf8e5289SKyle Evans			},
611cf8e5289SKyle Evans			exclude = excludes_stack_overflow,
612cf8e5289SKyle Evans			stackvars = "\tchar src[__len + 10];\n",
613cf8e5289SKyle Evans		},
614cf8e5289SKyle Evans		{
615020d003cSKyle Evans			func = "memmove",
616020d003cSKyle Evans			arguments = {
617020d003cSKyle Evans				"__buf",
618020d003cSKyle Evans				"src",
619020d003cSKyle Evans				"__len",
620020d003cSKyle Evans			},
621020d003cSKyle Evans			exclude = excludes_stack_overflow,
622020d003cSKyle Evans			stackvars = "\tchar src[__len + 10];\n",
623020d003cSKyle Evans		},
624020d003cSKyle Evans		{
625020d003cSKyle Evans			func = "memset",
626020d003cSKyle Evans			arguments = {
627020d003cSKyle Evans				"__buf",
628020d003cSKyle Evans				"0",
629020d003cSKyle Evans				"__len",
630020d003cSKyle Evans			},
631020d003cSKyle Evans			exclude = excludes_stack_overflow,
632020d003cSKyle Evans		},
633020d003cSKyle Evans		{
634020d003cSKyle Evans			func = "stpcpy",
635020d003cSKyle Evans			arguments = {
636020d003cSKyle Evans				"__buf",
637020d003cSKyle Evans				"src",
638020d003cSKyle Evans			},
639020d003cSKyle Evans			exclude = excludes_stack_overflow,
640020d003cSKyle Evans			stackvars = string_stackvars,
641020d003cSKyle Evans			init = string_init,
642020d003cSKyle Evans			uses_len = true,
643020d003cSKyle Evans		},
644020d003cSKyle Evans		{
645020d003cSKyle Evans			func = "stpncpy",
646020d003cSKyle Evans			arguments = {
647020d003cSKyle Evans				"__buf",
648020d003cSKyle Evans				"src",
649020d003cSKyle Evans				"__len",
650020d003cSKyle Evans			},
651020d003cSKyle Evans			exclude = excludes_stack_overflow,
652020d003cSKyle Evans			stackvars = string_stackvars,
653020d003cSKyle Evans			init = string_init,
654020d003cSKyle Evans		},
655020d003cSKyle Evans		{
656020d003cSKyle Evans			func = "strcat",
657020d003cSKyle Evans			arguments = {
658020d003cSKyle Evans				"__buf",
659020d003cSKyle Evans				"src",
660020d003cSKyle Evans			},
661020d003cSKyle Evans			exclude = excludes_stack_overflow,
662020d003cSKyle Evans			stackvars = string_stackvars,
663020d003cSKyle Evans			init = string_init,
664020d003cSKyle Evans			uses_len = true,
665020d003cSKyle Evans		},
666020d003cSKyle Evans		{
667cf8e5289SKyle Evans			func = "strlcat",
668cf8e5289SKyle Evans			arguments = {
669cf8e5289SKyle Evans				"__buf",
670cf8e5289SKyle Evans				"src",
671cf8e5289SKyle Evans				"__len",
672cf8e5289SKyle Evans			},
673cf8e5289SKyle Evans			exclude = excludes_stack_overflow,
674cf8e5289SKyle Evans			stackvars = string_stackvars,
675cf8e5289SKyle Evans			init = string_init,
676cf8e5289SKyle Evans		},
677cf8e5289SKyle Evans		{
678020d003cSKyle Evans			func = "strncat",
679020d003cSKyle Evans			arguments = {
680020d003cSKyle Evans				"__buf",
681020d003cSKyle Evans				"src",
682020d003cSKyle Evans				"__len",
683020d003cSKyle Evans			},
684020d003cSKyle Evans			exclude = excludes_stack_overflow,
685020d003cSKyle Evans			stackvars = string_stackvars,
686020d003cSKyle Evans			init = string_init,
687020d003cSKyle Evans		},
688020d003cSKyle Evans		{
689020d003cSKyle Evans			func = "strcpy",
690020d003cSKyle Evans			arguments = {
691020d003cSKyle Evans				"__buf",
692020d003cSKyle Evans				"src",
693020d003cSKyle Evans			},
694020d003cSKyle Evans			exclude = excludes_stack_overflow,
695020d003cSKyle Evans			stackvars = string_stackvars,
696020d003cSKyle Evans			init = string_init,
697020d003cSKyle Evans			uses_len = true,
698020d003cSKyle Evans		},
699020d003cSKyle Evans		{
700cf8e5289SKyle Evans			func = "strlcpy",
701cf8e5289SKyle Evans			arguments = {
702cf8e5289SKyle Evans				"__buf",
703cf8e5289SKyle Evans				"src",
704cf8e5289SKyle Evans				"__len",
705cf8e5289SKyle Evans			},
706cf8e5289SKyle Evans			exclude = excludes_stack_overflow,
707cf8e5289SKyle Evans			stackvars = string_stackvars,
708cf8e5289SKyle Evans			init = string_init,
709cf8e5289SKyle Evans		},
710cf8e5289SKyle Evans		{
711020d003cSKyle Evans			func = "strncpy",
712020d003cSKyle Evans			arguments = {
713020d003cSKyle Evans				"__buf",
714020d003cSKyle Evans				"src",
715020d003cSKyle Evans				"__len",
716020d003cSKyle Evans			},
717020d003cSKyle Evans			exclude = excludes_stack_overflow,
718020d003cSKyle Evans			stackvars = string_stackvars,
719020d003cSKyle Evans			init = string_init,
720020d003cSKyle Evans		},
721020d003cSKyle Evans	},
722020d003cSKyle Evans	strings = {
723020d003cSKyle Evans		-- <strings.h>
724020d003cSKyle Evans		{
725020d003cSKyle Evans			func = "bcopy",
726020d003cSKyle Evans			arguments = {
727020d003cSKyle Evans				"src",
728020d003cSKyle Evans				"__buf",
729020d003cSKyle Evans				"__len",
730020d003cSKyle Evans			},
731020d003cSKyle Evans			exclude = excludes_stack_overflow,
732020d003cSKyle Evans			stackvars = "\tchar src[__len + 10];\n",
733020d003cSKyle Evans		},
734020d003cSKyle Evans		{
735020d003cSKyle Evans			func = "bzero",
736020d003cSKyle Evans			arguments = {
737020d003cSKyle Evans				"__buf",
738020d003cSKyle Evans				"__len",
739020d003cSKyle Evans			},
740020d003cSKyle Evans			exclude = excludes_stack_overflow,
741020d003cSKyle Evans		},
742cf8e5289SKyle Evans		{
743cf8e5289SKyle Evans			func = "explicit_bzero",
744cf8e5289SKyle Evans			arguments = {
745cf8e5289SKyle Evans				"__buf",
746cf8e5289SKyle Evans				"__len",
747cf8e5289SKyle Evans			},
748cf8e5289SKyle Evans			exclude = excludes_stack_overflow,
749cf8e5289SKyle Evans		},
750020d003cSKyle Evans	},
751020d003cSKyle Evans	unistd = {
752020d003cSKyle Evans		-- <unistd.h>
753020d003cSKyle Evans		{
754020d003cSKyle Evans			func = "getcwd",
755020d003cSKyle Evans			bufsize = "8",
756020d003cSKyle Evans			arguments = {
757020d003cSKyle Evans				"__buf",
758020d003cSKyle Evans				"__len",
759020d003cSKyle Evans			},
760020d003cSKyle Evans			exclude = excludes_stack_overflow,
761020d003cSKyle Evans		},
762020d003cSKyle Evans		{
763cf8e5289SKyle Evans			func = "getgrouplist",
764cf8e5289SKyle Evans			bufsize = "4",
765cf8e5289SKyle Evans			buftype = "gid_t[]",
766cf8e5289SKyle Evans			arguments = {
767cf8e5289SKyle Evans				"\"root\"",
768cf8e5289SKyle Evans				"0",
769cf8e5289SKyle Evans				"__buf",
770cf8e5289SKyle Evans				"&intlen",
771cf8e5289SKyle Evans			},
772cf8e5289SKyle Evans			exclude = excludes_stack_overflow,
773cf8e5289SKyle Evans			stackvars = "\tint intlen = (int)__len;\n",
774cf8e5289SKyle Evans			uses_len = true,
775cf8e5289SKyle Evans		},
776cf8e5289SKyle Evans		{
777cf8e5289SKyle Evans			func = "getgroups",
778cf8e5289SKyle Evans			bufsize = "4",
779cf8e5289SKyle Evans			buftype = "gid_t[]",
780cf8e5289SKyle Evans			arguments = {
781cf8e5289SKyle Evans				"__len",
782cf8e5289SKyle Evans				"__buf",
783cf8e5289SKyle Evans			},
784cf8e5289SKyle Evans			exclude = excludes_stack_overflow,
785cf8e5289SKyle Evans		},
786cf8e5289SKyle Evans		{
787cf8e5289SKyle Evans			func = "getloginclass",
788cf8e5289SKyle Evans			arguments = {
789cf8e5289SKyle Evans				"__buf",
790cf8e5289SKyle Evans				"__len",
791cf8e5289SKyle Evans			},
792cf8e5289SKyle Evans			exclude = excludes_stack_overflow,
793cf8e5289SKyle Evans		},
794cf8e5289SKyle Evans		{
795cf8e5289SKyle Evans			func = "pread",
796cf8e5289SKyle Evans			bufsize = "41",
797cf8e5289SKyle Evans			arguments = {
798cf8e5289SKyle Evans				"fd",
799cf8e5289SKyle Evans				"__buf",
800cf8e5289SKyle Evans				"__len",
801cf8e5289SKyle Evans				"0",
802cf8e5289SKyle Evans			},
803cf8e5289SKyle Evans			exclude = excludes_stack_overflow,
804cf8e5289SKyle Evans			stackvars = "\tint fd;\n",
805cf8e5289SKyle Evans			init = [[
806cf8e5289SKyle Evans	fd = new_tmpfile();	/* Cannot fail */
807cf8e5289SKyle Evans]],
808cf8e5289SKyle Evans		},
809cf8e5289SKyle Evans		{
810020d003cSKyle Evans			func = "read",
811020d003cSKyle Evans			bufsize = "41",
812020d003cSKyle Evans			arguments = {
813020d003cSKyle Evans				"fd",
814020d003cSKyle Evans				"__buf",
815020d003cSKyle Evans				"__len",
816020d003cSKyle Evans			},
817020d003cSKyle Evans			exclude = excludes_stack_overflow,
818020d003cSKyle Evans			stackvars = "\tint fd;\n",
819020d003cSKyle Evans			init = [[
820020d003cSKyle Evans	fd = new_tmpfile();	/* Cannot fail */
821020d003cSKyle Evans]],
822020d003cSKyle Evans		},
823020d003cSKyle Evans		{
824020d003cSKyle Evans			func = "readlink",
825020d003cSKyle Evans			arguments = {
826020d003cSKyle Evans				"path",
827020d003cSKyle Evans				"__buf",
828020d003cSKyle Evans				"__len",
829020d003cSKyle Evans			},
830020d003cSKyle Evans			exclude = excludes_stack_overflow,
831020d003cSKyle Evans			stackvars = "\tconst char *path;\n",
832020d003cSKyle Evans			init = [[
833020d003cSKyle Evans	path = new_symlink(__len);		/* Cannot fail */
834020d003cSKyle Evans]],
835020d003cSKyle Evans		},
836cf8e5289SKyle Evans		{
837cf8e5289SKyle Evans			func = "readlinkat",
838cf8e5289SKyle Evans			arguments = {
839cf8e5289SKyle Evans				"AT_FDCWD",
840cf8e5289SKyle Evans				"path",
841cf8e5289SKyle Evans				"__buf",
842cf8e5289SKyle Evans				"__len",
843cf8e5289SKyle Evans			},
844cf8e5289SKyle Evans			exclude = excludes_stack_overflow,
845cf8e5289SKyle Evans			stackvars = "\tconst char *path;\n",
846cf8e5289SKyle Evans			init = [[
847cf8e5289SKyle Evans	path = new_symlink(__len);		/* Cannot fail */
848cf8e5289SKyle Evans]],
849cf8e5289SKyle Evans		},
850cf8e5289SKyle Evans		{
851cf8e5289SKyle Evans			func = "getdomainname",
852cf8e5289SKyle Evans			bufsize = "4",
853cf8e5289SKyle Evans			arguments = {
854cf8e5289SKyle Evans				"__buf",
855cf8e5289SKyle Evans				"__len",
856cf8e5289SKyle Evans			},
857cf8e5289SKyle Evans			exclude = excludes_stack_overflow,
858cf8e5289SKyle Evans			stackvars = "\tchar sysdomain[256];\n",
859cf8e5289SKyle Evans			early_init = [[
860cf8e5289SKyle Evans	(void)getdomainname(sysdomain, __len);
861cf8e5289SKyle Evans	if (strlen(sysdomain) <= __len)
862cf8e5289SKyle Evans		atf_tc_skip("domain name too short for testing");
863cf8e5289SKyle Evans]]
864cf8e5289SKyle Evans		},
865cf8e5289SKyle Evans		{
866cf8e5289SKyle Evans			func = "getentropy",
867cf8e5289SKyle Evans			arguments = {
868cf8e5289SKyle Evans				"__buf",
869cf8e5289SKyle Evans				"__len",
870cf8e5289SKyle Evans			},
871cf8e5289SKyle Evans			exclude = excludes_stack_overflow,
872cf8e5289SKyle Evans		},
873cf8e5289SKyle Evans		{
874cf8e5289SKyle Evans			func = "gethostname",
875cf8e5289SKyle Evans			bufsize = "4",
876cf8e5289SKyle Evans			arguments = {
877cf8e5289SKyle Evans				"__buf",
878cf8e5289SKyle Evans				"__len",
879cf8e5289SKyle Evans			},
880cf8e5289SKyle Evans			exclude = excludes_stack_overflow,
881cf8e5289SKyle Evans			stackvars = [[
882cf8e5289SKyle Evans	char syshost[256];
883cf8e5289SKyle Evans	int error;
884cf8e5289SKyle Evans]],
885cf8e5289SKyle Evans			early_init = [[
886cf8e5289SKyle Evans	error = gethostname(syshost, __len);
887cf8e5289SKyle Evans	if (error != 0 || strlen(syshost) <= __len)
888cf8e5289SKyle Evans		atf_tc_skip("hostname too short for testing");
889cf8e5289SKyle Evans]]
890cf8e5289SKyle Evans		},
891cf8e5289SKyle Evans		{
892cf8e5289SKyle Evans			func = "getlogin_r",
893cf8e5289SKyle Evans			bufsize = "MAXLOGNAME + 1",
894cf8e5289SKyle Evans			arguments = {
895cf8e5289SKyle Evans				"__buf",
896cf8e5289SKyle Evans				"__len",
897cf8e5289SKyle Evans			},
898cf8e5289SKyle Evans			exclude = excludes_stack_overflow,
899cf8e5289SKyle Evans		},
900cf8e5289SKyle Evans		{
901cf8e5289SKyle Evans			func = "ttyname_r",
902cf8e5289SKyle Evans			arguments = {
903cf8e5289SKyle Evans				"fd",
904cf8e5289SKyle Evans				"__buf",
905cf8e5289SKyle Evans				"__len",
906cf8e5289SKyle Evans			},
907cf8e5289SKyle Evans			exclude = excludes_stack_overflow,
908cf8e5289SKyle Evans			stackvars = "\tint fd;\n",
909cf8e5289SKyle Evans			early_init = [[
910cf8e5289SKyle Evans	fd = STDIN_FILENO;
911cf8e5289SKyle Evans	if (!isatty(fd))
912cf8e5289SKyle Evans		atf_tc_skip("stdin is not an fd");
913cf8e5289SKyle Evans]]
914cf8e5289SKyle Evans		},
915020d003cSKyle Evans	},
916b53d7aa8SKyle Evans	wchar = {
917b53d7aa8SKyle Evans		-- <wchar.h>
918b53d7aa8SKyle Evans		{
919b53d7aa8SKyle Evans			func = "wmemcpy",
920b53d7aa8SKyle Evans			buftype = "wchar_t[]",
921b53d7aa8SKyle Evans			arguments = {
922b53d7aa8SKyle Evans				"__buf",
923b53d7aa8SKyle Evans				"src",
924b53d7aa8SKyle Evans				"__len",
925b53d7aa8SKyle Evans			},
926b53d7aa8SKyle Evans			exclude = excludes_stack_overflow,
927b53d7aa8SKyle Evans			stackvars = "\twchar_t src[__len + 10];\n",
928b53d7aa8SKyle Evans		},
929b53d7aa8SKyle Evans		{
930b53d7aa8SKyle Evans			func = "wmempcpy",
931b53d7aa8SKyle Evans			buftype = "wchar_t[]",
932b53d7aa8SKyle Evans			arguments = {
933b53d7aa8SKyle Evans				"__buf",
934b53d7aa8SKyle Evans				"src",
935b53d7aa8SKyle Evans				"__len",
936b53d7aa8SKyle Evans			},
937b53d7aa8SKyle Evans			exclude = excludes_stack_overflow,
938b53d7aa8SKyle Evans			stackvars = "\twchar_t src[__len + 10];\n",
939b53d7aa8SKyle Evans		},
940b53d7aa8SKyle Evans		{
941b53d7aa8SKyle Evans			func = "wmemmove",
942b53d7aa8SKyle Evans			buftype = "wchar_t[]",
943b53d7aa8SKyle Evans			arguments = {
944b53d7aa8SKyle Evans				"__buf",
945b53d7aa8SKyle Evans				"src",
946b53d7aa8SKyle Evans				"__len",
947b53d7aa8SKyle Evans			},
948b53d7aa8SKyle Evans			exclude = excludes_stack_overflow,
949b53d7aa8SKyle Evans			stackvars = "\twchar_t src[__len + 10];\n",
950b53d7aa8SKyle Evans		},
951b53d7aa8SKyle Evans		{
952b53d7aa8SKyle Evans			func = "wmemset",
953b53d7aa8SKyle Evans			buftype = "wchar_t[]",
954b53d7aa8SKyle Evans			arguments = {
955b53d7aa8SKyle Evans				"__buf",
956b53d7aa8SKyle Evans				"L'0'",
957b53d7aa8SKyle Evans				"__len",
958b53d7aa8SKyle Evans			},
959b53d7aa8SKyle Evans			exclude = excludes_stack_overflow,
960b53d7aa8SKyle Evans		},
961b53d7aa8SKyle Evans		{
962b53d7aa8SKyle Evans			func = "wcpcpy",
963b53d7aa8SKyle Evans			buftype = "wchar_t[]",
964b53d7aa8SKyle Evans			arguments = {
965b53d7aa8SKyle Evans				"__buf",
966b53d7aa8SKyle Evans				"src",
967b53d7aa8SKyle Evans			},
968b53d7aa8SKyle Evans			exclude = excludes_stack_overflow,
969b53d7aa8SKyle Evans			stackvars = wstring_stackvars,
970b53d7aa8SKyle Evans			init = wstring_init,
971b53d7aa8SKyle Evans			uses_len = true,
972b53d7aa8SKyle Evans		},
973b53d7aa8SKyle Evans		{
974b53d7aa8SKyle Evans			func = "wcpncpy",
975b53d7aa8SKyle Evans			buftype = "wchar_t[]",
976b53d7aa8SKyle Evans			arguments = {
977b53d7aa8SKyle Evans				"__buf",
978b53d7aa8SKyle Evans				"src",
979b53d7aa8SKyle Evans				"__len",
980b53d7aa8SKyle Evans			},
981b53d7aa8SKyle Evans			exclude = excludes_stack_overflow,
982b53d7aa8SKyle Evans			stackvars = wstring_stackvars,
983b53d7aa8SKyle Evans			init = wstring_init,
984b53d7aa8SKyle Evans		},
985b53d7aa8SKyle Evans		{
986b53d7aa8SKyle Evans			func = "wcscat",
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 = "wcslcat",
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 = "wcsncat",
1011b53d7aa8SKyle Evans			buftype = "wchar_t[]",
1012b53d7aa8SKyle Evans			arguments = {
1013b53d7aa8SKyle Evans				"__buf",
1014b53d7aa8SKyle Evans				"src",
1015b53d7aa8SKyle Evans				"__len",
1016b53d7aa8SKyle Evans			},
1017b53d7aa8SKyle Evans			exclude = excludes_stack_overflow,
1018b53d7aa8SKyle Evans			stackvars = wstring_stackvars,
1019b53d7aa8SKyle Evans			init = wstring_init,
1020b53d7aa8SKyle Evans		},
1021b53d7aa8SKyle Evans		{
1022b53d7aa8SKyle Evans			func = "wcscpy",
1023b53d7aa8SKyle Evans			buftype = "wchar_t[]",
1024b53d7aa8SKyle Evans			arguments = {
1025b53d7aa8SKyle Evans				"__buf",
1026b53d7aa8SKyle Evans				"src",
1027b53d7aa8SKyle Evans			},
1028b53d7aa8SKyle Evans			exclude = excludes_stack_overflow,
1029b53d7aa8SKyle Evans			stackvars = wstring_stackvars,
1030b53d7aa8SKyle Evans			init = wstring_init,
1031b53d7aa8SKyle Evans			uses_len = true,
1032b53d7aa8SKyle Evans		},
1033b53d7aa8SKyle Evans		{
1034b53d7aa8SKyle Evans			func = "wcslcpy",
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 = "wcsncpy",
1047b53d7aa8SKyle Evans			buftype = "wchar_t[]",
1048b53d7aa8SKyle Evans			arguments = {
1049b53d7aa8SKyle Evans				"__buf",
1050b53d7aa8SKyle Evans				"src",
1051b53d7aa8SKyle Evans				"__len",
1052b53d7aa8SKyle Evans			},
1053b53d7aa8SKyle Evans			exclude = excludes_stack_overflow,
1054b53d7aa8SKyle Evans			stackvars = wstring_stackvars,
1055b53d7aa8SKyle Evans			init = wstring_init,
1056b53d7aa8SKyle Evans		},
1057b53d7aa8SKyle Evans	},
1058020d003cSKyle Evans}
1059020d003cSKyle Evans
1060020d003cSKyle Evanslocal function write_test_boilerplate(fh, name, body)
1061020d003cSKyle Evans	fh:write("ATF_TC_WITHOUT_HEAD(" .. name .. ");\n")
1062020d003cSKyle Evans	fh:write("ATF_TC_BODY(" .. name .. ", tc)\n")
1063020d003cSKyle Evans	fh:write("{\n" .. body .. "\n}\n\n")
1064020d003cSKyle Evans	return name
1065020d003cSKyle Evansend
1066020d003cSKyle Evans
1067020d003cSKyle Evanslocal function generate_test_name(func, variant, disposition, heap)
1068020d003cSKyle Evans	local basename = func
1069020d003cSKyle Evans	if variant then
1070020d003cSKyle Evans		basename = basename .. "_" .. variant
1071020d003cSKyle Evans	end
1072020d003cSKyle Evans	if heap then
1073020d003cSKyle Evans		basename = basename .. "_heap"
1074020d003cSKyle Evans	end
1075020d003cSKyle Evans	if disposition < 0 then
1076020d003cSKyle Evans		return basename .. "_before_end"
1077020d003cSKyle Evans	elseif disposition == 0 then
1078020d003cSKyle Evans		return basename .. "_end"
1079020d003cSKyle Evans	else
1080020d003cSKyle Evans		return basename .. "_after_end"
1081020d003cSKyle Evans	end
1082020d003cSKyle Evansend
1083020d003cSKyle Evans
1084020d003cSKyle Evanslocal function array_type(buftype)
1085020d003cSKyle Evans	if not buftype:match("%[%]") then
1086020d003cSKyle Evans		return nil
1087020d003cSKyle Evans	end
1088020d003cSKyle Evans
1089020d003cSKyle Evans	return buftype:gsub("%[%]", "")
1090020d003cSKyle Evansend
1091020d003cSKyle Evans
1092020d003cSKyle Evanslocal function configurable(def, idx)
1093020d003cSKyle Evans	local cfgitem = def[idx]
1094020d003cSKyle Evans
1095020d003cSKyle Evans	if not cfgitem then
1096020d003cSKyle Evans		return nil
1097020d003cSKyle Evans	end
1098020d003cSKyle Evans
1099020d003cSKyle Evans	if type(cfgitem) == "function" then
1100020d003cSKyle Evans		return cfgitem()
1101020d003cSKyle Evans	end
1102020d003cSKyle Evans
1103020d003cSKyle Evans	return cfgitem
1104020d003cSKyle Evansend
1105020d003cSKyle Evans
1106020d003cSKyle Evanslocal function generate_stackframe(buftype, bufsize, disposition, heap, def)
1107020d003cSKyle Evans	local function len_offset(inverted, disposition)
1108020d003cSKyle Evans		-- Tests that don't use __len in their arguments may use an
1109020d003cSKyle Evans		-- inverted sense because we can't just specify a length that
1110020d003cSKyle Evans		-- would induce an access just after the end.  Instead, we have
1111020d003cSKyle Evans		-- to manipulate the buffer size to be too short so that the
1112020d003cSKyle Evans		-- function under test would write one too many.
1113020d003cSKyle Evans		if disposition < 0 then
1114020d003cSKyle Evans			return ((inverted and " + ") or " - ") .. "1"
1115020d003cSKyle Evans		elseif disposition == 0 then
1116020d003cSKyle Evans			return ""
1117020d003cSKyle Evans		else
1118020d003cSKyle Evans			return ((inverted and " - ") or " + ") .. "1"
1119020d003cSKyle Evans		end
1120020d003cSKyle Evans	end
1121020d003cSKyle Evans
1122020d003cSKyle Evans	local function test_uses_len(def)
1123020d003cSKyle Evans		if def.uses_len then
1124020d003cSKyle Evans			return true
1125020d003cSKyle Evans		end
1126020d003cSKyle Evans
1127020d003cSKyle Evans		for _, arg in ipairs(def.arguments) do
1128020d003cSKyle Evans			if arg:match("__len") or arg:match("__idx") then
1129020d003cSKyle Evans				return true
1130020d003cSKyle Evans			end
1131020d003cSKyle Evans		end
1132020d003cSKyle Evans
1133020d003cSKyle Evans		return false
1134020d003cSKyle Evans	end
1135020d003cSKyle Evans
1136020d003cSKyle Evans
1137020d003cSKyle Evans	-- This is perhaps a little convoluted, but we toss the buffer into a
1138020d003cSKyle Evans	-- struct on the stack to guarantee that we have at least one valid
1139020d003cSKyle Evans	-- byte on either side of the buffer -- a measure to make sure that
1140020d003cSKyle Evans	-- we're tripping _FORTIFY_SOURCE specifically in the buffer + 1 case,
1141020d003cSKyle Evans	-- rather than some other stack or memory protection.
1142020d003cSKyle Evans	local vars = "\tstruct {\n"
1143020d003cSKyle Evans	vars = vars .. "\t\tuint8_t padding_l;\n"
1144020d003cSKyle Evans
1145020d003cSKyle Evans	local uses_len = test_uses_len(def)
1146020d003cSKyle Evans	local bufsize_offset = len_offset(not uses_len, disposition)
1147020d003cSKyle Evans	local buftype_elem = array_type(buftype)
1148020d003cSKyle Evans	local size_expr = bufsize
1149020d003cSKyle Evans
1150020d003cSKyle Evans	if not uses_len then
1151020d003cSKyle Evans		-- If the length isn't in use, we have to vary the buffer size
1152020d003cSKyle Evans		-- since the fortified function likely has some internal size
1153020d003cSKyle Evans		-- constraint that it's supposed to be checking.
1154020d003cSKyle Evans		size_expr = size_expr .. bufsize_offset
1155020d003cSKyle Evans	end
1156020d003cSKyle Evans
1157020d003cSKyle Evans	if not heap and buftype_elem then
1158020d003cSKyle Evans		-- Array type: size goes after identifier
1159020d003cSKyle Evans		vars = vars .. "\t\t" .. buftype_elem ..
1160020d003cSKyle Evans		    " __buf[" .. size_expr .. "];\n"
1161020d003cSKyle Evans	else
1162020d003cSKyle Evans		local basic_type = buftype_elem or buftype
1163020d003cSKyle Evans
1164020d003cSKyle Evans		-- Heap tests obviously just put a pointer on the stack that
1165020d003cSKyle Evans		-- points to our new allocation, but we leave it in the padded
1166020d003cSKyle Evans		-- struct just to simplify our generator.
1167020d003cSKyle Evans		if heap then
1168020d003cSKyle Evans			basic_type = basic_type .. " *"
1169020d003cSKyle Evans		end
1170020d003cSKyle Evans		vars = vars .. "\t\t" .. basic_type .. " __buf;\n"
1171020d003cSKyle Evans	end
1172020d003cSKyle Evans
1173020d003cSKyle Evans	-- padding_r is our just-past-the-end padding that we use to make sure
1174020d003cSKyle Evans	-- that there's a valid portion after the buffer that isn't being
1175020d003cSKyle Evans	-- included in our function calls.  If we didn't have it, then we'd have
1176020d003cSKyle Evans	-- a hard time feeling confident that an abort on the just-after tests
1177020d003cSKyle Evans	-- isn't maybe from some other memory or stack protection.
1178020d003cSKyle Evans	vars = vars .. "\t\tuint8_t padding_r;\n"
1179020d003cSKyle Evans	vars = vars .. "\t} __stack;\n"
1180020d003cSKyle Evans
1181020d003cSKyle Evans	-- Not all tests will use __bufsz, but some do for, e.g., clearing
1182020d003cSKyle Evans	-- memory..
1183020d003cSKyle Evans	vars = vars .. "\tconst size_t __bufsz __unused = "
1184020d003cSKyle Evans	if heap then
1185020d003cSKyle Evans		local scalar = 1
1186020d003cSKyle Evans		if buftype_elem then
1187020d003cSKyle Evans			scalar = size_expr
1188020d003cSKyle Evans		end
1189020d003cSKyle Evans
1190020d003cSKyle Evans		vars = vars .. "sizeof(*__stack.__buf) * (" .. scalar .. ");\n"
1191020d003cSKyle Evans	else
1192020d003cSKyle Evans		vars = vars .. "sizeof(__stack.__buf);\n"
1193020d003cSKyle Evans	end
1194020d003cSKyle Evans
1195020d003cSKyle Evans	vars = vars .. "\tconst size_t __len = " .. bufsize ..
1196020d003cSKyle Evans	    bufsize_offset .. ";\n"
1197020d003cSKyle Evans	vars = vars .. "\tconst size_t __idx __unused = __len - 1;\n"
1198020d003cSKyle Evans
1199020d003cSKyle Evans	-- For overflow testing, we need to fork() because we're expecting the
1200020d003cSKyle Evans	-- test to ultimately abort()/_exit().  Then we can collect the exit
1201020d003cSKyle Evans	-- status and report appropriately.
1202020d003cSKyle Evans	if disposition > 0 then
1203020d003cSKyle Evans		vars = vars .. "\tpid_t __child;\n"
1204020d003cSKyle Evans		vars = vars .. "\tint __status;\n"
1205020d003cSKyle Evans	end
1206020d003cSKyle Evans
1207020d003cSKyle Evans	-- Any other stackvars defined by the test get placed after everything
1208020d003cSKyle Evans	-- else.
1209020d003cSKyle Evans	vars = vars .. (configurable(def, "stackvars") or "")
1210020d003cSKyle Evans
1211020d003cSKyle Evans	return vars
1212020d003cSKyle Evansend
1213020d003cSKyle Evans
1214020d003cSKyle Evanslocal function write_test(fh, func, disposition, heap, def)
1215020d003cSKyle Evans	local testname = generate_test_name(func, def.variant, disposition, heap)
1216020d003cSKyle Evans	local buftype = def.buftype or "unsigned char[]"
1217020d003cSKyle Evans	local bufsize = def.bufsize or 42
1218020d003cSKyle Evans	local body = ""
1219020d003cSKyle Evans
1220020d003cSKyle Evans	if def.exclude and def.exclude(disposition, heap) then
1221020d003cSKyle Evans		return
1222020d003cSKyle Evans	end
1223020d003cSKyle Evans
1224020d003cSKyle Evans	local function need_addr(buftype)
1225020d003cSKyle Evans		return not (buftype:match("%[%]") or buftype:match("%*"))
1226020d003cSKyle Evans	end
1227020d003cSKyle Evans
1228020d003cSKyle Evans	if heap then
1229020d003cSKyle Evans		body = body .. "#define BUF __stack.__buf\n"
1230020d003cSKyle Evans	else
1231020d003cSKyle Evans		body = body .. "#define BUF &__stack.__buf\n"
1232020d003cSKyle Evans	end
1233020d003cSKyle Evans
1234020d003cSKyle Evans	-- Setup the buffer
1235020d003cSKyle Evans	body = body .. generate_stackframe(buftype, bufsize, disposition, heap, def) ..
1236020d003cSKyle Evans	    "\n"
1237020d003cSKyle Evans
1238020d003cSKyle Evans	-- Any early initialization goes before we would fork for the just-after
1239020d003cSKyle Evans	-- tests, because they may want to skip the test based on some criteria
1240020d003cSKyle Evans	-- and we can't propagate that up very easily once we're forked.
1241020d003cSKyle Evans	local early_init = configurable(def, "early_init")
1242020d003cSKyle Evans	body = body .. (early_init or "")
1243020d003cSKyle Evans	if early_init then
1244020d003cSKyle Evans		body = body .. "\n"
1245020d003cSKyle Evans	end
1246020d003cSKyle Evans
1247020d003cSKyle Evans	-- Fork off, iff we're testing some access past the end of the buffer.
1248020d003cSKyle Evans	if disposition > 0 then
1249020d003cSKyle Evans		body = body .. [[
1250020d003cSKyle Evans	__child = fork();
1251020d003cSKyle Evans	ATF_REQUIRE(__child >= 0);
1252020d003cSKyle Evans	if (__child > 0)
1253020d003cSKyle Evans		goto monitor;
1254020d003cSKyle Evans
1255020d003cSKyle Evans	/* Child */
1256020d003cSKyle Evans	disable_coredumps();
1257020d003cSKyle Evans]]
1258020d003cSKyle Evans	end
1259020d003cSKyle Evans
1260020d003cSKyle Evans	local bufvar = "__stack.__buf"
1261020d003cSKyle Evans	if heap then
1262020d003cSKyle Evans		-- Buffer needs to be initialized because it's a heap allocation.
1263020d003cSKyle Evans		body = body .. "\t" .. bufvar .. " = malloc(__bufsz);\n"
1264020d003cSKyle Evans	end
1265020d003cSKyle Evans
1266020d003cSKyle Evans	-- Non-early init happens just after the fork in the child, not the
1267020d003cSKyle Evans	-- monitor.  This is used to setup any other buffers we may need, for
1268020d003cSKyle Evans	-- instance.
1269020d003cSKyle Evans	local extra_init = configurable(def, "init")
1270020d003cSKyle Evans	body = body .. (extra_init or "")
1271020d003cSKyle Evans
1272020d003cSKyle Evans	if heap or extra_init then
1273020d003cSKyle Evans		body = body .. "\n"
1274020d003cSKyle Evans	end
1275020d003cSKyle Evans
1276020d003cSKyle Evans	-- Setup the function call with arguments as described in the test
1277020d003cSKyle Evans	-- definition.
1278020d003cSKyle Evans	body = body .. "\t" .. func .. "("
1279020d003cSKyle Evans
1280020d003cSKyle Evans	for idx, arg in ipairs(def.arguments) do
1281020d003cSKyle Evans		if idx > 1 then
1282020d003cSKyle Evans			body = body .. ", "
1283020d003cSKyle Evans		end
1284020d003cSKyle Evans
1285020d003cSKyle Evans		if arg == "__buf" then
1286020d003cSKyle Evans			if not heap and need_addr(buftype) then
1287020d003cSKyle Evans				body = body .. "&"
1288020d003cSKyle Evans			end
1289020d003cSKyle Evans
1290020d003cSKyle Evans			body = body .. bufvar
1291020d003cSKyle Evans		else
1292020d003cSKyle Evans			local argname = arg
1293020d003cSKyle Evans
1294020d003cSKyle Evans			if def.value_of then
1295020d003cSKyle Evans				argname = argname or def.value_of(arg)
1296020d003cSKyle Evans			end
1297020d003cSKyle Evans
1298020d003cSKyle Evans			body = body .. argname
1299020d003cSKyle Evans		end
1300020d003cSKyle Evans	end
1301020d003cSKyle Evans
1302020d003cSKyle Evans	body = body .. ");\n"
1303020d003cSKyle Evans
1304020d003cSKyle Evans	-- Monitor stuff follows, for OOB access.
1305020d003cSKyle Evans	if disposition <= 0 then
1306020d003cSKyle Evans		goto skip
1307020d003cSKyle Evans	end
1308020d003cSKyle Evans
1309020d003cSKyle Evans	body = body .. [[
1310020d003cSKyle Evans	_exit(EX_SOFTWARE);	/* Should have aborted. */
1311020d003cSKyle Evans
1312020d003cSKyle Evansmonitor:
1313020d003cSKyle Evans	while (waitpid(__child, &__status, 0) != __child) {
1314020d003cSKyle Evans		ATF_REQUIRE_EQ(EINTR, errno);
1315020d003cSKyle Evans	}
1316020d003cSKyle Evans
1317020d003cSKyle Evans	if (!WIFSIGNALED(__status)) {
1318020d003cSKyle Evans		switch (WEXITSTATUS(__status)) {
1319020d003cSKyle Evans		case EX_SOFTWARE:
1320020d003cSKyle Evans			atf_tc_fail("FORTIFY_SOURCE failed to abort");
1321020d003cSKyle Evans			break;
1322020d003cSKyle Evans		case EX_OSERR:
1323020d003cSKyle Evans			atf_tc_fail("setrlimit(2) failed");
1324020d003cSKyle Evans			break;
1325020d003cSKyle Evans		default:
1326020d003cSKyle Evans			atf_tc_fail("child exited with status %d",
1327020d003cSKyle Evans			    WEXITSTATUS(__status));
1328020d003cSKyle Evans		}
1329020d003cSKyle Evans	} else {
1330020d003cSKyle Evans		ATF_REQUIRE_EQ(SIGABRT, WTERMSIG(__status));
1331020d003cSKyle Evans	}
1332020d003cSKyle Evans]]
1333020d003cSKyle Evans
1334020d003cSKyle Evans::skip::
1335020d003cSKyle Evans	body = body .. "#undef BUF\n"
1336020d003cSKyle Evans	return write_test_boilerplate(fh, testname, body)
1337020d003cSKyle Evansend
1338020d003cSKyle Evans
1339020d003cSKyle Evans-- main()
1340020d003cSKyle Evanslocal tests
1341020d003cSKyle Evanslocal tcat = assert(arg[1], "usage: generate-fortify-tests.lua <category>")
1342020d003cSKyle Evansfor k, defs in pairs(all_tests) do
1343020d003cSKyle Evans	if k == tcat then
1344020d003cSKyle Evans		tests = defs
1345020d003cSKyle Evans		break
1346020d003cSKyle Evans	end
1347020d003cSKyle Evansend
1348020d003cSKyle Evans
1349020d003cSKyle Evansassert(tests, "category " .. tcat .. " not found")
1350020d003cSKyle Evans
1351020d003cSKyle Evanslocal fh = io.stdout
1352020d003cSKyle Evansfh:write("/* @" .. "generated" .. " by `generate-fortify-tests.lua \"" ..
1353020d003cSKyle Evans    tcat .. "\"` */\n\n")
1354020d003cSKyle Evansfh:write("#define	_FORTIFY_SOURCE	2\n")
1355020d003cSKyle Evansfh:write("#define	TMPFILE_SIZE	(1024 * 32)\n")
1356020d003cSKyle Evans
1357020d003cSKyle Evansfh:write("\n")
1358020d003cSKyle Evansfor _, inc in ipairs(includes) do
1359020d003cSKyle Evans	fh:write("#include <" .. inc .. ">\n")
1360020d003cSKyle Evansend
1361020d003cSKyle Evans
1362020d003cSKyle Evansfh:write([[
1363020d003cSKyle Evans
1364cf8e5289SKyle Evansstatic FILE * __unused
1365cf8e5289SKyle Evansnew_fp(size_t __len)
1366cf8e5289SKyle Evans{
1367cf8e5289SKyle Evans	static char fpbuf[LINE_MAX];
1368cf8e5289SKyle Evans	FILE *fp;
1369cf8e5289SKyle Evans
1370cf8e5289SKyle Evans	ATF_REQUIRE(__len <= sizeof(fpbuf));
1371cf8e5289SKyle Evans
1372cf8e5289SKyle Evans	memset(fpbuf, 'A', sizeof(fpbuf) - 1);
1373cf8e5289SKyle Evans	fpbuf[sizeof(fpbuf) - 1] = '\0';
1374cf8e5289SKyle Evans
1375cf8e5289SKyle Evans	fp = fmemopen(fpbuf, sizeof(fpbuf), "rb");
1376cf8e5289SKyle Evans	ATF_REQUIRE(fp != NULL);
1377cf8e5289SKyle Evans
1378cf8e5289SKyle Evans	return (fp);
1379cf8e5289SKyle Evans}
1380cf8e5289SKyle Evans
1381020d003cSKyle Evans/*
1382020d003cSKyle Evans * Create a new symlink to use for readlink(2) style tests, we'll just use a
1383020d003cSKyle Evans * random target name to have something interesting to look at.
1384020d003cSKyle Evans */
1385020d003cSKyle Evansstatic const char * __unused
1386020d003cSKyle Evansnew_symlink(size_t __len)
1387020d003cSKyle Evans{
1388020d003cSKyle Evans	static const char linkname[] = "link";
1389020d003cSKyle Evans	char target[MAXNAMLEN];
1390020d003cSKyle Evans	int error;
1391020d003cSKyle Evans
1392020d003cSKyle Evans	ATF_REQUIRE(__len <= sizeof(target));
1393020d003cSKyle Evans
1394020d003cSKyle Evans	arc4random_buf(target, sizeof(target));
1395020d003cSKyle Evans
1396020d003cSKyle Evans	error = unlink(linkname);
1397020d003cSKyle Evans	ATF_REQUIRE(error == 0 || errno == ENOENT);
1398020d003cSKyle Evans
1399020d003cSKyle Evans	error = symlink(target, linkname);
1400020d003cSKyle Evans	ATF_REQUIRE(error == 0);
1401020d003cSKyle Evans
1402020d003cSKyle Evans	return (linkname);
1403020d003cSKyle Evans}
1404020d003cSKyle Evans
1405020d003cSKyle Evans/*
1406*1f155d48SKyle Evans * For our purposes, first descriptor will be the reader; we'll send both
1407*1f155d48SKyle Evans * raw data and a control message over it so that the result can be used for
1408*1f155d48SKyle Evans * any of our recv*() tests.
1409*1f155d48SKyle Evans */
1410*1f155d48SKyle Evansstatic void __unused
1411*1f155d48SKyle Evansnew_socket(int sock[2])
1412*1f155d48SKyle Evans{
1413*1f155d48SKyle Evans	unsigned char ctrl[CMSG_SPACE(sizeof(int))] = { 0 };
1414*1f155d48SKyle Evans	static char sockbuf[256];
1415*1f155d48SKyle Evans	ssize_t rv;
1416*1f155d48SKyle Evans	size_t total = 0;
1417*1f155d48SKyle Evans	struct msghdr hdr = { 0 };
1418*1f155d48SKyle Evans	struct cmsghdr *cmsg;
1419*1f155d48SKyle Evans	int error, fd;
1420*1f155d48SKyle Evans
1421*1f155d48SKyle Evans	error = socketpair(AF_UNIX, SOCK_STREAM, 0, sock);
1422*1f155d48SKyle Evans	ATF_REQUIRE(error == 0);
1423*1f155d48SKyle Evans
1424*1f155d48SKyle Evans	while (total != sizeof(sockbuf)) {
1425*1f155d48SKyle Evans		rv = send(sock[1], &sockbuf[total], sizeof(sockbuf) - total, 0);
1426*1f155d48SKyle Evans
1427*1f155d48SKyle Evans		ATF_REQUIRE_MSG(rv > 0,
1428*1f155d48SKyle Evans		    "expected bytes sent, got %zd with %zu left (size %zu, total %zu)",
1429*1f155d48SKyle Evans		    rv, sizeof(sockbuf) - total, sizeof(sockbuf), total);
1430*1f155d48SKyle Evans		ATF_REQUIRE_MSG(total + (size_t)rv <= sizeof(sockbuf),
1431*1f155d48SKyle Evans		    "%zd exceeds total %zu", rv, sizeof(sockbuf));
1432*1f155d48SKyle Evans		total += rv;
1433*1f155d48SKyle Evans	}
1434*1f155d48SKyle Evans
1435*1f155d48SKyle Evans	hdr.msg_control = ctrl;
1436*1f155d48SKyle Evans	hdr.msg_controllen = sizeof(ctrl);
1437*1f155d48SKyle Evans
1438*1f155d48SKyle Evans	cmsg = CMSG_FIRSTHDR(&hdr);
1439*1f155d48SKyle Evans	cmsg->cmsg_level = SOL_SOCKET;
1440*1f155d48SKyle Evans	cmsg->cmsg_type = SCM_RIGHTS;
1441*1f155d48SKyle Evans	cmsg->cmsg_len = CMSG_LEN(sizeof(fd));
1442*1f155d48SKyle Evans	fd = STDIN_FILENO;
1443*1f155d48SKyle Evans	memcpy(CMSG_DATA(cmsg), &fd, sizeof(fd));
1444*1f155d48SKyle Evans
1445*1f155d48SKyle Evans	error = sendmsg(sock[1], &hdr, 0);
1446*1f155d48SKyle Evans	ATF_REQUIRE(error != -1);
1447*1f155d48SKyle Evans}
1448*1f155d48SKyle Evans
1449*1f155d48SKyle Evans/*
1450020d003cSKyle Evans * Constructs a tmpfile that we can use for testing read(2) and friends.
1451020d003cSKyle Evans */
1452020d003cSKyle Evansstatic int __unused
1453020d003cSKyle Evansnew_tmpfile(void)
1454020d003cSKyle Evans{
1455020d003cSKyle Evans	char buf[1024];
1456020d003cSKyle Evans	ssize_t rv;
1457020d003cSKyle Evans	size_t written;
1458020d003cSKyle Evans	int fd;
1459020d003cSKyle Evans
1460020d003cSKyle Evans	fd = open("tmpfile", O_RDWR | O_CREAT | O_TRUNC, 0644);
1461020d003cSKyle Evans	ATF_REQUIRE(fd >= 0);
1462020d003cSKyle Evans
1463020d003cSKyle Evans	written = 0;
1464020d003cSKyle Evans	while (written < TMPFILE_SIZE) {
1465020d003cSKyle Evans		rv = write(fd, buf, sizeof(buf));
1466020d003cSKyle Evans		ATF_REQUIRE(rv > 0);
1467020d003cSKyle Evans
1468020d003cSKyle Evans		written += rv;
1469020d003cSKyle Evans	}
1470020d003cSKyle Evans
1471020d003cSKyle Evans	ATF_REQUIRE_EQ(0, lseek(fd, 0, SEEK_SET));
1472020d003cSKyle Evans	return (fd);
1473020d003cSKyle Evans}
1474020d003cSKyle Evans
1475020d003cSKyle Evansstatic void
1476020d003cSKyle Evansdisable_coredumps(void)
1477020d003cSKyle Evans{
1478020d003cSKyle Evans	struct rlimit rl = { 0 };
1479020d003cSKyle Evans
1480020d003cSKyle Evans	if (setrlimit(RLIMIT_CORE, &rl) == -1)
1481020d003cSKyle Evans		_exit(EX_OSERR);
1482020d003cSKyle Evans}
1483020d003cSKyle Evans
1484cf8e5289SKyle Evans/*
1485cf8e5289SKyle Evans * Replaces stdin with a file that we can actually read from, for tests where
1486cf8e5289SKyle Evans * we want a FILE * or fd that we can get data from.
1487cf8e5289SKyle Evans */
1488cf8e5289SKyle Evansstatic void __unused
1489cf8e5289SKyle Evansreplace_stdin(void)
1490cf8e5289SKyle Evans{
1491cf8e5289SKyle Evans	int fd;
1492cf8e5289SKyle Evans
1493cf8e5289SKyle Evans	fd = new_tmpfile();
1494cf8e5289SKyle Evans
1495cf8e5289SKyle Evans	(void)dup2(fd, STDIN_FILENO);
1496cf8e5289SKyle Evans	if (fd != STDIN_FILENO)
1497cf8e5289SKyle Evans		close(fd);
1498cf8e5289SKyle Evans}
1499cf8e5289SKyle Evans
1500020d003cSKyle Evans]])
1501020d003cSKyle Evans
1502020d003cSKyle Evansfor _, def in pairs(tests) do
1503020d003cSKyle Evans	local func = def.func
1504020d003cSKyle Evans	local function write_tests(heap)
1505020d003cSKyle Evans		-- Dispositions here are relative to the buffer size prescribed
1506020d003cSKyle Evans		-- by the test definition.
1507020d003cSKyle Evans		local dispositions = def.dispositions or { -1, 0, 1 }
1508020d003cSKyle Evans
1509020d003cSKyle Evans		for _, disposition in ipairs(dispositions) do
1510020d003cSKyle Evans			tests_added[#tests_added + 1] = write_test(fh, func, disposition, heap, def)
1511020d003cSKyle Evans		end
1512020d003cSKyle Evans	end
1513020d003cSKyle Evans
1514020d003cSKyle Evans	write_tests(false)
1515020d003cSKyle Evans	write_tests(true)
1516020d003cSKyle Evansend
1517020d003cSKyle Evans
1518020d003cSKyle Evansfh:write("ATF_TP_ADD_TCS(tp)\n")
1519020d003cSKyle Evansfh:write("{\n")
1520020d003cSKyle Evansfor idx = 1, #tests_added do
1521020d003cSKyle Evans	fh:write("\tATF_TP_ADD_TC(tp, " .. tests_added[idx] .. ");\n")
1522020d003cSKyle Evansend
1523020d003cSKyle Evansfh:write("\treturn (atf_no_error());\n")
1524020d003cSKyle Evansfh:write("}\n")
1525