From: "David Hildenbrand (Arm)" <[email protected]>

Let's catch and prevent all abuse with dummy values on the stack
similar to:

        pud_t pud = pudp_get(pudp);
        pmd_t *pmdp = pud_offset(*pud, addr);

While this approach relies on the compiler propagating constants, it
should catch most of the issues in practice. It would have caught all
the issues we found through manual inspection.

To avoid build issues particularly on x86, where pgd_val() might not be
around in some inclusion paths, perform the new checks from wrapper
macros.

Signed-off-by: David Hildenbrand (Arm) <[email protected]>
Signed-off-by: Yeoreum Yun <[email protected]>
---
 include/asm-generic/pgtable-nop4d.h | 23 ++++++++++++++++++-----
 include/asm-generic/pgtable-nopmd.h | 24 ++++++++++++++++++------
 include/asm-generic/pgtable-nopud.h | 24 ++++++++++++++++++------
 3 files changed, 54 insertions(+), 17 deletions(-)

diff --git a/include/asm-generic/pgtable-nop4d.h 
b/include/asm-generic/pgtable-nop4d.h
index 84a529df27ee3..fcd86aabc592c 100644
--- a/include/asm-generic/pgtable-nop4d.h
+++ b/include/asm-generic/pgtable-nop4d.h
@@ -31,7 +31,7 @@ static inline bool pgd_leaf(pgd_t pgd)                { 
return false; }
 
 #define set_pgd(pgdptr, pgdval)                        BUILD_BUG()
 
-static inline pgd_t pgdp_get(pgd_t *p4dp)
+static __always_inline pgd_t pgdp_get(pgd_t *p4dp)
 {
        pgd_t dummy = { 0 };
 
@@ -39,17 +39,30 @@ static inline pgd_t pgdp_get(pgd_t *p4dp)
 }
 #define pgdp_get pgdp_get
 
-static inline p4d_t *p4d_offset(pgd_t *pgd, unsigned long address)
+#define pgd_check_dummy(pgd) BUILD_BUG_ON(__builtin_constant_p(pgd_val(pgd)))
+
+static __always_inline p4d_t *__p4d_offset(pgd_t *pgdp, unsigned long address)
 {
-       return (p4d_t *)pgd;
+       return (p4d_t *)pgdp;
 }
 
