Skip to content

Commit 29aaebb

Browse files
icklejoergroedel
authored andcommitted
iommu/vt-d: Handle 36bit addressing for x86-32
Beware that the address size for x86-32 may exceed unsigned long. [ 0.368971] UBSAN: shift-out-of-bounds in drivers/iommu/intel/iommu.c:128:14 [ 0.369055] shift exponent 36 is too large for 32-bit type 'long unsigned int' If we don't handle the wide addresses, the pages are mismapped and the device read/writes go astray, detected as DMAR faults and leading to device failure. The behaviour changed (from working to broken) in commit fa954e6 ("iommu/vt-d: Delegate the dma domain to upper layer"), but the error looks older. Fixes: fa954e6 ("iommu/vt-d: Delegate the dma domain to upper layer") Signed-off-by: Chris Wilson <[email protected]> Acked-by: Lu Baolu <[email protected]> Cc: James Sewart <[email protected]> Cc: Lu Baolu <[email protected]> Cc: Joerg Roedel <[email protected]> Cc: <[email protected]> # v5.3+ Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Joerg Roedel <[email protected]>
1 parent 2822e58 commit 29aaebb

File tree

1 file changed

+7
-7
lines changed

1 file changed

+7
-7
lines changed

drivers/iommu/intel/iommu.c

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -123,29 +123,29 @@ static inline unsigned int level_to_offset_bits(int level)
123123
return (level - 1) * LEVEL_STRIDE;
124124
}
125125

126-
static inline int pfn_level_offset(unsigned long pfn, int level)
126+
static inline int pfn_level_offset(u64 pfn, int level)
127127
{
128128
return (pfn >> level_to_offset_bits(level)) & LEVEL_MASK;
129129
}
130130

131-
static inline unsigned long level_mask(int level)
131+
static inline u64 level_mask(int level)
132132
{
133-
return -1UL << level_to_offset_bits(level);
133+
return -1ULL << level_to_offset_bits(level);
134134
}
135135

136-
static inline unsigned long level_size(int level)
136+
static inline u64 level_size(int level)
137137
{
138-
return 1UL << level_to_offset_bits(level);
138+
return 1ULL << level_to_offset_bits(level);
139139
}
140140

141-
static inline unsigned long align_to_level(unsigned long pfn, int level)
141+
static inline u64 align_to_level(u64 pfn, int level)
142142
{
143143
return (pfn + level_size(level) - 1) & level_mask(level);
144144
}
145145

146146
static inline unsigned long lvl_to_nr_pages(unsigned int lvl)
147147
{
148-
return 1 << min_t(int, (lvl - 1) * LEVEL_STRIDE, MAX_AGAW_PFN_WIDTH);
148+
return 1UL << min_t(int, (lvl - 1) * LEVEL_STRIDE, MAX_AGAW_PFN_WIDTH);
149149
}
150150

151151
/* VT-d pages must always be _smaller_ than MM pages. Otherwise things

0 commit comments

Comments
 (0)