diff mbox

powerpc/iommu: Avoid undefined right shift in iommu_range_alloc()

Message ID 1502175992-13626-1-git-send-email-mpe@ellerman.id.au (mailing list archive)
State Accepted
Commit 63b85621d9aa6bdc410f01b22f7821cea3d7bdc6
Headers show

Commit Message

Michael Ellerman Aug. 8, 2017, 7:06 a.m. UTC
In iommu_range_alloc() we generate a mask by right shifting ~0,
however if the specified alignment is 0 then we right shift by 64,
which is undefined. UBSAN tells us so:

  UBSAN: Undefined behaviour in ../arch/powerpc/kernel/iommu.c:193:35
  shift exponent 64 is too large for 64-bit type 'long unsigned int'

We can avoid it by instead generating the mask with:

  align_mask = (1ull << align_order) - 1;

That will also generate an undefined shift if align_order is 64 or
greater, but that shouldn't be a problem for a while.

Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
---
 arch/powerpc/kernel/iommu.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

Comments

Michael Ellerman Aug. 16, 2017, 12:29 p.m. UTC | #1
On Tue, 2017-08-08 at 07:06:32 UTC, Michael Ellerman wrote:
> In iommu_range_alloc() we generate a mask by right shifting ~0,
> however if the specified alignment is 0 then we right shift by 64,
> which is undefined. UBSAN tells us so:
> 
>   UBSAN: Undefined behaviour in ../arch/powerpc/kernel/iommu.c:193:35
>   shift exponent 64 is too large for 64-bit type 'long unsigned int'
> 
> We can avoid it by instead generating the mask with:
> 
>   align_mask = (1ull << align_order) - 1;
> 
> That will also generate an undefined shift if align_order is 64 or
> greater, but that shouldn't be a problem for a while.
> 
> Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>

Applied to powerpc next.

https://git.kernel.org/powerpc/c/63b85621d9aa6bdc410f01b22f7821

cheers
diff mbox

Patch

diff --git a/arch/powerpc/kernel/iommu.c b/arch/powerpc/kernel/iommu.c
index 0e49a4560cff..e0af6cd7ba4f 100644
--- a/arch/powerpc/kernel/iommu.c
+++ b/arch/powerpc/kernel/iommu.c
@@ -190,7 +190,7 @@  static unsigned long iommu_range_alloc(struct device *dev,
 	unsigned int pool_nr;
 	struct iommu_pool *pool;
 
-	align_mask = 0xffffffffffffffffl >> (64 - align_order);
+	align_mask = (1ull << align_order) - 1;
 
 	/* This allocator was derived from x86_64's bit string search */