mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-27 03:10:12 +00:00
s390/mm: fix pxd_bad with folded page tables
With git commitd1874a0c28
"s390/mm: make the pxd_offset functions more robust" and a 2-level page table it can now happen that pgd_bad() gets asked to verify a large segment table entry. If the entry is marked as dirty pgd_bad() will incorrectly return true. Change the pgd_bad(), p4d_bad(), pud_bad() and pmd_bad() functions to first verify the table type, return false if the table level is lower than what the function is suppossed to check, return true if the table level is too high, and otherwise check the relevant region and segment table bits. pmd_bad() has to check against ~SEGMENT_ENTRY_BITS for normal page table pointers or ~SEGMENT_ENTRY_BITS_LARGE for large segment table entries. Same for pud_bad() which has to check against ~_REGION_ENTRY_BITS or ~_REGION_ENTRY_BITS_LARGE. Fixes:d1874a0c28
("s390/mm: make the pxd_offset functions more robust") Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
This commit is contained in:
parent
01eb42afb4
commit
c9f621524e
1 changed files with 19 additions and 14 deletions
|
@ -238,7 +238,7 @@ static inline int is_module_addr(void *addr)
|
||||||
#define _REGION_ENTRY_NOEXEC 0x100 /* region no-execute bit */
|
#define _REGION_ENTRY_NOEXEC 0x100 /* region no-execute bit */
|
||||||
#define _REGION_ENTRY_OFFSET 0xc0 /* region table offset */
|
#define _REGION_ENTRY_OFFSET 0xc0 /* region table offset */
|
||||||
#define _REGION_ENTRY_INVALID 0x20 /* invalid region table entry */
|
#define _REGION_ENTRY_INVALID 0x20 /* invalid region table entry */
|
||||||
#define _REGION_ENTRY_TYPE_MASK 0x0c /* region/segment table type mask */
|
#define _REGION_ENTRY_TYPE_MASK 0x0c /* region table type mask */
|
||||||
#define _REGION_ENTRY_TYPE_R1 0x0c /* region first table type */
|
#define _REGION_ENTRY_TYPE_R1 0x0c /* region first table type */
|
||||||
#define _REGION_ENTRY_TYPE_R2 0x08 /* region second table type */
|
#define _REGION_ENTRY_TYPE_R2 0x08 /* region second table type */
|
||||||
#define _REGION_ENTRY_TYPE_R3 0x04 /* region third table type */
|
#define _REGION_ENTRY_TYPE_R3 0x04 /* region third table type */
|
||||||
|
@ -277,6 +277,7 @@ static inline int is_module_addr(void *addr)
|
||||||
#define _SEGMENT_ENTRY_PROTECT 0x200 /* segment protection bit */
|
#define _SEGMENT_ENTRY_PROTECT 0x200 /* segment protection bit */
|
||||||
#define _SEGMENT_ENTRY_NOEXEC 0x100 /* segment no-execute bit */
|
#define _SEGMENT_ENTRY_NOEXEC 0x100 /* segment no-execute bit */
|
||||||
#define _SEGMENT_ENTRY_INVALID 0x20 /* invalid segment table entry */
|
#define _SEGMENT_ENTRY_INVALID 0x20 /* invalid segment table entry */
|
||||||
|
#define _SEGMENT_ENTRY_TYPE_MASK 0x0c /* segment table type mask */
|
||||||
|
|
||||||
#define _SEGMENT_ENTRY (0)
|
#define _SEGMENT_ENTRY (0)
|
||||||
#define _SEGMENT_ENTRY_EMPTY (_SEGMENT_ENTRY_INVALID)
|
#define _SEGMENT_ENTRY_EMPTY (_SEGMENT_ENTRY_INVALID)
|
||||||
|
@ -614,15 +615,9 @@ static inline int pgd_none(pgd_t pgd)
|
||||||
|
|
||||||
static inline int pgd_bad(pgd_t pgd)
|
static inline int pgd_bad(pgd_t pgd)
|
||||||
{
|
{
|
||||||
/*
|
if ((pgd_val(pgd) & _REGION_ENTRY_TYPE_MASK) < _REGION_ENTRY_TYPE_R1)
|
||||||
* With dynamic page table levels the pgd can be a region table
|
return 0;
|
||||||
* entry or a segment table entry. Check for the bit that are
|
return (pgd_val(pgd) & ~_REGION_ENTRY_BITS) != 0;
|
||||||
* invalid for either table entry.
|
|
||||||
*/
|
|
||||||
unsigned long mask =
|
|
||||||
~_SEGMENT_ENTRY_ORIGIN & ~_REGION_ENTRY_INVALID &
|
|
||||||
~_REGION_ENTRY_TYPE_MASK & ~_REGION_ENTRY_LENGTH;
|
|
||||||
return (pgd_val(pgd) & mask) != 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline unsigned long pgd_pfn(pgd_t pgd)
|
static inline unsigned long pgd_pfn(pgd_t pgd)
|
||||||
|
@ -703,6 +698,8 @@ static inline int pmd_large(pmd_t pmd)
|
||||||
|
|
||||||
static inline int pmd_bad(pmd_t pmd)
|
static inline int pmd_bad(pmd_t pmd)
|
||||||
{
|
{
|
||||||
|
if ((pmd_val(pmd) & _SEGMENT_ENTRY_TYPE_MASK) > 0)
|
||||||
|
return 1;
|
||||||
if (pmd_large(pmd))
|
if (pmd_large(pmd))
|
||||||
return (pmd_val(pmd) & ~_SEGMENT_ENTRY_BITS_LARGE) != 0;
|
return (pmd_val(pmd) & ~_SEGMENT_ENTRY_BITS_LARGE) != 0;
|
||||||
return (pmd_val(pmd) & ~_SEGMENT_ENTRY_BITS) != 0;
|
return (pmd_val(pmd) & ~_SEGMENT_ENTRY_BITS) != 0;
|
||||||
|
@ -710,8 +707,12 @@ static inline int pmd_bad(pmd_t pmd)
|
||||||
|
|
||||||
static inline int pud_bad(pud_t pud)
|
static inline int pud_bad(pud_t pud)
|
||||||
{
|
{
|
||||||
if ((pud_val(pud) & _REGION_ENTRY_TYPE_MASK) < _REGION_ENTRY_TYPE_R3)
|
unsigned long type = pud_val(pud) & _REGION_ENTRY_TYPE_MASK;
|
||||||
return pmd_bad(__pmd(pud_val(pud)));
|
|
||||||
|
if (type > _REGION_ENTRY_TYPE_R3)
|
||||||
|
return 1;
|
||||||
|
if (type < _REGION_ENTRY_TYPE_R3)
|
||||||
|
return 0;
|
||||||
if (pud_large(pud))
|
if (pud_large(pud))
|
||||||
return (pud_val(pud) & ~_REGION_ENTRY_BITS_LARGE) != 0;
|
return (pud_val(pud) & ~_REGION_ENTRY_BITS_LARGE) != 0;
|
||||||
return (pud_val(pud) & ~_REGION_ENTRY_BITS) != 0;
|
return (pud_val(pud) & ~_REGION_ENTRY_BITS) != 0;
|
||||||
|
@ -719,8 +720,12 @@ static inline int pud_bad(pud_t pud)
|
||||||
|
|
||||||
static inline int p4d_bad(p4d_t p4d)
|
static inline int p4d_bad(p4d_t p4d)
|
||||||
{
|
{
|
||||||
if ((p4d_val(p4d) & _REGION_ENTRY_TYPE_MASK) < _REGION_ENTRY_TYPE_R2)
|
unsigned long type = p4d_val(p4d) & _REGION_ENTRY_TYPE_MASK;
|
||||||
return pud_bad(__pud(p4d_val(p4d)));
|
|
||||||
|
if (type > _REGION_ENTRY_TYPE_R2)
|
||||||
|
return 1;
|
||||||
|
if (type < _REGION_ENTRY_TYPE_R2)
|
||||||
|
return 0;
|
||||||
return (p4d_val(p4d) & ~_REGION_ENTRY_BITS) != 0;
|
return (p4d_val(p4d) & ~_REGION_ENTRY_BITS) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue