Skip to contentSkip to conversation

powerpc: Fail remap_4k_pfn() if PFN doesn't fit inside PTE

PATCH Superseded Madhusudanan Kandasamy 2 participants 3 messages Jul 9, 2014 – Jul 10, 2014 PowerPC

v1 of 3 Superseded Latest is v3 →

lore
Share & tools
lore
#0 lore raw

PATCH 1/1 powerpc: Fail remap_4k_pfn() if PFN doesn't fit inside PTE

remap_4k_pfn() silently truncates upper bits of input 4K PFN if it cannot be contained in PTE. This leads invalid memory mapping and could result in a system crash when the memory is accessed. This patch fails remap_4k_pfn() and returns -EINVAL if the input 4K PFN cannot be contained in PTE.
Used a helper inline function in the failure case so that the remap_4k_pfn() macro can still be used in expression contexts.

---
 arch/powerpc/include/asm/pte-hash64-64k.h | 11 +++++++++--
 1 file changed, 9 insertions(+), 2 deletions(-)
arch/powerpc/include/asm/pte-hash64-64k.h +9 -2
index d836d94..10af7f1 100644
@@ -74,8 +74,15 @@
 #define pte_pagesize_index(mm, addr, pte)	\
 	(((pte) & _PAGE_COMBO)? MMU_PAGE_4K: MMU_PAGE_64K)
 
+static inline int bad_4k_pfn(void)
+{
+	WARN_ON(1);
+	return -EINVAL;
+}
+
 #define remap_4k_pfn(vma, addr, pfn, prot)				\
-	remap_pfn_range((vma), (addr), (pfn), PAGE_SIZE,		\
-			__pgprot(pgprot_val((prot)) | _PAGE_4K_PFN))
+	((pfn >= (1UL << (64 - PTE_RPN_SHIFT))) ? bad_4k_pfn() :	\
+		remap_pfn_range((vma), (addr), (pfn), PAGE_SIZE,	\
+			__pgprot(pgprot_val((prot)) | _PAGE_4K_PFN)))
 
 #endif	/* __ASSEMBLY__ */
Signature · 1 line
2.0.1
#1 lore raw

Hi Madhusudanan,

Quoted 13 lines · On Wed, 09 Jul 2014 21:38:31 +0530 Madhusudanan Kandasamy…
arch/powerpc/include/asm/pte-hash64-64k.h +4 -0
index d836d94..10af7f1 100644
@@ -74,8 +74,15 @@
 #define pte_pagesize_index(mm, addr, pte)	\
 	(((pte) & _PAGE_COMBO)? MMU_PAGE_4K: MMU_PAGE_64K)
 
+static inline int bad_4k_pfn(void)
+{
+	WARN_ON(1);
+	return -EINVAL;

arch/powerpc/include/asm/pte-hash64-64k.h line 88

Quoted 10 lines
arch/powerpc/include/asm/pte-hash64-64k.h +5 -2
+}
+
 #define remap_4k_pfn(vma, addr, pfn, prot)				\
-	remap_pfn_range((vma), (addr), (pfn), PAGE_SIZE,		\
-			__pgprot(pgprot_val((prot)) | _PAGE_4K_PFN))
+	((pfn >= (1UL << (64 - PTE_RPN_SHIFT))) ? bad_4k_pfn() :	\
+		remap_pfn_range((vma), (addr), (pfn), PAGE_SIZE,	\
+			__pgprot(pgprot_val((prot)) | _PAGE_4K_PFN)))
 
 #endif	/* __ASSEMBLY__ */

WARN_ON() returns the value it is passed, so no helper is needed:

#define remap_4k_pfn(vma, addr, pfn, prot) \
- remap_pfn_range((vma), (addr), (pfn), PAGE_SIZE, \
- __pgprot(pgprot_val((prot)) | _PAGE_4K_PFN))
+ WARN_ON(((pfn >= (1UL << (64 - PTE_RPN_SHIFT)))) ? -EINVAL : \
+ remap_pfn_range((vma), (addr), (pfn), PAGE_SIZE, \
+ __pgprot(pgprot_val((prot)) | _PAGE_4K_PFN)))

Signature · 2 lines
Cheers,
Stephen Rothwell                    [email protected]
#2 lore raw

Hi Stephen,

Thanks for the suggestion, I'll send a new patch.

Quoted 36 lines · Stephen Rothwell

Hi Madhusudanan,

Quoted 13 lines · On Wed, 09 Jul 2014 21:38:31 +0530 Madhusudanan Kandasamy…
arch/powerpc/include/asm/pte-hash64-64k.h +4 -0
index d836d94..10af7f1 100644
@@ -74,8 +74,15 @@
 #define pte_pagesize_index(mm, addr, pte)	\
 	(((pte) & _PAGE_COMBO)? MMU_PAGE_4K: MMU_PAGE_64K)
 
+static inline int bad_4k_pfn(void)
+{
+	WARN_ON(1);
+	return -EINVAL;

arch/powerpc/include/asm/pte-hash64-64k.h line 88

Quoted 10 lines
arch/powerpc/include/asm/pte-hash64-64k.h +5 -2
+}
+
 #define remap_4k_pfn(vma, addr, pfn, prot)				\
-	remap_pfn_range((vma), (addr), (pfn), PAGE_SIZE,		\
-			__pgprot(pgprot_val((prot)) | _PAGE_4K_PFN))
+	((pfn >= (1UL << (64 - PTE_RPN_SHIFT))) ? bad_4k_pfn() :	\
+		remap_pfn_range((vma), (addr), (pfn), PAGE_SIZE,	\
+			__pgprot(pgprot_val((prot)) | _PAGE_4K_PFN)))
 
 #endif	/* __ASSEMBLY__ */

WARN_ON() returns the value it is passed, so no helper is needed:

#define remap_4k_pfn(vma, addr, pfn, prot) \

arch/powerpc/include/asm/pte-hash64-64k.h +3 -2
-	remap_pfn_range((vma), (addr), (pfn), PAGE_SIZE,		\
-			__pgprot(pgprot_val((prot)) | _PAGE_4K_PFN))
+	WARN_ON(((pfn >= (1UL << (64 - PTE_RPN_SHIFT)))) ? -EINVAL :	\
+		remap_pfn_range((vma), (addr), (pfn), PAGE_SIZE,	\
+			__pgprot(pgprot_val((prot)) | _PAGE_4K_PFN)))