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", 72*88276dfbSKyle 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 94*88276dfbSKyle Evanslocal poll_init = [[ 95*88276dfbSKyle Evans for (size_t i = 0; i < howmany(__bufsz, sizeof(struct pollfd)); i++) { 96*88276dfbSKyle Evans __stack.__buf[i].fd = -1; 97*88276dfbSKyle Evans } 98*88276dfbSKyle Evans]] 99*88276dfbSKyle 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 = { 142*88276dfbSKyle Evans poll = { 143*88276dfbSKyle Evans -- <poll.h> 144*88276dfbSKyle Evans { 145*88276dfbSKyle Evans func = "poll", 146*88276dfbSKyle Evans bufsize = "4", 147*88276dfbSKyle Evans buftype = "struct pollfd[]", 148*88276dfbSKyle Evans arguments = { 149*88276dfbSKyle Evans "__buf", 150*88276dfbSKyle Evans "__len", 151*88276dfbSKyle Evans "0", 152*88276dfbSKyle Evans }, 153*88276dfbSKyle Evans init = poll_init, 154*88276dfbSKyle Evans }, 155*88276dfbSKyle Evans { 156*88276dfbSKyle Evans func = "ppoll", 157*88276dfbSKyle Evans bufsize = "4", 158*88276dfbSKyle Evans buftype = "struct pollfd[]", 159*88276dfbSKyle Evans arguments = { 160*88276dfbSKyle Evans "__buf", 161*88276dfbSKyle Evans "__len", 162*88276dfbSKyle Evans "&tv", 163*88276dfbSKyle Evans "NULL", 164*88276dfbSKyle Evans }, 165*88276dfbSKyle Evans stackvars = "\tstruct timespec tv = { 0 };\n", 166*88276dfbSKyle Evans init = poll_init, 167*88276dfbSKyle Evans }, 168*88276dfbSKyle 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 }, 265020d003cSKyle Evans string = { 266020d003cSKyle Evans -- <string.h> 267020d003cSKyle Evans { 268020d003cSKyle Evans func = "memcpy", 269020d003cSKyle Evans arguments = { 270020d003cSKyle Evans "__buf", 271020d003cSKyle Evans "src", 272020d003cSKyle Evans "__len", 273020d003cSKyle Evans }, 274020d003cSKyle Evans exclude = excludes_stack_overflow, 275020d003cSKyle Evans stackvars = "\tchar src[__len + 10];\n", 276020d003cSKyle Evans }, 277020d003cSKyle Evans { 278cf8e5289SKyle Evans func = "mempcpy", 279cf8e5289SKyle Evans arguments = { 280cf8e5289SKyle Evans "__buf", 281cf8e5289SKyle Evans "src", 282cf8e5289SKyle Evans "__len", 283cf8e5289SKyle Evans }, 284cf8e5289SKyle Evans exclude = excludes_stack_overflow, 285cf8e5289SKyle Evans stackvars = "\tchar src[__len + 10];\n", 286cf8e5289SKyle Evans }, 287cf8e5289SKyle Evans { 288020d003cSKyle Evans func = "memmove", 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 { 298020d003cSKyle Evans func = "memset", 299020d003cSKyle Evans arguments = { 300020d003cSKyle Evans "__buf", 301020d003cSKyle Evans "0", 302020d003cSKyle Evans "__len", 303020d003cSKyle Evans }, 304020d003cSKyle Evans exclude = excludes_stack_overflow, 305020d003cSKyle Evans }, 306020d003cSKyle Evans { 307020d003cSKyle Evans func = "stpcpy", 308020d003cSKyle Evans arguments = { 309020d003cSKyle Evans "__buf", 310020d003cSKyle Evans "src", 311020d003cSKyle Evans }, 312020d003cSKyle Evans exclude = excludes_stack_overflow, 313020d003cSKyle Evans stackvars = string_stackvars, 314020d003cSKyle Evans init = string_init, 315020d003cSKyle Evans uses_len = true, 316020d003cSKyle Evans }, 317020d003cSKyle Evans { 318020d003cSKyle Evans func = "stpncpy", 319020d003cSKyle Evans arguments = { 320020d003cSKyle Evans "__buf", 321020d003cSKyle Evans "src", 322020d003cSKyle Evans "__len", 323020d003cSKyle Evans }, 324020d003cSKyle Evans exclude = excludes_stack_overflow, 325020d003cSKyle Evans stackvars = string_stackvars, 326020d003cSKyle Evans init = string_init, 327020d003cSKyle Evans }, 328020d003cSKyle Evans { 329020d003cSKyle Evans func = "strcat", 330020d003cSKyle Evans arguments = { 331020d003cSKyle Evans "__buf", 332020d003cSKyle Evans "src", 333020d003cSKyle Evans }, 334020d003cSKyle Evans exclude = excludes_stack_overflow, 335020d003cSKyle Evans stackvars = string_stackvars, 336020d003cSKyle Evans init = string_init, 337020d003cSKyle Evans uses_len = true, 338020d003cSKyle Evans }, 339020d003cSKyle Evans { 340cf8e5289SKyle Evans func = "strlcat", 341cf8e5289SKyle Evans arguments = { 342cf8e5289SKyle Evans "__buf", 343cf8e5289SKyle Evans "src", 344cf8e5289SKyle Evans "__len", 345cf8e5289SKyle Evans }, 346cf8e5289SKyle Evans exclude = excludes_stack_overflow, 347cf8e5289SKyle Evans stackvars = string_stackvars, 348cf8e5289SKyle Evans init = string_init, 349cf8e5289SKyle Evans }, 350cf8e5289SKyle Evans { 351020d003cSKyle Evans func = "strncat", 352020d003cSKyle Evans arguments = { 353020d003cSKyle Evans "__buf", 354020d003cSKyle Evans "src", 355020d003cSKyle Evans "__len", 356020d003cSKyle Evans }, 357020d003cSKyle Evans exclude = excludes_stack_overflow, 358020d003cSKyle Evans stackvars = string_stackvars, 359020d003cSKyle Evans init = string_init, 360020d003cSKyle Evans }, 361020d003cSKyle Evans { 362020d003cSKyle Evans func = "strcpy", 363020d003cSKyle Evans arguments = { 364020d003cSKyle Evans "__buf", 365020d003cSKyle Evans "src", 366020d003cSKyle Evans }, 367020d003cSKyle Evans exclude = excludes_stack_overflow, 368020d003cSKyle Evans stackvars = string_stackvars, 369020d003cSKyle Evans init = string_init, 370020d003cSKyle Evans uses_len = true, 371020d003cSKyle Evans }, 372020d003cSKyle Evans { 373cf8e5289SKyle Evans func = "strlcpy", 374cf8e5289SKyle Evans arguments = { 375cf8e5289SKyle Evans "__buf", 376cf8e5289SKyle Evans "src", 377cf8e5289SKyle Evans "__len", 378cf8e5289SKyle Evans }, 379cf8e5289SKyle Evans exclude = excludes_stack_overflow, 380cf8e5289SKyle Evans stackvars = string_stackvars, 381cf8e5289SKyle Evans init = string_init, 382cf8e5289SKyle Evans }, 383cf8e5289SKyle Evans { 384020d003cSKyle Evans func = "strncpy", 385020d003cSKyle Evans arguments = { 386020d003cSKyle Evans "__buf", 387020d003cSKyle Evans "src", 388020d003cSKyle Evans "__len", 389020d003cSKyle Evans }, 390020d003cSKyle Evans exclude = excludes_stack_overflow, 391020d003cSKyle Evans stackvars = string_stackvars, 392020d003cSKyle Evans init = string_init, 393020d003cSKyle Evans }, 394020d003cSKyle Evans }, 395020d003cSKyle Evans strings = { 396020d003cSKyle Evans -- <strings.h> 397020d003cSKyle Evans { 398020d003cSKyle Evans func = "bcopy", 399020d003cSKyle Evans arguments = { 400020d003cSKyle Evans "src", 401020d003cSKyle Evans "__buf", 402020d003cSKyle Evans "__len", 403020d003cSKyle Evans }, 404020d003cSKyle Evans exclude = excludes_stack_overflow, 405020d003cSKyle Evans stackvars = "\tchar src[__len + 10];\n", 406020d003cSKyle Evans }, 407020d003cSKyle Evans { 408020d003cSKyle Evans func = "bzero", 409020d003cSKyle Evans arguments = { 410020d003cSKyle Evans "__buf", 411020d003cSKyle Evans "__len", 412020d003cSKyle Evans }, 413020d003cSKyle Evans exclude = excludes_stack_overflow, 414020d003cSKyle Evans }, 415cf8e5289SKyle Evans { 416cf8e5289SKyle Evans func = "explicit_bzero", 417cf8e5289SKyle Evans arguments = { 418cf8e5289SKyle Evans "__buf", 419cf8e5289SKyle Evans "__len", 420cf8e5289SKyle Evans }, 421cf8e5289SKyle Evans exclude = excludes_stack_overflow, 422cf8e5289SKyle Evans }, 423020d003cSKyle Evans }, 424020d003cSKyle Evans unistd = { 425020d003cSKyle Evans -- <unistd.h> 426020d003cSKyle Evans { 427020d003cSKyle Evans func = "getcwd", 428020d003cSKyle Evans bufsize = "8", 429020d003cSKyle Evans arguments = { 430020d003cSKyle Evans "__buf", 431020d003cSKyle Evans "__len", 432020d003cSKyle Evans }, 433020d003cSKyle Evans exclude = excludes_stack_overflow, 434020d003cSKyle Evans }, 435020d003cSKyle Evans { 436cf8e5289SKyle Evans func = "getgrouplist", 437cf8e5289SKyle Evans bufsize = "4", 438cf8e5289SKyle Evans buftype = "gid_t[]", 439cf8e5289SKyle Evans arguments = { 440cf8e5289SKyle Evans "\"root\"", 441cf8e5289SKyle Evans "0", 442cf8e5289SKyle Evans "__buf", 443cf8e5289SKyle Evans "&intlen", 444cf8e5289SKyle Evans }, 445cf8e5289SKyle Evans exclude = excludes_stack_overflow, 446cf8e5289SKyle Evans stackvars = "\tint intlen = (int)__len;\n", 447cf8e5289SKyle Evans uses_len = true, 448cf8e5289SKyle Evans }, 449cf8e5289SKyle Evans { 450cf8e5289SKyle Evans func = "getgroups", 451cf8e5289SKyle Evans bufsize = "4", 452cf8e5289SKyle Evans buftype = "gid_t[]", 453cf8e5289SKyle Evans arguments = { 454cf8e5289SKyle Evans "__len", 455cf8e5289SKyle Evans "__buf", 456cf8e5289SKyle Evans }, 457cf8e5289SKyle Evans exclude = excludes_stack_overflow, 458cf8e5289SKyle Evans }, 459cf8e5289SKyle Evans { 460cf8e5289SKyle Evans func = "getloginclass", 461cf8e5289SKyle Evans arguments = { 462cf8e5289SKyle Evans "__buf", 463cf8e5289SKyle Evans "__len", 464cf8e5289SKyle Evans }, 465cf8e5289SKyle Evans exclude = excludes_stack_overflow, 466cf8e5289SKyle Evans }, 467cf8e5289SKyle Evans { 468cf8e5289SKyle Evans func = "pread", 469cf8e5289SKyle Evans bufsize = "41", 470cf8e5289SKyle Evans arguments = { 471cf8e5289SKyle Evans "fd", 472cf8e5289SKyle Evans "__buf", 473cf8e5289SKyle Evans "__len", 474cf8e5289SKyle Evans "0", 475cf8e5289SKyle Evans }, 476cf8e5289SKyle Evans exclude = excludes_stack_overflow, 477cf8e5289SKyle Evans stackvars = "\tint fd;\n", 478cf8e5289SKyle Evans init = [[ 479cf8e5289SKyle Evans fd = new_tmpfile(); /* Cannot fail */ 480cf8e5289SKyle Evans]], 481cf8e5289SKyle Evans }, 482cf8e5289SKyle Evans { 483020d003cSKyle Evans func = "read", 484020d003cSKyle Evans bufsize = "41", 485020d003cSKyle Evans arguments = { 486020d003cSKyle Evans "fd", 487020d003cSKyle Evans "__buf", 488020d003cSKyle Evans "__len", 489020d003cSKyle Evans }, 490020d003cSKyle Evans exclude = excludes_stack_overflow, 491020d003cSKyle Evans stackvars = "\tint fd;\n", 492020d003cSKyle Evans init = [[ 493020d003cSKyle Evans fd = new_tmpfile(); /* Cannot fail */ 494020d003cSKyle Evans]], 495020d003cSKyle Evans }, 496020d003cSKyle Evans { 497020d003cSKyle Evans func = "readlink", 498020d003cSKyle Evans arguments = { 499020d003cSKyle Evans "path", 500020d003cSKyle Evans "__buf", 501020d003cSKyle Evans "__len", 502020d003cSKyle Evans }, 503020d003cSKyle Evans exclude = excludes_stack_overflow, 504020d003cSKyle Evans stackvars = "\tconst char *path;\n", 505020d003cSKyle Evans init = [[ 506020d003cSKyle Evans path = new_symlink(__len); /* Cannot fail */ 507020d003cSKyle Evans]], 508020d003cSKyle Evans }, 509cf8e5289SKyle Evans { 510cf8e5289SKyle Evans func = "readlinkat", 511cf8e5289SKyle Evans arguments = { 512cf8e5289SKyle Evans "AT_FDCWD", 513cf8e5289SKyle Evans "path", 514cf8e5289SKyle Evans "__buf", 515cf8e5289SKyle Evans "__len", 516cf8e5289SKyle Evans }, 517cf8e5289SKyle Evans exclude = excludes_stack_overflow, 518cf8e5289SKyle Evans stackvars = "\tconst char *path;\n", 519cf8e5289SKyle Evans init = [[ 520cf8e5289SKyle Evans path = new_symlink(__len); /* Cannot fail */ 521cf8e5289SKyle Evans]], 522cf8e5289SKyle Evans }, 523cf8e5289SKyle Evans { 524cf8e5289SKyle Evans func = "getdomainname", 525cf8e5289SKyle Evans bufsize = "4", 526cf8e5289SKyle Evans arguments = { 527cf8e5289SKyle Evans "__buf", 528cf8e5289SKyle Evans "__len", 529cf8e5289SKyle Evans }, 530cf8e5289SKyle Evans exclude = excludes_stack_overflow, 531cf8e5289SKyle Evans stackvars = "\tchar sysdomain[256];\n", 532cf8e5289SKyle Evans early_init = [[ 533cf8e5289SKyle Evans (void)getdomainname(sysdomain, __len); 534cf8e5289SKyle Evans if (strlen(sysdomain) <= __len) 535cf8e5289SKyle Evans atf_tc_skip("domain name too short for testing"); 536cf8e5289SKyle Evans]] 537cf8e5289SKyle Evans }, 538cf8e5289SKyle Evans { 539cf8e5289SKyle Evans func = "getentropy", 540cf8e5289SKyle Evans arguments = { 541cf8e5289SKyle Evans "__buf", 542cf8e5289SKyle Evans "__len", 543cf8e5289SKyle Evans }, 544cf8e5289SKyle Evans exclude = excludes_stack_overflow, 545cf8e5289SKyle Evans }, 546cf8e5289SKyle Evans { 547cf8e5289SKyle Evans func = "gethostname", 548cf8e5289SKyle Evans bufsize = "4", 549cf8e5289SKyle Evans arguments = { 550cf8e5289SKyle Evans "__buf", 551cf8e5289SKyle Evans "__len", 552cf8e5289SKyle Evans }, 553cf8e5289SKyle Evans exclude = excludes_stack_overflow, 554cf8e5289SKyle Evans stackvars = [[ 555cf8e5289SKyle Evans char syshost[256]; 556cf8e5289SKyle Evans int error; 557cf8e5289SKyle Evans]], 558cf8e5289SKyle Evans early_init = [[ 559cf8e5289SKyle Evans error = gethostname(syshost, __len); 560cf8e5289SKyle Evans if (error != 0 || strlen(syshost) <= __len) 561cf8e5289SKyle Evans atf_tc_skip("hostname too short for testing"); 562cf8e5289SKyle Evans]] 563cf8e5289SKyle Evans }, 564cf8e5289SKyle Evans { 565cf8e5289SKyle Evans func = "getlogin_r", 566cf8e5289SKyle Evans bufsize = "MAXLOGNAME + 1", 567cf8e5289SKyle Evans arguments = { 568cf8e5289SKyle Evans "__buf", 569cf8e5289SKyle Evans "__len", 570cf8e5289SKyle Evans }, 571cf8e5289SKyle Evans exclude = excludes_stack_overflow, 572cf8e5289SKyle Evans }, 573cf8e5289SKyle Evans { 574cf8e5289SKyle Evans func = "ttyname_r", 575cf8e5289SKyle Evans arguments = { 576cf8e5289SKyle Evans "fd", 577cf8e5289SKyle Evans "__buf", 578cf8e5289SKyle Evans "__len", 579cf8e5289SKyle Evans }, 580cf8e5289SKyle Evans exclude = excludes_stack_overflow, 581cf8e5289SKyle Evans stackvars = "\tint fd;\n", 582cf8e5289SKyle Evans early_init = [[ 583cf8e5289SKyle Evans fd = STDIN_FILENO; 584cf8e5289SKyle Evans if (!isatty(fd)) 585cf8e5289SKyle Evans atf_tc_skip("stdin is not an fd"); 586cf8e5289SKyle Evans]] 587cf8e5289SKyle Evans }, 588020d003cSKyle Evans }, 589020d003cSKyle Evans} 590020d003cSKyle Evans 591020d003cSKyle Evanslocal function write_test_boilerplate(fh, name, body) 592020d003cSKyle Evans fh:write("ATF_TC_WITHOUT_HEAD(" .. name .. ");\n") 593020d003cSKyle Evans fh:write("ATF_TC_BODY(" .. name .. ", tc)\n") 594020d003cSKyle Evans fh:write("{\n" .. body .. "\n}\n\n") 595020d003cSKyle Evans return name 596020d003cSKyle Evansend 597020d003cSKyle Evans 598020d003cSKyle Evanslocal function generate_test_name(func, variant, disposition, heap) 599020d003cSKyle Evans local basename = func 600020d003cSKyle Evans if variant then 601020d003cSKyle Evans basename = basename .. "_" .. variant 602020d003cSKyle Evans end 603020d003cSKyle Evans if heap then 604020d003cSKyle Evans basename = basename .. "_heap" 605020d003cSKyle Evans end 606020d003cSKyle Evans if disposition < 0 then 607020d003cSKyle Evans return basename .. "_before_end" 608020d003cSKyle Evans elseif disposition == 0 then 609020d003cSKyle Evans return basename .. "_end" 610020d003cSKyle Evans else 611020d003cSKyle Evans return basename .. "_after_end" 612020d003cSKyle Evans end 613020d003cSKyle Evansend 614020d003cSKyle Evans 615020d003cSKyle Evanslocal function array_type(buftype) 616020d003cSKyle Evans if not buftype:match("%[%]") then 617020d003cSKyle Evans return nil 618020d003cSKyle Evans end 619020d003cSKyle Evans 620020d003cSKyle Evans return buftype:gsub("%[%]", "") 621020d003cSKyle Evansend 622020d003cSKyle Evans 623020d003cSKyle Evanslocal function configurable(def, idx) 624020d003cSKyle Evans local cfgitem = def[idx] 625020d003cSKyle Evans 626020d003cSKyle Evans if not cfgitem then 627020d003cSKyle Evans return nil 628020d003cSKyle Evans end 629020d003cSKyle Evans 630020d003cSKyle Evans if type(cfgitem) == "function" then 631020d003cSKyle Evans return cfgitem() 632020d003cSKyle Evans end 633020d003cSKyle Evans 634020d003cSKyle Evans return cfgitem 635020d003cSKyle Evansend 636020d003cSKyle Evans 637020d003cSKyle Evanslocal function generate_stackframe(buftype, bufsize, disposition, heap, def) 638020d003cSKyle Evans local function len_offset(inverted, disposition) 639020d003cSKyle Evans -- Tests that don't use __len in their arguments may use an 640020d003cSKyle Evans -- inverted sense because we can't just specify a length that 641020d003cSKyle Evans -- would induce an access just after the end. Instead, we have 642020d003cSKyle Evans -- to manipulate the buffer size to be too short so that the 643020d003cSKyle Evans -- function under test would write one too many. 644020d003cSKyle Evans if disposition < 0 then 645020d003cSKyle Evans return ((inverted and " + ") or " - ") .. "1" 646020d003cSKyle Evans elseif disposition == 0 then 647020d003cSKyle Evans return "" 648020d003cSKyle Evans else 649020d003cSKyle Evans return ((inverted and " - ") or " + ") .. "1" 650020d003cSKyle Evans end 651020d003cSKyle Evans end 652020d003cSKyle Evans 653020d003cSKyle Evans local function test_uses_len(def) 654020d003cSKyle Evans if def.uses_len then 655020d003cSKyle Evans return true 656020d003cSKyle Evans end 657020d003cSKyle Evans 658020d003cSKyle Evans for _, arg in ipairs(def.arguments) do 659020d003cSKyle Evans if arg:match("__len") or arg:match("__idx") then 660020d003cSKyle Evans return true 661020d003cSKyle Evans end 662020d003cSKyle Evans end 663020d003cSKyle Evans 664020d003cSKyle Evans return false 665020d003cSKyle Evans end 666020d003cSKyle Evans 667020d003cSKyle Evans 668020d003cSKyle Evans -- This is perhaps a little convoluted, but we toss the buffer into a 669020d003cSKyle Evans -- struct on the stack to guarantee that we have at least one valid 670020d003cSKyle Evans -- byte on either side of the buffer -- a measure to make sure that 671020d003cSKyle Evans -- we're tripping _FORTIFY_SOURCE specifically in the buffer + 1 case, 672020d003cSKyle Evans -- rather than some other stack or memory protection. 673020d003cSKyle Evans local vars = "\tstruct {\n" 674020d003cSKyle Evans vars = vars .. "\t\tuint8_t padding_l;\n" 675020d003cSKyle Evans 676020d003cSKyle Evans local uses_len = test_uses_len(def) 677020d003cSKyle Evans local bufsize_offset = len_offset(not uses_len, disposition) 678020d003cSKyle Evans local buftype_elem = array_type(buftype) 679020d003cSKyle Evans local size_expr = bufsize 680020d003cSKyle Evans 681020d003cSKyle Evans if not uses_len then 682020d003cSKyle Evans -- If the length isn't in use, we have to vary the buffer size 683020d003cSKyle Evans -- since the fortified function likely has some internal size 684020d003cSKyle Evans -- constraint that it's supposed to be checking. 685020d003cSKyle Evans size_expr = size_expr .. bufsize_offset 686020d003cSKyle Evans end 687020d003cSKyle Evans 688020d003cSKyle Evans if not heap and buftype_elem then 689020d003cSKyle Evans -- Array type: size goes after identifier 690020d003cSKyle Evans vars = vars .. "\t\t" .. buftype_elem .. 691020d003cSKyle Evans " __buf[" .. size_expr .. "];\n" 692020d003cSKyle Evans else 693020d003cSKyle Evans local basic_type = buftype_elem or buftype 694020d003cSKyle Evans 695020d003cSKyle Evans -- Heap tests obviously just put a pointer on the stack that 696020d003cSKyle Evans -- points to our new allocation, but we leave it in the padded 697020d003cSKyle Evans -- struct just to simplify our generator. 698020d003cSKyle Evans if heap then 699020d003cSKyle Evans basic_type = basic_type .. " *" 700020d003cSKyle Evans end 701020d003cSKyle Evans vars = vars .. "\t\t" .. basic_type .. " __buf;\n" 702020d003cSKyle Evans end 703020d003cSKyle Evans 704020d003cSKyle Evans -- padding_r is our just-past-the-end padding that we use to make sure 705020d003cSKyle Evans -- that there's a valid portion after the buffer that isn't being 706020d003cSKyle Evans -- included in our function calls. If we didn't have it, then we'd have 707020d003cSKyle Evans -- a hard time feeling confident that an abort on the just-after tests 708020d003cSKyle Evans -- isn't maybe from some other memory or stack protection. 709020d003cSKyle Evans vars = vars .. "\t\tuint8_t padding_r;\n" 710020d003cSKyle Evans vars = vars .. "\t} __stack;\n" 711020d003cSKyle Evans 712020d003cSKyle Evans -- Not all tests will use __bufsz, but some do for, e.g., clearing 713020d003cSKyle Evans -- memory.. 714020d003cSKyle Evans vars = vars .. "\tconst size_t __bufsz __unused = " 715020d003cSKyle Evans if heap then 716020d003cSKyle Evans local scalar = 1 717020d003cSKyle Evans if buftype_elem then 718020d003cSKyle Evans scalar = size_expr 719020d003cSKyle Evans end 720020d003cSKyle Evans 721020d003cSKyle Evans vars = vars .. "sizeof(*__stack.__buf) * (" .. scalar .. ");\n" 722020d003cSKyle Evans else 723020d003cSKyle Evans vars = vars .. "sizeof(__stack.__buf);\n" 724020d003cSKyle Evans end 725020d003cSKyle Evans 726020d003cSKyle Evans vars = vars .. "\tconst size_t __len = " .. bufsize .. 727020d003cSKyle Evans bufsize_offset .. ";\n" 728020d003cSKyle Evans vars = vars .. "\tconst size_t __idx __unused = __len - 1;\n" 729020d003cSKyle Evans 730020d003cSKyle Evans -- For overflow testing, we need to fork() because we're expecting the 731020d003cSKyle Evans -- test to ultimately abort()/_exit(). Then we can collect the exit 732020d003cSKyle Evans -- status and report appropriately. 733020d003cSKyle Evans if disposition > 0 then 734020d003cSKyle Evans vars = vars .. "\tpid_t __child;\n" 735020d003cSKyle Evans vars = vars .. "\tint __status;\n" 736020d003cSKyle Evans end 737020d003cSKyle Evans 738020d003cSKyle Evans -- Any other stackvars defined by the test get placed after everything 739020d003cSKyle Evans -- else. 740020d003cSKyle Evans vars = vars .. (configurable(def, "stackvars") or "") 741020d003cSKyle Evans 742020d003cSKyle Evans return vars 743020d003cSKyle Evansend 744020d003cSKyle Evans 745020d003cSKyle Evanslocal function write_test(fh, func, disposition, heap, def) 746020d003cSKyle Evans local testname = generate_test_name(func, def.variant, disposition, heap) 747020d003cSKyle Evans local buftype = def.buftype or "unsigned char[]" 748020d003cSKyle Evans local bufsize = def.bufsize or 42 749020d003cSKyle Evans local body = "" 750020d003cSKyle Evans 751020d003cSKyle Evans if def.exclude and def.exclude(disposition, heap) then 752020d003cSKyle Evans return 753020d003cSKyle Evans end 754020d003cSKyle Evans 755020d003cSKyle Evans local function need_addr(buftype) 756020d003cSKyle Evans return not (buftype:match("%[%]") or buftype:match("%*")) 757020d003cSKyle Evans end 758020d003cSKyle Evans 759020d003cSKyle Evans if heap then 760020d003cSKyle Evans body = body .. "#define BUF __stack.__buf\n" 761020d003cSKyle Evans else 762020d003cSKyle Evans body = body .. "#define BUF &__stack.__buf\n" 763020d003cSKyle Evans end 764020d003cSKyle Evans 765020d003cSKyle Evans -- Setup the buffer 766020d003cSKyle Evans body = body .. generate_stackframe(buftype, bufsize, disposition, heap, def) .. 767020d003cSKyle Evans "\n" 768020d003cSKyle Evans 769020d003cSKyle Evans -- Any early initialization goes before we would fork for the just-after 770020d003cSKyle Evans -- tests, because they may want to skip the test based on some criteria 771020d003cSKyle Evans -- and we can't propagate that up very easily once we're forked. 772020d003cSKyle Evans local early_init = configurable(def, "early_init") 773020d003cSKyle Evans body = body .. (early_init or "") 774020d003cSKyle Evans if early_init then 775020d003cSKyle Evans body = body .. "\n" 776020d003cSKyle Evans end 777020d003cSKyle Evans 778020d003cSKyle Evans -- Fork off, iff we're testing some access past the end of the buffer. 779020d003cSKyle Evans if disposition > 0 then 780020d003cSKyle Evans body = body .. [[ 781020d003cSKyle Evans __child = fork(); 782020d003cSKyle Evans ATF_REQUIRE(__child >= 0); 783020d003cSKyle Evans if (__child > 0) 784020d003cSKyle Evans goto monitor; 785020d003cSKyle Evans 786020d003cSKyle Evans /* Child */ 787020d003cSKyle Evans disable_coredumps(); 788020d003cSKyle Evans]] 789020d003cSKyle Evans end 790020d003cSKyle Evans 791020d003cSKyle Evans local bufvar = "__stack.__buf" 792020d003cSKyle Evans if heap then 793020d003cSKyle Evans -- Buffer needs to be initialized because it's a heap allocation. 794020d003cSKyle Evans body = body .. "\t" .. bufvar .. " = malloc(__bufsz);\n" 795020d003cSKyle Evans end 796020d003cSKyle Evans 797020d003cSKyle Evans -- Non-early init happens just after the fork in the child, not the 798020d003cSKyle Evans -- monitor. This is used to setup any other buffers we may need, for 799020d003cSKyle Evans -- instance. 800020d003cSKyle Evans local extra_init = configurable(def, "init") 801020d003cSKyle Evans body = body .. (extra_init or "") 802020d003cSKyle Evans 803020d003cSKyle Evans if heap or extra_init then 804020d003cSKyle Evans body = body .. "\n" 805020d003cSKyle Evans end 806020d003cSKyle Evans 807020d003cSKyle Evans -- Setup the function call with arguments as described in the test 808020d003cSKyle Evans -- definition. 809020d003cSKyle Evans body = body .. "\t" .. func .. "(" 810020d003cSKyle Evans 811020d003cSKyle Evans for idx, arg in ipairs(def.arguments) do 812020d003cSKyle Evans if idx > 1 then 813020d003cSKyle Evans body = body .. ", " 814020d003cSKyle Evans end 815020d003cSKyle Evans 816020d003cSKyle Evans if arg == "__buf" then 817020d003cSKyle Evans if not heap and need_addr(buftype) then 818020d003cSKyle Evans body = body .. "&" 819020d003cSKyle Evans end 820020d003cSKyle Evans 821020d003cSKyle Evans body = body .. bufvar 822020d003cSKyle Evans else 823020d003cSKyle Evans local argname = arg 824020d003cSKyle Evans 825020d003cSKyle Evans if def.value_of then 826020d003cSKyle Evans argname = argname or def.value_of(arg) 827020d003cSKyle Evans end 828020d003cSKyle Evans 829020d003cSKyle Evans body = body .. argname 830020d003cSKyle Evans end 831020d003cSKyle Evans end 832020d003cSKyle Evans 833020d003cSKyle Evans body = body .. ");\n" 834020d003cSKyle Evans 835020d003cSKyle Evans -- Monitor stuff follows, for OOB access. 836020d003cSKyle Evans if disposition <= 0 then 837020d003cSKyle Evans goto skip 838020d003cSKyle Evans end 839020d003cSKyle Evans 840020d003cSKyle Evans body = body .. [[ 841020d003cSKyle Evans _exit(EX_SOFTWARE); /* Should have aborted. */ 842020d003cSKyle Evans 843020d003cSKyle Evansmonitor: 844020d003cSKyle Evans while (waitpid(__child, &__status, 0) != __child) { 845020d003cSKyle Evans ATF_REQUIRE_EQ(EINTR, errno); 846020d003cSKyle Evans } 847020d003cSKyle Evans 848020d003cSKyle Evans if (!WIFSIGNALED(__status)) { 849020d003cSKyle Evans switch (WEXITSTATUS(__status)) { 850020d003cSKyle Evans case EX_SOFTWARE: 851020d003cSKyle Evans atf_tc_fail("FORTIFY_SOURCE failed to abort"); 852020d003cSKyle Evans break; 853020d003cSKyle Evans case EX_OSERR: 854020d003cSKyle Evans atf_tc_fail("setrlimit(2) failed"); 855020d003cSKyle Evans break; 856020d003cSKyle Evans default: 857020d003cSKyle Evans atf_tc_fail("child exited with status %d", 858020d003cSKyle Evans WEXITSTATUS(__status)); 859020d003cSKyle Evans } 860020d003cSKyle Evans } else { 861020d003cSKyle Evans ATF_REQUIRE_EQ(SIGABRT, WTERMSIG(__status)); 862020d003cSKyle Evans } 863020d003cSKyle Evans]] 864020d003cSKyle Evans 865020d003cSKyle Evans::skip:: 866020d003cSKyle Evans body = body .. "#undef BUF\n" 867020d003cSKyle Evans return write_test_boilerplate(fh, testname, body) 868020d003cSKyle Evansend 869020d003cSKyle Evans 870020d003cSKyle Evans-- main() 871020d003cSKyle Evanslocal tests 872020d003cSKyle Evanslocal tcat = assert(arg[1], "usage: generate-fortify-tests.lua <category>") 873020d003cSKyle Evansfor k, defs in pairs(all_tests) do 874020d003cSKyle Evans if k == tcat then 875020d003cSKyle Evans tests = defs 876020d003cSKyle Evans break 877020d003cSKyle Evans end 878020d003cSKyle Evansend 879020d003cSKyle Evans 880020d003cSKyle Evansassert(tests, "category " .. tcat .. " not found") 881020d003cSKyle Evans 882020d003cSKyle Evanslocal fh = io.stdout 883020d003cSKyle Evansfh:write("/* @" .. "generated" .. " by `generate-fortify-tests.lua \"" .. 884020d003cSKyle Evans tcat .. "\"` */\n\n") 885020d003cSKyle Evansfh:write("#define _FORTIFY_SOURCE 2\n") 886020d003cSKyle Evansfh:write("#define TMPFILE_SIZE (1024 * 32)\n") 887020d003cSKyle Evans 888020d003cSKyle Evansfh:write("\n") 889020d003cSKyle Evansfor _, inc in ipairs(includes) do 890020d003cSKyle Evans fh:write("#include <" .. inc .. ">\n") 891020d003cSKyle Evansend 892020d003cSKyle Evans 893020d003cSKyle Evansfh:write([[ 894020d003cSKyle Evans 895cf8e5289SKyle Evansstatic FILE * __unused 896cf8e5289SKyle Evansnew_fp(size_t __len) 897cf8e5289SKyle Evans{ 898cf8e5289SKyle Evans static char fpbuf[LINE_MAX]; 899cf8e5289SKyle Evans FILE *fp; 900cf8e5289SKyle Evans 901cf8e5289SKyle Evans ATF_REQUIRE(__len <= sizeof(fpbuf)); 902cf8e5289SKyle Evans 903cf8e5289SKyle Evans memset(fpbuf, 'A', sizeof(fpbuf) - 1); 904cf8e5289SKyle Evans fpbuf[sizeof(fpbuf) - 1] = '\0'; 905cf8e5289SKyle Evans 906cf8e5289SKyle Evans fp = fmemopen(fpbuf, sizeof(fpbuf), "rb"); 907cf8e5289SKyle Evans ATF_REQUIRE(fp != NULL); 908cf8e5289SKyle Evans 909cf8e5289SKyle Evans return (fp); 910cf8e5289SKyle Evans} 911cf8e5289SKyle Evans 912020d003cSKyle Evans/* 913020d003cSKyle Evans * Create a new symlink to use for readlink(2) style tests, we'll just use a 914020d003cSKyle Evans * random target name to have something interesting to look at. 915020d003cSKyle Evans */ 916020d003cSKyle Evansstatic const char * __unused 917020d003cSKyle Evansnew_symlink(size_t __len) 918020d003cSKyle Evans{ 919020d003cSKyle Evans static const char linkname[] = "link"; 920020d003cSKyle Evans char target[MAXNAMLEN]; 921020d003cSKyle Evans int error; 922020d003cSKyle Evans 923020d003cSKyle Evans ATF_REQUIRE(__len <= sizeof(target)); 924020d003cSKyle Evans 925020d003cSKyle Evans arc4random_buf(target, sizeof(target)); 926020d003cSKyle Evans 927020d003cSKyle Evans error = unlink(linkname); 928020d003cSKyle Evans ATF_REQUIRE(error == 0 || errno == ENOENT); 929020d003cSKyle Evans 930020d003cSKyle Evans error = symlink(target, linkname); 931020d003cSKyle Evans ATF_REQUIRE(error == 0); 932020d003cSKyle Evans 933020d003cSKyle Evans return (linkname); 934020d003cSKyle Evans} 935020d003cSKyle Evans 936020d003cSKyle Evans/* 937020d003cSKyle Evans * Constructs a tmpfile that we can use for testing read(2) and friends. 938020d003cSKyle Evans */ 939020d003cSKyle Evansstatic int __unused 940020d003cSKyle Evansnew_tmpfile(void) 941020d003cSKyle Evans{ 942020d003cSKyle Evans char buf[1024]; 943020d003cSKyle Evans ssize_t rv; 944020d003cSKyle Evans size_t written; 945020d003cSKyle Evans int fd; 946020d003cSKyle Evans 947020d003cSKyle Evans fd = open("tmpfile", O_RDWR | O_CREAT | O_TRUNC, 0644); 948020d003cSKyle Evans ATF_REQUIRE(fd >= 0); 949020d003cSKyle Evans 950020d003cSKyle Evans written = 0; 951020d003cSKyle Evans while (written < TMPFILE_SIZE) { 952020d003cSKyle Evans rv = write(fd, buf, sizeof(buf)); 953020d003cSKyle Evans ATF_REQUIRE(rv > 0); 954020d003cSKyle Evans 955020d003cSKyle Evans written += rv; 956020d003cSKyle Evans } 957020d003cSKyle Evans 958020d003cSKyle Evans ATF_REQUIRE_EQ(0, lseek(fd, 0, SEEK_SET)); 959020d003cSKyle Evans return (fd); 960020d003cSKyle Evans} 961020d003cSKyle Evans 962020d003cSKyle Evansstatic void 963020d003cSKyle Evansdisable_coredumps(void) 964020d003cSKyle Evans{ 965020d003cSKyle Evans struct rlimit rl = { 0 }; 966020d003cSKyle Evans 967020d003cSKyle Evans if (setrlimit(RLIMIT_CORE, &rl) == -1) 968020d003cSKyle Evans _exit(EX_OSERR); 969020d003cSKyle Evans} 970020d003cSKyle Evans 971cf8e5289SKyle Evans/* 972cf8e5289SKyle Evans * Replaces stdin with a file that we can actually read from, for tests where 973cf8e5289SKyle Evans * we want a FILE * or fd that we can get data from. 974cf8e5289SKyle Evans */ 975cf8e5289SKyle Evansstatic void __unused 976cf8e5289SKyle Evansreplace_stdin(void) 977cf8e5289SKyle Evans{ 978cf8e5289SKyle Evans int fd; 979cf8e5289SKyle Evans 980cf8e5289SKyle Evans fd = new_tmpfile(); 981cf8e5289SKyle Evans 982cf8e5289SKyle Evans (void)dup2(fd, STDIN_FILENO); 983cf8e5289SKyle Evans if (fd != STDIN_FILENO) 984cf8e5289SKyle Evans close(fd); 985cf8e5289SKyle Evans} 986cf8e5289SKyle Evans 987020d003cSKyle Evans]]) 988020d003cSKyle Evans 989020d003cSKyle Evansfor _, def in pairs(tests) do 990020d003cSKyle Evans local func = def.func 991020d003cSKyle Evans local function write_tests(heap) 992020d003cSKyle Evans -- Dispositions here are relative to the buffer size prescribed 993020d003cSKyle Evans -- by the test definition. 994020d003cSKyle Evans local dispositions = def.dispositions or { -1, 0, 1 } 995020d003cSKyle Evans 996020d003cSKyle Evans for _, disposition in ipairs(dispositions) do 997020d003cSKyle Evans tests_added[#tests_added + 1] = write_test(fh, func, disposition, heap, def) 998020d003cSKyle Evans end 999020d003cSKyle Evans end 1000020d003cSKyle Evans 1001020d003cSKyle Evans write_tests(false) 1002020d003cSKyle Evans write_tests(true) 1003020d003cSKyle Evansend 1004020d003cSKyle Evans 1005020d003cSKyle Evansfh:write("ATF_TP_ADD_TCS(tp)\n") 1006020d003cSKyle Evansfh:write("{\n") 1007020d003cSKyle Evansfor idx = 1, #tests_added do 1008020d003cSKyle Evans fh:write("\tATF_TP_ADD_TC(tp, " .. tests_added[idx] .. ");\n") 1009020d003cSKyle Evansend 1010020d003cSKyle Evansfh:write("\treturn (atf_no_error());\n") 1011020d003cSKyle Evansfh:write("}\n") 1012