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++) {