s390x/mmu: Check table length and offset fields

The ACSEs have a table length field and the region entries have
table length and offset fields which must be checked during
translation to see whether the given virtual address is really
covered by the translation table.

Signed-off-by: Thomas Huth <thuth@linux.vnet.ibm.com>
Signed-off-by: Jens Freimann <jfrei@linux.vnet.ibm.com>
Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
This commit is contained in:
Thomas Huth 2015-02-12 18:09:21 +01:00 committed by Christian Borntraeger
parent f8f84e93ab
commit 5d180439d0
2 changed files with 30 additions and 0 deletions

View File

@ -837,6 +837,7 @@ struct sysib_322 {
#define _ASCE_TABLE_LENGTH 0x03 /* region table length */ #define _ASCE_TABLE_LENGTH 0x03 /* region table length */
#define _REGION_ENTRY_ORIGIN ~0xfffULL /* region/segment table origin */ #define _REGION_ENTRY_ORIGIN ~0xfffULL /* region/segment table origin */
#define _REGION_ENTRY_TF 0xc0 /* region/segment table offset */
#define _REGION_ENTRY_INV 0x20 /* invalid region table entry */ #define _REGION_ENTRY_INV 0x20 /* invalid region table entry */
#define _REGION_ENTRY_TYPE_MASK 0x0c /* region/segment table type mask */ #define _REGION_ENTRY_TYPE_MASK 0x0c /* region/segment table type mask */
#define _REGION_ENTRY_TYPE_R1 0x0c /* region first table type */ #define _REGION_ENTRY_TYPE_R1 0x0c /* region first table type */

View File

@ -171,6 +171,10 @@ static int mmu_translate_region(CPUS390XState *env, target_ulong vaddr,
{ {
CPUState *cs = CPU(s390_env_get_cpu(env)); CPUState *cs = CPU(s390_env_get_cpu(env));
uint64_t origin, offs, new_entry; uint64_t origin, offs, new_entry;
const int pchks[4] = {
PGM_SEGMENT_TRANS, PGM_REG_THIRD_TRANS,
PGM_REG_SEC_TRANS, PGM_REG_FIRST_TRANS
};
PTE_DPRINTF("%s: 0x%" PRIx64 "\n", __func__, entry); PTE_DPRINTF("%s: 0x%" PRIx64 "\n", __func__, entry);
@ -201,6 +205,15 @@ static int mmu_translate_region(CPUS390XState *env, target_ulong vaddr,
rw); rw);
} }
/* Check region table offset and length */
offs = (vaddr >> (28 + 11 * (level - 4) / 4)) & 3;
if (offs < ((new_entry & _REGION_ENTRY_TF) >> 6)
|| offs > (new_entry & _REGION_ENTRY_LENGTH)) {
DPRINTF("%s: invalid offset or len (%lx)\n", __func__, new_entry);
trigger_page_fault(env, vaddr, pchks[level / 4 - 1], asc, rw);
return -1;
}
/* yet another region */ /* yet another region */
return mmu_translate_region(env, vaddr, asc, new_entry, level - 4, return mmu_translate_region(env, vaddr, asc, new_entry, level - 4,
raddr, flags, rw); raddr, flags, rw);
@ -238,6 +251,10 @@ static int mmu_translate_asc(CPUS390XState *env, target_ulong vaddr,
level = asce & _ASCE_TYPE_MASK; level = asce & _ASCE_TYPE_MASK;
switch (level) { switch (level) {
case _ASCE_TYPE_REGION1: case _ASCE_TYPE_REGION1:
if ((vaddr >> 62) > (asce & _ASCE_TABLE_LENGTH)) {
trigger_page_fault(env, vaddr, PGM_REG_FIRST_TRANS, asc, rw);
return -1;
}
break; break;
case _ASCE_TYPE_REGION2: case _ASCE_TYPE_REGION2:
if (vaddr & 0xffe0000000000000ULL) { if (vaddr & 0xffe0000000000000ULL) {
@ -246,6 +263,10 @@ static int mmu_translate_asc(CPUS390XState *env, target_ulong vaddr,
trigger_page_fault(env, vaddr, PGM_TRANS_SPEC, asc, rw); trigger_page_fault(env, vaddr, PGM_TRANS_SPEC, asc, rw);
return -1; return -1;
} }
if ((vaddr >> 51 & 3) > (asce & _ASCE_TABLE_LENGTH)) {
trigger_page_fault(env, vaddr, PGM_REG_SEC_TRANS, asc, rw);
return -1;
}
break; break;
case _ASCE_TYPE_REGION3: case _ASCE_TYPE_REGION3:
if (vaddr & 0xfffffc0000000000ULL) { if (vaddr & 0xfffffc0000000000ULL) {
@ -254,6 +275,10 @@ static int mmu_translate_asc(CPUS390XState *env, target_ulong vaddr,
trigger_page_fault(env, vaddr, PGM_TRANS_SPEC, asc, rw); trigger_page_fault(env, vaddr, PGM_TRANS_SPEC, asc, rw);
return -1; return -1;
} }
if ((vaddr >> 40 & 3) > (asce & _ASCE_TABLE_LENGTH)) {
trigger_page_fault(env, vaddr, PGM_REG_THIRD_TRANS, asc, rw);
return -1;
}
break; break;
case _ASCE_TYPE_SEGMENT: case _ASCE_TYPE_SEGMENT:
if (vaddr & 0xffffffff80000000ULL) { if (vaddr & 0xffffffff80000000ULL) {
@ -262,6 +287,10 @@ static int mmu_translate_asc(CPUS390XState *env, target_ulong vaddr,
trigger_page_fault(env, vaddr, PGM_TRANS_SPEC, asc, rw); trigger_page_fault(env, vaddr, PGM_TRANS_SPEC, asc, rw);
return -1; return -1;
} }
if ((vaddr >> 29 & 3) > (asce & _ASCE_TABLE_LENGTH)) {
trigger_page_fault(env, vaddr, PGM_SEGMENT_TRANS, asc, rw);
return -1;
}
break; break;
} }