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().
Maxim Dounin
1 year, 6 months ago
264 | 264 | return NGX_ERROR; |
265 | 265 | } |
266 | 266 | |
267 | if (hinit->bucket_size > 65536 - ngx_cacheline_size) { | |
268 | ngx_log_error(NGX_LOG_EMERG, hinit->pool->log, 0, | |
269 | "could not build %s, too large " | |
270 | "%s_bucket_size: %i", | |
271 | hinit->name, hinit->name, hinit->bucket_size); | |
272 | return NGX_ERROR; | |
273 | } | |
274 | ||
267 | 275 | for (n = 0; n < nelts; n++) { |
268 | 276 | if (hinit->bucket_size < NGX_HASH_ELT_SIZE(&names[n]) + sizeof(void *)) |
269 | 277 | { |
299 | 307 | } |
300 | 308 | |
301 | 309 | key = names[n].key_hash % size; |
302 | test[key] = (u_short) (test[key] + NGX_HASH_ELT_SIZE(&names[n])); | |
310 | len = test[key] + NGX_HASH_ELT_SIZE(&names[n]); | |
303 | 311 | |
304 | 312 | #if 0 |
305 | 313 | ngx_log_error(NGX_LOG_ALERT, hinit->pool->log, 0, |
306 | "%ui: %ui %ui \"%V\"", | |
307 | size, key, test[key], &names[n].key); | |
308 | #endif | |
309 | ||
310 | if (test[key] > (u_short) bucket_size) { | |
314 | "%ui: %ui %uz \"%V\"", | |
315 | size, key, len, &names[n].key); | |
316 | #endif | |
317 | ||
318 | if (len > bucket_size) { | |
311 | 319 | goto next; |
312 | 320 | } |
321 | ||
322 | test[key] = (u_short) len; | |
313 | 323 | } |
314 | 324 | |
315 | 325 | goto found; |
340 | 350 | } |
341 | 351 | |
342 | 352 | key = names[n].key_hash % size; |
343 | test[key] = (u_short) (test[key] + NGX_HASH_ELT_SIZE(&names[n])); | |
353 | len = test[key] + NGX_HASH_ELT_SIZE(&names[n]); | |
354 | ||
355 | if (len > 65536 - ngx_cacheline_size) { | |
356 | ngx_log_error(NGX_LOG_EMERG, hinit->pool->log, 0, | |
357 | "could not build %s, you should " | |
358 | "increase %s_max_size: %i", | |
359 | hinit->name, hinit->name, hinit->max_size); | |
360 | return NGX_ERROR; | |
361 | } | |
362 | ||
363 | test[key] = (u_short) len; | |
344 | 364 | } |
345 | 365 | |
346 | 366 | len = 0; |