Mercurial > hg > nginx-quic
comparison src/core/ngx_regex.c @ 8769:2ca57257252d
Core: fixed ngx_pcre_studies cleanup.
If a configuration parsing fails for some reason, ngx_regex_module_init()
is not called, and ngx_pcre_studies remained set despite the fact that
the pool it was allocated from is already freed. This might result in
a segmentation fault during runtime regular expression compilation, such
as in SSI, for example, in the single process mode, or if a worker process
died and was respawned from a master process in such an inconsistent state.
Fix is to clear ngx_pcre_studies from the pool cleanup handler (which is
anyway used to free JIT-compiled patterns).
author | Maxim Dounin <mdounin@mdounin.ru> |
---|---|
date | Sat, 25 Dec 2021 01:07:10 +0300 |
parents | f684178faec9 |
children | 060bf88d2473 |
comparison
equal
deleted
inserted
replaced
8754:336084ff943b | 8769:2ca57257252d |
---|---|
8 #include <ngx_config.h> | 8 #include <ngx_config.h> |
9 #include <ngx_core.h> | 9 #include <ngx_core.h> |
10 | 10 |
11 | 11 |
12 typedef struct { | 12 typedef struct { |
13 ngx_flag_t pcre_jit; | 13 ngx_flag_t pcre_jit; |
14 ngx_list_t *studies; | |
14 } ngx_regex_conf_t; | 15 } ngx_regex_conf_t; |
15 | 16 |
16 | 17 |
17 static void * ngx_libc_cdecl ngx_regex_malloc(size_t size); | 18 static void * ngx_libc_cdecl ngx_regex_malloc(size_t size); |
18 static void ngx_libc_cdecl ngx_regex_free(void *p); | 19 static void ngx_libc_cdecl ngx_regex_free(void *p); |
19 #if (NGX_HAVE_PCRE_JIT) | 20 static void ngx_regex_cleanup(void *data); |
20 static void ngx_pcre_free_studies(void *data); | |
21 #endif | |
22 | 21 |
23 static ngx_int_t ngx_regex_module_init(ngx_cycle_t *cycle); | 22 static ngx_int_t ngx_regex_module_init(ngx_cycle_t *cycle); |
24 | 23 |
25 static void *ngx_regex_create_conf(ngx_cycle_t *cycle); | 24 static void *ngx_regex_create_conf(ngx_cycle_t *cycle); |
26 static char *ngx_regex_init_conf(ngx_cycle_t *cycle, void *conf); | 25 static char *ngx_regex_init_conf(ngx_cycle_t *cycle, void *conf); |
246 { | 245 { |
247 return; | 246 return; |
248 } | 247 } |
249 | 248 |
250 | 249 |
250 static void | |
251 ngx_regex_cleanup(void *data) | |
252 { | |
251 #if (NGX_HAVE_PCRE_JIT) | 253 #if (NGX_HAVE_PCRE_JIT) |
252 | 254 ngx_regex_conf_t *rcf = data; |
253 static void | |
254 ngx_pcre_free_studies(void *data) | |
255 { | |
256 ngx_list_t *studies = data; | |
257 | 255 |
258 ngx_uint_t i; | 256 ngx_uint_t i; |
259 ngx_list_part_t *part; | 257 ngx_list_part_t *part; |
260 ngx_regex_elt_t *elts; | 258 ngx_regex_elt_t *elts; |
261 | 259 |
262 part = &studies->part; | 260 part = &rcf->studies->part; |
263 elts = part->elts; | 261 elts = part->elts; |
264 | 262 |
265 for (i = 0; /* void */ ; i++) { | 263 for (i = 0; /* void */ ; i++) { |
266 | 264 |
267 if (i >= part->nelts) { | 265 if (i >= part->nelts) { |
271 | 269 |
272 part = part->next; | 270 part = part->next; |
273 elts = part->elts; | 271 elts = part->elts; |
274 i = 0; | 272 i = 0; |
275 } | 273 } |
276 | |
277 if (elts[i].regex->extra != NULL) { | |
278 pcre_free_study(elts[i].regex->extra); | |
279 } | |
280 } | |
281 } | |
282 | |
283 #endif | |
284 | |
285 | |
286 static ngx_int_t | |
287 ngx_regex_module_init(ngx_cycle_t *cycle) | |
288 { | |
289 int opt; | |
290 const char *errstr; | |
291 ngx_uint_t i; | |
292 ngx_list_part_t *part; | |
293 ngx_regex_elt_t *elts; | |
294 | |
295 opt = 0; | |
296 | |
297 #if (NGX_HAVE_PCRE_JIT) | |
298 { | |
299 ngx_regex_conf_t *rcf; | |
300 ngx_pool_cleanup_t *cln; | |
301 | |
302 rcf = (ngx_regex_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_regex_module); | |
303 | |
304 if (rcf->pcre_jit) { | |
305 opt = PCRE_STUDY_JIT_COMPILE; | |
306 | 274 |
307 /* | 275 /* |
308 * The PCRE JIT compiler uses mmap for its executable codes, so we | 276 * The PCRE JIT compiler uses mmap for its executable codes, so we |
309 * have to explicitly call the pcre_free_study() function to free | 277 * have to explicitly call the pcre_free_study() function to free |
310 * this memory. | 278 * this memory. |
311 */ | 279 */ |
312 | 280 |
313 cln = ngx_pool_cleanup_add(cycle->pool, 0); | 281 if (elts[i].regex->extra != NULL) { |
314 if (cln == NULL) { | 282 pcre_free_study(elts[i].regex->extra); |
315 return NGX_ERROR; | 283 } |
316 } | |
317 | |
318 cln->handler = ngx_pcre_free_studies; | |
319 cln->data = ngx_pcre_studies; | |
320 } | |
321 } | 284 } |
322 #endif | 285 #endif |
323 | 286 |
287 /* | |
288 * On configuration parsing errors ngx_regex_module_init() will not | |
289 * be called. Make sure ngx_pcre_studies is properly cleared anyway. | |
290 */ | |
291 | |
292 ngx_pcre_studies = NULL; | |
293 } | |
294 | |
295 | |
296 static ngx_int_t | |
297 ngx_regex_module_init(ngx_cycle_t *cycle) | |
298 { | |
299 int opt; | |
300 const char *errstr; | |
301 ngx_uint_t i; | |
302 ngx_list_part_t *part; | |
303 ngx_regex_elt_t *elts; | |
304 ngx_regex_conf_t *rcf; | |
305 | |
306 opt = 0; | |
307 | |
308 rcf = (ngx_regex_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_regex_module); | |
309 | |
310 #if (NGX_HAVE_PCRE_JIT) | |
311 if (rcf->pcre_jit) { | |
312 opt = PCRE_STUDY_JIT_COMPILE; | |
313 } | |
314 #endif | |
315 | |
324 ngx_regex_malloc_init(cycle->pool); | 316 ngx_regex_malloc_init(cycle->pool); |
325 | 317 |
326 part = &ngx_pcre_studies->part; | 318 part = &rcf->studies->part; |
327 elts = part->elts; | 319 elts = part->elts; |
328 | 320 |
329 for (i = 0; /* void */ ; i++) { | 321 for (i = 0; /* void */ ; i++) { |
330 | 322 |
331 if (i >= part->nelts) { | 323 if (i >= part->nelts) { |
372 | 364 |
373 | 365 |
374 static void * | 366 static void * |
375 ngx_regex_create_conf(ngx_cycle_t *cycle) | 367 ngx_regex_create_conf(ngx_cycle_t *cycle) |
376 { | 368 { |
377 ngx_regex_conf_t *rcf; | 369 ngx_regex_conf_t *rcf; |
370 ngx_pool_cleanup_t *cln; | |
378 | 371 |
379 rcf = ngx_pcalloc(cycle->pool, sizeof(ngx_regex_conf_t)); | 372 rcf = ngx_pcalloc(cycle->pool, sizeof(ngx_regex_conf_t)); |
380 if (rcf == NULL) { | 373 if (rcf == NULL) { |
381 return NULL; | 374 return NULL; |
382 } | 375 } |
383 | 376 |
384 rcf->pcre_jit = NGX_CONF_UNSET; | 377 rcf->pcre_jit = NGX_CONF_UNSET; |
385 | 378 |
386 ngx_pcre_studies = ngx_list_create(cycle->pool, 8, sizeof(ngx_regex_elt_t)); | 379 cln = ngx_pool_cleanup_add(cycle->pool, 0); |
387 if (ngx_pcre_studies == NULL) { | 380 if (cln == NULL) { |
388 return NULL; | 381 return NULL; |
389 } | 382 } |
383 | |
384 cln->handler = ngx_regex_cleanup; | |
385 cln->data = rcf; | |
386 | |
387 rcf->studies = ngx_list_create(cycle->pool, 8, sizeof(ngx_regex_elt_t)); | |
388 if (rcf->studies == NULL) { | |
389 return NULL; | |
390 } | |
391 | |
392 ngx_pcre_studies = rcf->studies; | |
390 | 393 |
391 return rcf; | 394 return rcf; |
392 } | 395 } |
393 | 396 |
394 | 397 |