1 /* $OpenBSD: strlcattest.c,v 1.2 2014/12/03 18:25:18 millert Exp $ */ 2 3 /* 4 * Copyright (c) 2014 Todd C. Miller <Todd.Miller@courtesan.com> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <sys/types.h> 20 21 #include <stdio.h> 22 #include <stdlib.h> 23 #include <string.h> 24 #include <setjmp.h> 25 #include <signal.h> 26 #include <unistd.h> 27 28 volatile sig_atomic_t got_signal; 29 sigjmp_buf jmpenv; 30 31 void 32 handler(int signo) 33 { 34 got_signal = signo; 35 siglongjmp(jmpenv, 1); 36 } 37 38 int 39 main(int argc, char *argv[]) 40 { 41 char *buf, *cp, *ep; 42 struct sigaction sa; 43 size_t len, bufsize; 44 int failures = 0; 45 46 /* Enable malloc security options. */ 47 setenv("MALLOC_OPTIONS", "S", 0); 48 49 bufsize = getpagesize(); /* trigger guard pages easily */ 50 buf = malloc(bufsize); 51 if (buf == NULL) { 52 fprintf(stderr, "unable to allocate memory\n"); 53 return 1; 54 } 55 memset(buf, 'z', bufsize); 56 ep = buf + bufsize; 57 58 /* Test appending to an unterminated string. */ 59 len = strlcat(buf, "abcd", bufsize); 60 if (len != 4 + bufsize) { 61 fprintf(stderr, 62 "strlcat: failed unterminated buffer test (1a)\n"); 63 failures++; 64 } 65 /* Make sure we only wrote where expected. */ 66 for (cp = buf; cp < ep; cp++) { 67 if (*cp != 'z') { 68 fprintf(stderr, 69 "strlcat: failed unterminated buffer test (1b)\n"); 70 failures++; 71 break; 72 } 73 } 74 75 /* Test appending to a full string. */ 76 ep[-1] = '\0'; 77 len = strlcat(buf, "abcd", bufsize); 78 if (len != 4 + bufsize - 1) { 79 fprintf(stderr, "strlcat: failed full buffer test (2a)\n"); 80 failures++; 81 } 82 /* Make sure we only wrote where expected. */ 83 for (cp = buf; cp < ep - 1; cp++) { 84 if (*cp != 'z') { 85 fprintf(stderr, 86 "strlcat: failed full buffer test (2b)\n"); 87 failures++; 88 break; 89 } 90 } 91 92 /* Test appending to an empty string. */ 93 ep[-1] = 'z'; 94 buf[0] = '\0'; 95 len = strlcat(buf, "abcd", bufsize); 96 if (len != 4) { 97 fprintf(stderr, "strlcat: failed empty buffer test (3a)\n"); 98 failures++; 99 } 100 /* Make sure we only wrote where expected. */ 101 if (memcmp(buf, "abcd", sizeof("abcd")) != 0) { 102 fprintf(stderr, "strlcat: failed empty buffer test (3b)\n"); 103 failures++; 104 } 105 for (cp = buf + len + 1; cp < ep; cp++) { 106 if (*cp != 'z') { 107 fprintf(stderr, 108 "strlcat: failed empty buffer test (3c)\n"); 109 failures++; 110 break; 111 } 112 } 113 114 /* Test appending to a NUL-terminated string. */ 115 memcpy(buf, "abcd", sizeof("abcd")); 116 len = strlcat(buf, "efgh", bufsize); 117 if (len != 8) { 118 fprintf(stderr, "strlcat: failed empty buffer test (4a)\n"); 119 failures++; 120 } 121 /* Make sure we only wrote where expected. */ 122 if (memcmp(buf, "abcdefgh", sizeof("abcdefgh")) != 0) { 123 fprintf(stderr, "strlcat: failed empty buffer test (4b)\n"); 124 failures++; 125 } 126 for (cp = buf + len + 1; cp < ep; cp++) { 127 if (*cp != 'z') { 128 fprintf(stderr, 129 "strlcat: failed empty buffer test (4c)\n"); 130 failures++; 131 break; 132 } 133 } 134 135 /* 136 * The following tests should result in SIGSEGV, however some 137 * systems may erroneously report SIGBUS. 138 * These tests assume that strlcat() is signal-safe. 139 */ 140 memset(&sa, 0, sizeof(sa)); 141 sigemptyset(&sa.sa_mask); 142 sa.sa_handler = handler; 143 sigaction(SIGSEGV, &sa, NULL); 144 sigaction(SIGBUS, &sa, NULL); 145 146 /* Test copying to a NULL buffer with non-zero size. */ 147 got_signal = 0; 148 if (sigsetjmp(jmpenv, 1) == 0) { 149 len = strlcat(NULL, "abcd", sizeof(buf)); 150 fprintf(stderr, "strlcat: failed NULL dst test (5a), " 151 "expected signal %d, got len %zu\n", SIGSEGV, len); 152 failures++; 153 } else if (got_signal != SIGSEGV) { 154 fprintf(stderr, "strlcat: failed NULL dst test (5b), " 155 "expected signal %d, got %d\n", SIGSEGV, got_signal); 156 failures++; 157 } 158 159 /* Test copying from a NULL src. */ 160 memcpy(buf, "abcd", sizeof("abcd")); 161 got_signal = 0; 162 if (sigsetjmp(jmpenv, 1) == 0) { 163 len = strlcat(buf, NULL, sizeof(buf)); 164 fprintf(stderr, "strlcat: failed NULL src test (6a), " 165 "expected signal %d, got len %zu\n", SIGSEGV, len); 166 failures++; 167 } else if (got_signal != SIGSEGV) { 168 fprintf(stderr, "strlcat: failed NULL src test (6b), " 169 "expected signal %d, got %d\n", SIGSEGV, got_signal); 170 failures++; 171 } 172 173 return failures; 174 } 175