Search code examples
operating-systemarmtlbmmuarmv8

Why are ASID only in the TLB in ARMv8-A? How to avoid unauthorized access to memory present in tables but ejected from TLB?


I have a quick question about TLBs and ASIDs in ARMv8-A.
From what I understand (from ARM's programmer guide and Architecture Reference Manual) :
- Page/block descriptors (leaf MMU table entries) do not contain an ASID identifier, only a nG (non-global) bit, which says the ASID should be used for this page.
- The actual ASID value that is matched against the register value resides in the TLB. It is set when a page walk occurs and the corresponding entry is added to the TLB (with the current ASID, so that subsequent TLB lookups will check that the new ASID matches).

Say I want to use ASIDs to avoid updating tables when context switching. Each process has a resident ASID value. Process 1 some data at vaddr a1, process 2 at vaddr a2. I context switch from 1 to 2. During execution the TLB entry corresponding to a1 gets ejected (for some reason). Process 2 accesses a1, a TLB miss occurs, and a page walk happens, succeeds and stores process 1's entry using ASID2 value, giving process 2 access to process 1's data.

What am I not understanding? Shouldn't the ASID mechanic provide security between process 1 and 2 while avoiding updating tables?

Optional question: if all my programs have .text section at the same virtual address (at least, all programs have the same entry point address), do I need to update tables every time I context switch or can I have several entries matching the same vaddr, using different ASIDs?


Solution

  • It seems I had a misconception about ASIDs. I got the answer thanks to @artlessnoise's comment.

    In the case I was describing, I missed the fact that we have to map process 2's pages at some point.

    So what we actually do is this:
    - Update tables: add process 2's pages, and remove any page process 2 must not see (including, in my example, page at address a1)
    - Change the ASID so any cached value with an old ASID cannot be used in TLB
    - Start process 2. If process 1's corresponding page is still cached in TLB, it is ignored (since ASIDs mismatch). In both cases, a page walk happens, with the updated table containing only process-2-accessible pages.

    So the (main) security is provided by the tables present when process 2 is running. And additional security in the TLB only is provided by the ASID mechanic, allowing us to not flush the TLB at every context switch.

    EDIT: Another (far-fetched) solution would be to disable page walks for non-cached pages (trigger a MMU fault instead), and to manually check (from the kernel) process permissions every time a process accesses a non-cached page. It seems horrible performance-wise (as well as design-wise).