diff options
author | Thomas Huth <thuth@linux.vnet.ibm.com> | 2015-02-12 18:09:21 +0100 |
---|---|---|
committer | Christian Borntraeger <borntraeger@de.ibm.com> | 2015-02-18 09:37:14 +0100 |
commit | 5d180439d07774c5a2477cf9901c9b51c9edd74b (patch) | |
tree | 7946e236f6436644498e9f1a45cd1f2a96188558 /target-s390x/mmu_helper.c | |
parent | f8f84e93ab6111848cfc83b3d6122573eb03bccf (diff) |
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>
Diffstat (limited to 'target-s390x/mmu_helper.c')
-rw-r--r-- | target-s390x/mmu_helper.c | 29 |
1 files changed, 29 insertions, 0 deletions
diff --git a/target-s390x/mmu_helper.c b/target-s390x/mmu_helper.c index 01d819e026..d4087ba3ce 100644 --- a/target-s390x/mmu_helper.c +++ b/target-s390x/mmu_helper.c @@ -171,6 +171,10 @@ static int mmu_translate_region(CPUS390XState *env, target_ulong vaddr, { CPUState *cs = CPU(s390_env_get_cpu(env)); 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); @@ -201,6 +205,15 @@ static int mmu_translate_region(CPUS390XState *env, target_ulong vaddr, 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 */ return mmu_translate_region(env, vaddr, asc, new_entry, level - 4, raddr, flags, rw); @@ -238,6 +251,10 @@ static int mmu_translate_asc(CPUS390XState *env, target_ulong vaddr, level = asce & _ASCE_TYPE_MASK; switch (level) { 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; case _ASCE_TYPE_REGION2: 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); return -1; } + if ((vaddr >> 51 & 3) > (asce & _ASCE_TABLE_LENGTH)) { + trigger_page_fault(env, vaddr, PGM_REG_SEC_TRANS, asc, rw); + return -1; + } break; case _ASCE_TYPE_REGION3: 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); return -1; } + if ((vaddr >> 40 & 3) > (asce & _ASCE_TABLE_LENGTH)) { + trigger_page_fault(env, vaddr, PGM_REG_THIRD_TRANS, asc, rw); + return -1; + } break; case _ASCE_TYPE_SEGMENT: 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); return -1; } + if ((vaddr >> 29 & 3) > (asce & _ASCE_TABLE_LENGTH)) { + trigger_page_fault(env, vaddr, PGM_SEGMENT_TRANS, asc, rw); + return -1; + } break; } |