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", 6522178cb2SKyle Evans "sys/jail.h", 66062d9380SKyle Evans "sys/random.h", 67020d003cSKyle Evans "sys/resource.h", 682aba0eeaSKyle Evans "sys/select.h", 691f155d48SKyle Evans "sys/socket.h", 70020d003cSKyle Evans "sys/time.h", 711ace24b3SKyle Evans "sys/uio.h", 72020d003cSKyle Evans "sys/wait.h", 73020d003cSKyle Evans "dirent.h", 74020d003cSKyle Evans "errno.h", 75020d003cSKyle Evans "fcntl.h", 76020d003cSKyle Evans "limits.h", 7788276dfbSKyle Evans "poll.h", 78020d003cSKyle Evans "signal.h", 79020d003cSKyle Evans "stdio.h", 80020d003cSKyle Evans "stdlib.h", 81020d003cSKyle Evans "string.h", 82020d003cSKyle Evans "strings.h", 83020d003cSKyle Evans "sysexits.h", 84020d003cSKyle Evans "unistd.h", 85b53d7aa8SKyle Evans "wchar.h", 86020d003cSKyle Evans "atf-c.h", 87020d003cSKyle Evans} 88020d003cSKyle Evans 89020d003cSKyle Evanslocal tests_added = {} 90020d003cSKyle Evans 9122178cb2SKyle Evans-- Configuration for tests that want the host/domainname 9222178cb2SKyle Evanslocal hostname = "host.example.com" 9322178cb2SKyle Evanslocal domainname = "example.com" 9422178cb2SKyle Evans 95020d003cSKyle Evans-- Some of these will need to be excluded because clang sees the wrong size when 96020d003cSKyle Evans-- an array is embedded inside a struct, we'll get something that looks more 97020d003cSKyle Evans-- like __builtin_object_size(ptr, 0) than it does the correct 98020d003cSKyle Evans-- __builtin_object_size(ptr, 1) (i.e., includes the padding after). This is 99020d003cSKyle Evans-- almost certainly a bug in llvm. 100020d003cSKyle Evanslocal function excludes_stack_overflow(disposition, is_heap) 101020d003cSKyle Evans return (not is_heap) and disposition > 0 102020d003cSKyle Evansend 103020d003cSKyle Evans 10488276dfbSKyle Evanslocal poll_init = [[ 10588276dfbSKyle Evans for (size_t i = 0; i < howmany(__bufsz, sizeof(struct pollfd)); i++) { 10688276dfbSKyle Evans __stack.__buf[i].fd = -1; 10788276dfbSKyle Evans } 10888276dfbSKyle Evans]] 10988276dfbSKyle Evans 110020d003cSKyle Evanslocal printf_stackvars = "\tchar srcvar[__len + 10];\n" 111020d003cSKyle Evanslocal printf_init = [[ 112020d003cSKyle Evans memset(srcvar, 'A', sizeof(srcvar) - 1); 113020d003cSKyle Evans srcvar[sizeof(srcvar) - 1] = '\0'; 114020d003cSKyle Evans]] 115020d003cSKyle Evans 1161ace24b3SKyle Evanslocal readv_stackvars = "\tstruct iovec iov[1];\n" 1171ace24b3SKyle Evanslocal readv_init = [[ 1181ace24b3SKyle Evans iov[0].iov_base = __stack.__buf; 1191ace24b3SKyle Evans iov[0].iov_len = __len; 1201ace24b3SKyle Evans 1211ace24b3SKyle Evans replace_stdin(); 1221ace24b3SKyle Evans]] 1231ace24b3SKyle Evans 1241f155d48SKyle Evanslocal socket_stackvars = "\tint sock[2] = { -1, -1 };\n" 1251f155d48SKyle Evanslocal recvfrom_sockaddr_stackvars = socket_stackvars .. [[ 1261f155d48SKyle Evans char data[16]; 1271f155d48SKyle Evans socklen_t socklen; 1281f155d48SKyle Evans]] 1291f155d48SKyle Evanslocal recvmsg_stackvars = socket_stackvars .. "\tstruct msghdr msg;\n" 1301f155d48SKyle Evanslocal socket_init = [[ 1311f155d48SKyle Evans new_socket(sock); 1321f155d48SKyle Evans]] 1331f155d48SKyle Evanslocal socket_socklen_init = socket_init .. [[ 1341f155d48SKyle Evans socklen = __len; 1351f155d48SKyle Evans]] 1361f155d48SKyle Evans 137cf8e5289SKyle Evanslocal stdio_init = [[ 138cf8e5289SKyle Evans replace_stdin(); 139cf8e5289SKyle Evans]] 140cf8e5289SKyle Evans 141020d003cSKyle Evanslocal string_stackvars = "\tchar src[__len];\n" 142020d003cSKyle Evanslocal string_init = [[ 143020d003cSKyle Evans memset(__stack.__buf, 0, __len); 144020d003cSKyle Evans memset(src, 'A', __len - 1); 145020d003cSKyle Evans src[__len - 1] = '\0'; 146020d003cSKyle Evans]] 147020d003cSKyle Evans 148b53d7aa8SKyle Evanslocal wstring_stackvars = "\twchar_t src[__len];\n" 149b53d7aa8SKyle Evanslocal wstring_init = [[ 150b53d7aa8SKyle Evans wmemset(__stack.__buf, 0, __len); 151b53d7aa8SKyle Evans wmemset(src, 'A', __len - 1); 152b53d7aa8SKyle Evans src[__len - 1] = '\0'; 153b53d7aa8SKyle Evans]] 154b53d7aa8SKyle Evans 155020d003cSKyle Evans-- Each test entry describes how to test a given function. We need to know how 156020d003cSKyle Evans-- to construct the buffer, we need to know the argument set we're dealing with, 157020d003cSKyle Evans-- and we need to know what we're passing to each argument. We could be passing 158020d003cSKyle Evans-- fixed values, or we could be passing the __buf under test. 159020d003cSKyle Evans-- 160020d003cSKyle Evans-- definition: 161020d003cSKyle Evans-- func: name of the function under test to call 162020d003cSKyle Evans-- bufsize: size of buffer to generate, defaults to 42 163020d003cSKyle Evans-- buftype: type of buffer to generate, defaults to unsigned char[] 164020d003cSKyle Evans-- arguments: __buf, __len, or the name of a variable placed on the stack 165020d003cSKyle Evans-- exclude: a function(disposition, is_heap) that returns true if this combo 166020d003cSKyle Evans-- should be excluded. 167020d003cSKyle Evans-- stackvars: extra variables to be placed on the stack, should be a string 168020d003cSKyle Evans-- optionally formatted with tabs and newlines 169020d003cSKyle Evans-- init: extra code to inject just before the function call for initialization 170020d003cSKyle Evans-- of the buffer or any of the above-added stackvars; also a string 171020d003cSKyle Evans-- uses_len: bool-ish, necessary if arguments doesn't include either __idx or 172020d003cSKyle Evans-- or __len so that the test generator doesn't try to vary the size of the 173020d003cSKyle Evans-- buffer instead of just manipulating __idx/__len to try and induce an 174020d003cSKyle Evans-- overflow. 175020d003cSKyle Evans-- 176020d003cSKyle Evans-- Most tests will just use the default bufsize/buftype, but under some 177020d003cSKyle Evans-- circumstances it's useful to use a different type (e.g., for alignment 178020d003cSKyle Evans-- requirements). 179020d003cSKyle Evanslocal all_tests = { 180062d9380SKyle Evans random = { 181062d9380SKyle Evans -- <sys/random.h> 182062d9380SKyle Evans { 183062d9380SKyle Evans func = "getrandom", 184062d9380SKyle Evans arguments = { 185062d9380SKyle Evans "__buf", 186062d9380SKyle Evans "__len", 187062d9380SKyle Evans "0", 188062d9380SKyle Evans }, 189062d9380SKyle Evans exclude = excludes_stack_overflow, 190062d9380SKyle Evans }, 191062d9380SKyle Evans }, 1922aba0eeaSKyle Evans select = { 1932aba0eeaSKyle Evans -- <sys/select.h> 1942aba0eeaSKyle Evans { 1952aba0eeaSKyle Evans func = "FD_SET", 1962aba0eeaSKyle Evans bufsize = "FD_SETSIZE", 1972aba0eeaSKyle Evans buftype = "fd_set", 1982aba0eeaSKyle Evans arguments = { 1992aba0eeaSKyle Evans "__idx", 2002aba0eeaSKyle Evans "__buf", 2012aba0eeaSKyle Evans }, 2022aba0eeaSKyle Evans }, 2032aba0eeaSKyle Evans { 2042aba0eeaSKyle Evans func = "FD_CLR", 2052aba0eeaSKyle Evans bufsize = "FD_SETSIZE", 2062aba0eeaSKyle Evans buftype = "fd_set", 2072aba0eeaSKyle Evans arguments = { 2082aba0eeaSKyle Evans "__idx", 2092aba0eeaSKyle Evans "__buf", 2102aba0eeaSKyle Evans }, 2112aba0eeaSKyle Evans }, 2122aba0eeaSKyle Evans { 2132aba0eeaSKyle Evans func = "FD_ISSET", 2142aba0eeaSKyle Evans bufsize = "FD_SETSIZE", 2152aba0eeaSKyle Evans buftype = "fd_set", 2162aba0eeaSKyle Evans arguments = { 2172aba0eeaSKyle Evans "__idx", 2182aba0eeaSKyle Evans "__buf", 2192aba0eeaSKyle Evans }, 2202aba0eeaSKyle Evans }, 2212aba0eeaSKyle Evans }, 2221f155d48SKyle Evans socket = { 2231f155d48SKyle Evans -- <sys/socket.h> 2241f155d48SKyle Evans { 2251f155d48SKyle Evans func = "getpeername", 2261f155d48SKyle Evans buftype = "struct sockaddr", 2271f155d48SKyle Evans bufsize = "sizeof(struct sockaddr)", 2281f155d48SKyle Evans arguments = { 2291f155d48SKyle Evans "sock[0]", 2301f155d48SKyle Evans "__buf", 2311f155d48SKyle Evans "&socklen", 2321f155d48SKyle Evans }, 2331f155d48SKyle Evans exclude = excludes_stack_overflow, 2341f155d48SKyle Evans stackvars = socket_stackvars .. "\tsocklen_t socklen;", 2351f155d48SKyle Evans init = socket_socklen_init, 2361f155d48SKyle Evans uses_len = true, 2371f155d48SKyle Evans }, 2381f155d48SKyle Evans { 2391f155d48SKyle Evans func = "getsockname", 2401f155d48SKyle Evans buftype = "struct sockaddr", 2411f155d48SKyle Evans bufsize = "sizeof(struct sockaddr)", 2421f155d48SKyle Evans arguments = { 2431f155d48SKyle Evans "sock[0]", 2441f155d48SKyle Evans "__buf", 2451f155d48SKyle Evans "&socklen", 2461f155d48SKyle Evans }, 2471f155d48SKyle Evans exclude = excludes_stack_overflow, 2481f155d48SKyle Evans stackvars = socket_stackvars .. "\tsocklen_t socklen;", 2491f155d48SKyle Evans init = socket_socklen_init, 2501f155d48SKyle Evans uses_len = true, 2511f155d48SKyle Evans }, 2521f155d48SKyle Evans { 2531f155d48SKyle Evans func = "recv", 2541f155d48SKyle Evans arguments = { 2551f155d48SKyle Evans "sock[0]", 2561f155d48SKyle Evans "__buf", 2571f155d48SKyle Evans "__len", 2581f155d48SKyle Evans "0", 2591f155d48SKyle Evans }, 2601f155d48SKyle Evans exclude = excludes_stack_overflow, 2611f155d48SKyle Evans stackvars = socket_stackvars, 2621f155d48SKyle Evans init = socket_init, 2631f155d48SKyle Evans }, 2641f155d48SKyle Evans { 2651f155d48SKyle Evans func = "recvfrom", 2661f155d48SKyle Evans arguments = { 2671f155d48SKyle Evans "sock[0]", 2681f155d48SKyle Evans "__buf", 2691f155d48SKyle Evans "__len", 2701f155d48SKyle Evans "0", 2711f155d48SKyle Evans "NULL", 2721f155d48SKyle Evans "NULL", 2731f155d48SKyle Evans }, 2741f155d48SKyle Evans exclude = excludes_stack_overflow, 2751f155d48SKyle Evans stackvars = socket_stackvars, 2761f155d48SKyle Evans init = socket_init, 2771f155d48SKyle Evans }, 2781f155d48SKyle Evans { 2791f155d48SKyle Evans func = "recvfrom", 2801f155d48SKyle Evans variant = "sockaddr", 2811f155d48SKyle Evans buftype = "struct sockaddr", 2821f155d48SKyle Evans bufsize = "sizeof(struct sockaddr)", 2831f155d48SKyle Evans arguments = { 2841f155d48SKyle Evans "sock[0]", 2851f155d48SKyle Evans "data", 2861f155d48SKyle Evans "sizeof(data)", 2871f155d48SKyle Evans "0", 2881f155d48SKyle Evans "__buf", 2891f155d48SKyle Evans "&socklen", 2901f155d48SKyle Evans }, 2911f155d48SKyle Evans exclude = excludes_stack_overflow, 2921f155d48SKyle Evans stackvars = recvfrom_sockaddr_stackvars, 2931f155d48SKyle Evans init = socket_socklen_init, 2941f155d48SKyle Evans uses_len = true, 2951f155d48SKyle Evans }, 2961f155d48SKyle Evans { 2971f155d48SKyle Evans func = "recvmsg", 2981f155d48SKyle Evans variant = "msg_name", 2991f155d48SKyle Evans buftype = "struct sockaddr", 3001f155d48SKyle Evans bufsize = "sizeof(struct sockaddr)", 3011f155d48SKyle Evans arguments = { 3021f155d48SKyle Evans "sock[0]", 3031f155d48SKyle Evans "&msg", 3041f155d48SKyle Evans "0", 3051f155d48SKyle Evans }, 3061f155d48SKyle Evans exclude = excludes_stack_overflow, 3071f155d48SKyle Evans stackvars = recvmsg_stackvars, 3081f155d48SKyle Evans init = [[ 3091f155d48SKyle Evans memset(&msg, 0, sizeof(msg)); 3101f155d48SKyle Evans msg.msg_name = BUF; 3111f155d48SKyle Evans msg.msg_namelen = __len; 3121f155d48SKyle Evans]], 3131f155d48SKyle Evans uses_len = true, 3141f155d48SKyle Evans }, 3151f155d48SKyle Evans { 3161f155d48SKyle Evans func = "recvmsg", 3171f155d48SKyle Evans variant = "msg_iov", 3181f155d48SKyle Evans arguments = { 3191f155d48SKyle Evans "sock[0]", 3201f155d48SKyle Evans "&msg", 3211f155d48SKyle Evans "0", 3221f155d48SKyle Evans }, 3231f155d48SKyle Evans exclude = excludes_stack_overflow, 3241f155d48SKyle Evans stackvars = recvmsg_stackvars .. "\tstruct iovec iov[2];\n", 3251f155d48SKyle Evans init = [[ 3261f155d48SKyle Evans memset(&msg, 0, sizeof(msg)); 3271f155d48SKyle Evans memset(&iov[0], 0, sizeof(iov)); 3281f155d48SKyle Evans 3291f155d48SKyle Evans /* 3301f155d48SKyle Evans * We position the buffer second just so that we can confirm that the 3311f155d48SKyle Evans * fortification bits are traversing the iovec correctly. 3321f155d48SKyle Evans */ 3331f155d48SKyle Evans iov[1].iov_base = BUF; 3341f155d48SKyle Evans iov[1].iov_len = __len; 3351f155d48SKyle Evans 3361f155d48SKyle Evans msg.msg_iov = &iov[0]; 3371f155d48SKyle Evans msg.msg_iovlen = nitems(iov); 3381f155d48SKyle Evans]], 3391f155d48SKyle Evans uses_len = true, 3401f155d48SKyle Evans }, 3411f155d48SKyle Evans { 3421f155d48SKyle Evans func = "recvmsg", 3431f155d48SKyle Evans variant = "msg_control", 3441f155d48SKyle Evans bufsize = "CMSG_SPACE(sizeof(int))", 3451f155d48SKyle Evans arguments = { 3461f155d48SKyle Evans "sock[0]", 3471f155d48SKyle Evans "&msg", 3481f155d48SKyle Evans "0", 3491f155d48SKyle Evans }, 3501f155d48SKyle Evans exclude = excludes_stack_overflow, 3511f155d48SKyle Evans stackvars = recvmsg_stackvars, 3521f155d48SKyle Evans init = [[ 3531f155d48SKyle Evans memset(&msg, 0, sizeof(msg)); 3541f155d48SKyle Evans 3551f155d48SKyle Evans msg.msg_control = BUF; 3561f155d48SKyle Evans msg.msg_controllen = __len; 3571f155d48SKyle Evans]], 3581f155d48SKyle Evans uses_len = true, 3591f155d48SKyle Evans }, 3601f155d48SKyle Evans { 3611f155d48SKyle Evans func = "recvmmsg", 3621f155d48SKyle Evans variant = "msgvec", 3631f155d48SKyle Evans buftype = "struct mmsghdr[]", 3641f155d48SKyle Evans bufsize = "2", 3651f155d48SKyle Evans arguments = { 3661f155d48SKyle Evans "sock[0]", 3671f155d48SKyle Evans "__buf", 3681f155d48SKyle Evans "__len", 3691f155d48SKyle Evans "0", 3701f155d48SKyle Evans "NULL", 3711f155d48SKyle Evans }, 3721f155d48SKyle Evans stackvars = socket_stackvars, 3731f155d48SKyle Evans }, 3741f155d48SKyle Evans { 3751f155d48SKyle Evans -- We'll assume that recvmsg is covering msghdr 3761f155d48SKyle Evans -- validation thoroughly enough, we'll just try tossing 3771f155d48SKyle Evans -- an error in the second element of a msgvec to try and 3781f155d48SKyle Evans -- make sure that each one is being validated. 3791f155d48SKyle Evans func = "recvmmsg", 3801f155d48SKyle Evans variant = "msghdr", 3811f155d48SKyle Evans arguments = { 3821f155d48SKyle Evans "sock[0]", 3831f155d48SKyle Evans "&msgvec[0]", 3841f155d48SKyle Evans "nitems(msgvec)", 3851f155d48SKyle Evans "0", 3861f155d48SKyle Evans "NULL", 3871f155d48SKyle Evans }, 3881f155d48SKyle Evans exclude = excludes_stack_overflow, 3891f155d48SKyle Evans stackvars = socket_stackvars .. "\tstruct mmsghdr msgvec[2];\n", 3901f155d48SKyle Evans init = [[ 3911f155d48SKyle Evans memset(&msgvec[0], 0, sizeof(msgvec)); 3921f155d48SKyle Evans 3931f155d48SKyle Evans /* 3941f155d48SKyle Evans * Same as above, make sure fortification isn't ignoring n > 1 elements 3951f155d48SKyle Evans * of the msgvec. 3961f155d48SKyle Evans */ 3971f155d48SKyle Evans msgvec[1].msg_hdr.msg_control = BUF; 3981f155d48SKyle Evans msgvec[1].msg_hdr.msg_controllen = __len; 3991f155d48SKyle Evans]], 4001f155d48SKyle Evans uses_len = true, 4011f155d48SKyle Evans }, 4021f155d48SKyle Evans }, 4031ace24b3SKyle Evans uio = { 4041ace24b3SKyle Evans -- <sys/uio.h> 4051ace24b3SKyle Evans { 4061ace24b3SKyle Evans func = "readv", 4071ace24b3SKyle Evans buftype = "struct iovec[]", 4081ace24b3SKyle Evans bufsize = 2, 4091ace24b3SKyle Evans arguments = { 4101ace24b3SKyle Evans "STDIN_FILENO", 4111ace24b3SKyle Evans "__buf", 4121ace24b3SKyle Evans "__len", 4131ace24b3SKyle Evans }, 4141ace24b3SKyle Evans }, 4151ace24b3SKyle Evans { 4161ace24b3SKyle Evans func = "readv", 4171ace24b3SKyle Evans variant = "iov", 4181ace24b3SKyle Evans arguments = { 4191ace24b3SKyle Evans "STDIN_FILENO", 4201ace24b3SKyle Evans "iov", 4211ace24b3SKyle Evans "nitems(iov)", 4221ace24b3SKyle Evans }, 4231ace24b3SKyle Evans exclude = excludes_stack_overflow, 4241ace24b3SKyle Evans stackvars = readv_stackvars, 4251ace24b3SKyle Evans init = readv_init, 4261ace24b3SKyle Evans uses_len = true, 4271ace24b3SKyle Evans }, 4281ace24b3SKyle Evans { 4291ace24b3SKyle Evans func = "preadv", 4301ace24b3SKyle Evans buftype = "struct iovec[]", 4311ace24b3SKyle Evans bufsize = 2, 4321ace24b3SKyle Evans arguments = { 4331ace24b3SKyle Evans "STDIN_FILENO", 4341ace24b3SKyle Evans "__buf", 4351ace24b3SKyle Evans "__len", 4361ace24b3SKyle Evans "0", 4371ace24b3SKyle Evans }, 4381ace24b3SKyle Evans }, 4391ace24b3SKyle Evans { 4401ace24b3SKyle Evans func = "preadv", 4411ace24b3SKyle Evans variant = "iov", 4421ace24b3SKyle Evans arguments = { 4431ace24b3SKyle Evans "STDIN_FILENO", 4441ace24b3SKyle Evans "iov", 4451ace24b3SKyle Evans "nitems(iov)", 4461ace24b3SKyle Evans "0", 4471ace24b3SKyle Evans }, 4481ace24b3SKyle Evans exclude = excludes_stack_overflow, 4491ace24b3SKyle Evans stackvars = readv_stackvars, 4501ace24b3SKyle Evans init = readv_init, 4511ace24b3SKyle Evans uses_len = true, 4521ace24b3SKyle Evans }, 4531ace24b3SKyle Evans }, 45488276dfbSKyle Evans poll = { 45588276dfbSKyle Evans -- <poll.h> 45688276dfbSKyle Evans { 45788276dfbSKyle Evans func = "poll", 45888276dfbSKyle Evans bufsize = "4", 45988276dfbSKyle Evans buftype = "struct pollfd[]", 46088276dfbSKyle Evans arguments = { 46188276dfbSKyle Evans "__buf", 46288276dfbSKyle Evans "__len", 46388276dfbSKyle Evans "0", 46488276dfbSKyle Evans }, 46588276dfbSKyle Evans init = poll_init, 46688276dfbSKyle Evans }, 46788276dfbSKyle Evans { 46888276dfbSKyle Evans func = "ppoll", 46988276dfbSKyle Evans bufsize = "4", 47088276dfbSKyle Evans buftype = "struct pollfd[]", 47188276dfbSKyle Evans arguments = { 47288276dfbSKyle Evans "__buf", 47388276dfbSKyle Evans "__len", 47488276dfbSKyle Evans "&tv", 47588276dfbSKyle Evans "NULL", 47688276dfbSKyle Evans }, 47788276dfbSKyle Evans stackvars = "\tstruct timespec tv = { 0 };\n", 47888276dfbSKyle Evans init = poll_init, 47988276dfbSKyle Evans }, 48088276dfbSKyle Evans }, 481020d003cSKyle Evans stdio = { 482020d003cSKyle Evans -- <stdio.h> 483020d003cSKyle Evans { 484cf8e5289SKyle Evans func = "ctermid", 485cf8e5289SKyle Evans bufsize = "L_ctermid", 486cf8e5289SKyle Evans arguments = { 487cf8e5289SKyle Evans "__buf", 488cf8e5289SKyle Evans }, 489cf8e5289SKyle Evans exclude = excludes_stack_overflow, 490cf8e5289SKyle Evans }, 491cf8e5289SKyle Evans { 492cf8e5289SKyle Evans func = "ctermid_r", 493cf8e5289SKyle Evans bufsize = "L_ctermid", 494cf8e5289SKyle Evans arguments = { 495cf8e5289SKyle Evans "__buf", 496cf8e5289SKyle Evans }, 497cf8e5289SKyle Evans exclude = excludes_stack_overflow, 498cf8e5289SKyle Evans }, 499cf8e5289SKyle Evans { 500cf8e5289SKyle Evans func = "fread", 501cf8e5289SKyle Evans arguments = { 502cf8e5289SKyle Evans "__buf", 503cf8e5289SKyle Evans "__len", 504cf8e5289SKyle Evans "1", 505cf8e5289SKyle Evans "stdin", 506cf8e5289SKyle Evans }, 507cf8e5289SKyle Evans exclude = excludes_stack_overflow, 508cf8e5289SKyle Evans init = stdio_init, 509cf8e5289SKyle Evans }, 510cf8e5289SKyle Evans { 511cf8e5289SKyle Evans func = "fread_unlocked", 512cf8e5289SKyle Evans arguments = { 513cf8e5289SKyle Evans "__buf", 514cf8e5289SKyle Evans "__len", 515cf8e5289SKyle Evans "1", 516cf8e5289SKyle Evans "stdin", 517cf8e5289SKyle Evans }, 518cf8e5289SKyle Evans exclude = excludes_stack_overflow, 519cf8e5289SKyle Evans init = stdio_init, 520cf8e5289SKyle Evans }, 521cf8e5289SKyle Evans { 522cf8e5289SKyle Evans func = "gets_s", 523cf8e5289SKyle Evans arguments = { 524cf8e5289SKyle Evans "__buf", 525cf8e5289SKyle Evans "__len", 526cf8e5289SKyle Evans }, 527cf8e5289SKyle Evans exclude = excludes_stack_overflow, 528cf8e5289SKyle Evans init = stdio_init, 529cf8e5289SKyle Evans }, 530cf8e5289SKyle Evans { 531020d003cSKyle Evans func = "sprintf", 532020d003cSKyle Evans arguments = { 533020d003cSKyle Evans "__buf", 534020d003cSKyle Evans "\"%.*s\"", 535020d003cSKyle Evans "(int)__len - 1", -- - 1 for NUL terminator 536020d003cSKyle Evans "srcvar", 537020d003cSKyle Evans }, 538020d003cSKyle Evans exclude = excludes_stack_overflow, 539020d003cSKyle Evans stackvars = printf_stackvars, 540020d003cSKyle Evans init = printf_init, 541020d003cSKyle Evans }, 542020d003cSKyle Evans { 543020d003cSKyle Evans func = "snprintf", 544020d003cSKyle Evans arguments = { 545020d003cSKyle Evans "__buf", 546020d003cSKyle Evans "__len", 547020d003cSKyle Evans "\"%.*s\"", 548020d003cSKyle Evans "(int)__len - 1", -- - 1 for NUL terminator 549020d003cSKyle Evans "srcvar", 550020d003cSKyle Evans }, 551020d003cSKyle Evans exclude = excludes_stack_overflow, 552020d003cSKyle Evans stackvars = printf_stackvars, 553020d003cSKyle Evans init = printf_init, 554020d003cSKyle Evans }, 555cf8e5289SKyle Evans { 556cf8e5289SKyle Evans func = "tmpnam", 557cf8e5289SKyle Evans bufsize = "L_tmpnam", 558cf8e5289SKyle Evans arguments = { 559cf8e5289SKyle Evans "__buf", 560cf8e5289SKyle Evans }, 561cf8e5289SKyle Evans exclude = excludes_stack_overflow, 562cf8e5289SKyle Evans }, 563cf8e5289SKyle Evans { 564cf8e5289SKyle Evans func = "fgets", 565cf8e5289SKyle Evans arguments = { 566cf8e5289SKyle Evans "__buf", 567cf8e5289SKyle Evans "__len", 568cf8e5289SKyle Evans "fp", 569cf8e5289SKyle Evans }, 570cf8e5289SKyle Evans exclude = excludes_stack_overflow, 571cf8e5289SKyle Evans stackvars = "\tFILE *fp;\n", 572cf8e5289SKyle Evans init = [[ 573cf8e5289SKyle Evans fp = new_fp(__len); 574cf8e5289SKyle Evans]], 575cf8e5289SKyle Evans }, 576020d003cSKyle Evans }, 577d0b74459SKyle Evans stdlib = { 578d0b74459SKyle Evans -- <stdlib.h> 579d0b74459SKyle Evans { 580d0b74459SKyle Evans func = "arc4random_buf", 581d0b74459SKyle Evans arguments = { 582d0b74459SKyle Evans "__buf", 583d0b74459SKyle Evans "__len", 584d0b74459SKyle Evans }, 585d0b74459SKyle Evans exclude = excludes_stack_overflow, 586d0b74459SKyle Evans }, 587d0b74459SKyle Evans { 588*873420caSDag-Erling Smørgrav func = "getenv_r", 589*873420caSDag-Erling Smørgrav arguments = { 590*873420caSDag-Erling Smørgrav "\"PATH\"", 591*873420caSDag-Erling Smørgrav "__buf", 592*873420caSDag-Erling Smørgrav "__len", 593*873420caSDag-Erling Smørgrav }, 594*873420caSDag-Erling Smørgrav exclude = excludes_stack_overflow, 595*873420caSDag-Erling Smørgrav }, 596*873420caSDag-Erling Smørgrav { 597d0b74459SKyle Evans func = "realpath", 598d0b74459SKyle Evans bufsize = "PATH_MAX", 599d0b74459SKyle Evans arguments = { 600d0b74459SKyle Evans "\".\"", 601d0b74459SKyle Evans "__buf", 602d0b74459SKyle Evans }, 603d0b74459SKyle Evans exclude = excludes_stack_overflow, 604d0b74459SKyle Evans }, 605d0b74459SKyle Evans }, 606020d003cSKyle Evans string = { 607020d003cSKyle Evans -- <string.h> 608020d003cSKyle Evans { 609020d003cSKyle Evans func = "memcpy", 610020d003cSKyle Evans arguments = { 611020d003cSKyle Evans "__buf", 612020d003cSKyle Evans "src", 613020d003cSKyle Evans "__len", 614020d003cSKyle Evans }, 615020d003cSKyle Evans exclude = excludes_stack_overflow, 616020d003cSKyle Evans stackvars = "\tchar src[__len + 10];\n", 617020d003cSKyle Evans }, 618020d003cSKyle Evans { 619cf8e5289SKyle Evans func = "mempcpy", 620cf8e5289SKyle Evans arguments = { 621cf8e5289SKyle Evans "__buf", 622cf8e5289SKyle Evans "src", 623cf8e5289SKyle Evans "__len", 624cf8e5289SKyle Evans }, 625cf8e5289SKyle Evans exclude = excludes_stack_overflow, 626cf8e5289SKyle Evans stackvars = "\tchar src[__len + 10];\n", 627cf8e5289SKyle Evans }, 628cf8e5289SKyle Evans { 629020d003cSKyle Evans func = "memmove", 630020d003cSKyle Evans arguments = { 631020d003cSKyle Evans "__buf", 632020d003cSKyle Evans "src", 633020d003cSKyle Evans "__len", 634020d003cSKyle Evans }, 635020d003cSKyle Evans exclude = excludes_stack_overflow, 636020d003cSKyle Evans stackvars = "\tchar src[__len + 10];\n", 637020d003cSKyle Evans }, 638020d003cSKyle Evans { 639020d003cSKyle Evans func = "memset", 640020d003cSKyle Evans arguments = { 641020d003cSKyle Evans "__buf", 642020d003cSKyle Evans "0", 643020d003cSKyle Evans "__len", 644020d003cSKyle Evans }, 645020d003cSKyle Evans exclude = excludes_stack_overflow, 646020d003cSKyle Evans }, 647020d003cSKyle Evans { 6488983acc8SRobert Clausecker func = "memset_explicit", 6498983acc8SRobert Clausecker arguments = { 6508983acc8SRobert Clausecker "__buf", 6518983acc8SRobert Clausecker "0", 6528983acc8SRobert Clausecker "__len", 6538983acc8SRobert Clausecker }, 6548983acc8SRobert Clausecker exclude = excludes_stack_overflow, 6558983acc8SRobert Clausecker }, 6568983acc8SRobert Clausecker { 657020d003cSKyle Evans func = "stpcpy", 658020d003cSKyle Evans arguments = { 659020d003cSKyle Evans "__buf", 660020d003cSKyle Evans "src", 661020d003cSKyle Evans }, 662020d003cSKyle Evans exclude = excludes_stack_overflow, 663020d003cSKyle Evans stackvars = string_stackvars, 664020d003cSKyle Evans init = string_init, 665020d003cSKyle Evans uses_len = true, 666020d003cSKyle Evans }, 667020d003cSKyle Evans { 668020d003cSKyle Evans func = "stpncpy", 669020d003cSKyle Evans arguments = { 670020d003cSKyle Evans "__buf", 671020d003cSKyle Evans "src", 672020d003cSKyle Evans "__len", 673020d003cSKyle Evans }, 674020d003cSKyle Evans exclude = excludes_stack_overflow, 675020d003cSKyle Evans stackvars = string_stackvars, 676020d003cSKyle Evans init = string_init, 677020d003cSKyle Evans }, 678020d003cSKyle Evans { 679020d003cSKyle Evans func = "strcat", 680020d003cSKyle Evans arguments = { 681020d003cSKyle Evans "__buf", 682020d003cSKyle Evans "src", 683020d003cSKyle Evans }, 684020d003cSKyle Evans exclude = excludes_stack_overflow, 685020d003cSKyle Evans stackvars = string_stackvars, 686020d003cSKyle Evans init = string_init, 687020d003cSKyle Evans uses_len = true, 688020d003cSKyle Evans }, 689020d003cSKyle Evans { 690cf8e5289SKyle Evans func = "strlcat", 691cf8e5289SKyle Evans arguments = { 692cf8e5289SKyle Evans "__buf", 693cf8e5289SKyle Evans "src", 694cf8e5289SKyle Evans "__len", 695cf8e5289SKyle Evans }, 696cf8e5289SKyle Evans exclude = excludes_stack_overflow, 697cf8e5289SKyle Evans stackvars = string_stackvars, 698cf8e5289SKyle Evans init = string_init, 699cf8e5289SKyle Evans }, 700cf8e5289SKyle Evans { 701020d003cSKyle Evans func = "strncat", 702020d003cSKyle Evans arguments = { 703020d003cSKyle Evans "__buf", 704020d003cSKyle Evans "src", 705020d003cSKyle Evans "__len", 706020d003cSKyle Evans }, 707020d003cSKyle Evans exclude = excludes_stack_overflow, 708020d003cSKyle Evans stackvars = string_stackvars, 709020d003cSKyle Evans init = string_init, 710020d003cSKyle Evans }, 711020d003cSKyle Evans { 712020d003cSKyle Evans func = "strcpy", 713020d003cSKyle Evans arguments = { 714020d003cSKyle Evans "__buf", 715020d003cSKyle Evans "src", 716020d003cSKyle Evans }, 717020d003cSKyle Evans exclude = excludes_stack_overflow, 718020d003cSKyle Evans stackvars = string_stackvars, 719020d003cSKyle Evans init = string_init, 720020d003cSKyle Evans uses_len = true, 721020d003cSKyle Evans }, 722020d003cSKyle Evans { 723cf8e5289SKyle Evans func = "strlcpy", 724cf8e5289SKyle Evans arguments = { 725cf8e5289SKyle Evans "__buf", 726cf8e5289SKyle Evans "src", 727cf8e5289SKyle Evans "__len", 728cf8e5289SKyle Evans }, 729cf8e5289SKyle Evans exclude = excludes_stack_overflow, 730cf8e5289SKyle Evans stackvars = string_stackvars, 731cf8e5289SKyle Evans init = string_init, 732cf8e5289SKyle Evans }, 733cf8e5289SKyle Evans { 734020d003cSKyle Evans func = "strncpy", 735020d003cSKyle Evans arguments = { 736020d003cSKyle Evans "__buf", 737020d003cSKyle Evans "src", 738020d003cSKyle Evans "__len", 739020d003cSKyle Evans }, 740020d003cSKyle Evans exclude = excludes_stack_overflow, 741020d003cSKyle Evans stackvars = string_stackvars, 742020d003cSKyle Evans init = string_init, 743020d003cSKyle Evans }, 744020d003cSKyle Evans }, 745020d003cSKyle Evans strings = { 746020d003cSKyle Evans -- <strings.h> 747020d003cSKyle Evans { 748020d003cSKyle Evans func = "bcopy", 749020d003cSKyle Evans arguments = { 750020d003cSKyle Evans "src", 751020d003cSKyle Evans "__buf", 752020d003cSKyle Evans "__len", 753020d003cSKyle Evans }, 754020d003cSKyle Evans exclude = excludes_stack_overflow, 755020d003cSKyle Evans stackvars = "\tchar src[__len + 10];\n", 756020d003cSKyle Evans }, 757020d003cSKyle Evans { 758020d003cSKyle Evans func = "bzero", 759020d003cSKyle Evans arguments = { 760020d003cSKyle Evans "__buf", 761020d003cSKyle Evans "__len", 762020d003cSKyle Evans }, 763020d003cSKyle Evans exclude = excludes_stack_overflow, 764020d003cSKyle Evans }, 765cf8e5289SKyle Evans { 766cf8e5289SKyle Evans func = "explicit_bzero", 767cf8e5289SKyle Evans arguments = { 768cf8e5289SKyle Evans "__buf", 769cf8e5289SKyle Evans "__len", 770cf8e5289SKyle Evans }, 771cf8e5289SKyle Evans exclude = excludes_stack_overflow, 772cf8e5289SKyle Evans }, 773020d003cSKyle Evans }, 774020d003cSKyle Evans unistd = { 775020d003cSKyle Evans -- <unistd.h> 776020d003cSKyle Evans { 777020d003cSKyle Evans func = "getcwd", 778020d003cSKyle Evans bufsize = "8", 779020d003cSKyle Evans arguments = { 780020d003cSKyle Evans "__buf", 781020d003cSKyle Evans "__len", 782020d003cSKyle Evans }, 783020d003cSKyle Evans exclude = excludes_stack_overflow, 784020d003cSKyle Evans }, 785020d003cSKyle Evans { 786cf8e5289SKyle Evans func = "getgrouplist", 787cf8e5289SKyle Evans bufsize = "4", 788cf8e5289SKyle Evans buftype = "gid_t[]", 789cf8e5289SKyle Evans arguments = { 790cf8e5289SKyle Evans "\"root\"", 791cf8e5289SKyle Evans "0", 792cf8e5289SKyle Evans "__buf", 793cf8e5289SKyle Evans "&intlen", 794cf8e5289SKyle Evans }, 795cf8e5289SKyle Evans exclude = excludes_stack_overflow, 796cf8e5289SKyle Evans stackvars = "\tint intlen = (int)__len;\n", 797cf8e5289SKyle Evans uses_len = true, 798cf8e5289SKyle Evans }, 799cf8e5289SKyle Evans { 800cf8e5289SKyle Evans func = "getgroups", 801cf8e5289SKyle Evans bufsize = "4", 802cf8e5289SKyle Evans buftype = "gid_t[]", 803cf8e5289SKyle Evans arguments = { 804cf8e5289SKyle Evans "__len", 805cf8e5289SKyle Evans "__buf", 806cf8e5289SKyle Evans }, 807cf8e5289SKyle Evans exclude = excludes_stack_overflow, 808cf8e5289SKyle Evans }, 809cf8e5289SKyle Evans { 810cf8e5289SKyle Evans func = "getloginclass", 811cf8e5289SKyle Evans arguments = { 812cf8e5289SKyle Evans "__buf", 813cf8e5289SKyle Evans "__len", 814cf8e5289SKyle Evans }, 815cf8e5289SKyle Evans exclude = excludes_stack_overflow, 816cf8e5289SKyle Evans }, 817cf8e5289SKyle Evans { 818cf8e5289SKyle Evans func = "pread", 819cf8e5289SKyle Evans bufsize = "41", 820cf8e5289SKyle Evans arguments = { 821cf8e5289SKyle Evans "fd", 822cf8e5289SKyle Evans "__buf", 823cf8e5289SKyle Evans "__len", 824cf8e5289SKyle Evans "0", 825cf8e5289SKyle Evans }, 826cf8e5289SKyle Evans exclude = excludes_stack_overflow, 827cf8e5289SKyle Evans stackvars = "\tint fd;\n", 828cf8e5289SKyle Evans init = [[ 829cf8e5289SKyle Evans fd = new_tmpfile(); /* Cannot fail */ 830cf8e5289SKyle Evans]], 831cf8e5289SKyle Evans }, 832cf8e5289SKyle Evans { 833020d003cSKyle Evans func = "read", 834020d003cSKyle Evans bufsize = "41", 835020d003cSKyle Evans arguments = { 836020d003cSKyle Evans "fd", 837020d003cSKyle Evans "__buf", 838020d003cSKyle Evans "__len", 839020d003cSKyle Evans }, 840020d003cSKyle Evans exclude = excludes_stack_overflow, 841020d003cSKyle Evans stackvars = "\tint fd;\n", 842020d003cSKyle Evans init = [[ 843020d003cSKyle Evans fd = new_tmpfile(); /* Cannot fail */ 844020d003cSKyle Evans]], 845020d003cSKyle Evans }, 846020d003cSKyle Evans { 847020d003cSKyle Evans func = "readlink", 848020d003cSKyle Evans arguments = { 849020d003cSKyle Evans "path", 850020d003cSKyle Evans "__buf", 851020d003cSKyle Evans "__len", 852020d003cSKyle Evans }, 853020d003cSKyle Evans exclude = excludes_stack_overflow, 854020d003cSKyle Evans stackvars = "\tconst char *path;\n", 855020d003cSKyle Evans init = [[ 856020d003cSKyle Evans path = new_symlink(__len); /* Cannot fail */ 857020d003cSKyle Evans]], 858020d003cSKyle Evans }, 859cf8e5289SKyle Evans { 860cf8e5289SKyle Evans func = "readlinkat", 861cf8e5289SKyle Evans arguments = { 862cf8e5289SKyle Evans "AT_FDCWD", 863cf8e5289SKyle Evans "path", 864cf8e5289SKyle Evans "__buf", 865cf8e5289SKyle Evans "__len", 866cf8e5289SKyle Evans }, 867cf8e5289SKyle Evans exclude = excludes_stack_overflow, 868cf8e5289SKyle Evans stackvars = "\tconst char *path;\n", 869cf8e5289SKyle Evans init = [[ 870cf8e5289SKyle Evans path = new_symlink(__len); /* Cannot fail */ 871cf8e5289SKyle Evans]], 872cf8e5289SKyle Evans }, 873cf8e5289SKyle Evans { 874cf8e5289SKyle Evans func = "getdomainname", 87522178cb2SKyle Evans bufsize = #domainname + 1, 876cf8e5289SKyle Evans arguments = { 877cf8e5289SKyle Evans "__buf", 878cf8e5289SKyle Evans "__len", 879cf8e5289SKyle Evans }, 88022178cb2SKyle Evans need_root = true, 881cf8e5289SKyle Evans exclude = excludes_stack_overflow, 88222178cb2SKyle Evans early_init = " dhost_jail();", 883cf8e5289SKyle Evans }, 884cf8e5289SKyle Evans { 885cf8e5289SKyle Evans func = "getentropy", 886cf8e5289SKyle Evans arguments = { 887cf8e5289SKyle Evans "__buf", 888cf8e5289SKyle Evans "__len", 889cf8e5289SKyle Evans }, 890cf8e5289SKyle Evans exclude = excludes_stack_overflow, 891cf8e5289SKyle Evans }, 892cf8e5289SKyle Evans { 893cf8e5289SKyle Evans func = "gethostname", 89422178cb2SKyle Evans bufsize = #hostname + 1, 895cf8e5289SKyle Evans arguments = { 896cf8e5289SKyle Evans "__buf", 897cf8e5289SKyle Evans "__len", 898cf8e5289SKyle Evans }, 89922178cb2SKyle Evans need_root = true, 900cf8e5289SKyle Evans exclude = excludes_stack_overflow, 90122178cb2SKyle Evans early_init = " dhost_jail();", 902cf8e5289SKyle Evans }, 903cf8e5289SKyle Evans { 904cf8e5289SKyle Evans func = "getlogin_r", 905cf8e5289SKyle Evans bufsize = "MAXLOGNAME + 1", 906cf8e5289SKyle Evans arguments = { 907cf8e5289SKyle Evans "__buf", 908cf8e5289SKyle Evans "__len", 909cf8e5289SKyle Evans }, 910cf8e5289SKyle Evans exclude = excludes_stack_overflow, 911cf8e5289SKyle Evans }, 912cf8e5289SKyle Evans { 913cf8e5289SKyle Evans func = "ttyname_r", 914cf8e5289SKyle Evans arguments = { 915cf8e5289SKyle Evans "fd", 916cf8e5289SKyle Evans "__buf", 917cf8e5289SKyle Evans "__len", 918cf8e5289SKyle Evans }, 919cf8e5289SKyle Evans exclude = excludes_stack_overflow, 920cf8e5289SKyle Evans stackvars = "\tint fd;\n", 921cf8e5289SKyle Evans early_init = [[ 922cf8e5289SKyle Evans fd = STDIN_FILENO; 923cf8e5289SKyle Evans if (!isatty(fd)) 924cf8e5289SKyle Evans atf_tc_skip("stdin is not an fd"); 925cf8e5289SKyle Evans]] 926cf8e5289SKyle Evans }, 927020d003cSKyle Evans }, 928b53d7aa8SKyle Evans wchar = { 929b53d7aa8SKyle Evans -- <wchar.h> 930b53d7aa8SKyle Evans { 931b53d7aa8SKyle Evans func = "wmemcpy", 932b53d7aa8SKyle Evans buftype = "wchar_t[]", 933b53d7aa8SKyle Evans arguments = { 934b53d7aa8SKyle Evans "__buf", 935b53d7aa8SKyle Evans "src", 936b53d7aa8SKyle Evans "__len", 937b53d7aa8SKyle Evans }, 938b53d7aa8SKyle Evans exclude = excludes_stack_overflow, 939b53d7aa8SKyle Evans stackvars = "\twchar_t src[__len + 10];\n", 940b53d7aa8SKyle Evans }, 941b53d7aa8SKyle Evans { 942b53d7aa8SKyle Evans func = "wmempcpy", 943b53d7aa8SKyle Evans buftype = "wchar_t[]", 944b53d7aa8SKyle Evans arguments = { 945b53d7aa8SKyle Evans "__buf", 946b53d7aa8SKyle Evans "src", 947b53d7aa8SKyle Evans "__len", 948b53d7aa8SKyle Evans }, 949b53d7aa8SKyle Evans exclude = excludes_stack_overflow, 950b53d7aa8SKyle Evans stackvars = "\twchar_t src[__len + 10];\n", 951b53d7aa8SKyle Evans }, 952b53d7aa8SKyle Evans { 953b53d7aa8SKyle Evans func = "wmemmove", 954b53d7aa8SKyle Evans buftype = "wchar_t[]", 955b53d7aa8SKyle Evans arguments = { 956b53d7aa8SKyle Evans "__buf", 957b53d7aa8SKyle Evans "src", 958b53d7aa8SKyle Evans "__len", 959b53d7aa8SKyle Evans }, 960b53d7aa8SKyle Evans exclude = excludes_stack_overflow, 961b53d7aa8SKyle Evans stackvars = "\twchar_t src[__len + 10];\n", 962b53d7aa8SKyle Evans }, 963b53d7aa8SKyle Evans { 964b53d7aa8SKyle Evans func = "wmemset", 965b53d7aa8SKyle Evans buftype = "wchar_t[]", 966b53d7aa8SKyle Evans arguments = { 967b53d7aa8SKyle Evans "__buf", 968b53d7aa8SKyle Evans "L'0'", 969b53d7aa8SKyle Evans "__len", 970b53d7aa8SKyle Evans }, 971b53d7aa8SKyle Evans exclude = excludes_stack_overflow, 972b53d7aa8SKyle Evans }, 973b53d7aa8SKyle Evans { 974b53d7aa8SKyle Evans func = "wcpcpy", 975b53d7aa8SKyle Evans buftype = "wchar_t[]", 976b53d7aa8SKyle Evans arguments = { 977b53d7aa8SKyle Evans "__buf", 978b53d7aa8SKyle Evans "src", 979b53d7aa8SKyle Evans }, 980b53d7aa8SKyle Evans exclude = excludes_stack_overflow, 981b53d7aa8SKyle Evans stackvars = wstring_stackvars, 982b53d7aa8SKyle Evans init = wstring_init, 983b53d7aa8SKyle Evans uses_len = true, 984b53d7aa8SKyle Evans }, 985b53d7aa8SKyle Evans { 986b53d7aa8SKyle Evans func = "wcpncpy", 987b53d7aa8SKyle Evans buftype = "wchar_t[]", 988b53d7aa8SKyle Evans arguments = { 989b53d7aa8SKyle Evans "__buf", 990b53d7aa8SKyle Evans "src", 991b53d7aa8SKyle Evans "__len", 992b53d7aa8SKyle Evans }, 993b53d7aa8SKyle Evans exclude = excludes_stack_overflow, 994b53d7aa8SKyle Evans stackvars = wstring_stackvars, 995b53d7aa8SKyle Evans init = wstring_init, 996b53d7aa8SKyle Evans }, 997b53d7aa8SKyle Evans { 998b53d7aa8SKyle Evans func = "wcscat", 999b53d7aa8SKyle Evans buftype = "wchar_t[]", 1000b53d7aa8SKyle Evans arguments = { 1001b53d7aa8SKyle Evans "__buf", 1002b53d7aa8SKyle Evans "src", 1003b53d7aa8SKyle Evans }, 1004b53d7aa8SKyle Evans exclude = excludes_stack_overflow, 1005b53d7aa8SKyle Evans stackvars = wstring_stackvars, 1006b53d7aa8SKyle Evans init = wstring_init, 1007b53d7aa8SKyle Evans uses_len = true, 1008b53d7aa8SKyle Evans }, 1009b53d7aa8SKyle Evans { 1010b53d7aa8SKyle Evans func = "wcslcat", 1011b53d7aa8SKyle Evans buftype = "wchar_t[]", 1012b53d7aa8SKyle Evans arguments = { 1013b53d7aa8SKyle Evans "__buf", 1014b53d7aa8SKyle Evans "src", 1015b53d7aa8SKyle Evans "__len", 1016b53d7aa8SKyle Evans }, 1017b53d7aa8SKyle Evans exclude = excludes_stack_overflow, 1018b53d7aa8SKyle Evans stackvars = wstring_stackvars, 1019b53d7aa8SKyle Evans init = wstring_init, 1020b53d7aa8SKyle Evans }, 1021b53d7aa8SKyle Evans { 1022b53d7aa8SKyle Evans func = "wcsncat", 1023b53d7aa8SKyle Evans buftype = "wchar_t[]", 1024b53d7aa8SKyle Evans arguments = { 1025b53d7aa8SKyle Evans "__buf", 1026b53d7aa8SKyle Evans "src", 1027b53d7aa8SKyle Evans "__len", 1028b53d7aa8SKyle Evans }, 1029b53d7aa8SKyle Evans exclude = excludes_stack_overflow, 1030b53d7aa8SKyle Evans stackvars = wstring_stackvars, 1031b53d7aa8SKyle Evans init = wstring_init, 1032b53d7aa8SKyle Evans }, 1033b53d7aa8SKyle Evans { 1034b53d7aa8SKyle Evans func = "wcscpy", 1035b53d7aa8SKyle Evans buftype = "wchar_t[]", 1036b53d7aa8SKyle Evans arguments = { 1037b53d7aa8SKyle Evans "__buf", 1038b53d7aa8SKyle Evans "src", 1039b53d7aa8SKyle Evans }, 1040b53d7aa8SKyle Evans exclude = excludes_stack_overflow, 1041b53d7aa8SKyle Evans stackvars = wstring_stackvars, 1042b53d7aa8SKyle Evans init = wstring_init, 1043b53d7aa8SKyle Evans uses_len = true, 1044b53d7aa8SKyle Evans }, 1045b53d7aa8SKyle Evans { 1046b53d7aa8SKyle Evans func = "wcslcpy", 1047b53d7aa8SKyle Evans buftype = "wchar_t[]", 1048b53d7aa8SKyle Evans arguments = { 1049b53d7aa8SKyle Evans "__buf", 1050b53d7aa8SKyle Evans "src", 1051b53d7aa8SKyle Evans "__len", 1052b53d7aa8SKyle Evans }, 1053b53d7aa8SKyle Evans exclude = excludes_stack_overflow, 1054b53d7aa8SKyle Evans stackvars = wstring_stackvars, 1055b53d7aa8SKyle Evans init = wstring_init, 1056b53d7aa8SKyle Evans }, 1057b53d7aa8SKyle Evans { 1058b53d7aa8SKyle Evans func = "wcsncpy", 1059b53d7aa8SKyle Evans buftype = "wchar_t[]", 1060b53d7aa8SKyle Evans arguments = { 1061b53d7aa8SKyle Evans "__buf", 1062b53d7aa8SKyle Evans "src", 1063b53d7aa8SKyle Evans "__len", 1064b53d7aa8SKyle Evans }, 1065b53d7aa8SKyle Evans exclude = excludes_stack_overflow, 1066b53d7aa8SKyle Evans stackvars = wstring_stackvars, 1067b53d7aa8SKyle Evans init = wstring_init, 1068b53d7aa8SKyle Evans }, 1069b53d7aa8SKyle Evans }, 1070020d003cSKyle Evans} 1071020d003cSKyle Evans 107209cdbf04SKyle Evanslocal function write_test_boilerplate(fh, name, body, def) 107309cdbf04SKyle Evans fh:write("ATF_TC(" .. name .. ");\n") 107409cdbf04SKyle Evans fh:write("ATF_TC_HEAD(" .. name .. ", tc)\n") 107509cdbf04SKyle Evans fh:write("{\n") 107609cdbf04SKyle Evans if def.need_root then 107709cdbf04SKyle Evans fh:write(" atf_tc_set_md_var(tc, \"require.user\", \"root\");\n") 107809cdbf04SKyle Evans end 107909cdbf04SKyle Evans fh:write("}\n") 108009cdbf04SKyle Evans 1081020d003cSKyle Evans fh:write("ATF_TC_BODY(" .. name .. ", tc)\n") 1082020d003cSKyle Evans fh:write("{\n" .. body .. "\n}\n\n") 1083020d003cSKyle Evans return name 1084020d003cSKyle Evansend 1085020d003cSKyle Evans 1086020d003cSKyle Evanslocal function generate_test_name(func, variant, disposition, heap) 1087020d003cSKyle Evans local basename = func 1088020d003cSKyle Evans if variant then 1089020d003cSKyle Evans basename = basename .. "_" .. variant 1090020d003cSKyle Evans end 1091020d003cSKyle Evans if heap then 1092020d003cSKyle Evans basename = basename .. "_heap" 1093020d003cSKyle Evans end 1094020d003cSKyle Evans if disposition < 0 then 1095020d003cSKyle Evans return basename .. "_before_end" 1096020d003cSKyle Evans elseif disposition == 0 then 1097020d003cSKyle Evans return basename .. "_end" 1098020d003cSKyle Evans else 1099020d003cSKyle Evans return basename .. "_after_end" 1100020d003cSKyle Evans end 1101020d003cSKyle Evansend 1102020d003cSKyle Evans 1103020d003cSKyle Evanslocal function array_type(buftype) 1104020d003cSKyle Evans if not buftype:match("%[%]") then 1105020d003cSKyle Evans return nil 1106020d003cSKyle Evans end 1107020d003cSKyle Evans 1108020d003cSKyle Evans return buftype:gsub("%[%]", "") 1109020d003cSKyle Evansend 1110020d003cSKyle Evans 1111020d003cSKyle Evanslocal function configurable(def, idx) 1112020d003cSKyle Evans local cfgitem = def[idx] 1113020d003cSKyle Evans 1114020d003cSKyle Evans if not cfgitem then 1115020d003cSKyle Evans return nil 1116020d003cSKyle Evans end 1117020d003cSKyle Evans 1118020d003cSKyle Evans if type(cfgitem) == "function" then 1119020d003cSKyle Evans return cfgitem() 1120020d003cSKyle Evans end 1121020d003cSKyle Evans 1122020d003cSKyle Evans return cfgitem 1123020d003cSKyle Evansend 1124020d003cSKyle Evans 1125020d003cSKyle Evanslocal function generate_stackframe(buftype, bufsize, disposition, heap, def) 112685242b59SKyle Evans local function len_offset(inverted) 1127020d003cSKyle Evans -- Tests that don't use __len in their arguments may use an 1128020d003cSKyle Evans -- inverted sense because we can't just specify a length that 1129020d003cSKyle Evans -- would induce an access just after the end. Instead, we have 1130020d003cSKyle Evans -- to manipulate the buffer size to be too short so that the 1131020d003cSKyle Evans -- function under test would write one too many. 1132020d003cSKyle Evans if disposition < 0 then 1133020d003cSKyle Evans return ((inverted and " + ") or " - ") .. "1" 1134020d003cSKyle Evans elseif disposition == 0 then 1135020d003cSKyle Evans return "" 1136020d003cSKyle Evans else 1137020d003cSKyle Evans return ((inverted and " - ") or " + ") .. "1" 1138020d003cSKyle Evans end 1139020d003cSKyle Evans end 1140020d003cSKyle Evans 114185242b59SKyle Evans local function test_uses_len() 1142020d003cSKyle Evans if def.uses_len then 1143020d003cSKyle Evans return true 1144020d003cSKyle Evans end 1145020d003cSKyle Evans 1146020d003cSKyle Evans for _, arg in ipairs(def.arguments) do 1147020d003cSKyle Evans if arg:match("__len") or arg:match("__idx") then 1148020d003cSKyle Evans return true 1149020d003cSKyle Evans end 1150020d003cSKyle Evans end 1151020d003cSKyle Evans 1152020d003cSKyle Evans return false 1153020d003cSKyle Evans end 1154020d003cSKyle Evans 1155020d003cSKyle Evans 1156020d003cSKyle Evans -- This is perhaps a little convoluted, but we toss the buffer into a 1157020d003cSKyle Evans -- struct on the stack to guarantee that we have at least one valid 1158020d003cSKyle Evans -- byte on either side of the buffer -- a measure to make sure that 1159020d003cSKyle Evans -- we're tripping _FORTIFY_SOURCE specifically in the buffer + 1 case, 1160020d003cSKyle Evans -- rather than some other stack or memory protection. 1161020d003cSKyle Evans local vars = "\tstruct {\n" 1162020d003cSKyle Evans vars = vars .. "\t\tuint8_t padding_l;\n" 1163020d003cSKyle Evans 116485242b59SKyle Evans local uses_len = test_uses_len() 116585242b59SKyle Evans local bufsize_offset = len_offset(not uses_len) 1166020d003cSKyle Evans local buftype_elem = array_type(buftype) 1167020d003cSKyle Evans local size_expr = bufsize 1168020d003cSKyle Evans 1169020d003cSKyle Evans if not uses_len then 1170020d003cSKyle Evans -- If the length isn't in use, we have to vary the buffer size 1171020d003cSKyle Evans -- since the fortified function likely has some internal size 1172020d003cSKyle Evans -- constraint that it's supposed to be checking. 1173020d003cSKyle Evans size_expr = size_expr .. bufsize_offset 1174020d003cSKyle Evans end 1175020d003cSKyle Evans 1176020d003cSKyle Evans if not heap and buftype_elem then 1177020d003cSKyle Evans -- Array type: size goes after identifier 1178020d003cSKyle Evans vars = vars .. "\t\t" .. buftype_elem .. 1179020d003cSKyle Evans " __buf[" .. size_expr .. "];\n" 1180020d003cSKyle Evans else 1181020d003cSKyle Evans local basic_type = buftype_elem or buftype 1182020d003cSKyle Evans 1183020d003cSKyle Evans -- Heap tests obviously just put a pointer on the stack that 1184020d003cSKyle Evans -- points to our new allocation, but we leave it in the padded 1185020d003cSKyle Evans -- struct just to simplify our generator. 1186020d003cSKyle Evans if heap then 1187020d003cSKyle Evans basic_type = basic_type .. " *" 1188020d003cSKyle Evans end 1189020d003cSKyle Evans vars = vars .. "\t\t" .. basic_type .. " __buf;\n" 1190020d003cSKyle Evans end 1191020d003cSKyle Evans 1192020d003cSKyle Evans -- padding_r is our just-past-the-end padding that we use to make sure 1193020d003cSKyle Evans -- that there's a valid portion after the buffer that isn't being 1194020d003cSKyle Evans -- included in our function calls. If we didn't have it, then we'd have 1195020d003cSKyle Evans -- a hard time feeling confident that an abort on the just-after tests 1196020d003cSKyle Evans -- isn't maybe from some other memory or stack protection. 1197020d003cSKyle Evans vars = vars .. "\t\tuint8_t padding_r;\n" 1198020d003cSKyle Evans vars = vars .. "\t} __stack;\n" 1199020d003cSKyle Evans 1200020d003cSKyle Evans -- Not all tests will use __bufsz, but some do for, e.g., clearing 1201020d003cSKyle Evans -- memory.. 1202020d003cSKyle Evans vars = vars .. "\tconst size_t __bufsz __unused = " 1203020d003cSKyle Evans if heap then 1204020d003cSKyle Evans local scalar = 1 1205020d003cSKyle Evans if buftype_elem then 1206020d003cSKyle Evans scalar = size_expr 1207020d003cSKyle Evans end 1208020d003cSKyle Evans 1209020d003cSKyle Evans vars = vars .. "sizeof(*__stack.__buf) * (" .. scalar .. ");\n" 1210020d003cSKyle Evans else 1211020d003cSKyle Evans vars = vars .. "sizeof(__stack.__buf);\n" 1212020d003cSKyle Evans end 1213020d003cSKyle Evans 1214020d003cSKyle Evans vars = vars .. "\tconst size_t __len = " .. bufsize .. 1215020d003cSKyle Evans bufsize_offset .. ";\n" 1216020d003cSKyle Evans vars = vars .. "\tconst size_t __idx __unused = __len - 1;\n" 1217020d003cSKyle Evans 1218020d003cSKyle Evans -- For overflow testing, we need to fork() because we're expecting the 1219020d003cSKyle Evans -- test to ultimately abort()/_exit(). Then we can collect the exit 1220020d003cSKyle Evans -- status and report appropriately. 1221020d003cSKyle Evans if disposition > 0 then 1222020d003cSKyle Evans vars = vars .. "\tpid_t __child;\n" 1223020d003cSKyle Evans vars = vars .. "\tint __status;\n" 1224020d003cSKyle Evans end 1225020d003cSKyle Evans 1226020d003cSKyle Evans -- Any other stackvars defined by the test get placed after everything 1227020d003cSKyle Evans -- else. 1228020d003cSKyle Evans vars = vars .. (configurable(def, "stackvars") or "") 1229020d003cSKyle Evans 1230020d003cSKyle Evans return vars 1231020d003cSKyle Evansend 1232020d003cSKyle Evans 1233020d003cSKyle Evanslocal function write_test(fh, func, disposition, heap, def) 1234020d003cSKyle Evans local testname = generate_test_name(func, def.variant, disposition, heap) 1235020d003cSKyle Evans local buftype = def.buftype or "unsigned char[]" 1236020d003cSKyle Evans local bufsize = def.bufsize or 42 1237020d003cSKyle Evans local body = "" 1238020d003cSKyle Evans 1239020d003cSKyle Evans if def.exclude and def.exclude(disposition, heap) then 1240020d003cSKyle Evans return 1241020d003cSKyle Evans end 1242020d003cSKyle Evans 124385242b59SKyle Evans local function need_addr() 1244020d003cSKyle Evans return not (buftype:match("%[%]") or buftype:match("%*")) 1245020d003cSKyle Evans end 1246020d003cSKyle Evans 1247020d003cSKyle Evans if heap then 1248020d003cSKyle Evans body = body .. "#define BUF __stack.__buf\n" 1249020d003cSKyle Evans else 1250020d003cSKyle Evans body = body .. "#define BUF &__stack.__buf\n" 1251020d003cSKyle Evans end 1252020d003cSKyle Evans 1253020d003cSKyle Evans -- Setup the buffer 1254020d003cSKyle Evans body = body .. generate_stackframe(buftype, bufsize, disposition, heap, def) .. 1255020d003cSKyle Evans "\n" 1256020d003cSKyle Evans 1257020d003cSKyle Evans -- Any early initialization goes before we would fork for the just-after 1258020d003cSKyle Evans -- tests, because they may want to skip the test based on some criteria 1259020d003cSKyle Evans -- and we can't propagate that up very easily once we're forked. 1260020d003cSKyle Evans local early_init = configurable(def, "early_init") 1261020d003cSKyle Evans body = body .. (early_init or "") 1262020d003cSKyle Evans if early_init then 1263020d003cSKyle Evans body = body .. "\n" 1264020d003cSKyle Evans end 1265020d003cSKyle Evans 1266020d003cSKyle Evans -- Fork off, iff we're testing some access past the end of the buffer. 1267020d003cSKyle Evans if disposition > 0 then 1268020d003cSKyle Evans body = body .. [[ 1269020d003cSKyle Evans __child = fork(); 1270020d003cSKyle Evans ATF_REQUIRE(__child >= 0); 1271020d003cSKyle Evans if (__child > 0) 1272020d003cSKyle Evans goto monitor; 1273020d003cSKyle Evans 1274020d003cSKyle Evans /* Child */ 1275020d003cSKyle Evans disable_coredumps(); 1276020d003cSKyle Evans]] 1277020d003cSKyle Evans end 1278020d003cSKyle Evans 1279020d003cSKyle Evans local bufvar = "__stack.__buf" 1280020d003cSKyle Evans if heap then 1281020d003cSKyle Evans -- Buffer needs to be initialized because it's a heap allocation. 1282020d003cSKyle Evans body = body .. "\t" .. bufvar .. " = malloc(__bufsz);\n" 1283020d003cSKyle Evans end 1284020d003cSKyle Evans 1285020d003cSKyle Evans -- Non-early init happens just after the fork in the child, not the 1286020d003cSKyle Evans -- monitor. This is used to setup any other buffers we may need, for 1287020d003cSKyle Evans -- instance. 1288020d003cSKyle Evans local extra_init = configurable(def, "init") 1289020d003cSKyle Evans body = body .. (extra_init or "") 1290020d003cSKyle Evans 1291020d003cSKyle Evans if heap or extra_init then 1292020d003cSKyle Evans body = body .. "\n" 1293020d003cSKyle Evans end 1294020d003cSKyle Evans 1295020d003cSKyle Evans -- Setup the function call with arguments as described in the test 1296020d003cSKyle Evans -- definition. 1297020d003cSKyle Evans body = body .. "\t" .. func .. "(" 1298020d003cSKyle Evans 1299020d003cSKyle Evans for idx, arg in ipairs(def.arguments) do 1300020d003cSKyle Evans if idx > 1 then 1301020d003cSKyle Evans body = body .. ", " 1302020d003cSKyle Evans end 1303020d003cSKyle Evans 1304020d003cSKyle Evans if arg == "__buf" then 130585242b59SKyle Evans if not heap and need_addr() then 1306020d003cSKyle Evans body = body .. "&" 1307020d003cSKyle Evans end 1308020d003cSKyle Evans 1309020d003cSKyle Evans body = body .. bufvar 1310020d003cSKyle Evans else 1311020d003cSKyle Evans local argname = arg 1312020d003cSKyle Evans 1313020d003cSKyle Evans if def.value_of then 1314020d003cSKyle Evans argname = argname or def.value_of(arg) 1315020d003cSKyle Evans end 1316020d003cSKyle Evans 1317020d003cSKyle Evans body = body .. argname 1318020d003cSKyle Evans end 1319020d003cSKyle Evans end 1320020d003cSKyle Evans 1321020d003cSKyle Evans body = body .. ");\n" 1322020d003cSKyle Evans 1323020d003cSKyle Evans -- Monitor stuff follows, for OOB access. 1324020d003cSKyle Evans if disposition <= 0 then 1325020d003cSKyle Evans goto skip 1326020d003cSKyle Evans end 1327020d003cSKyle Evans 1328020d003cSKyle Evans body = body .. [[ 1329020d003cSKyle Evans _exit(EX_SOFTWARE); /* Should have aborted. */ 1330020d003cSKyle Evans 1331020d003cSKyle Evansmonitor: 1332020d003cSKyle Evans while (waitpid(__child, &__status, 0) != __child) { 1333020d003cSKyle Evans ATF_REQUIRE_EQ(EINTR, errno); 1334020d003cSKyle Evans } 1335020d003cSKyle Evans 1336020d003cSKyle Evans if (!WIFSIGNALED(__status)) { 1337020d003cSKyle Evans switch (WEXITSTATUS(__status)) { 1338020d003cSKyle Evans case EX_SOFTWARE: 1339020d003cSKyle Evans atf_tc_fail("FORTIFY_SOURCE failed to abort"); 1340020d003cSKyle Evans break; 1341020d003cSKyle Evans case EX_OSERR: 1342020d003cSKyle Evans atf_tc_fail("setrlimit(2) failed"); 1343020d003cSKyle Evans break; 1344020d003cSKyle Evans default: 1345020d003cSKyle Evans atf_tc_fail("child exited with status %d", 1346020d003cSKyle Evans WEXITSTATUS(__status)); 1347020d003cSKyle Evans } 1348020d003cSKyle Evans } else { 1349020d003cSKyle Evans ATF_REQUIRE_EQ(SIGABRT, WTERMSIG(__status)); 1350020d003cSKyle Evans } 1351020d003cSKyle Evans]] 1352020d003cSKyle Evans 1353020d003cSKyle Evans::skip:: 1354020d003cSKyle Evans body = body .. "#undef BUF\n" 135509cdbf04SKyle Evans return write_test_boilerplate(fh, testname, body, def) 1356020d003cSKyle Evansend 1357020d003cSKyle Evans 1358020d003cSKyle Evans-- main() 1359020d003cSKyle Evanslocal tests 1360020d003cSKyle Evanslocal tcat = assert(arg[1], "usage: generate-fortify-tests.lua <category>") 1361020d003cSKyle Evansfor k, defs in pairs(all_tests) do 1362020d003cSKyle Evans if k == tcat then 1363020d003cSKyle Evans tests = defs 1364020d003cSKyle Evans break 1365020d003cSKyle Evans end 1366020d003cSKyle Evansend 1367020d003cSKyle Evans 1368020d003cSKyle Evansassert(tests, "category " .. tcat .. " not found") 1369020d003cSKyle Evans 1370020d003cSKyle Evanslocal fh = io.stdout 1371020d003cSKyle Evansfh:write("/* @" .. "generated" .. " by `generate-fortify-tests.lua \"" .. 1372020d003cSKyle Evans tcat .. "\"` */\n\n") 1373020d003cSKyle Evansfh:write("#define _FORTIFY_SOURCE 2\n") 1374020d003cSKyle Evansfh:write("#define TMPFILE_SIZE (1024 * 32)\n") 1375020d003cSKyle Evans 1376020d003cSKyle Evansfh:write("\n") 1377020d003cSKyle Evansfor _, inc in ipairs(includes) do 1378020d003cSKyle Evans fh:write("#include <" .. inc .. ">\n") 1379020d003cSKyle Evansend 1380020d003cSKyle Evans 1381020d003cSKyle Evansfh:write([[ 1382020d003cSKyle Evans 1383cf8e5289SKyle Evansstatic FILE * __unused 1384cf8e5289SKyle Evansnew_fp(size_t __len) 1385cf8e5289SKyle Evans{ 1386cf8e5289SKyle Evans static char fpbuf[LINE_MAX]; 1387cf8e5289SKyle Evans FILE *fp; 1388cf8e5289SKyle Evans 1389cf8e5289SKyle Evans ATF_REQUIRE(__len <= sizeof(fpbuf)); 1390cf8e5289SKyle Evans 1391cf8e5289SKyle Evans memset(fpbuf, 'A', sizeof(fpbuf) - 1); 1392cf8e5289SKyle Evans fpbuf[sizeof(fpbuf) - 1] = '\0'; 1393cf8e5289SKyle Evans 1394cf8e5289SKyle Evans fp = fmemopen(fpbuf, sizeof(fpbuf), "rb"); 1395cf8e5289SKyle Evans ATF_REQUIRE(fp != NULL); 1396cf8e5289SKyle Evans 1397cf8e5289SKyle Evans return (fp); 1398cf8e5289SKyle Evans} 1399cf8e5289SKyle Evans 1400020d003cSKyle Evans/* 1401020d003cSKyle Evans * Create a new symlink to use for readlink(2) style tests, we'll just use a 1402020d003cSKyle Evans * random target name to have something interesting to look at. 1403020d003cSKyle Evans */ 1404020d003cSKyle Evansstatic const char * __unused 1405020d003cSKyle Evansnew_symlink(size_t __len) 1406020d003cSKyle Evans{ 1407020d003cSKyle Evans static const char linkname[] = "link"; 1408020d003cSKyle Evans char target[MAXNAMLEN]; 1409020d003cSKyle Evans int error; 1410020d003cSKyle Evans 1411020d003cSKyle Evans ATF_REQUIRE(__len <= sizeof(target)); 1412020d003cSKyle Evans 1413020d003cSKyle Evans arc4random_buf(target, sizeof(target)); 1414020d003cSKyle Evans 1415020d003cSKyle Evans error = unlink(linkname); 1416020d003cSKyle Evans ATF_REQUIRE(error == 0 || errno == ENOENT); 1417020d003cSKyle Evans 1418020d003cSKyle Evans error = symlink(target, linkname); 1419020d003cSKyle Evans ATF_REQUIRE(error == 0); 1420020d003cSKyle Evans 1421020d003cSKyle Evans return (linkname); 1422020d003cSKyle Evans} 1423020d003cSKyle Evans 1424020d003cSKyle Evans/* 14251f155d48SKyle Evans * For our purposes, first descriptor will be the reader; we'll send both 14261f155d48SKyle Evans * raw data and a control message over it so that the result can be used for 14271f155d48SKyle Evans * any of our recv*() tests. 14281f155d48SKyle Evans */ 14291f155d48SKyle Evansstatic void __unused 14301f155d48SKyle Evansnew_socket(int sock[2]) 14311f155d48SKyle Evans{ 14321f155d48SKyle Evans unsigned char ctrl[CMSG_SPACE(sizeof(int))] = { 0 }; 14331f155d48SKyle Evans static char sockbuf[256]; 14341f155d48SKyle Evans ssize_t rv; 14351f155d48SKyle Evans size_t total = 0; 14361f155d48SKyle Evans struct msghdr hdr = { 0 }; 14371f155d48SKyle Evans struct cmsghdr *cmsg; 14381f155d48SKyle Evans int error, fd; 14391f155d48SKyle Evans 14401f155d48SKyle Evans error = socketpair(AF_UNIX, SOCK_STREAM, 0, sock); 14411f155d48SKyle Evans ATF_REQUIRE(error == 0); 14421f155d48SKyle Evans 14431f155d48SKyle Evans while (total != sizeof(sockbuf)) { 14441f155d48SKyle Evans rv = send(sock[1], &sockbuf[total], sizeof(sockbuf) - total, 0); 14451f155d48SKyle Evans 14461f155d48SKyle Evans ATF_REQUIRE_MSG(rv > 0, 14471f155d48SKyle Evans "expected bytes sent, got %zd with %zu left (size %zu, total %zu)", 14481f155d48SKyle Evans rv, sizeof(sockbuf) - total, sizeof(sockbuf), total); 14491f155d48SKyle Evans ATF_REQUIRE_MSG(total + (size_t)rv <= sizeof(sockbuf), 14501f155d48SKyle Evans "%zd exceeds total %zu", rv, sizeof(sockbuf)); 14511f155d48SKyle Evans total += rv; 14521f155d48SKyle Evans } 14531f155d48SKyle Evans 14541f155d48SKyle Evans hdr.msg_control = ctrl; 14551f155d48SKyle Evans hdr.msg_controllen = sizeof(ctrl); 14561f155d48SKyle Evans 14571f155d48SKyle Evans cmsg = CMSG_FIRSTHDR(&hdr); 14581f155d48SKyle Evans cmsg->cmsg_level = SOL_SOCKET; 14591f155d48SKyle Evans cmsg->cmsg_type = SCM_RIGHTS; 14601f155d48SKyle Evans cmsg->cmsg_len = CMSG_LEN(sizeof(fd)); 14611f155d48SKyle Evans fd = STDIN_FILENO; 14621f155d48SKyle Evans memcpy(CMSG_DATA(cmsg), &fd, sizeof(fd)); 14631f155d48SKyle Evans 14641f155d48SKyle Evans error = sendmsg(sock[1], &hdr, 0); 14651f155d48SKyle Evans ATF_REQUIRE(error != -1); 14661f155d48SKyle Evans} 14671f155d48SKyle Evans 14681f155d48SKyle Evans/* 1469020d003cSKyle Evans * Constructs a tmpfile that we can use for testing read(2) and friends. 1470020d003cSKyle Evans */ 1471020d003cSKyle Evansstatic int __unused 1472020d003cSKyle Evansnew_tmpfile(void) 1473020d003cSKyle Evans{ 1474020d003cSKyle Evans char buf[1024]; 1475020d003cSKyle Evans ssize_t rv; 1476020d003cSKyle Evans size_t written; 1477020d003cSKyle Evans int fd; 1478020d003cSKyle Evans 1479020d003cSKyle Evans fd = open("tmpfile", O_RDWR | O_CREAT | O_TRUNC, 0644); 1480020d003cSKyle Evans ATF_REQUIRE(fd >= 0); 1481020d003cSKyle Evans 1482020d003cSKyle Evans written = 0; 1483020d003cSKyle Evans while (written < TMPFILE_SIZE) { 1484020d003cSKyle Evans rv = write(fd, buf, sizeof(buf)); 1485020d003cSKyle Evans ATF_REQUIRE(rv > 0); 1486020d003cSKyle Evans 1487020d003cSKyle Evans written += rv; 1488020d003cSKyle Evans } 1489020d003cSKyle Evans 1490020d003cSKyle Evans ATF_REQUIRE_EQ(0, lseek(fd, 0, SEEK_SET)); 1491020d003cSKyle Evans return (fd); 1492020d003cSKyle Evans} 1493020d003cSKyle Evans 1494020d003cSKyle Evansstatic void 1495020d003cSKyle Evansdisable_coredumps(void) 1496020d003cSKyle Evans{ 1497020d003cSKyle Evans struct rlimit rl = { 0 }; 1498020d003cSKyle Evans 1499020d003cSKyle Evans if (setrlimit(RLIMIT_CORE, &rl) == -1) 1500020d003cSKyle Evans _exit(EX_OSERR); 1501020d003cSKyle Evans} 1502020d003cSKyle Evans 1503cf8e5289SKyle Evans/* 1504cf8e5289SKyle Evans * Replaces stdin with a file that we can actually read from, for tests where 1505cf8e5289SKyle Evans * we want a FILE * or fd that we can get data from. 1506cf8e5289SKyle Evans */ 1507cf8e5289SKyle Evansstatic void __unused 1508cf8e5289SKyle Evansreplace_stdin(void) 1509cf8e5289SKyle Evans{ 1510cf8e5289SKyle Evans int fd; 1511cf8e5289SKyle Evans 1512cf8e5289SKyle Evans fd = new_tmpfile(); 1513cf8e5289SKyle Evans 1514cf8e5289SKyle Evans (void)dup2(fd, STDIN_FILENO); 1515cf8e5289SKyle Evans if (fd != STDIN_FILENO) 1516cf8e5289SKyle Evans close(fd); 1517cf8e5289SKyle Evans} 1518cf8e5289SKyle Evans 1519020d003cSKyle Evans]]) 1520020d003cSKyle Evans 152122178cb2SKyle Evansif tcat == "unistd" then 152222178cb2SKyle Evans fh:write("#define JAIL_HOSTNAME \"" .. hostname .. "\"\n") 152322178cb2SKyle Evans fh:write("#define JAIL_DOMAINNAME \"" .. domainname .. "\"\n") 152422178cb2SKyle Evans fh:write([[ 152522178cb2SKyle Evansstatic void 152622178cb2SKyle Evansdhost_jail(void) 152722178cb2SKyle Evans{ 152822178cb2SKyle Evans struct iovec iov[4]; 152922178cb2SKyle Evans int jid; 153022178cb2SKyle Evans 153122178cb2SKyle Evans iov[0].iov_base = __DECONST(char *, "host.hostname"); 153222178cb2SKyle Evans iov[0].iov_len = sizeof("host.hostname"); 153322178cb2SKyle Evans iov[1].iov_base = __DECONST(char *, JAIL_HOSTNAME); 153422178cb2SKyle Evans iov[1].iov_len = sizeof(JAIL_HOSTNAME); 153522178cb2SKyle Evans iov[2].iov_base = __DECONST(char *, "host.domainname"); 153622178cb2SKyle Evans iov[2].iov_len = sizeof("host.domainname"); 153722178cb2SKyle Evans iov[3].iov_base = __DECONST(char *, JAIL_DOMAINNAME); 153822178cb2SKyle Evans iov[3].iov_len = sizeof(JAIL_DOMAINNAME); 153922178cb2SKyle Evans 154022178cb2SKyle Evans jid = jail_set(iov, nitems(iov), JAIL_CREATE | JAIL_ATTACH); 154122178cb2SKyle Evans ATF_REQUIRE_MSG(jid > 0, "Jail creation failed: %s", strerror(errno)); 154222178cb2SKyle Evans} 154322178cb2SKyle Evans 154422178cb2SKyle Evans]]) 154522178cb2SKyle Evansend 154622178cb2SKyle Evans 1547020d003cSKyle Evansfor _, def in pairs(tests) do 1548020d003cSKyle Evans local func = def.func 1549020d003cSKyle Evans local function write_tests(heap) 1550020d003cSKyle Evans -- Dispositions here are relative to the buffer size prescribed 1551020d003cSKyle Evans -- by the test definition. 1552020d003cSKyle Evans local dispositions = def.dispositions or { -1, 0, 1 } 1553020d003cSKyle Evans 1554020d003cSKyle Evans for _, disposition in ipairs(dispositions) do 1555020d003cSKyle Evans tests_added[#tests_added + 1] = write_test(fh, func, disposition, heap, def) 1556020d003cSKyle Evans end 1557020d003cSKyle Evans end 1558020d003cSKyle Evans 1559020d003cSKyle Evans write_tests(false) 1560020d003cSKyle Evans write_tests(true) 1561020d003cSKyle Evansend 1562020d003cSKyle Evans 1563020d003cSKyle Evansfh:write("ATF_TP_ADD_TCS(tp)\n") 1564020d003cSKyle Evansfh:write("{\n") 1565020d003cSKyle Evansfor idx = 1, #tests_added do 1566020d003cSKyle Evans fh:write("\tATF_TP_ADD_TC(tp, " .. tests_added[idx] .. ");\n") 1567020d003cSKyle Evansend 1568020d003cSKyle Evansfh:write("\treturn (atf_no_error());\n") 1569020d003cSKyle Evansfh:write("}\n") 1570