From 12311959ecf8a3a64676c01b62ce67a0c5f0fd49 Mon Sep 17 00:00:00 2001 From: Vegard Nossum Date: Fri, 12 Aug 2016 20:10:44 +0200 Subject: [PATCH] rhashtable: fix shift by 64 when shrinking I got this: ================================================================================ UBSAN: Undefined behaviour in ./include/linux/log2.h:63:13 shift exponent 64 is too large for 64-bit type 'long unsigned int' CPU: 1 PID: 721 Comm: kworker/1:1 Not tainted 4.8.0-rc1+ #87 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.9.3-0-ge2fc41e-prebuilt.qemu-project.org 04/01/2014 Workqueue: events rht_deferred_worker 0000000000000000 ffff88011661f8d8 ffffffff82344f50 0000000041b58ab3 ffffffff84f98000 ffffffff82344ea4 ffff88011661f900 ffff88011661f8b0 0000000000000001 ffff88011661f6b8 dffffc0000000000 ffffffff867f7640 Call Trace: [] dump_stack+0xac/0xfc [] ? _atomic_dec_and_lock+0xc4/0xc4 [] ubsan_epilogue+0xd/0x8a [] __ubsan_handle_shift_out_of_bounds+0x255/0x29a [] ? __ubsan_handle_out_of_bounds+0x180/0x180 [] ? nl80211_req_set_reg+0x256/0x2f0 [] ? print_context_stack+0x8a/0x160 [] ? amd_pmu_reset+0x341/0x380 [] rht_deferred_worker+0x1618/0x1790 [] ? rht_deferred_worker+0x1618/0x1790 [] ? rhashtable_jhash2+0x370/0x370 [] ? process_one_work+0x6fd/0x1970 [] process_one_work+0x79f/0x1970 [] ? process_one_work+0x6fd/0x1970 [] ? try_to_grab_pending+0x4c0/0x4c0 [] ? worker_thread+0x1c4/0x1340 [] worker_thread+0x55f/0x1340 [] ? __schedule+0x4df/0x1d40 [] ? process_one_work+0x1970/0x1970 [] ? process_one_work+0x1970/0x1970 [] kthread+0x237/0x390 [] ? __kthread_parkme+0x280/0x280 [] ? _raw_spin_unlock_irq+0x33/0x50 [] ret_from_fork+0x1f/0x40 [] ? __kthread_parkme+0x280/0x280 ================================================================================ roundup_pow_of_two() is undefined when called with an argument of 0, so let's avoid the call and just fall back to ht->p.min_size (which should never be smaller than HASH_MIN_SIZE). Cc: Herbert Xu Signed-off-by: Vegard Nossum Acked-by: Herbert Xu Signed-off-by: David S. Miller --- lib/rhashtable.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/rhashtable.c b/lib/rhashtable.c index 42acd81f10dbc9..5ba520b544d73f 100644 --- a/lib/rhashtable.c +++ b/lib/rhashtable.c @@ -324,12 +324,14 @@ static int rhashtable_expand(struct rhashtable *ht) static int rhashtable_shrink(struct rhashtable *ht) { struct bucket_table *new_tbl, *old_tbl = rht_dereference(ht->tbl, ht); - unsigned int size; + unsigned int nelems = atomic_read(&ht->nelems); + unsigned int size = 0; int err; ASSERT_RHT_MUTEX(ht); - size = roundup_pow_of_two(atomic_read(&ht->nelems) * 3 / 2); + if (nelems) + size = roundup_pow_of_two(nelems * 3 / 2); if (size < ht->p.min_size) size = ht->p.min_size;