1 /* $NetBSD: t_exhaust.c,v 1.14 2021/06/09 21:09:20 christos Exp $ */ 2 3 /*- 4 * Copyright (c) 2011 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Christos Zoulas. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the NetBSD 21 * Foundation, Inc. and its contributors. 22 * 4. Neither the name of The NetBSD Foundation nor the names of its 23 * contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 * POSSIBILITY OF SUCH DAMAGE. 37 */ 38 39 #include <sys/cdefs.h> 40 __RCSID("$NetBSD: t_exhaust.c,v 1.14 2021/06/09 21:09:20 christos Exp $"); 41 42 #include <sys/resource.h> 43 #include <err.h> 44 45 #ifdef TEST 46 # include <assert.h> 47 # define ATF_REQUIRE(a) assert(a) 48 # define ATF_REQUIRE_MSG(a, fmt, ...) \ 49 if (!(a)) err(EXIT_FAILURE, fmt, __VA_ARGS__) 50 #else 51 # include <atf-c.h> 52 #endif 53 54 #include <regex.h> 55 #include <stdio.h> 56 #include <stdlib.h> 57 #include <string.h> 58 59 #ifndef REGEX_MAXSIZE 60 #define REGEX_MAXSIZE 9999 61 #endif 62 63 #ifdef TRACE 64 65 #include <dlfcn.h> 66 void * 67 malloc(size_t l) 68 { 69 static void *(*m)(size_t); 70 static int q; 71 if (m == NULL) m = dlsym(RTLD_NEXT, "malloc"); 72 void *p = (*m)(l); 73 if (q) 74 return p; 75 q = 1; 76 printf("%p m %zu\n", p, l); 77 q = 0; 78 return p; 79 } 80 81 void 82 free(void *p) 83 { 84 static void (*f)(void *); 85 if (f == NULL) f = dlsym(RTLD_NEXT, "malloc"); 86 printf("%p f\n", p); 87 (*f)(p); 88 } 89 #endif 90 91 static char * 92 mkstr(const char *str, size_t len) 93 { 94 size_t slen = strlen(str); 95 char *p = malloc(slen * len + 1); 96 ATF_REQUIRE_MSG(p != NULL, "slen=%zu, len=%zu", slen, len); 97 for (size_t i = 0; i < len; i++) 98 strcpy(&p[i * slen], str); 99 return p; 100 } 101 102 static char * 103 concat(const char *d, const char *s) 104 { 105 size_t dlen = strlen(d); 106 size_t slen = strlen(s); 107 char *p = malloc(dlen + slen + 1); 108 109 ATF_REQUIRE_MSG(p != NULL, "slen=%zu, dlen=%zu", slen, dlen); 110 strcpy(p, d); 111 strcpy(p + dlen, s); 112 return p; 113 } 114 115 static char * 116 p0(size_t len) 117 { 118 char *d, *s1, *s2; 119 s1 = mkstr("\\(", len); 120 s2 = concat(s1, ")"); 121 free(s1); 122 d = concat("(", s2); 123 free(s2); 124 return d; 125 } 126 127 static char * 128 p1(size_t len) 129 { 130 char *d, *s1, *s2, *s3; 131 s1 = mkstr("\\(", 60); 132 s2 = mkstr("(.*)", len); 133 s3 = concat(s1, s2); 134 free(s2); 135 free(s1); 136 s1 = concat(s3, ")"); 137 free(s3); 138 d = concat("(", s1); 139 free(s1); 140 return d; 141 } 142 143 static char * 144 ps(const char *m, const char *s, size_t len) 145 { 146 char *d, *s1, *s2, *s3; 147 s1 = mkstr(m, len); 148 s2 = mkstr(s, len); 149 s3 = concat(s1, s2); 150 free(s2); 151 free(s1); 152 d = concat("(.?)", s3); 153 free(s3); 154 return d; 155 } 156 157 static char * 158 p2(size_t len) 159 { 160 return ps("((.*){0,255}", ")", len); 161 } 162 163 static char * 164 p3(size_t len) 165 { 166 return ps("(.\\{0,}", ")", len); 167 } 168 169 static char * 170 p4(size_t len) 171 { 172 return ps("((.*){1,255}", ")", len); 173 } 174 175 static char * 176 p5(size_t len) 177 { 178 return ps("(", "){1,100}", len); 179 } 180 181 static char * 182 p6(size_t len) 183 { 184 char *d, *s1, *s2; 185 s1 = mkstr("(?:(.*)|", len); 186 s2 = concat(s1, "(.*)"); 187 free(s1); 188 s1 = mkstr(")", len); 189 d = concat(s2, s1); 190 free(s1); 191 free(s2); 192 return d; 193 } 194 195 static const struct { 196 char *(*pattern)(size_t); 197 int type; 198 } tests[] = { 199 { p0, REG_EXTENDED }, 200 { p1, REG_EXTENDED }, 201 { p2, REG_EXTENDED }, 202 { p3, REG_EXTENDED }, 203 { p4, REG_EXTENDED }, 204 { p5, REG_EXTENDED }, 205 { p6, REG_BASIC }, 206 }; 207 208 static void 209 run(void) 210 { 211 regex_t re; 212 int e; 213 struct rlimit limit; 214 char *patterns[__arraycount(tests)]; 215 216 for (size_t i = 0; i < __arraycount(patterns); i++) { 217 patterns[i] = (*tests[i].pattern)(REGEX_MAXSIZE); 218 } 219 220 limit.rlim_cur = limit.rlim_max = 256 * 1024 * 1024; 221 ATF_REQUIRE(setrlimit(RLIMIT_VMEM, &limit) != -1); 222 223 for (size_t i = 0; i < __arraycount(tests); i++) { 224 e = regcomp(&re, patterns[i], tests[i].type); 225 if (e) { 226 char ebuf[1024]; 227 (void)regerror(e, &re, ebuf, sizeof(ebuf)); 228 ATF_REQUIRE_MSG(e == REG_ESPACE, 229 "regcomp returned %d (%s) for pattern %zu [%s]", e, 230 ebuf, i, patterns[i]); 231 continue; 232 } 233 (void)regexec(&re, "aaaaaaaaaaa", 0, NULL, 0); 234 regfree(&re); 235 } 236 for (size_t i = 0; i < __arraycount(patterns); i++) { 237 free(patterns[i]); 238 } 239 } 240 241 #ifndef TEST 242 243 ATF_TC(regcomp_too_big); 244 245 ATF_TC_HEAD(regcomp_too_big, tc) 246 { 247 248 atf_tc_set_md_var(tc, "descr", "Check that large patterns don't" 249 " crash, but return a proper error code"); 250 // libtre needs it. 251 atf_tc_set_md_var(tc, "timeout", "600"); 252 atf_tc_set_md_var(tc, "require.memory", "256M"); 253 } 254 255 ATF_TC_BODY(regcomp_too_big, tc) 256 { 257 run(); 258 } 259 260 ATF_TP_ADD_TCS(tp) 261 { 262 263 ATF_TP_ADD_TC(tp, regcomp_too_big); 264 return atf_no_error(); 265 } 266 #else 267 int 268 main(void) 269 { 270 run(); 271 return 0; 272 } 273 #endif 274