From 9181beb963ecc206c145f229c3f7a7be3b080271 Mon Sep 17 00:00:00 2001 From: Gerwin Klein Date: Sun, 19 Apr 2020 14:56:20 +0800 Subject: [PATCH] riscv: avoid undefined access in lookupPTSlot The function getPPtrFromHWPTE is not applicable to invalid PTEs, so this commit refactors the loop such that the the access is guaranteed to be guarded by the corresponding isPTEPageTable check. Signed-off-by: Gerwin Klein --- src/arch/riscv/kernel/vspace.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/src/arch/riscv/kernel/vspace.c b/src/arch/riscv/kernel/vspace.c index 8bbc94cb0..fd9b63b5d 100644 --- a/src/arch/riscv/kernel/vspace.c +++ b/src/arch/riscv/kernel/vspace.c @@ -372,22 +372,24 @@ static inline pte_t *getPPtrFromHWPTE(pte_t *pte) lookupPTSlot_ret_t lookupPTSlot(pte_t *lvl1pt, vptr_t vptr) { lookupPTSlot_ret_t ret; + + word_t level = CONFIG_PT_LEVELS - 1; + pte_t *pt = lvl1pt; + /* this is how many bits we potentially have left to decode. Initially we have the * full address space to decode, and every time we walk this will be reduced. The * final value of this after the walk is the size of the frame that can be inserted, - * or already exists, in ret.ptSlot */ - ret.ptBitsLeft = PT_INDEX_BITS * CONFIG_PT_LEVELS + seL4_PageBits; - ret.ptSlot = NULL; + * or already exists, in ret.ptSlot. The following formulation is an invariant of + * the loop: */ + ret.ptBitsLeft = PT_INDEX_BITS * level + seL4_PageBits; + ret.ptSlot = pt + ((vptr >> ret.ptBitsLeft) & MASK(PT_INDEX_BITS)); - pte_t *pt = lvl1pt; - do { + while (isPTEPageTable(ret.ptSlot) && likely(0 < level)) { + level--; ret.ptBitsLeft -= PT_INDEX_BITS; - word_t index = (vptr >> ret.ptBitsLeft) & MASK(PT_INDEX_BITS); - ret.ptSlot = pt + index; pt = getPPtrFromHWPTE(ret.ptSlot); - /* stop when we find something that isn't a page table - either a mapped frame or - * an empty slot */ - } while (isPTEPageTable(ret.ptSlot)); + ret.ptSlot = pt + ((vptr >> ret.ptBitsLeft) & MASK(PT_INDEX_BITS)); + } return ret; }