Mercurial > hg > nginx
comparison src/core/ngx_hash.c @ 7536:c3f60d618c17
Core: fixed segfault with too large bucket sizes (ticket #1806).
To save memory hash code uses u_short to store resulting bucket sizes,
so maximum bucket size is limited to 65536 minus ngx_cacheline_size (larger
values will be aligned to 65536 which will overflow u_short). However,
there were no checks to enforce this, and using larger bucket sizes
resulted in overflows and segmentation faults.
Appropriate safety checks to enforce this added to ngx_hash_init().
author | Maxim Dounin <mdounin@mdounin.ru> |
---|---|
date | Thu, 18 Jul 2019 18:27:44 +0300 |
parents | 7fc16ff7ddc4 |
children | eb9c7fb796d5 |
comparison
equal
deleted
inserted
replaced
7535:56b4fb46ba7d | 7536:c3f60d618c17 |
---|---|
263 "increase %s_max_size: %i", | 263 "increase %s_max_size: %i", |
264 hinit->name, hinit->name, hinit->max_size); | 264 hinit->name, hinit->name, hinit->max_size); |
265 return NGX_ERROR; | 265 return NGX_ERROR; |
266 } | 266 } |
267 | 267 |
268 if (hinit->bucket_size > 65536 - ngx_cacheline_size) { | |
269 ngx_log_error(NGX_LOG_EMERG, hinit->pool->log, 0, | |
270 "could not build %s, too large " | |
271 "%s_bucket_size: %i", | |
272 hinit->name, hinit->name, hinit->bucket_size); | |
273 return NGX_ERROR; | |
274 } | |
275 | |
268 for (n = 0; n < nelts; n++) { | 276 for (n = 0; n < nelts; n++) { |
269 if (hinit->bucket_size < NGX_HASH_ELT_SIZE(&names[n]) + sizeof(void *)) | 277 if (hinit->bucket_size < NGX_HASH_ELT_SIZE(&names[n]) + sizeof(void *)) |
270 { | 278 { |
271 ngx_log_error(NGX_LOG_EMERG, hinit->pool->log, 0, | 279 ngx_log_error(NGX_LOG_EMERG, hinit->pool->log, 0, |
272 "could not build %s, you should " | 280 "could not build %s, you should " |
298 if (names[n].key.data == NULL) { | 306 if (names[n].key.data == NULL) { |
299 continue; | 307 continue; |
300 } | 308 } |
301 | 309 |
302 key = names[n].key_hash % size; | 310 key = names[n].key_hash % size; |
303 test[key] = (u_short) (test[key] + NGX_HASH_ELT_SIZE(&names[n])); | 311 len = test[key] + NGX_HASH_ELT_SIZE(&names[n]); |
304 | 312 |
305 #if 0 | 313 #if 0 |
306 ngx_log_error(NGX_LOG_ALERT, hinit->pool->log, 0, | 314 ngx_log_error(NGX_LOG_ALERT, hinit->pool->log, 0, |
307 "%ui: %ui %ui \"%V\"", | 315 "%ui: %ui %uz \"%V\"", |
308 size, key, test[key], &names[n].key); | 316 size, key, len, &names[n].key); |
309 #endif | 317 #endif |
310 | 318 |
311 if (test[key] > (u_short) bucket_size) { | 319 if (len > bucket_size) { |
312 goto next; | 320 goto next; |
313 } | 321 } |
322 | |
323 test[key] = (u_short) len; | |
314 } | 324 } |
315 | 325 |
316 goto found; | 326 goto found; |
317 | 327 |
318 next: | 328 next: |
339 if (names[n].key.data == NULL) { | 349 if (names[n].key.data == NULL) { |
340 continue; | 350 continue; |
341 } | 351 } |
342 | 352 |
343 key = names[n].key_hash % size; | 353 key = names[n].key_hash % size; |
344 test[key] = (u_short) (test[key] + NGX_HASH_ELT_SIZE(&names[n])); | 354 len = test[key] + NGX_HASH_ELT_SIZE(&names[n]); |
355 | |
356 if (len > 65536 - ngx_cacheline_size) { | |
357 ngx_log_error(NGX_LOG_EMERG, hinit->pool->log, 0, | |
358 "could not build %s, you should " | |
359 "increase %s_max_size: %i", | |
360 hinit->name, hinit->name, hinit->max_size); | |
361 return NGX_ERROR; | |
362 } | |
363 | |
364 test[key] = (u_short) len; | |
345 } | 365 } |
346 | 366 |
347 len = 0; | 367 len = 0; |
348 | 368 |
349 for (i = 0; i < size; i++) { | 369 for (i = 0; i < size; i++) { |