From: Robin Murphy Date: Mon, 3 Apr 2017 12:12:10 +0000 (+0100) Subject: iommu/io-pgtable-arm: Avoid shift overflow in block size X-Git-Tag: v4.12-rc1~50^2^5~2^2 X-Git-Url: https://git.kernelconcepts.de/?p=karo-tx-linux.git;a=commitdiff_plain;h=022f4e4f31fea69702f3ec810dc567af6a6d86d8 iommu/io-pgtable-arm: Avoid shift overflow in block size The recursive nature of __arm_lpae_{map,unmap}() means that ARM_LPAE_BLOCK_SIZE() is evaluated for every level, including those where block mappings aren't possible. This in itself is harmless enough, as we will only ever be called with valid sizes from the pgsize_bitmap, and thus always recurse down past any imaginary block sizes. The only problem is that most of those imaginary sizes overflow the type used for the calculation, and thus trigger warnings under UBsan: [ 63.020939] ================================================================================ [ 63.021284] UBSAN: Undefined behaviour in drivers/iommu/io-pgtable-arm.c:312:22 [ 63.021602] shift exponent 39 is too large for 32-bit type 'int' [ 63.021909] CPU: 0 PID: 1119 Comm: lkvm Not tainted 4.7.0-rc3+ #819 [ 63.022163] Hardware name: FVP Base (DT) [ 63.022345] Call trace: [ 63.022629] [] dump_backtrace+0x0/0x3a8 [ 63.022975] [] show_stack+0x14/0x20 [ 63.023294] [] dump_stack+0x104/0x148 [ 63.023609] [] ubsan_epilogue+0x18/0x68 [ 63.023956] [] __ubsan_handle_shift_out_of_bounds+0x18c/0x1bc [ 63.024365] [] __arm_lpae_map+0x720/0xae0 [ 63.024732] [] arm_lpae_map+0x100/0x190 [ 63.025049] [] arm_smmu_map+0x78/0xc8 [ 63.025390] [] iommu_map+0x130/0x230 [ 63.025763] [] vfio_iommu_type1_attach_group+0x4bc/0xa00 [ 63.026156] [] vfio_fops_unl_ioctl+0x320/0x580 [ 63.026515] [] do_vfs_ioctl+0x140/0xd28 [ 63.026858] [] SyS_ioctl+0x8c/0xa0 [ 63.027179] [] el0_svc_naked+0x24/0x28 [ 63.027412] ================================================================================ Perform the shift in a 64-bit type to prevent the theoretical overflow and keep the peace. As it turns out, this generates identical code for 32-bit ARM, and marginally shorter AArch64 code, so it's good all round. Signed-off-by: Robin Murphy Signed-off-by: Will Deacon --- diff --git a/drivers/iommu/io-pgtable-arm.c b/drivers/iommu/io-pgtable-arm.c index f9bc6ebb8140..6e5df5e0a3bd 100644 --- a/drivers/iommu/io-pgtable-arm.c +++ b/drivers/iommu/io-pgtable-arm.c @@ -74,7 +74,7 @@ /* Calculate the block/page mapping size at level l for pagetable in d. */ #define ARM_LPAE_BLOCK_SIZE(l,d) \ - (1 << (ilog2(sizeof(arm_lpae_iopte)) + \ + (1ULL << (ilog2(sizeof(arm_lpae_iopte)) + \ ((ARM_LPAE_MAX_LEVELS - (l)) * (d)->bits_per_level))) /* Page table bits */