Commit f93d930d authored by Jeffrey Lee's avatar Jeffrey Lee Committed by ROOL
Browse files

Add AP 1 emulation for long descriptor page tables

The long descriptor page table format doesn't support RISC OS access
privilege 1 (user RX, privileged RWX). Previously we were downgrading
this to AP 0 (user RWX, privielged RWX), which obviously weakens the
security of the memory. However now that we have an AbortTrap
implementation, we can map the memory as "user none, privileged RWX" and
provide user read support via AbortTrap's instruction decode & execute
logic.

There's no support for executing usermode code from the memory, but the
compatibility issues caused by that are likely to be minimal.
parent 84c73735
......@@ -198,6 +198,14 @@ CacheablePageTables SETL {TRUE} ; Use cacheable page tables wher
GBLL SyncPageTables
SyncPageTables SETL (MEMM_Type = "VMSAv6") :LOR: CacheablePageTables ; Any page table modification (specifically, overwriting faulting entries) requires synchronisation
; Control over behaviour of memory access privilege 1 when
; using long descriptor page tables:
; Traditional permissions are user RX + privileged RWX
; EmulateAP1 {TRUE} will provide user R + privileged RWX, by using AbortTrap to implement user read support
; EmulateAP1 {FALSE} will provide user RWX + privileged RWX (weaker security since user code can now write to the memory)
GBLL EmulateAP1
EmulateAP1 SETL LongDesc :LAND: {TRUE}
[ :LNOT: :DEF: SMP
GBLL SMP
SMP SETL (MEMM_Type = "VMSAv6") :LAND: {TRUE} ; Enable SMP-related changes
......
......@@ -154,7 +154,11 @@ IRQStack DefAreaFlags None, PageFlags_Unavailable
ABTStack DefAreaFlags None, PageFlags_Unavailable
UNDStack DefAreaFlags None, PageFlags_Unavailable
Kbuffs DefAreaFlags Read, PageFlags_Unavailable
[ EmulateAP1
DebuggerSpace DefAreaFlags Full, PageFlags_Unavailable ; Downgrade from read-only to full access in usermode, to avoid LongDesc AP1 emulation causing it to become non-executable in usermode
|
DebuggerSpace DefAreaFlags Read, PageFlags_Unavailable
]
RWArea DefAreaFlags None, PageFlags_Unavailable
[ DA_Batman
......
......@@ -612,6 +612,13 @@ AccessPhysicalAddress_LongDesc ROUT
GetPTE a1, 2M, ip, a1, LongDesc
; Force XN (easier to do afterwards since PPL mapping is non-trivial)
ORR a2, a2, #LL_Page_HighAttr_XN
[ EmulateAP1
; Don't allow AP1 emulation (usermode readonly); there's no XN+SW0
; format defined in PPLTrans, so to ensure we can map from the page
; table entry flags back to a valid AP number, we must clear SW0 and
; lose the usermode access.
BIC a2, a2, #LL_Page_HighAttr_SW0
]
MOV lr, a4
LDR ip, =LL2PT + (PhysicalAccess:SHR:18) ; ip -> L2PT entry
LDRD a3, [ip] ; Get old entry
......@@ -713,6 +720,13 @@ RISCOS_MapInIO_LowAttr_LongDesc ; a1 bits 0-11 = low attributes, bits 20+ = our
ORR a1, a1, v4, LSL #21
MOV a2, v4, LSR #11
ORR a2, a2, #LL_Page_HighAttr_XN ; a1,a2 = first PT entry to match
[ EmulateAP1
; Don't allow AP1 emulation (usermode readonly); there's no XN+SW0
; format defined in PPLTrans, so to ensure we can map from the page
; table entry flags back to a valid AP number, we must clear SW0 and
; lose the usermode access.
BIC a2, a2, #LL_Page_HighAttr_SW0
]
LDR v7, [ip, #IOAllocPtr]
MOV v7, v7, LSR #18 ; v7 = logical 2MB*8 that we're checking for a match
LDR v1, =LL2PT
......
......@@ -2557,6 +2557,21 @@ CMA_AddRange2 ; r3 = start, r4 = end (excl.)
; Exit if the range starts after our end point
CMP r3, r2
BHI %FT10
[ EmulateAP1
Push "r8-r9"
[ ShortDesc
PTWhich r8
BEQ %FT03
]
; Detect AP1 areas and flag them as UserXN + Abort
LDR r9, =CMA_Read :AND: :NOT: CMA_Partially_UserXN ; Might already be flagged as UserXN, depending on how the flags were fetched
BIC r8, r5, #CMA_Partially_UserXN+CMA_Partially_Phys
TEQ r8, r9
BICEQ r5, r5, #CMA_Partially_UserXN
ORREQ r5, r5, #CMA_Partially_Abort
03
Pull "r8-r9"
]
; Process the range
TST r5, #CMA_CheckL2PT
BNE %FT20
......@@ -2637,6 +2652,17 @@ CMA_Done
LDR r5, [r0, #MMU_PPLAccess]
AND lr, r2, #DynAreaFlags_APBits
LDR r5, [r5, lr, LSL #2]
[ EmulateAP1
[ ShortDesc
PTWhich r0
BEQ %FT42
]
; Detect AP1 areas and them as UserXN + Abort
TEQ lr, #OSAP_Read
BICEQ r5, r5, #CMA_Partially_UserXN
ORREQ r5, r5, #CMA_Partially_Abort
42
]
Pull "r0-r3"
ORR r10, r5, r10
ORR r0, r0, r5 ; Set new partial flags
......
......@@ -265,36 +265,60 @@ TTBRCacheMunge
; XN, PXN, AP2, AP1 mean we theoretically have 16 permission levels. However
; some are redundant (e.g. setting both XN+PXN)
[ EmulateAP1
; Because the long descriptor format doesn't support RISC OS AP 1 (user RX,
; priv RWX), we instead map the memory as user None, priv RWX, (equivalent to
; RISC OS AP 2). User mode read access is provided by the AbortTrap code; when
; AbortTrap examines the page it will see the "correct" permissions, and so will
; do a direct memcpy from the page, without needing any special code or needing
; to invoke any AbortTrap handlers.
;
; Some parts of the OS (including AbortTrap) need to be able to decode page
; table entries and map the flags back to the corresponding AP value. So for
; the OS to correctly differentiate between AP 1 & AP 2, we now consider the
; SW0 flag bit to be one of the permission bits.
;
; Note that we currently don't provide any support for executing usermode code
; from AP 1 memory, and the advertised permissions reflect this.
]
; Encode both high and low attributes in one word
ASSERT LL_HighAttr_Start >= LL_LowAttr_Start+LL_LowAttr_Size
MACRO
LongPPL $XN, $PXN, $AP2, $AP1
DCD ($XN * LL_Page_HighAttr_XN) + ($PXN * LL_Page_HighAttr_PXN) + ($AP2 * LL_Page_LowAttr_AP2) + ($AP1 * LL_Page_LowAttr_AP1) + LL_Page_LowAttr_SH1 + LL_Page_LowAttr_SH0
LongPPL $XN, $PXN, $AP2, $AP1, $SW0
DCD ($XN * LL_Page_HighAttr_XN) + ($PXN * LL_Page_HighAttr_PXN) + ($AP2 * LL_Page_LowAttr_AP2) + ($AP1 * LL_Page_LowAttr_AP1) + LL_Page_LowAttr_SH1 + LL_Page_LowAttr_SH0 + ($SW0 * LL_Page_HighAttr_SW0)
MEND
; AP2 = read-only
; AP1 = enable unprivileged access
PPLTrans_LongDesc
; XN PXN AP2 AP1 EL1 EL0
LongPPL 0, 0, 0, 1 ; RWX RWX
! 0, "LongDescTODO Implement solution for PPL 1"
LongPPL 0, 0, 0, 1 ; RWX RWX *** downgraded from RWX R X
LongPPL 0, 0, 0, 0 ; RWX
LongPPL 0, 0, 1, 1 ; R X R X
LongPPL 0, 0, 1, 0 ; R X
LongPPL 1, 0, 0, 0 ; RW
LongPPL 1, 0, 0, 1 ; RW RW
LongPPL 1, 0, 1, 0 ; R
LongPPL 1, 0, 1, 1 ; R R
LongPPL 0, 1, 0, 1 ; RW RWX
LongPPL 0, 1, 1, 1 ; R R X
; XN PXN AP2 AP1 SW0 EL1 EL0
LongPPL 0, 0, 0, 1, 0 ; RWX RWX
[ EmulateAP1
LongPPL 0, 0, 0, 0, 1 ; RWX R
|
LongPPL 0, 0, 0, 1, 0 ; RWX RWX
]
LongPPL 0, 0, 0, 0, 0 ; RWX
LongPPL 0, 0, 1, 1, 0 ; R X R X
LongPPL 0, 0, 1, 0, 0 ; R X
LongPPL 1, 0, 0, 0, 0 ; RW
LongPPL 1, 0, 0, 1, 0 ; RW RW
LongPPL 1, 0, 1, 0, 0 ; R
LongPPL 1, 0, 1, 1, 0 ; R R
LongPPL 0, 1, 0, 1, 0 ; RW RWX
LongPPL 0, 1, 1, 1, 0 ; R R X
PPLAccess_LongDesc ; EL1EL0
; RWXRWX
GenPPLAccess 2_111111
GenPPLAccess 2_111111 ; *** downgraded from RWX R X
[ EmulateAP1
GenPPLAccess 2_111100
|
GenPPLAccess 2_111111
]
GenPPLAccess 2_111000
GenPPLAccess 2_101101
GenPPLAccess 2_101000
......@@ -310,10 +334,10 @@ PPLAccess_LongDesc ; EL1EL0
LTORG
; PPLTrans should contain XN + PXN + AP2 + AP1 + SH1 + SH0
; PPLTrans should contain XN + PXN + AP2 + AP1 + SH1 + SH0 + SW0
; PCBTrans should contain AttrIndx
LL_HighPPLBits * LL_Page_HighAttr_XN + LL_Page_HighAttr_PXN
LL_HighPPLBits * LL_Page_HighAttr_XN + LL_Page_HighAttr_PXN + LL_Page_HighAttr_SW0
LL_LowPPLBits * LL_Page_LowAttr_SH1 + LL_Page_LowAttr_SH0 + LL_Page_LowAttr_AP2 + LL_Page_LowAttr_AP1
; In:
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment