1*020d003cSKyle Evans#!/usr/libexec/flua 2*020d003cSKyle Evans-- 3*020d003cSKyle Evans-- SPDX-License-Identifier: BSD-2-Clause 4*020d003cSKyle Evans-- 5*020d003cSKyle Evans-- Copyright (c) 2024, Klara, Inc. 6*020d003cSKyle Evans-- 7*020d003cSKyle Evans-- Redistribution and use in source and binary forms, with or without 8*020d003cSKyle Evans-- modification, are permitted provided that the following conditions 9*020d003cSKyle Evans-- are met: 10*020d003cSKyle Evans-- 1. Redistributions of source code must retain the above copyright 11*020d003cSKyle Evans-- notice, this list of conditions and the following disclaimer. 12*020d003cSKyle Evans-- 2. Redistributions in binary form must reproduce the above copyright 13*020d003cSKyle Evans-- notice, this list of conditions and the following disclaimer in the 14*020d003cSKyle Evans-- documentation and/or other materials provided with the distribution. 15*020d003cSKyle Evans-- 16*020d003cSKyle Evans-- THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17*020d003cSKyle Evans-- ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18*020d003cSKyle Evans-- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19*020d003cSKyle Evans-- ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20*020d003cSKyle Evans-- FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21*020d003cSKyle Evans-- DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22*020d003cSKyle Evans-- OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23*020d003cSKyle Evans-- HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24*020d003cSKyle Evans-- LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25*020d003cSKyle Evans-- OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26*020d003cSKyle Evans-- SUCH DAMAGE. 27*020d003cSKyle Evans-- 28*020d003cSKyle Evans 29*020d003cSKyle Evans-- THEORY OF OPERATION 30*020d003cSKyle Evans-- 31*020d003cSKyle Evans-- generate-fortify-tests.lua is intended to test fortified functions as found 32*020d003cSKyle Evans-- mostly in the various headers in /usr/include/ssp. Each fortified function 33*020d003cSKyle Evans-- gets three basic tests: 34*020d003cSKyle Evans-- 35*020d003cSKyle Evans-- 1. Write just before the end of the buffer, 36*020d003cSKyle Evans-- 2. Write right at the end of the buffer, 37*020d003cSKyle Evans-- 3. Write just after the end of the buffer. 38*020d003cSKyle Evans-- 39*020d003cSKyle Evans-- Each test is actually generated twice: once with a buffer on the stack, and 40*020d003cSKyle Evans-- again with a buffer on the heap, to confirm that __builtin_object_size(3) can 41*020d003cSKyle Evans-- deduce the buffer size in both scenarios. The tests work by setting up the 42*020d003cSKyle Evans-- stack with our buffer (and some padding on either side to avoid tripping any 43*020d003cSKyle Evans-- other stack or memory protection), doing any initialization as described by 44*020d003cSKyle Evans-- the test definition, then calling the fortified function with the buffer as 45*020d003cSKyle Evans-- outlined by the test definition. 46*020d003cSKyle Evans-- 47*020d003cSKyle Evans-- For the 'before' and 'at' the end tests, we're ensuring that valid writes 48*020d003cSKyle Evans-- that are on the verge of being invalid aren't accidentally being detected as 49*020d003cSKyle Evans-- invalid. 50*020d003cSKyle Evans-- 51*020d003cSKyle Evans-- The 'after' test is the one that actually tests the functional benefit of 52*020d003cSKyle Evans-- _FORTIFY_SOURCE by violating a boundary that should trigger an abort. As 53*020d003cSKyle Evans-- such, this test differs more from the other two in that it has to fork() off 54*020d003cSKyle Evans-- the fortified function call so that we can monitor for a SIGABRT and 55*020d003cSKyle Evans-- pass/fail the test at function end appropriately. 56*020d003cSKyle Evans 57*020d003cSKyle Evans-- Some tests, like the FD_*() macros, may define these differently. For 58*020d003cSKyle Evans-- instance, for fd sets we're varying the index we pass and not using arbitrary 59*020d003cSKyle Evans-- buffers. Other tests that don't use the length in any way may physically 60*020d003cSKyle Evans-- vary the buffer size for each test case when we'd typically vary the length 61*020d003cSKyle Evans-- we're requesting a write for. 62*020d003cSKyle Evans 63*020d003cSKyle Evanslocal includes = { 64*020d003cSKyle Evans "sys/param.h", 65*020d003cSKyle Evans "sys/resource.h", 66*020d003cSKyle Evans "sys/time.h", 67*020d003cSKyle Evans "sys/wait.h", 68*020d003cSKyle Evans "dirent.h", 69*020d003cSKyle Evans "errno.h", 70*020d003cSKyle Evans "fcntl.h", 71*020d003cSKyle Evans "limits.h", 72*020d003cSKyle Evans "signal.h", 73*020d003cSKyle Evans "stdio.h", 74*020d003cSKyle Evans "stdlib.h", 75*020d003cSKyle Evans "string.h", 76*020d003cSKyle Evans "strings.h", 77*020d003cSKyle Evans "sysexits.h", 78*020d003cSKyle Evans "unistd.h", 79*020d003cSKyle Evans "atf-c.h", 80*020d003cSKyle Evans} 81*020d003cSKyle Evans 82*020d003cSKyle Evanslocal tests_added = {} 83*020d003cSKyle Evans 84*020d003cSKyle Evans-- Some of these will need to be excluded because clang sees the wrong size when 85*020d003cSKyle Evans-- an array is embedded inside a struct, we'll get something that looks more 86*020d003cSKyle Evans-- like __builtin_object_size(ptr, 0) than it does the correct 87*020d003cSKyle Evans-- __builtin_object_size(ptr, 1) (i.e., includes the padding after). This is 88*020d003cSKyle Evans-- almost certainly a bug in llvm. 89*020d003cSKyle Evanslocal function excludes_stack_overflow(disposition, is_heap) 90*020d003cSKyle Evans return (not is_heap) and disposition > 0 91*020d003cSKyle Evansend 92*020d003cSKyle Evans 93*020d003cSKyle Evanslocal printf_stackvars = "\tchar srcvar[__len + 10];\n" 94*020d003cSKyle Evanslocal printf_init = [[ 95*020d003cSKyle Evans memset(srcvar, 'A', sizeof(srcvar) - 1); 96*020d003cSKyle Evans srcvar[sizeof(srcvar) - 1] = '\0'; 97*020d003cSKyle Evans]] 98*020d003cSKyle Evans 99*020d003cSKyle Evanslocal string_stackvars = "\tchar src[__len];\n" 100*020d003cSKyle Evanslocal string_init = [[ 101*020d003cSKyle Evans memset(__stack.__buf, 0, __len); 102*020d003cSKyle Evans memset(src, 'A', __len - 1); 103*020d003cSKyle Evans src[__len - 1] = '\0'; 104*020d003cSKyle Evans]] 105*020d003cSKyle Evans 106*020d003cSKyle Evans-- Each test entry describes how to test a given function. We need to know how 107*020d003cSKyle Evans-- to construct the buffer, we need to know the argument set we're dealing with, 108*020d003cSKyle Evans-- and we need to know what we're passing to each argument. We could be passing 109*020d003cSKyle Evans-- fixed values, or we could be passing the __buf under test. 110*020d003cSKyle Evans-- 111*020d003cSKyle Evans-- definition: 112*020d003cSKyle Evans-- func: name of the function under test to call 113*020d003cSKyle Evans-- bufsize: size of buffer to generate, defaults to 42 114*020d003cSKyle Evans-- buftype: type of buffer to generate, defaults to unsigned char[] 115*020d003cSKyle Evans-- arguments: __buf, __len, or the name of a variable placed on the stack 116*020d003cSKyle Evans-- exclude: a function(disposition, is_heap) that returns true if this combo 117*020d003cSKyle Evans-- should be excluded. 118*020d003cSKyle Evans-- stackvars: extra variables to be placed on the stack, should be a string 119*020d003cSKyle Evans-- optionally formatted with tabs and newlines 120*020d003cSKyle Evans-- init: extra code to inject just before the function call for initialization 121*020d003cSKyle Evans-- of the buffer or any of the above-added stackvars; also a string 122*020d003cSKyle Evans-- uses_len: bool-ish, necessary if arguments doesn't include either __idx or 123*020d003cSKyle Evans-- or __len so that the test generator doesn't try to vary the size of the 124*020d003cSKyle Evans-- buffer instead of just manipulating __idx/__len to try and induce an 125*020d003cSKyle Evans-- overflow. 126*020d003cSKyle Evans-- 127*020d003cSKyle Evans-- Most tests will just use the default bufsize/buftype, but under some 128*020d003cSKyle Evans-- circumstances it's useful to use a different type (e.g., for alignment 129*020d003cSKyle Evans-- requirements). 130*020d003cSKyle Evanslocal all_tests = { 131*020d003cSKyle Evans stdio = { 132*020d003cSKyle Evans -- <stdio.h> 133*020d003cSKyle Evans { 134*020d003cSKyle Evans func = "sprintf", 135*020d003cSKyle Evans arguments = { 136*020d003cSKyle Evans "__buf", 137*020d003cSKyle Evans "\"%.*s\"", 138*020d003cSKyle Evans "(int)__len - 1", -- - 1 for NUL terminator 139*020d003cSKyle Evans "srcvar", 140*020d003cSKyle Evans }, 141*020d003cSKyle Evans exclude = excludes_stack_overflow, 142*020d003cSKyle Evans stackvars = printf_stackvars, 143*020d003cSKyle Evans init = printf_init, 144*020d003cSKyle Evans }, 145*020d003cSKyle Evans { 146*020d003cSKyle Evans func = "snprintf", 147*020d003cSKyle Evans arguments = { 148*020d003cSKyle Evans "__buf", 149*020d003cSKyle Evans "__len", 150*020d003cSKyle Evans "\"%.*s\"", 151*020d003cSKyle Evans "(int)__len - 1", -- - 1 for NUL terminator 152*020d003cSKyle Evans "srcvar", 153*020d003cSKyle Evans }, 154*020d003cSKyle Evans exclude = excludes_stack_overflow, 155*020d003cSKyle Evans stackvars = printf_stackvars, 156*020d003cSKyle Evans init = printf_init, 157*020d003cSKyle Evans }, 158*020d003cSKyle Evans }, 159*020d003cSKyle Evans string = { 160*020d003cSKyle Evans -- <string.h> 161*020d003cSKyle Evans { 162*020d003cSKyle Evans func = "memcpy", 163*020d003cSKyle Evans arguments = { 164*020d003cSKyle Evans "__buf", 165*020d003cSKyle Evans "src", 166*020d003cSKyle Evans "__len", 167*020d003cSKyle Evans }, 168*020d003cSKyle Evans exclude = excludes_stack_overflow, 169*020d003cSKyle Evans stackvars = "\tchar src[__len + 10];\n", 170*020d003cSKyle Evans }, 171*020d003cSKyle Evans { 172*020d003cSKyle Evans func = "memmove", 173*020d003cSKyle Evans arguments = { 174*020d003cSKyle Evans "__buf", 175*020d003cSKyle Evans "src", 176*020d003cSKyle Evans "__len", 177*020d003cSKyle Evans }, 178*020d003cSKyle Evans exclude = excludes_stack_overflow, 179*020d003cSKyle Evans stackvars = "\tchar src[__len + 10];\n", 180*020d003cSKyle Evans }, 181*020d003cSKyle Evans { 182*020d003cSKyle Evans func = "memset", 183*020d003cSKyle Evans arguments = { 184*020d003cSKyle Evans "__buf", 185*020d003cSKyle Evans "0", 186*020d003cSKyle Evans "__len", 187*020d003cSKyle Evans }, 188*020d003cSKyle Evans exclude = excludes_stack_overflow, 189*020d003cSKyle Evans }, 190*020d003cSKyle Evans { 191*020d003cSKyle Evans func = "stpcpy", 192*020d003cSKyle Evans arguments = { 193*020d003cSKyle Evans "__buf", 194*020d003cSKyle Evans "src", 195*020d003cSKyle Evans }, 196*020d003cSKyle Evans exclude = excludes_stack_overflow, 197*020d003cSKyle Evans stackvars = string_stackvars, 198*020d003cSKyle Evans init = string_init, 199*020d003cSKyle Evans uses_len = true, 200*020d003cSKyle Evans }, 201*020d003cSKyle Evans { 202*020d003cSKyle Evans func = "stpncpy", 203*020d003cSKyle Evans arguments = { 204*020d003cSKyle Evans "__buf", 205*020d003cSKyle Evans "src", 206*020d003cSKyle Evans "__len", 207*020d003cSKyle Evans }, 208*020d003cSKyle Evans exclude = excludes_stack_overflow, 209*020d003cSKyle Evans stackvars = string_stackvars, 210*020d003cSKyle Evans init = string_init, 211*020d003cSKyle Evans }, 212*020d003cSKyle Evans { 213*020d003cSKyle Evans func = "strcat", 214*020d003cSKyle Evans arguments = { 215*020d003cSKyle Evans "__buf", 216*020d003cSKyle Evans "src", 217*020d003cSKyle Evans }, 218*020d003cSKyle Evans exclude = excludes_stack_overflow, 219*020d003cSKyle Evans stackvars = string_stackvars, 220*020d003cSKyle Evans init = string_init, 221*020d003cSKyle Evans uses_len = true, 222*020d003cSKyle Evans }, 223*020d003cSKyle Evans { 224*020d003cSKyle Evans func = "strncat", 225*020d003cSKyle Evans arguments = { 226*020d003cSKyle Evans "__buf", 227*020d003cSKyle Evans "src", 228*020d003cSKyle Evans "__len", 229*020d003cSKyle Evans }, 230*020d003cSKyle Evans exclude = excludes_stack_overflow, 231*020d003cSKyle Evans stackvars = string_stackvars, 232*020d003cSKyle Evans init = string_init, 233*020d003cSKyle Evans }, 234*020d003cSKyle Evans { 235*020d003cSKyle Evans func = "strcpy", 236*020d003cSKyle Evans arguments = { 237*020d003cSKyle Evans "__buf", 238*020d003cSKyle Evans "src", 239*020d003cSKyle Evans }, 240*020d003cSKyle Evans exclude = excludes_stack_overflow, 241*020d003cSKyle Evans stackvars = string_stackvars, 242*020d003cSKyle Evans init = string_init, 243*020d003cSKyle Evans uses_len = true, 244*020d003cSKyle Evans }, 245*020d003cSKyle Evans { 246*020d003cSKyle Evans func = "strncpy", 247*020d003cSKyle Evans arguments = { 248*020d003cSKyle Evans "__buf", 249*020d003cSKyle Evans "src", 250*020d003cSKyle Evans "__len", 251*020d003cSKyle Evans }, 252*020d003cSKyle Evans exclude = excludes_stack_overflow, 253*020d003cSKyle Evans stackvars = string_stackvars, 254*020d003cSKyle Evans init = string_init, 255*020d003cSKyle Evans }, 256*020d003cSKyle Evans }, 257*020d003cSKyle Evans strings = { 258*020d003cSKyle Evans -- <strings.h> 259*020d003cSKyle Evans { 260*020d003cSKyle Evans func = "bcopy", 261*020d003cSKyle Evans arguments = { 262*020d003cSKyle Evans "src", 263*020d003cSKyle Evans "__buf", 264*020d003cSKyle Evans "__len", 265*020d003cSKyle Evans }, 266*020d003cSKyle Evans exclude = excludes_stack_overflow, 267*020d003cSKyle Evans stackvars = "\tchar src[__len + 10];\n", 268*020d003cSKyle Evans }, 269*020d003cSKyle Evans { 270*020d003cSKyle Evans func = "bzero", 271*020d003cSKyle Evans arguments = { 272*020d003cSKyle Evans "__buf", 273*020d003cSKyle Evans "__len", 274*020d003cSKyle Evans }, 275*020d003cSKyle Evans exclude = excludes_stack_overflow, 276*020d003cSKyle Evans }, 277*020d003cSKyle Evans }, 278*020d003cSKyle Evans unistd = { 279*020d003cSKyle Evans -- <unistd.h> 280*020d003cSKyle Evans { 281*020d003cSKyle Evans func = "getcwd", 282*020d003cSKyle Evans bufsize = "8", 283*020d003cSKyle Evans arguments = { 284*020d003cSKyle Evans "__buf", 285*020d003cSKyle Evans "__len", 286*020d003cSKyle Evans }, 287*020d003cSKyle Evans exclude = excludes_stack_overflow, 288*020d003cSKyle Evans }, 289*020d003cSKyle Evans { 290*020d003cSKyle Evans func = "read", 291*020d003cSKyle Evans bufsize = "41", 292*020d003cSKyle Evans arguments = { 293*020d003cSKyle Evans "fd", 294*020d003cSKyle Evans "__buf", 295*020d003cSKyle Evans "__len", 296*020d003cSKyle Evans }, 297*020d003cSKyle Evans exclude = excludes_stack_overflow, 298*020d003cSKyle Evans stackvars = "\tint fd;\n", 299*020d003cSKyle Evans init = [[ 300*020d003cSKyle Evans fd = new_tmpfile(); /* Cannot fail */ 301*020d003cSKyle Evans]], 302*020d003cSKyle Evans }, 303*020d003cSKyle Evans { 304*020d003cSKyle Evans func = "readlink", 305*020d003cSKyle Evans arguments = { 306*020d003cSKyle Evans "path", 307*020d003cSKyle Evans "__buf", 308*020d003cSKyle Evans "__len", 309*020d003cSKyle Evans }, 310*020d003cSKyle Evans exclude = excludes_stack_overflow, 311*020d003cSKyle Evans stackvars = "\tconst char *path;\n", 312*020d003cSKyle Evans init = [[ 313*020d003cSKyle Evans path = new_symlink(__len); /* Cannot fail */ 314*020d003cSKyle Evans]], 315*020d003cSKyle Evans }, 316*020d003cSKyle Evans }, 317*020d003cSKyle Evans} 318*020d003cSKyle Evans 319*020d003cSKyle Evanslocal function write_test_boilerplate(fh, name, body) 320*020d003cSKyle Evans fh:write("ATF_TC_WITHOUT_HEAD(" .. name .. ");\n") 321*020d003cSKyle Evans fh:write("ATF_TC_BODY(" .. name .. ", tc)\n") 322*020d003cSKyle Evans fh:write("{\n" .. body .. "\n}\n\n") 323*020d003cSKyle Evans return name 324*020d003cSKyle Evansend 325*020d003cSKyle Evans 326*020d003cSKyle Evanslocal function generate_test_name(func, variant, disposition, heap) 327*020d003cSKyle Evans local basename = func 328*020d003cSKyle Evans if variant then 329*020d003cSKyle Evans basename = basename .. "_" .. variant 330*020d003cSKyle Evans end 331*020d003cSKyle Evans if heap then 332*020d003cSKyle Evans basename = basename .. "_heap" 333*020d003cSKyle Evans end 334*020d003cSKyle Evans if disposition < 0 then 335*020d003cSKyle Evans return basename .. "_before_end" 336*020d003cSKyle Evans elseif disposition == 0 then 337*020d003cSKyle Evans return basename .. "_end" 338*020d003cSKyle Evans else 339*020d003cSKyle Evans return basename .. "_after_end" 340*020d003cSKyle Evans end 341*020d003cSKyle Evansend 342*020d003cSKyle Evans 343*020d003cSKyle Evanslocal function array_type(buftype) 344*020d003cSKyle Evans if not buftype:match("%[%]") then 345*020d003cSKyle Evans return nil 346*020d003cSKyle Evans end 347*020d003cSKyle Evans 348*020d003cSKyle Evans return buftype:gsub("%[%]", "") 349*020d003cSKyle Evansend 350*020d003cSKyle Evans 351*020d003cSKyle Evanslocal function configurable(def, idx) 352*020d003cSKyle Evans local cfgitem = def[idx] 353*020d003cSKyle Evans 354*020d003cSKyle Evans if not cfgitem then 355*020d003cSKyle Evans return nil 356*020d003cSKyle Evans end 357*020d003cSKyle Evans 358*020d003cSKyle Evans if type(cfgitem) == "function" then 359*020d003cSKyle Evans return cfgitem() 360*020d003cSKyle Evans end 361*020d003cSKyle Evans 362*020d003cSKyle Evans return cfgitem 363*020d003cSKyle Evansend 364*020d003cSKyle Evans 365*020d003cSKyle Evanslocal function generate_stackframe(buftype, bufsize, disposition, heap, def) 366*020d003cSKyle Evans local function len_offset(inverted, disposition) 367*020d003cSKyle Evans -- Tests that don't use __len in their arguments may use an 368*020d003cSKyle Evans -- inverted sense because we can't just specify a length that 369*020d003cSKyle Evans -- would induce an access just after the end. Instead, we have 370*020d003cSKyle Evans -- to manipulate the buffer size to be too short so that the 371*020d003cSKyle Evans -- function under test would write one too many. 372*020d003cSKyle Evans if disposition < 0 then 373*020d003cSKyle Evans return ((inverted and " + ") or " - ") .. "1" 374*020d003cSKyle Evans elseif disposition == 0 then 375*020d003cSKyle Evans return "" 376*020d003cSKyle Evans else 377*020d003cSKyle Evans return ((inverted and " - ") or " + ") .. "1" 378*020d003cSKyle Evans end 379*020d003cSKyle Evans end 380*020d003cSKyle Evans 381*020d003cSKyle Evans local function test_uses_len(def) 382*020d003cSKyle Evans if def.uses_len then 383*020d003cSKyle Evans return true 384*020d003cSKyle Evans end 385*020d003cSKyle Evans 386*020d003cSKyle Evans for _, arg in ipairs(def.arguments) do 387*020d003cSKyle Evans if arg:match("__len") or arg:match("__idx") then 388*020d003cSKyle Evans return true 389*020d003cSKyle Evans end 390*020d003cSKyle Evans end 391*020d003cSKyle Evans 392*020d003cSKyle Evans return false 393*020d003cSKyle Evans end 394*020d003cSKyle Evans 395*020d003cSKyle Evans 396*020d003cSKyle Evans -- This is perhaps a little convoluted, but we toss the buffer into a 397*020d003cSKyle Evans -- struct on the stack to guarantee that we have at least one valid 398*020d003cSKyle Evans -- byte on either side of the buffer -- a measure to make sure that 399*020d003cSKyle Evans -- we're tripping _FORTIFY_SOURCE specifically in the buffer + 1 case, 400*020d003cSKyle Evans -- rather than some other stack or memory protection. 401*020d003cSKyle Evans local vars = "\tstruct {\n" 402*020d003cSKyle Evans vars = vars .. "\t\tuint8_t padding_l;\n" 403*020d003cSKyle Evans 404*020d003cSKyle Evans local uses_len = test_uses_len(def) 405*020d003cSKyle Evans local bufsize_offset = len_offset(not uses_len, disposition) 406*020d003cSKyle Evans local buftype_elem = array_type(buftype) 407*020d003cSKyle Evans local size_expr = bufsize 408*020d003cSKyle Evans 409*020d003cSKyle Evans if not uses_len then 410*020d003cSKyle Evans -- If the length isn't in use, we have to vary the buffer size 411*020d003cSKyle Evans -- since the fortified function likely has some internal size 412*020d003cSKyle Evans -- constraint that it's supposed to be checking. 413*020d003cSKyle Evans size_expr = size_expr .. bufsize_offset 414*020d003cSKyle Evans end 415*020d003cSKyle Evans 416*020d003cSKyle Evans if not heap and buftype_elem then 417*020d003cSKyle Evans -- Array type: size goes after identifier 418*020d003cSKyle Evans vars = vars .. "\t\t" .. buftype_elem .. 419*020d003cSKyle Evans " __buf[" .. size_expr .. "];\n" 420*020d003cSKyle Evans else 421*020d003cSKyle Evans local basic_type = buftype_elem or buftype 422*020d003cSKyle Evans 423*020d003cSKyle Evans -- Heap tests obviously just put a pointer on the stack that 424*020d003cSKyle Evans -- points to our new allocation, but we leave it in the padded 425*020d003cSKyle Evans -- struct just to simplify our generator. 426*020d003cSKyle Evans if heap then 427*020d003cSKyle Evans basic_type = basic_type .. " *" 428*020d003cSKyle Evans end 429*020d003cSKyle Evans vars = vars .. "\t\t" .. basic_type .. " __buf;\n" 430*020d003cSKyle Evans end 431*020d003cSKyle Evans 432*020d003cSKyle Evans -- padding_r is our just-past-the-end padding that we use to make sure 433*020d003cSKyle Evans -- that there's a valid portion after the buffer that isn't being 434*020d003cSKyle Evans -- included in our function calls. If we didn't have it, then we'd have 435*020d003cSKyle Evans -- a hard time feeling confident that an abort on the just-after tests 436*020d003cSKyle Evans -- isn't maybe from some other memory or stack protection. 437*020d003cSKyle Evans vars = vars .. "\t\tuint8_t padding_r;\n" 438*020d003cSKyle Evans vars = vars .. "\t} __stack;\n" 439*020d003cSKyle Evans 440*020d003cSKyle Evans -- Not all tests will use __bufsz, but some do for, e.g., clearing 441*020d003cSKyle Evans -- memory.. 442*020d003cSKyle Evans vars = vars .. "\tconst size_t __bufsz __unused = " 443*020d003cSKyle Evans if heap then 444*020d003cSKyle Evans local scalar = 1 445*020d003cSKyle Evans if buftype_elem then 446*020d003cSKyle Evans scalar = size_expr 447*020d003cSKyle Evans end 448*020d003cSKyle Evans 449*020d003cSKyle Evans vars = vars .. "sizeof(*__stack.__buf) * (" .. scalar .. ");\n" 450*020d003cSKyle Evans else 451*020d003cSKyle Evans vars = vars .. "sizeof(__stack.__buf);\n" 452*020d003cSKyle Evans end 453*020d003cSKyle Evans 454*020d003cSKyle Evans vars = vars .. "\tconst size_t __len = " .. bufsize .. 455*020d003cSKyle Evans bufsize_offset .. ";\n" 456*020d003cSKyle Evans vars = vars .. "\tconst size_t __idx __unused = __len - 1;\n" 457*020d003cSKyle Evans 458*020d003cSKyle Evans -- For overflow testing, we need to fork() because we're expecting the 459*020d003cSKyle Evans -- test to ultimately abort()/_exit(). Then we can collect the exit 460*020d003cSKyle Evans -- status and report appropriately. 461*020d003cSKyle Evans if disposition > 0 then 462*020d003cSKyle Evans vars = vars .. "\tpid_t __child;\n" 463*020d003cSKyle Evans vars = vars .. "\tint __status;\n" 464*020d003cSKyle Evans end 465*020d003cSKyle Evans 466*020d003cSKyle Evans -- Any other stackvars defined by the test get placed after everything 467*020d003cSKyle Evans -- else. 468*020d003cSKyle Evans vars = vars .. (configurable(def, "stackvars") or "") 469*020d003cSKyle Evans 470*020d003cSKyle Evans return vars 471*020d003cSKyle Evansend 472*020d003cSKyle Evans 473*020d003cSKyle Evanslocal function write_test(fh, func, disposition, heap, def) 474*020d003cSKyle Evans local testname = generate_test_name(func, def.variant, disposition, heap) 475*020d003cSKyle Evans local buftype = def.buftype or "unsigned char[]" 476*020d003cSKyle Evans local bufsize = def.bufsize or 42 477*020d003cSKyle Evans local body = "" 478*020d003cSKyle Evans 479*020d003cSKyle Evans if def.exclude and def.exclude(disposition, heap) then 480*020d003cSKyle Evans return 481*020d003cSKyle Evans end 482*020d003cSKyle Evans 483*020d003cSKyle Evans local function need_addr(buftype) 484*020d003cSKyle Evans return not (buftype:match("%[%]") or buftype:match("%*")) 485*020d003cSKyle Evans end 486*020d003cSKyle Evans 487*020d003cSKyle Evans if heap then 488*020d003cSKyle Evans body = body .. "#define BUF __stack.__buf\n" 489*020d003cSKyle Evans else 490*020d003cSKyle Evans body = body .. "#define BUF &__stack.__buf\n" 491*020d003cSKyle Evans end 492*020d003cSKyle Evans 493*020d003cSKyle Evans -- Setup the buffer 494*020d003cSKyle Evans body = body .. generate_stackframe(buftype, bufsize, disposition, heap, def) .. 495*020d003cSKyle Evans "\n" 496*020d003cSKyle Evans 497*020d003cSKyle Evans -- Any early initialization goes before we would fork for the just-after 498*020d003cSKyle Evans -- tests, because they may want to skip the test based on some criteria 499*020d003cSKyle Evans -- and we can't propagate that up very easily once we're forked. 500*020d003cSKyle Evans local early_init = configurable(def, "early_init") 501*020d003cSKyle Evans body = body .. (early_init or "") 502*020d003cSKyle Evans if early_init then 503*020d003cSKyle Evans body = body .. "\n" 504*020d003cSKyle Evans end 505*020d003cSKyle Evans 506*020d003cSKyle Evans -- Fork off, iff we're testing some access past the end of the buffer. 507*020d003cSKyle Evans if disposition > 0 then 508*020d003cSKyle Evans body = body .. [[ 509*020d003cSKyle Evans __child = fork(); 510*020d003cSKyle Evans ATF_REQUIRE(__child >= 0); 511*020d003cSKyle Evans if (__child > 0) 512*020d003cSKyle Evans goto monitor; 513*020d003cSKyle Evans 514*020d003cSKyle Evans /* Child */ 515*020d003cSKyle Evans disable_coredumps(); 516*020d003cSKyle Evans]] 517*020d003cSKyle Evans end 518*020d003cSKyle Evans 519*020d003cSKyle Evans local bufvar = "__stack.__buf" 520*020d003cSKyle Evans if heap then 521*020d003cSKyle Evans -- Buffer needs to be initialized because it's a heap allocation. 522*020d003cSKyle Evans body = body .. "\t" .. bufvar .. " = malloc(__bufsz);\n" 523*020d003cSKyle Evans end 524*020d003cSKyle Evans 525*020d003cSKyle Evans -- Non-early init happens just after the fork in the child, not the 526*020d003cSKyle Evans -- monitor. This is used to setup any other buffers we may need, for 527*020d003cSKyle Evans -- instance. 528*020d003cSKyle Evans local extra_init = configurable(def, "init") 529*020d003cSKyle Evans body = body .. (extra_init or "") 530*020d003cSKyle Evans 531*020d003cSKyle Evans if heap or extra_init then 532*020d003cSKyle Evans body = body .. "\n" 533*020d003cSKyle Evans end 534*020d003cSKyle Evans 535*020d003cSKyle Evans -- Setup the function call with arguments as described in the test 536*020d003cSKyle Evans -- definition. 537*020d003cSKyle Evans body = body .. "\t" .. func .. "(" 538*020d003cSKyle Evans 539*020d003cSKyle Evans for idx, arg in ipairs(def.arguments) do 540*020d003cSKyle Evans if idx > 1 then 541*020d003cSKyle Evans body = body .. ", " 542*020d003cSKyle Evans end 543*020d003cSKyle Evans 544*020d003cSKyle Evans if arg == "__buf" then 545*020d003cSKyle Evans if not heap and need_addr(buftype) then 546*020d003cSKyle Evans body = body .. "&" 547*020d003cSKyle Evans end 548*020d003cSKyle Evans 549*020d003cSKyle Evans body = body .. bufvar 550*020d003cSKyle Evans else 551*020d003cSKyle Evans local argname = arg 552*020d003cSKyle Evans 553*020d003cSKyle Evans if def.value_of then 554*020d003cSKyle Evans argname = argname or def.value_of(arg) 555*020d003cSKyle Evans end 556*020d003cSKyle Evans 557*020d003cSKyle Evans body = body .. argname 558*020d003cSKyle Evans end 559*020d003cSKyle Evans end 560*020d003cSKyle Evans 561*020d003cSKyle Evans body = body .. ");\n" 562*020d003cSKyle Evans 563*020d003cSKyle Evans -- Monitor stuff follows, for OOB access. 564*020d003cSKyle Evans if disposition <= 0 then 565*020d003cSKyle Evans goto skip 566*020d003cSKyle Evans end 567*020d003cSKyle Evans 568*020d003cSKyle Evans body = body .. [[ 569*020d003cSKyle Evans _exit(EX_SOFTWARE); /* Should have aborted. */ 570*020d003cSKyle Evans 571*020d003cSKyle Evansmonitor: 572*020d003cSKyle Evans while (waitpid(__child, &__status, 0) != __child) { 573*020d003cSKyle Evans ATF_REQUIRE_EQ(EINTR, errno); 574*020d003cSKyle Evans } 575*020d003cSKyle Evans 576*020d003cSKyle Evans if (!WIFSIGNALED(__status)) { 577*020d003cSKyle Evans switch (WEXITSTATUS(__status)) { 578*020d003cSKyle Evans case EX_SOFTWARE: 579*020d003cSKyle Evans atf_tc_fail("FORTIFY_SOURCE failed to abort"); 580*020d003cSKyle Evans break; 581*020d003cSKyle Evans case EX_OSERR: 582*020d003cSKyle Evans atf_tc_fail("setrlimit(2) failed"); 583*020d003cSKyle Evans break; 584*020d003cSKyle Evans default: 585*020d003cSKyle Evans atf_tc_fail("child exited with status %d", 586*020d003cSKyle Evans WEXITSTATUS(__status)); 587*020d003cSKyle Evans } 588*020d003cSKyle Evans } else { 589*020d003cSKyle Evans ATF_REQUIRE_EQ(SIGABRT, WTERMSIG(__status)); 590*020d003cSKyle Evans } 591*020d003cSKyle Evans]] 592*020d003cSKyle Evans 593*020d003cSKyle Evans::skip:: 594*020d003cSKyle Evans body = body .. "#undef BUF\n" 595*020d003cSKyle Evans return write_test_boilerplate(fh, testname, body) 596*020d003cSKyle Evansend 597*020d003cSKyle Evans 598*020d003cSKyle Evans-- main() 599*020d003cSKyle Evanslocal tests 600*020d003cSKyle Evanslocal tcat = assert(arg[1], "usage: generate-fortify-tests.lua <category>") 601*020d003cSKyle Evansfor k, defs in pairs(all_tests) do 602*020d003cSKyle Evans if k == tcat then 603*020d003cSKyle Evans tests = defs 604*020d003cSKyle Evans break 605*020d003cSKyle Evans end 606*020d003cSKyle Evansend 607*020d003cSKyle Evans 608*020d003cSKyle Evansassert(tests, "category " .. tcat .. " not found") 609*020d003cSKyle Evans 610*020d003cSKyle Evanslocal fh = io.stdout 611*020d003cSKyle Evansfh:write("/* @" .. "generated" .. " by `generate-fortify-tests.lua \"" .. 612*020d003cSKyle Evans tcat .. "\"` */\n\n") 613*020d003cSKyle Evansfh:write("#define _FORTIFY_SOURCE 2\n") 614*020d003cSKyle Evansfh:write("#define TMPFILE_SIZE (1024 * 32)\n") 615*020d003cSKyle Evans 616*020d003cSKyle Evansfh:write("\n") 617*020d003cSKyle Evansfor _, inc in ipairs(includes) do 618*020d003cSKyle Evans fh:write("#include <" .. inc .. ">\n") 619*020d003cSKyle Evansend 620*020d003cSKyle Evans 621*020d003cSKyle Evansfh:write([[ 622*020d003cSKyle Evans 623*020d003cSKyle Evans/* 624*020d003cSKyle Evans * Create a new symlink to use for readlink(2) style tests, we'll just use a 625*020d003cSKyle Evans * random target name to have something interesting to look at. 626*020d003cSKyle Evans */ 627*020d003cSKyle Evansstatic const char * __unused 628*020d003cSKyle Evansnew_symlink(size_t __len) 629*020d003cSKyle Evans{ 630*020d003cSKyle Evans static const char linkname[] = "link"; 631*020d003cSKyle Evans char target[MAXNAMLEN]; 632*020d003cSKyle Evans int error; 633*020d003cSKyle Evans 634*020d003cSKyle Evans ATF_REQUIRE(__len <= sizeof(target)); 635*020d003cSKyle Evans 636*020d003cSKyle Evans arc4random_buf(target, sizeof(target)); 637*020d003cSKyle Evans 638*020d003cSKyle Evans error = unlink(linkname); 639*020d003cSKyle Evans ATF_REQUIRE(error == 0 || errno == ENOENT); 640*020d003cSKyle Evans 641*020d003cSKyle Evans error = symlink(target, linkname); 642*020d003cSKyle Evans ATF_REQUIRE(error == 0); 643*020d003cSKyle Evans 644*020d003cSKyle Evans return (linkname); 645*020d003cSKyle Evans} 646*020d003cSKyle Evans 647*020d003cSKyle Evans/* 648*020d003cSKyle Evans * Constructs a tmpfile that we can use for testing read(2) and friends. 649*020d003cSKyle Evans */ 650*020d003cSKyle Evansstatic int __unused 651*020d003cSKyle Evansnew_tmpfile(void) 652*020d003cSKyle Evans{ 653*020d003cSKyle Evans char buf[1024]; 654*020d003cSKyle Evans ssize_t rv; 655*020d003cSKyle Evans size_t written; 656*020d003cSKyle Evans int fd; 657*020d003cSKyle Evans 658*020d003cSKyle Evans fd = open("tmpfile", O_RDWR | O_CREAT | O_TRUNC, 0644); 659*020d003cSKyle Evans ATF_REQUIRE(fd >= 0); 660*020d003cSKyle Evans 661*020d003cSKyle Evans written = 0; 662*020d003cSKyle Evans while (written < TMPFILE_SIZE) { 663*020d003cSKyle Evans rv = write(fd, buf, sizeof(buf)); 664*020d003cSKyle Evans ATF_REQUIRE(rv > 0); 665*020d003cSKyle Evans 666*020d003cSKyle Evans written += rv; 667*020d003cSKyle Evans } 668*020d003cSKyle Evans 669*020d003cSKyle Evans ATF_REQUIRE_EQ(0, lseek(fd, 0, SEEK_SET)); 670*020d003cSKyle Evans return (fd); 671*020d003cSKyle Evans} 672*020d003cSKyle Evans 673*020d003cSKyle Evansstatic void 674*020d003cSKyle Evansdisable_coredumps(void) 675*020d003cSKyle Evans{ 676*020d003cSKyle Evans struct rlimit rl = { 0 }; 677*020d003cSKyle Evans 678*020d003cSKyle Evans if (setrlimit(RLIMIT_CORE, &rl) == -1) 679*020d003cSKyle Evans _exit(EX_OSERR); 680*020d003cSKyle Evans} 681*020d003cSKyle Evans 682*020d003cSKyle Evans]]) 683*020d003cSKyle Evans 684*020d003cSKyle Evansfor _, def in pairs(tests) do 685*020d003cSKyle Evans local func = def.func 686*020d003cSKyle Evans local function write_tests(heap) 687*020d003cSKyle Evans -- Dispositions here are relative to the buffer size prescribed 688*020d003cSKyle Evans -- by the test definition. 689*020d003cSKyle Evans local dispositions = def.dispositions or { -1, 0, 1 } 690*020d003cSKyle Evans 691*020d003cSKyle Evans for _, disposition in ipairs(dispositions) do 692*020d003cSKyle Evans tests_added[#tests_added + 1] = write_test(fh, func, disposition, heap, def) 693*020d003cSKyle Evans end 694*020d003cSKyle Evans end 695*020d003cSKyle Evans 696*020d003cSKyle Evans write_tests(false) 697*020d003cSKyle Evans write_tests(true) 698*020d003cSKyle Evansend 699*020d003cSKyle Evans 700*020d003cSKyle Evansfh:write("ATF_TP_ADD_TCS(tp)\n") 701*020d003cSKyle Evansfh:write("{\n") 702*020d003cSKyle Evansfor idx = 1, #tests_added do 703*020d003cSKyle Evans fh:write("\tATF_TP_ADD_TC(tp, " .. tests_added[idx] .. ");\n") 704*020d003cSKyle Evansend 705*020d003cSKyle Evansfh:write("\treturn (atf_no_error());\n") 706*020d003cSKyle Evansfh:write("}\n") 707