xref: /freebsd/lib/libc/tests/secure/generate-fortify-tests.lua (revision d0b7445904f592bf379d64932fb6f1fdc29c4aa7)
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",
65020d003cSKyle Evans	"sys/resource.h",
66020d003cSKyle Evans	"sys/time.h",
67020d003cSKyle Evans	"sys/wait.h",
68020d003cSKyle Evans	"dirent.h",
69020d003cSKyle Evans	"errno.h",
70020d003cSKyle Evans	"fcntl.h",
71020d003cSKyle Evans	"limits.h",
7288276dfbSKyle Evans	"poll.h",
73020d003cSKyle Evans	"signal.h",
74020d003cSKyle Evans	"stdio.h",
75020d003cSKyle Evans	"stdlib.h",
76020d003cSKyle Evans	"string.h",
77020d003cSKyle Evans	"strings.h",
78020d003cSKyle Evans	"sysexits.h",
79020d003cSKyle Evans	"unistd.h",
80020d003cSKyle Evans	"atf-c.h",
81020d003cSKyle Evans}
82020d003cSKyle Evans
83020d003cSKyle Evanslocal tests_added = {}
84020d003cSKyle Evans
85020d003cSKyle Evans-- Some of these will need to be excluded because clang sees the wrong size when
86020d003cSKyle Evans-- an array is embedded inside a struct, we'll get something that looks more
87020d003cSKyle Evans-- like __builtin_object_size(ptr, 0) than it does the correct
88020d003cSKyle Evans-- __builtin_object_size(ptr, 1) (i.e., includes the padding after).  This is
89020d003cSKyle Evans-- almost certainly a bug in llvm.
90020d003cSKyle Evanslocal function excludes_stack_overflow(disposition, is_heap)
91020d003cSKyle Evans	return (not is_heap) and disposition > 0
92020d003cSKyle Evansend
93020d003cSKyle Evans
9488276dfbSKyle Evanslocal poll_init = [[
9588276dfbSKyle Evans	for (size_t i = 0; i < howmany(__bufsz, sizeof(struct pollfd)); i++) {
9688276dfbSKyle Evans		__stack.__buf[i].fd = -1;
9788276dfbSKyle Evans	}
9888276dfbSKyle Evans]]
9988276dfbSKyle Evans
100020d003cSKyle Evanslocal printf_stackvars = "\tchar srcvar[__len + 10];\n"
101020d003cSKyle Evanslocal printf_init = [[
102020d003cSKyle Evans	memset(srcvar, 'A', sizeof(srcvar) - 1);
103020d003cSKyle Evans	srcvar[sizeof(srcvar) - 1] = '\0';
104020d003cSKyle Evans]]
105020d003cSKyle Evans
106cf8e5289SKyle Evanslocal stdio_init = [[
107cf8e5289SKyle Evans	replace_stdin();
108cf8e5289SKyle Evans]]
109cf8e5289SKyle Evans
110020d003cSKyle Evanslocal string_stackvars = "\tchar src[__len];\n"
111020d003cSKyle Evanslocal string_init = [[
112020d003cSKyle Evans	memset(__stack.__buf, 0, __len);
113020d003cSKyle Evans	memset(src, 'A', __len - 1);
114020d003cSKyle Evans	src[__len - 1] = '\0';
115020d003cSKyle Evans]]
116020d003cSKyle Evans
117020d003cSKyle Evans-- Each test entry describes how to test a given function.  We need to know how
118020d003cSKyle Evans-- to construct the buffer, we need to know the argument set we're dealing with,
119020d003cSKyle Evans-- and we need to know what we're passing to each argument.  We could be passing
120020d003cSKyle Evans-- fixed values, or we could be passing the __buf under test.
121020d003cSKyle Evans--
122020d003cSKyle Evans-- definition:
123020d003cSKyle Evans--   func: name of the function under test to call
124020d003cSKyle Evans--   bufsize: size of buffer to generate, defaults to 42
125020d003cSKyle Evans--   buftype: type of buffer to generate, defaults to unsigned char[]
126020d003cSKyle Evans--   arguments: __buf, __len, or the name of a variable placed on the stack
127020d003cSKyle Evans--   exclude: a function(disposition, is_heap) that returns true if this combo
128020d003cSKyle Evans--     should be excluded.
129020d003cSKyle Evans--   stackvars: extra variables to be placed on the stack, should be a string
130020d003cSKyle Evans--     optionally formatted with tabs and newlines
131020d003cSKyle Evans--   init: extra code to inject just before the function call for initialization
132020d003cSKyle Evans--     of the buffer or any of the above-added stackvars; also a string
133020d003cSKyle Evans--   uses_len: bool-ish, necessary if arguments doesn't include either __idx or
134020d003cSKyle Evans--     or __len so that the test generator doesn't try to vary the size of the
135020d003cSKyle Evans--     buffer instead of just manipulating __idx/__len to try and induce an
136020d003cSKyle Evans--     overflow.
137020d003cSKyle Evans--
138020d003cSKyle Evans-- Most tests will just use the default bufsize/buftype, but under some
139020d003cSKyle Evans-- circumstances it's useful to use a different type (e.g., for alignment
140020d003cSKyle Evans-- requirements).
141020d003cSKyle Evanslocal all_tests = {
14288276dfbSKyle Evans	poll = {
14388276dfbSKyle Evans		-- <poll.h>
14488276dfbSKyle Evans		{
14588276dfbSKyle Evans			func = "poll",
14688276dfbSKyle Evans			bufsize = "4",
14788276dfbSKyle Evans			buftype = "struct pollfd[]",
14888276dfbSKyle Evans			arguments = {
14988276dfbSKyle Evans				"__buf",
15088276dfbSKyle Evans				"__len",
15188276dfbSKyle Evans				"0",
15288276dfbSKyle Evans			},
15388276dfbSKyle Evans			init = poll_init,
15488276dfbSKyle Evans		},
15588276dfbSKyle Evans		{
15688276dfbSKyle Evans			func = "ppoll",
15788276dfbSKyle Evans			bufsize = "4",
15888276dfbSKyle Evans			buftype = "struct pollfd[]",
15988276dfbSKyle Evans			arguments = {
16088276dfbSKyle Evans				"__buf",
16188276dfbSKyle Evans				"__len",
16288276dfbSKyle Evans				"&tv",
16388276dfbSKyle Evans				"NULL",
16488276dfbSKyle Evans			},
16588276dfbSKyle Evans			stackvars = "\tstruct timespec tv = { 0 };\n",
16688276dfbSKyle Evans			init = poll_init,
16788276dfbSKyle Evans		},
16888276dfbSKyle Evans	},
169020d003cSKyle Evans	stdio = {
170020d003cSKyle Evans		-- <stdio.h>
171020d003cSKyle Evans		{
172cf8e5289SKyle Evans			func = "ctermid",
173cf8e5289SKyle Evans			bufsize = "L_ctermid",
174cf8e5289SKyle Evans			arguments = {
175cf8e5289SKyle Evans				"__buf",
176cf8e5289SKyle Evans			},
177cf8e5289SKyle Evans			exclude = excludes_stack_overflow,
178cf8e5289SKyle Evans		},
179cf8e5289SKyle Evans		{
180cf8e5289SKyle Evans			func = "ctermid_r",
181cf8e5289SKyle Evans			bufsize = "L_ctermid",
182cf8e5289SKyle Evans			arguments = {
183cf8e5289SKyle Evans				"__buf",
184cf8e5289SKyle Evans			},
185cf8e5289SKyle Evans			exclude = excludes_stack_overflow,
186cf8e5289SKyle Evans		},
187cf8e5289SKyle Evans		{
188cf8e5289SKyle Evans			func = "fread",
189cf8e5289SKyle Evans			arguments = {
190cf8e5289SKyle Evans				"__buf",
191cf8e5289SKyle Evans				"__len",
192cf8e5289SKyle Evans				"1",
193cf8e5289SKyle Evans				"stdin",
194cf8e5289SKyle Evans			},
195cf8e5289SKyle Evans			exclude = excludes_stack_overflow,
196cf8e5289SKyle Evans			init = stdio_init,
197cf8e5289SKyle Evans		},
198cf8e5289SKyle Evans		{
199cf8e5289SKyle Evans			func = "fread_unlocked",
200cf8e5289SKyle Evans			arguments = {
201cf8e5289SKyle Evans				"__buf",
202cf8e5289SKyle Evans				"__len",
203cf8e5289SKyle Evans				"1",
204cf8e5289SKyle Evans				"stdin",
205cf8e5289SKyle Evans			},
206cf8e5289SKyle Evans			exclude = excludes_stack_overflow,
207cf8e5289SKyle Evans			init = stdio_init,
208cf8e5289SKyle Evans		},
209cf8e5289SKyle Evans		{
210cf8e5289SKyle Evans			func = "gets_s",
211cf8e5289SKyle Evans			arguments = {
212cf8e5289SKyle Evans				"__buf",
213cf8e5289SKyle Evans				"__len",
214cf8e5289SKyle Evans			},
215cf8e5289SKyle Evans			exclude = excludes_stack_overflow,
216cf8e5289SKyle Evans			init = stdio_init,
217cf8e5289SKyle Evans		},
218cf8e5289SKyle Evans		{
219020d003cSKyle Evans			func = "sprintf",
220020d003cSKyle Evans			arguments = {
221020d003cSKyle Evans				"__buf",
222020d003cSKyle Evans				"\"%.*s\"",
223020d003cSKyle Evans				"(int)__len - 1",	-- - 1 for NUL terminator
224020d003cSKyle Evans				"srcvar",
225020d003cSKyle Evans			},
226020d003cSKyle Evans			exclude = excludes_stack_overflow,
227020d003cSKyle Evans			stackvars = printf_stackvars,
228020d003cSKyle Evans			init = printf_init,
229020d003cSKyle Evans		},
230020d003cSKyle Evans		{
231020d003cSKyle Evans			func = "snprintf",
232020d003cSKyle Evans			arguments = {
233020d003cSKyle Evans				"__buf",
234020d003cSKyle Evans				"__len",
235020d003cSKyle Evans				"\"%.*s\"",
236020d003cSKyle Evans				"(int)__len - 1",	-- - 1 for NUL terminator
237020d003cSKyle Evans				"srcvar",
238020d003cSKyle Evans			},
239020d003cSKyle Evans			exclude = excludes_stack_overflow,
240020d003cSKyle Evans			stackvars = printf_stackvars,
241020d003cSKyle Evans			init = printf_init,
242020d003cSKyle Evans		},
243cf8e5289SKyle Evans		{
244cf8e5289SKyle Evans			func = "tmpnam",
245cf8e5289SKyle Evans			bufsize = "L_tmpnam",
246cf8e5289SKyle Evans			arguments = {
247cf8e5289SKyle Evans				"__buf",
248cf8e5289SKyle Evans			},
249cf8e5289SKyle Evans			exclude = excludes_stack_overflow,
250cf8e5289SKyle Evans		},
251cf8e5289SKyle Evans		{
252cf8e5289SKyle Evans			func = "fgets",
253cf8e5289SKyle Evans			arguments = {
254cf8e5289SKyle Evans				"__buf",
255cf8e5289SKyle Evans				"__len",
256cf8e5289SKyle Evans				"fp",
257cf8e5289SKyle Evans			},
258cf8e5289SKyle Evans			exclude = excludes_stack_overflow,
259cf8e5289SKyle Evans			stackvars = "\tFILE *fp;\n",
260cf8e5289SKyle Evans			init = [[
261cf8e5289SKyle Evans	fp = new_fp(__len);
262cf8e5289SKyle Evans]],
263cf8e5289SKyle Evans		},
264020d003cSKyle Evans	},
265*d0b74459SKyle Evans	stdlib = {
266*d0b74459SKyle Evans		-- <stdlib.h>
267*d0b74459SKyle Evans		{
268*d0b74459SKyle Evans			func = "arc4random_buf",
269*d0b74459SKyle Evans			arguments = {
270*d0b74459SKyle Evans				"__buf",
271*d0b74459SKyle Evans				"__len",
272*d0b74459SKyle Evans			},
273*d0b74459SKyle Evans			exclude = excludes_stack_overflow,
274*d0b74459SKyle Evans		},
275*d0b74459SKyle Evans		{
276*d0b74459SKyle Evans			func = "realpath",
277*d0b74459SKyle Evans			bufsize = "PATH_MAX",
278*d0b74459SKyle Evans			arguments = {
279*d0b74459SKyle Evans				"\".\"",
280*d0b74459SKyle Evans				"__buf",
281*d0b74459SKyle Evans			},
282*d0b74459SKyle Evans			exclude = excludes_stack_overflow,
283*d0b74459SKyle Evans		},
284*d0b74459SKyle Evans	},
285020d003cSKyle Evans	string = {
286020d003cSKyle Evans		-- <string.h>
287020d003cSKyle Evans		{
288020d003cSKyle Evans			func = "memcpy",
289020d003cSKyle Evans			arguments = {
290020d003cSKyle Evans				"__buf",
291020d003cSKyle Evans				"src",
292020d003cSKyle Evans				"__len",
293020d003cSKyle Evans			},
294020d003cSKyle Evans			exclude = excludes_stack_overflow,
295020d003cSKyle Evans			stackvars = "\tchar src[__len + 10];\n",
296020d003cSKyle Evans		},
297020d003cSKyle Evans		{
298cf8e5289SKyle Evans			func = "mempcpy",
299cf8e5289SKyle Evans			arguments = {
300cf8e5289SKyle Evans				"__buf",
301cf8e5289SKyle Evans				"src",
302cf8e5289SKyle Evans				"__len",
303cf8e5289SKyle Evans			},
304cf8e5289SKyle Evans			exclude = excludes_stack_overflow,
305cf8e5289SKyle Evans			stackvars = "\tchar src[__len + 10];\n",
306cf8e5289SKyle Evans		},
307cf8e5289SKyle Evans		{
308020d003cSKyle Evans			func = "memmove",
309020d003cSKyle Evans			arguments = {
310020d003cSKyle Evans				"__buf",
311020d003cSKyle Evans				"src",
312020d003cSKyle Evans				"__len",
313020d003cSKyle Evans			},
314020d003cSKyle Evans			exclude = excludes_stack_overflow,
315020d003cSKyle Evans			stackvars = "\tchar src[__len + 10];\n",
316020d003cSKyle Evans		},
317020d003cSKyle Evans		{
318020d003cSKyle Evans			func = "memset",
319020d003cSKyle Evans			arguments = {
320020d003cSKyle Evans				"__buf",
321020d003cSKyle Evans				"0",
322020d003cSKyle Evans				"__len",
323020d003cSKyle Evans			},
324020d003cSKyle Evans			exclude = excludes_stack_overflow,
325020d003cSKyle Evans		},
326020d003cSKyle Evans		{
327020d003cSKyle Evans			func = "stpcpy",
328020d003cSKyle Evans			arguments = {
329020d003cSKyle Evans				"__buf",
330020d003cSKyle Evans				"src",
331020d003cSKyle Evans			},
332020d003cSKyle Evans			exclude = excludes_stack_overflow,
333020d003cSKyle Evans			stackvars = string_stackvars,
334020d003cSKyle Evans			init = string_init,
335020d003cSKyle Evans			uses_len = true,
336020d003cSKyle Evans		},
337020d003cSKyle Evans		{
338020d003cSKyle Evans			func = "stpncpy",
339020d003cSKyle Evans			arguments = {
340020d003cSKyle Evans				"__buf",
341020d003cSKyle Evans				"src",
342020d003cSKyle Evans				"__len",
343020d003cSKyle Evans			},
344020d003cSKyle Evans			exclude = excludes_stack_overflow,
345020d003cSKyle Evans			stackvars = string_stackvars,
346020d003cSKyle Evans			init = string_init,
347020d003cSKyle Evans		},
348020d003cSKyle Evans		{
349020d003cSKyle Evans			func = "strcat",
350020d003cSKyle Evans			arguments = {
351020d003cSKyle Evans				"__buf",
352020d003cSKyle Evans				"src",
353020d003cSKyle Evans			},
354020d003cSKyle Evans			exclude = excludes_stack_overflow,
355020d003cSKyle Evans			stackvars = string_stackvars,
356020d003cSKyle Evans			init = string_init,
357020d003cSKyle Evans			uses_len = true,
358020d003cSKyle Evans		},
359020d003cSKyle Evans		{
360cf8e5289SKyle Evans			func = "strlcat",
361cf8e5289SKyle Evans			arguments = {
362cf8e5289SKyle Evans				"__buf",
363cf8e5289SKyle Evans				"src",
364cf8e5289SKyle Evans				"__len",
365cf8e5289SKyle Evans			},
366cf8e5289SKyle Evans			exclude = excludes_stack_overflow,
367cf8e5289SKyle Evans			stackvars = string_stackvars,
368cf8e5289SKyle Evans			init = string_init,
369cf8e5289SKyle Evans		},
370cf8e5289SKyle Evans		{
371020d003cSKyle Evans			func = "strncat",
372020d003cSKyle Evans			arguments = {
373020d003cSKyle Evans				"__buf",
374020d003cSKyle Evans				"src",
375020d003cSKyle Evans				"__len",
376020d003cSKyle Evans			},
377020d003cSKyle Evans			exclude = excludes_stack_overflow,
378020d003cSKyle Evans			stackvars = string_stackvars,
379020d003cSKyle Evans			init = string_init,
380020d003cSKyle Evans		},
381020d003cSKyle Evans		{
382020d003cSKyle Evans			func = "strcpy",
383020d003cSKyle Evans			arguments = {
384020d003cSKyle Evans				"__buf",
385020d003cSKyle Evans				"src",
386020d003cSKyle Evans			},
387020d003cSKyle Evans			exclude = excludes_stack_overflow,
388020d003cSKyle Evans			stackvars = string_stackvars,
389020d003cSKyle Evans			init = string_init,
390020d003cSKyle Evans			uses_len = true,
391020d003cSKyle Evans		},
392020d003cSKyle Evans		{
393cf8e5289SKyle Evans			func = "strlcpy",
394cf8e5289SKyle Evans			arguments = {
395cf8e5289SKyle Evans				"__buf",
396cf8e5289SKyle Evans				"src",
397cf8e5289SKyle Evans				"__len",
398cf8e5289SKyle Evans			},
399cf8e5289SKyle Evans			exclude = excludes_stack_overflow,
400cf8e5289SKyle Evans			stackvars = string_stackvars,
401cf8e5289SKyle Evans			init = string_init,
402cf8e5289SKyle Evans		},
403cf8e5289SKyle Evans		{
404020d003cSKyle Evans			func = "strncpy",
405020d003cSKyle Evans			arguments = {
406020d003cSKyle Evans				"__buf",
407020d003cSKyle Evans				"src",
408020d003cSKyle Evans				"__len",
409020d003cSKyle Evans			},
410020d003cSKyle Evans			exclude = excludes_stack_overflow,
411020d003cSKyle Evans			stackvars = string_stackvars,
412020d003cSKyle Evans			init = string_init,
413020d003cSKyle Evans		},
414020d003cSKyle Evans	},
415020d003cSKyle Evans	strings = {
416020d003cSKyle Evans		-- <strings.h>
417020d003cSKyle Evans		{
418020d003cSKyle Evans			func = "bcopy",
419020d003cSKyle Evans			arguments = {
420020d003cSKyle Evans				"src",
421020d003cSKyle Evans				"__buf",
422020d003cSKyle Evans				"__len",
423020d003cSKyle Evans			},
424020d003cSKyle Evans			exclude = excludes_stack_overflow,
425020d003cSKyle Evans			stackvars = "\tchar src[__len + 10];\n",
426020d003cSKyle Evans		},
427020d003cSKyle Evans		{
428020d003cSKyle Evans			func = "bzero",
429020d003cSKyle Evans			arguments = {
430020d003cSKyle Evans				"__buf",
431020d003cSKyle Evans				"__len",
432020d003cSKyle Evans			},
433020d003cSKyle Evans			exclude = excludes_stack_overflow,
434020d003cSKyle Evans		},
435cf8e5289SKyle Evans		{
436cf8e5289SKyle Evans			func = "explicit_bzero",
437cf8e5289SKyle Evans			arguments = {
438cf8e5289SKyle Evans				"__buf",
439cf8e5289SKyle Evans				"__len",
440cf8e5289SKyle Evans			},
441cf8e5289SKyle Evans			exclude = excludes_stack_overflow,
442cf8e5289SKyle Evans		},
443020d003cSKyle Evans	},
444020d003cSKyle Evans	unistd = {
445020d003cSKyle Evans		-- <unistd.h>
446020d003cSKyle Evans		{
447020d003cSKyle Evans			func = "getcwd",
448020d003cSKyle Evans			bufsize = "8",
449020d003cSKyle Evans			arguments = {
450020d003cSKyle Evans				"__buf",
451020d003cSKyle Evans				"__len",
452020d003cSKyle Evans			},
453020d003cSKyle Evans			exclude = excludes_stack_overflow,
454020d003cSKyle Evans		},
455020d003cSKyle Evans		{
456cf8e5289SKyle Evans			func = "getgrouplist",
457cf8e5289SKyle Evans			bufsize = "4",
458cf8e5289SKyle Evans			buftype = "gid_t[]",
459cf8e5289SKyle Evans			arguments = {
460cf8e5289SKyle Evans				"\"root\"",
461cf8e5289SKyle Evans				"0",
462cf8e5289SKyle Evans				"__buf",
463cf8e5289SKyle Evans				"&intlen",
464cf8e5289SKyle Evans			},
465cf8e5289SKyle Evans			exclude = excludes_stack_overflow,
466cf8e5289SKyle Evans			stackvars = "\tint intlen = (int)__len;\n",
467cf8e5289SKyle Evans			uses_len = true,
468cf8e5289SKyle Evans		},
469cf8e5289SKyle Evans		{
470cf8e5289SKyle Evans			func = "getgroups",
471cf8e5289SKyle Evans			bufsize = "4",
472cf8e5289SKyle Evans			buftype = "gid_t[]",
473cf8e5289SKyle Evans			arguments = {
474cf8e5289SKyle Evans				"__len",
475cf8e5289SKyle Evans				"__buf",
476cf8e5289SKyle Evans			},
477cf8e5289SKyle Evans			exclude = excludes_stack_overflow,
478cf8e5289SKyle Evans		},
479cf8e5289SKyle Evans		{
480cf8e5289SKyle Evans			func = "getloginclass",
481cf8e5289SKyle Evans			arguments = {
482cf8e5289SKyle Evans				"__buf",
483cf8e5289SKyle Evans				"__len",
484cf8e5289SKyle Evans			},
485cf8e5289SKyle Evans			exclude = excludes_stack_overflow,
486cf8e5289SKyle Evans		},
487cf8e5289SKyle Evans		{
488cf8e5289SKyle Evans			func = "pread",
489cf8e5289SKyle Evans			bufsize = "41",
490cf8e5289SKyle Evans			arguments = {
491cf8e5289SKyle Evans				"fd",
492cf8e5289SKyle Evans				"__buf",
493cf8e5289SKyle Evans				"__len",
494cf8e5289SKyle Evans				"0",
495cf8e5289SKyle Evans			},
496cf8e5289SKyle Evans			exclude = excludes_stack_overflow,
497cf8e5289SKyle Evans			stackvars = "\tint fd;\n",
498cf8e5289SKyle Evans			init = [[
499cf8e5289SKyle Evans	fd = new_tmpfile();	/* Cannot fail */
500cf8e5289SKyle Evans]],
501cf8e5289SKyle Evans		},
502cf8e5289SKyle Evans		{
503020d003cSKyle Evans			func = "read",
504020d003cSKyle Evans			bufsize = "41",
505020d003cSKyle Evans			arguments = {
506020d003cSKyle Evans				"fd",
507020d003cSKyle Evans				"__buf",
508020d003cSKyle Evans				"__len",
509020d003cSKyle Evans			},
510020d003cSKyle Evans			exclude = excludes_stack_overflow,
511020d003cSKyle Evans			stackvars = "\tint fd;\n",
512020d003cSKyle Evans			init = [[
513020d003cSKyle Evans	fd = new_tmpfile();	/* Cannot fail */
514020d003cSKyle Evans]],
515020d003cSKyle Evans		},
516020d003cSKyle Evans		{
517020d003cSKyle Evans			func = "readlink",
518020d003cSKyle Evans			arguments = {
519020d003cSKyle Evans				"path",
520020d003cSKyle Evans				"__buf",
521020d003cSKyle Evans				"__len",
522020d003cSKyle Evans			},
523020d003cSKyle Evans			exclude = excludes_stack_overflow,
524020d003cSKyle Evans			stackvars = "\tconst char *path;\n",
525020d003cSKyle Evans			init = [[
526020d003cSKyle Evans	path = new_symlink(__len);		/* Cannot fail */
527020d003cSKyle Evans]],
528020d003cSKyle Evans		},
529cf8e5289SKyle Evans		{
530cf8e5289SKyle Evans			func = "readlinkat",
531cf8e5289SKyle Evans			arguments = {
532cf8e5289SKyle Evans				"AT_FDCWD",
533cf8e5289SKyle Evans				"path",
534cf8e5289SKyle Evans				"__buf",
535cf8e5289SKyle Evans				"__len",
536cf8e5289SKyle Evans			},
537cf8e5289SKyle Evans			exclude = excludes_stack_overflow,
538cf8e5289SKyle Evans			stackvars = "\tconst char *path;\n",
539cf8e5289SKyle Evans			init = [[
540cf8e5289SKyle Evans	path = new_symlink(__len);		/* Cannot fail */
541cf8e5289SKyle Evans]],
542cf8e5289SKyle Evans		},
543cf8e5289SKyle Evans		{
544cf8e5289SKyle Evans			func = "getdomainname",
545cf8e5289SKyle Evans			bufsize = "4",
546cf8e5289SKyle Evans			arguments = {
547cf8e5289SKyle Evans				"__buf",
548cf8e5289SKyle Evans				"__len",
549cf8e5289SKyle Evans			},
550cf8e5289SKyle Evans			exclude = excludes_stack_overflow,
551cf8e5289SKyle Evans			stackvars = "\tchar sysdomain[256];\n",
552cf8e5289SKyle Evans			early_init = [[
553cf8e5289SKyle Evans	(void)getdomainname(sysdomain, __len);
554cf8e5289SKyle Evans	if (strlen(sysdomain) <= __len)
555cf8e5289SKyle Evans		atf_tc_skip("domain name too short for testing");
556cf8e5289SKyle Evans]]
557cf8e5289SKyle Evans		},
558cf8e5289SKyle Evans		{
559cf8e5289SKyle Evans			func = "getentropy",
560cf8e5289SKyle Evans			arguments = {
561cf8e5289SKyle Evans				"__buf",
562cf8e5289SKyle Evans				"__len",
563cf8e5289SKyle Evans			},
564cf8e5289SKyle Evans			exclude = excludes_stack_overflow,
565cf8e5289SKyle Evans		},
566cf8e5289SKyle Evans		{
567cf8e5289SKyle Evans			func = "gethostname",
568cf8e5289SKyle Evans			bufsize = "4",
569cf8e5289SKyle Evans			arguments = {
570cf8e5289SKyle Evans				"__buf",
571cf8e5289SKyle Evans				"__len",
572cf8e5289SKyle Evans			},
573cf8e5289SKyle Evans			exclude = excludes_stack_overflow,
574cf8e5289SKyle Evans			stackvars = [[
575cf8e5289SKyle Evans	char syshost[256];
576cf8e5289SKyle Evans	int error;
577cf8e5289SKyle Evans]],
578cf8e5289SKyle Evans			early_init = [[
579cf8e5289SKyle Evans	error = gethostname(syshost, __len);
580cf8e5289SKyle Evans	if (error != 0 || strlen(syshost) <= __len)
581cf8e5289SKyle Evans		atf_tc_skip("hostname too short for testing");
582cf8e5289SKyle Evans]]
583cf8e5289SKyle Evans		},
584cf8e5289SKyle Evans		{
585cf8e5289SKyle Evans			func = "getlogin_r",
586cf8e5289SKyle Evans			bufsize = "MAXLOGNAME + 1",
587cf8e5289SKyle Evans			arguments = {
588cf8e5289SKyle Evans				"__buf",
589cf8e5289SKyle Evans				"__len",
590cf8e5289SKyle Evans			},
591cf8e5289SKyle Evans			exclude = excludes_stack_overflow,
592cf8e5289SKyle Evans		},
593cf8e5289SKyle Evans		{
594cf8e5289SKyle Evans			func = "ttyname_r",
595cf8e5289SKyle Evans			arguments = {
596cf8e5289SKyle Evans				"fd",
597cf8e5289SKyle Evans				"__buf",
598cf8e5289SKyle Evans				"__len",
599cf8e5289SKyle Evans			},
600cf8e5289SKyle Evans			exclude = excludes_stack_overflow,
601cf8e5289SKyle Evans			stackvars = "\tint fd;\n",
602cf8e5289SKyle Evans			early_init = [[
603cf8e5289SKyle Evans	fd = STDIN_FILENO;
604cf8e5289SKyle Evans	if (!isatty(fd))
605cf8e5289SKyle Evans		atf_tc_skip("stdin is not an fd");
606cf8e5289SKyle Evans]]
607cf8e5289SKyle Evans		},
608020d003cSKyle Evans	},
609020d003cSKyle Evans}
610020d003cSKyle Evans
611020d003cSKyle Evanslocal function write_test_boilerplate(fh, name, body)
612020d003cSKyle Evans	fh:write("ATF_TC_WITHOUT_HEAD(" .. name .. ");\n")
613020d003cSKyle Evans	fh:write("ATF_TC_BODY(" .. name .. ", tc)\n")
614020d003cSKyle Evans	fh:write("{\n" .. body .. "\n}\n\n")
615020d003cSKyle Evans	return name
616020d003cSKyle Evansend
617020d003cSKyle Evans
618020d003cSKyle Evanslocal function generate_test_name(func, variant, disposition, heap)
619020d003cSKyle Evans	local basename = func
620020d003cSKyle Evans	if variant then
621020d003cSKyle Evans		basename = basename .. "_" .. variant
622020d003cSKyle Evans	end
623020d003cSKyle Evans	if heap then
624020d003cSKyle Evans		basename = basename .. "_heap"
625020d003cSKyle Evans	end
626020d003cSKyle Evans	if disposition < 0 then
627020d003cSKyle Evans		return basename .. "_before_end"
628020d003cSKyle Evans	elseif disposition == 0 then
629020d003cSKyle Evans		return basename .. "_end"
630020d003cSKyle Evans	else
631020d003cSKyle Evans		return basename .. "_after_end"
632020d003cSKyle Evans	end
633020d003cSKyle Evansend
634020d003cSKyle Evans
635020d003cSKyle Evanslocal function array_type(buftype)
636020d003cSKyle Evans	if not buftype:match("%[%]") then
637020d003cSKyle Evans		return nil
638020d003cSKyle Evans	end
639020d003cSKyle Evans
640020d003cSKyle Evans	return buftype:gsub("%[%]", "")
641020d003cSKyle Evansend
642020d003cSKyle Evans
643020d003cSKyle Evanslocal function configurable(def, idx)
644020d003cSKyle Evans	local cfgitem = def[idx]
645020d003cSKyle Evans
646020d003cSKyle Evans	if not cfgitem then
647020d003cSKyle Evans		return nil
648020d003cSKyle Evans	end
649020d003cSKyle Evans
650020d003cSKyle Evans	if type(cfgitem) == "function" then
651020d003cSKyle Evans		return cfgitem()
652020d003cSKyle Evans	end
653020d003cSKyle Evans
654020d003cSKyle Evans	return cfgitem
655020d003cSKyle Evansend
656020d003cSKyle Evans
657020d003cSKyle Evanslocal function generate_stackframe(buftype, bufsize, disposition, heap, def)
658020d003cSKyle Evans	local function len_offset(inverted, disposition)
659020d003cSKyle Evans		-- Tests that don't use __len in their arguments may use an
660020d003cSKyle Evans		-- inverted sense because we can't just specify a length that
661020d003cSKyle Evans		-- would induce an access just after the end.  Instead, we have
662020d003cSKyle Evans		-- to manipulate the buffer size to be too short so that the
663020d003cSKyle Evans		-- function under test would write one too many.
664020d003cSKyle Evans		if disposition < 0 then
665020d003cSKyle Evans			return ((inverted and " + ") or " - ") .. "1"
666020d003cSKyle Evans		elseif disposition == 0 then
667020d003cSKyle Evans			return ""
668020d003cSKyle Evans		else
669020d003cSKyle Evans			return ((inverted and " - ") or " + ") .. "1"
670020d003cSKyle Evans		end
671020d003cSKyle Evans	end
672020d003cSKyle Evans
673020d003cSKyle Evans	local function test_uses_len(def)
674020d003cSKyle Evans		if def.uses_len then
675020d003cSKyle Evans			return true
676020d003cSKyle Evans		end
677020d003cSKyle Evans
678020d003cSKyle Evans		for _, arg in ipairs(def.arguments) do
679020d003cSKyle Evans			if arg:match("__len") or arg:match("__idx") then
680020d003cSKyle Evans				return true
681020d003cSKyle Evans			end
682020d003cSKyle Evans		end
683020d003cSKyle Evans
684020d003cSKyle Evans		return false
685020d003cSKyle Evans	end
686020d003cSKyle Evans
687020d003cSKyle Evans
688020d003cSKyle Evans	-- This is perhaps a little convoluted, but we toss the buffer into a
689020d003cSKyle Evans	-- struct on the stack to guarantee that we have at least one valid
690020d003cSKyle Evans	-- byte on either side of the buffer -- a measure to make sure that
691020d003cSKyle Evans	-- we're tripping _FORTIFY_SOURCE specifically in the buffer + 1 case,
692020d003cSKyle Evans	-- rather than some other stack or memory protection.
693020d003cSKyle Evans	local vars = "\tstruct {\n"
694020d003cSKyle Evans	vars = vars .. "\t\tuint8_t padding_l;\n"
695020d003cSKyle Evans
696020d003cSKyle Evans	local uses_len = test_uses_len(def)
697020d003cSKyle Evans	local bufsize_offset = len_offset(not uses_len, disposition)
698020d003cSKyle Evans	local buftype_elem = array_type(buftype)
699020d003cSKyle Evans	local size_expr = bufsize
700020d003cSKyle Evans
701020d003cSKyle Evans	if not uses_len then
702020d003cSKyle Evans		-- If the length isn't in use, we have to vary the buffer size
703020d003cSKyle Evans		-- since the fortified function likely has some internal size
704020d003cSKyle Evans		-- constraint that it's supposed to be checking.
705020d003cSKyle Evans		size_expr = size_expr .. bufsize_offset
706020d003cSKyle Evans	end
707020d003cSKyle Evans
708020d003cSKyle Evans	if not heap and buftype_elem then
709020d003cSKyle Evans		-- Array type: size goes after identifier
710020d003cSKyle Evans		vars = vars .. "\t\t" .. buftype_elem ..
711020d003cSKyle Evans		    " __buf[" .. size_expr .. "];\n"
712020d003cSKyle Evans	else
713020d003cSKyle Evans		local basic_type = buftype_elem or buftype
714020d003cSKyle Evans
715020d003cSKyle Evans		-- Heap tests obviously just put a pointer on the stack that
716020d003cSKyle Evans		-- points to our new allocation, but we leave it in the padded
717020d003cSKyle Evans		-- struct just to simplify our generator.
718020d003cSKyle Evans		if heap then
719020d003cSKyle Evans			basic_type = basic_type .. " *"
720020d003cSKyle Evans		end
721020d003cSKyle Evans		vars = vars .. "\t\t" .. basic_type .. " __buf;\n"
722020d003cSKyle Evans	end
723020d003cSKyle Evans
724020d003cSKyle Evans	-- padding_r is our just-past-the-end padding that we use to make sure
725020d003cSKyle Evans	-- that there's a valid portion after the buffer that isn't being
726020d003cSKyle Evans	-- included in our function calls.  If we didn't have it, then we'd have
727020d003cSKyle Evans	-- a hard time feeling confident that an abort on the just-after tests
728020d003cSKyle Evans	-- isn't maybe from some other memory or stack protection.
729020d003cSKyle Evans	vars = vars .. "\t\tuint8_t padding_r;\n"
730020d003cSKyle Evans	vars = vars .. "\t} __stack;\n"
731020d003cSKyle Evans
732020d003cSKyle Evans	-- Not all tests will use __bufsz, but some do for, e.g., clearing
733020d003cSKyle Evans	-- memory..
734020d003cSKyle Evans	vars = vars .. "\tconst size_t __bufsz __unused = "
735020d003cSKyle Evans	if heap then
736020d003cSKyle Evans		local scalar = 1
737020d003cSKyle Evans		if buftype_elem then
738020d003cSKyle Evans			scalar = size_expr
739020d003cSKyle Evans		end
740020d003cSKyle Evans
741020d003cSKyle Evans		vars = vars .. "sizeof(*__stack.__buf) * (" .. scalar .. ");\n"
742020d003cSKyle Evans	else
743020d003cSKyle Evans		vars = vars .. "sizeof(__stack.__buf);\n"
744020d003cSKyle Evans	end
745020d003cSKyle Evans
746020d003cSKyle Evans	vars = vars .. "\tconst size_t __len = " .. bufsize ..
747020d003cSKyle Evans	    bufsize_offset .. ";\n"
748020d003cSKyle Evans	vars = vars .. "\tconst size_t __idx __unused = __len - 1;\n"
749020d003cSKyle Evans
750020d003cSKyle Evans	-- For overflow testing, we need to fork() because we're expecting the
751020d003cSKyle Evans	-- test to ultimately abort()/_exit().  Then we can collect the exit
752020d003cSKyle Evans	-- status and report appropriately.
753020d003cSKyle Evans	if disposition > 0 then
754020d003cSKyle Evans		vars = vars .. "\tpid_t __child;\n"
755020d003cSKyle Evans		vars = vars .. "\tint __status;\n"
756020d003cSKyle Evans	end
757020d003cSKyle Evans
758020d003cSKyle Evans	-- Any other stackvars defined by the test get placed after everything
759020d003cSKyle Evans	-- else.
760020d003cSKyle Evans	vars = vars .. (configurable(def, "stackvars") or "")
761020d003cSKyle Evans
762020d003cSKyle Evans	return vars
763020d003cSKyle Evansend
764020d003cSKyle Evans
765020d003cSKyle Evanslocal function write_test(fh, func, disposition, heap, def)
766020d003cSKyle Evans	local testname = generate_test_name(func, def.variant, disposition, heap)
767020d003cSKyle Evans	local buftype = def.buftype or "unsigned char[]"
768020d003cSKyle Evans	local bufsize = def.bufsize or 42
769020d003cSKyle Evans	local body = ""
770020d003cSKyle Evans
771020d003cSKyle Evans	if def.exclude and def.exclude(disposition, heap) then
772020d003cSKyle Evans		return
773020d003cSKyle Evans	end
774020d003cSKyle Evans
775020d003cSKyle Evans	local function need_addr(buftype)
776020d003cSKyle Evans		return not (buftype:match("%[%]") or buftype:match("%*"))
777020d003cSKyle Evans	end
778020d003cSKyle Evans
779020d003cSKyle Evans	if heap then
780020d003cSKyle Evans		body = body .. "#define BUF __stack.__buf\n"
781020d003cSKyle Evans	else
782020d003cSKyle Evans		body = body .. "#define BUF &__stack.__buf\n"
783020d003cSKyle Evans	end
784020d003cSKyle Evans
785020d003cSKyle Evans	-- Setup the buffer
786020d003cSKyle Evans	body = body .. generate_stackframe(buftype, bufsize, disposition, heap, def) ..
787020d003cSKyle Evans	    "\n"
788020d003cSKyle Evans
789020d003cSKyle Evans	-- Any early initialization goes before we would fork for the just-after
790020d003cSKyle Evans	-- tests, because they may want to skip the test based on some criteria
791020d003cSKyle Evans	-- and we can't propagate that up very easily once we're forked.
792020d003cSKyle Evans	local early_init = configurable(def, "early_init")
793020d003cSKyle Evans	body = body .. (early_init or "")
794020d003cSKyle Evans	if early_init then
795020d003cSKyle Evans		body = body .. "\n"
796020d003cSKyle Evans	end
797020d003cSKyle Evans
798020d003cSKyle Evans	-- Fork off, iff we're testing some access past the end of the buffer.
799020d003cSKyle Evans	if disposition > 0 then
800020d003cSKyle Evans		body = body .. [[
801020d003cSKyle Evans	__child = fork();
802020d003cSKyle Evans	ATF_REQUIRE(__child >= 0);
803020d003cSKyle Evans	if (__child > 0)
804020d003cSKyle Evans		goto monitor;
805020d003cSKyle Evans
806020d003cSKyle Evans	/* Child */
807020d003cSKyle Evans	disable_coredumps();
808020d003cSKyle Evans]]
809020d003cSKyle Evans	end
810020d003cSKyle Evans
811020d003cSKyle Evans	local bufvar = "__stack.__buf"
812020d003cSKyle Evans	if heap then
813020d003cSKyle Evans		-- Buffer needs to be initialized because it's a heap allocation.
814020d003cSKyle Evans		body = body .. "\t" .. bufvar .. " = malloc(__bufsz);\n"
815020d003cSKyle Evans	end
816020d003cSKyle Evans
817020d003cSKyle Evans	-- Non-early init happens just after the fork in the child, not the
818020d003cSKyle Evans	-- monitor.  This is used to setup any other buffers we may need, for
819020d003cSKyle Evans	-- instance.
820020d003cSKyle Evans	local extra_init = configurable(def, "init")
821020d003cSKyle Evans	body = body .. (extra_init or "")
822020d003cSKyle Evans
823020d003cSKyle Evans	if heap or extra_init then
824020d003cSKyle Evans		body = body .. "\n"
825020d003cSKyle Evans	end
826020d003cSKyle Evans
827020d003cSKyle Evans	-- Setup the function call with arguments as described in the test
828020d003cSKyle Evans	-- definition.
829020d003cSKyle Evans	body = body .. "\t" .. func .. "("
830020d003cSKyle Evans
831020d003cSKyle Evans	for idx, arg in ipairs(def.arguments) do
832020d003cSKyle Evans		if idx > 1 then
833020d003cSKyle Evans			body = body .. ", "
834020d003cSKyle Evans		end
835020d003cSKyle Evans
836020d003cSKyle Evans		if arg == "__buf" then
837020d003cSKyle Evans			if not heap and need_addr(buftype) then
838020d003cSKyle Evans				body = body .. "&"
839020d003cSKyle Evans			end
840020d003cSKyle Evans
841020d003cSKyle Evans			body = body .. bufvar
842020d003cSKyle Evans		else
843020d003cSKyle Evans			local argname = arg
844020d003cSKyle Evans
845020d003cSKyle Evans			if def.value_of then
846020d003cSKyle Evans				argname = argname or def.value_of(arg)
847020d003cSKyle Evans			end
848020d003cSKyle Evans
849020d003cSKyle Evans			body = body .. argname
850020d003cSKyle Evans		end
851020d003cSKyle Evans	end
852020d003cSKyle Evans
853020d003cSKyle Evans	body = body .. ");\n"
854020d003cSKyle Evans
855020d003cSKyle Evans	-- Monitor stuff follows, for OOB access.
856020d003cSKyle Evans	if disposition <= 0 then
857020d003cSKyle Evans		goto skip
858020d003cSKyle Evans	end
859020d003cSKyle Evans
860020d003cSKyle Evans	body = body .. [[
861020d003cSKyle Evans	_exit(EX_SOFTWARE);	/* Should have aborted. */
862020d003cSKyle Evans
863020d003cSKyle Evansmonitor:
864020d003cSKyle Evans	while (waitpid(__child, &__status, 0) != __child) {
865020d003cSKyle Evans		ATF_REQUIRE_EQ(EINTR, errno);
866020d003cSKyle Evans	}
867020d003cSKyle Evans
868020d003cSKyle Evans	if (!WIFSIGNALED(__status)) {
869020d003cSKyle Evans		switch (WEXITSTATUS(__status)) {
870020d003cSKyle Evans		case EX_SOFTWARE:
871020d003cSKyle Evans			atf_tc_fail("FORTIFY_SOURCE failed to abort");
872020d003cSKyle Evans			break;
873020d003cSKyle Evans		case EX_OSERR:
874020d003cSKyle Evans			atf_tc_fail("setrlimit(2) failed");
875020d003cSKyle Evans			break;
876020d003cSKyle Evans		default:
877020d003cSKyle Evans			atf_tc_fail("child exited with status %d",
878020d003cSKyle Evans			    WEXITSTATUS(__status));
879020d003cSKyle Evans		}
880020d003cSKyle Evans	} else {
881020d003cSKyle Evans		ATF_REQUIRE_EQ(SIGABRT, WTERMSIG(__status));
882020d003cSKyle Evans	}
883020d003cSKyle Evans]]
884020d003cSKyle Evans
885020d003cSKyle Evans::skip::
886020d003cSKyle Evans	body = body .. "#undef BUF\n"
887020d003cSKyle Evans	return write_test_boilerplate(fh, testname, body)
888020d003cSKyle Evansend
889020d003cSKyle Evans
890020d003cSKyle Evans-- main()
891020d003cSKyle Evanslocal tests
892020d003cSKyle Evanslocal tcat = assert(arg[1], "usage: generate-fortify-tests.lua <category>")
893020d003cSKyle Evansfor k, defs in pairs(all_tests) do
894020d003cSKyle Evans	if k == tcat then
895020d003cSKyle Evans		tests = defs
896020d003cSKyle Evans		break
897020d003cSKyle Evans	end
898020d003cSKyle Evansend
899020d003cSKyle Evans
900020d003cSKyle Evansassert(tests, "category " .. tcat .. " not found")
901020d003cSKyle Evans
902020d003cSKyle Evanslocal fh = io.stdout
903020d003cSKyle Evansfh:write("/* @" .. "generated" .. " by `generate-fortify-tests.lua \"" ..
904020d003cSKyle Evans    tcat .. "\"` */\n\n")
905020d003cSKyle Evansfh:write("#define	_FORTIFY_SOURCE	2\n")
906020d003cSKyle Evansfh:write("#define	TMPFILE_SIZE	(1024 * 32)\n")
907020d003cSKyle Evans
908020d003cSKyle Evansfh:write("\n")
909020d003cSKyle Evansfor _, inc in ipairs(includes) do
910020d003cSKyle Evans	fh:write("#include <" .. inc .. ">\n")
911020d003cSKyle Evansend
912020d003cSKyle Evans
913020d003cSKyle Evansfh:write([[
914020d003cSKyle Evans
915cf8e5289SKyle Evansstatic FILE * __unused
916cf8e5289SKyle Evansnew_fp(size_t __len)
917cf8e5289SKyle Evans{
918cf8e5289SKyle Evans	static char fpbuf[LINE_MAX];
919cf8e5289SKyle Evans	FILE *fp;
920cf8e5289SKyle Evans
921cf8e5289SKyle Evans	ATF_REQUIRE(__len <= sizeof(fpbuf));
922cf8e5289SKyle Evans
923cf8e5289SKyle Evans	memset(fpbuf, 'A', sizeof(fpbuf) - 1);
924cf8e5289SKyle Evans	fpbuf[sizeof(fpbuf) - 1] = '\0';
925cf8e5289SKyle Evans
926cf8e5289SKyle Evans	fp = fmemopen(fpbuf, sizeof(fpbuf), "rb");
927cf8e5289SKyle Evans	ATF_REQUIRE(fp != NULL);
928cf8e5289SKyle Evans
929cf8e5289SKyle Evans	return (fp);
930cf8e5289SKyle Evans}
931cf8e5289SKyle Evans
932020d003cSKyle Evans/*
933020d003cSKyle Evans * Create a new symlink to use for readlink(2) style tests, we'll just use a
934020d003cSKyle Evans * random target name to have something interesting to look at.
935020d003cSKyle Evans */
936020d003cSKyle Evansstatic const char * __unused
937020d003cSKyle Evansnew_symlink(size_t __len)
938020d003cSKyle Evans{
939020d003cSKyle Evans	static const char linkname[] = "link";
940020d003cSKyle Evans	char target[MAXNAMLEN];
941020d003cSKyle Evans	int error;
942020d003cSKyle Evans
943020d003cSKyle Evans	ATF_REQUIRE(__len <= sizeof(target));
944020d003cSKyle Evans
945020d003cSKyle Evans	arc4random_buf(target, sizeof(target));
946020d003cSKyle Evans
947020d003cSKyle Evans	error = unlink(linkname);
948020d003cSKyle Evans	ATF_REQUIRE(error == 0 || errno == ENOENT);
949020d003cSKyle Evans
950020d003cSKyle Evans	error = symlink(target, linkname);
951020d003cSKyle Evans	ATF_REQUIRE(error == 0);
952020d003cSKyle Evans
953020d003cSKyle Evans	return (linkname);
954020d003cSKyle Evans}
955020d003cSKyle Evans
956020d003cSKyle Evans/*
957020d003cSKyle Evans * Constructs a tmpfile that we can use for testing read(2) and friends.
958020d003cSKyle Evans */
959020d003cSKyle Evansstatic int __unused
960020d003cSKyle Evansnew_tmpfile(void)
961020d003cSKyle Evans{
962020d003cSKyle Evans	char buf[1024];
963020d003cSKyle Evans	ssize_t rv;
964020d003cSKyle Evans	size_t written;
965020d003cSKyle Evans	int fd;
966020d003cSKyle Evans
967020d003cSKyle Evans	fd = open("tmpfile", O_RDWR | O_CREAT | O_TRUNC, 0644);
968020d003cSKyle Evans	ATF_REQUIRE(fd >= 0);
969020d003cSKyle Evans
970020d003cSKyle Evans	written = 0;
971020d003cSKyle Evans	while (written < TMPFILE_SIZE) {
972020d003cSKyle Evans		rv = write(fd, buf, sizeof(buf));
973020d003cSKyle Evans		ATF_REQUIRE(rv > 0);
974020d003cSKyle Evans
975020d003cSKyle Evans		written += rv;
976020d003cSKyle Evans	}
977020d003cSKyle Evans
978020d003cSKyle Evans	ATF_REQUIRE_EQ(0, lseek(fd, 0, SEEK_SET));
979020d003cSKyle Evans	return (fd);
980020d003cSKyle Evans}
981020d003cSKyle Evans
982020d003cSKyle Evansstatic void
983020d003cSKyle Evansdisable_coredumps(void)
984020d003cSKyle Evans{
985020d003cSKyle Evans	struct rlimit rl = { 0 };
986020d003cSKyle Evans
987020d003cSKyle Evans	if (setrlimit(RLIMIT_CORE, &rl) == -1)
988020d003cSKyle Evans		_exit(EX_OSERR);
989020d003cSKyle Evans}
990020d003cSKyle Evans
991cf8e5289SKyle Evans/*
992cf8e5289SKyle Evans * Replaces stdin with a file that we can actually read from, for tests where
993cf8e5289SKyle Evans * we want a FILE * or fd that we can get data from.
994cf8e5289SKyle Evans */
995cf8e5289SKyle Evansstatic void __unused
996cf8e5289SKyle Evansreplace_stdin(void)
997cf8e5289SKyle Evans{
998cf8e5289SKyle Evans	int fd;
999cf8e5289SKyle Evans
1000cf8e5289SKyle Evans	fd = new_tmpfile();
1001cf8e5289SKyle Evans
1002cf8e5289SKyle Evans	(void)dup2(fd, STDIN_FILENO);
1003cf8e5289SKyle Evans	if (fd != STDIN_FILENO)
1004cf8e5289SKyle Evans		close(fd);
1005cf8e5289SKyle Evans}
1006cf8e5289SKyle Evans
1007020d003cSKyle Evans]])
1008020d003cSKyle Evans
1009020d003cSKyle Evansfor _, def in pairs(tests) do
1010020d003cSKyle Evans	local func = def.func
1011020d003cSKyle Evans	local function write_tests(heap)
1012020d003cSKyle Evans		-- Dispositions here are relative to the buffer size prescribed
1013020d003cSKyle Evans		-- by the test definition.
1014020d003cSKyle Evans		local dispositions = def.dispositions or { -1, 0, 1 }
1015020d003cSKyle Evans
1016020d003cSKyle Evans		for _, disposition in ipairs(dispositions) do
1017020d003cSKyle Evans			tests_added[#tests_added + 1] = write_test(fh, func, disposition, heap, def)
1018020d003cSKyle Evans		end
1019020d003cSKyle Evans	end
1020020d003cSKyle Evans
1021020d003cSKyle Evans	write_tests(false)
1022020d003cSKyle Evans	write_tests(true)
1023020d003cSKyle Evansend
1024020d003cSKyle Evans
1025020d003cSKyle Evansfh:write("ATF_TP_ADD_TCS(tp)\n")
1026020d003cSKyle Evansfh:write("{\n")
1027020d003cSKyle Evansfor idx = 1, #tests_added do
1028020d003cSKyle Evans	fh:write("\tATF_TP_ADD_TC(tp, " .. tests_added[idx] .. ");\n")
1029020d003cSKyle Evansend
1030020d003cSKyle Evansfh:write("\treturn (atf_no_error());\n")
1031020d003cSKyle Evansfh:write("}\n")
1032