I am going through the Arm Pseudocode for memory translation, and I stumbled upon something that I cannot really explain.
In the functions S2Translate and S2Walk (similar for stage 1) for Aarch64, there are loops that correspond to "repeat until descriptor does not change anymore" (the access flags, dirty bits etc might be changing upon translation, and these changes are written during translation). I was now wondering whether this repeat loop is bounded by some condition. At first sight, I assumed it would be repeated at most once, but I am too ignorant in the realms of Arm to conclude that this is the case.
Intuitively, an adversary can keep changing the descriptor in memory (resetting the accessflag and whatnot), resulting in an infinite loop. Is this actually possible, or are there memory consistency rules or atomicity constraints that I overlooked? If yes (which I assume), can you please point me to what I should read up on? It seems odd that Arm would formulate their specification like this, but also cannot see something preventing a loop (assuming "perfect conditions").
Thank you
Let's take the S2Walk as one example.
Please be aware that the MMU translation table is 64-bit VA, which can have 3-level or 4-level MMU tables with different MMU translation table granule size.
<quote>
repeat
...
case desctype of when DescriptorType_Table walkstate = AArch64.S2NextWalkStateTable(walkstate, walkparams, descriptor); // Detect Address Size Fault by table descriptor if AArch64.OAOutOfRange(walkstate, walkparams.ps, walkparams.tgx, ipa_64) then fault.statuscode = Fault_AddressSize; return (fault, AddressDescriptor UNKNOWN, TTWState UNKNOWN, bits(64) UNKNOWN); when DescriptorType_Page, DescriptorType_Block walkstate = AArch64.S2NextWalkStateLast(walkstate, ss, walkparams, ipa, descriptor); when DescriptorType_Invalid fault.statuscode = Fault_Translation; return (fault, AddressDescriptor UNKNOWN, TTWState UNKNOWN, bits(64) UNKNOWN); otherwise Unreachable(); until desctype IN {DescriptorType_Page, DescriptorType_Block};
</quote>
Thank you for the response. I was just wondering about the inner loop though. What prevents this from looping indefinitely? Is there a consistency rule that ensures boundedness?
I am not sure I got your concern points. Why you think the inner loop will have the infinite looping?VA->PA address translation is 64-bit VA in AArch64 state. The parameters of S2Walk() are finite width, but not infinite?
Please refer to Arm.ARM Chapter D. Arm AArch64 memory model.
The inner loop is a `repeat ... until new_descriptor == descriptor`. This loops. If a malicious actor tries to overwrite the descriptor, and `MemSwapTableDesc` always needs to swap 2 non-identical descriptors, what will happen? Is it an infinite loop?
I am aware what code is called and that everything is finite, it is just that one loop and condition that seems strange to me
AArch64.MemSwapTableDesc is an atomic operation. I cannot image one scenario that how the offending descriptor is repeatedly looped here.
If a malicious actor overwrites a offending descriptor, it is possible. However, the memory attribute check or permission check will figure it out or raise the fault as the bad descriptor. Even though the offending descriptor passes all the checks and goes into S1Translate(), S2Translate() for EL0/EL1, I think it is still finite loops as it obeys the AArch64 VMSA rules.