-static inline p4d_t *p4d_offset_lockless(pgd_t *pgdp, pgd_t pgd,
+#define p4d_offset(pgdp, address)                                      \
+({                                                                     \
+       pgd_check_dummy(*(pgdp));                                       \
+       __p4d_offset(pgdp, address);                                    \
+})
+
+static __always_inline p4d_t *__p4d_offset_lockless(pgd_t *pgdp, pgd_t pgd,
                unsigned long address)
 {
        return (p4d_t *)pgdp;
 }
-#define p4d_offset_lockless p4d_offset_lockless
+
+#define p4d_offset_lockless(pgdp, pgd, address)                                
\
+({                                                                     \
+       pgd_check_dummy(*(pgdp));                                       \
+       __p4d_offset_lockless(pgdp, pgd, address);                      \
+})
 
 #define p4d_val(x)                             (pgd_val((x).pgd))
 #define __p4d(x)                               ((p4d_t) { __pgd(x) })
diff --git a/include/asm-generic/pgtable-nopmd.h 
b/include/asm-generic/pgtable-nopmd.h
index 96f3fccd22fda..ef6dd5895e7ba 100644
--- a/include/asm-generic/pgtable-nopmd.h
+++ b/include/asm-generic/pgtable-nopmd.h
@@ -40,7 +40,7 @@ static inline void pud_clear(pud_t *pud)      { }
 
 #define set_pud(pudptr, pudval)                        BUILD_BUG()
 
-static inline pud_t pudp_get(pud_t *pudp)
+static __always_inline pud_t pudp_get(pud_t *pudp)
 {
        pud_t dummy = { 0 };
 
@@ -48,18 +48,30 @@ static inline pud_t pudp_get(pud_t *pudp)
 }
 #define pudp_get pudp_get
 
-static inline pmd_t * pmd_offset(pud_t * pud, unsigned long address)
+#define pud_check_dummy(pud) BUILD_BUG_ON(__builtin_constant_p(pud_val(pud)))
+
+static __always_inline pmd_t *__pmd_offset(pud_t *pudp, unsigned long address)
 {
-       return (pmd_t *)pud;
+       return (pmd_t *)pudp;
 }
-#define pmd_offset pmd_offset
 
-static inline pmd_t *pmd_offset_lockless(pud_t *pudp, pud_t pud,
+#define pmd_offset(pudp, address)                                      \
+({                                                                     \
+       pud_check_dummy(*(pudp));                                       \
+       __pmd_offset(pudp, address);                                    \
+})
+
+static __always_inline pmd_t *__pmd_offset_lockless(pud_t *pudp, pud_t pud,
                unsigned long address)
 {
        return (pmd_t *)pudp;
 }
-#define pmd_offset_lockless pmd_offset_lockless
+
+#define pmd_offset_lockless(pudp, pud, address)                                
\
+({                                                                     \
+       pud_check_dummy(*(pudp));                                       \
+       __pmd_offset_lockless(pudp, pud, address);                      \
+})
 
 #define pmd_val(x)                             (pud_val((x).pud))
 #define __pmd(x)                               ((pmd_t) { __pud(x) } )
diff --git a/include/asm-generic/pgtable-nopud.h 
b/include/asm-generic/pgtable-nopud.h
index faa0233bcde80..873940f9d3f9b 100644
--- a/include/asm-generic/pgtable-nopud.h
+++ b/include/asm-generic/pgtable-nopud.h
@@ -38,7 +38,7 @@ static inline bool p4d_leaf(p4d_t p4d)                { 
return false; }
 
 #define set_p4d(p4dptr, p4dval)                        BUILD_BUG()
 
-static inline p4d_t p4dp_get(p4d_t *p4dp)
+static __always_inline p4d_t p4dp_get(p4d_t *p4dp)
 {
        p4d_t dummy = { 0 };
 
@@ -46,18 +46,30 @@ static inline p4d_t p4dp_get(p4d_t *p4dp)
 }
 #define p4dp_get p4dp_get
 
-static inline pud_t *pud_offset(p4d_t *p4d, unsigned long address)
+#define p4d_check_dummy(p4d) BUILD_BUG_ON(__builtin_constant_p(p4d_val(p4d)))
+
+static __always_inline pud_t *__pud_offset(p4d_t *p4dp, unsigned long address)
 {
-       return (pud_t *)p4d;
+       return (pud_t *)p4dp;
 }
-#define pud_offset pud_offset
 
-static inline pud_t *pud_offset_lockless(p4d_t *p4dp, p4d_t p4d,
+#define pud_offset(p4dp, address)                                      \
+({                                                                     \
+       p4d_check_dummy(*(p4dp));                                       \
+       __pud_offset(p4dp, address);                                    \
+})
+
+static __always_inline pud_t *__pud_offset_lockless(p4d_t *p4dp, p4d_t p4d,
                unsigned long address)
 {
        return (pud_t *)p4dp;
 }
-#define pud_offset_lockless pud_offset_lockless
+
+#define pud_offset_lockless(p4dp, p4d, address)                                
\
+({                                                                     \
+       p4d_check_dummy(*(p4dp));                                       \
+       __pud_offset_lockless(p4dp, p4d, address);                      \
+})
 
 #define pud_val(x)                             (p4d_val((x).p4d))
 #define __pud(x)                               ((pud_t) { __p4d(x) })
-- 
LEVI:{C3F47F37-75D8-414A-A8BA-3980EC8A46D7}


Reply via email to