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