-
Notifications
You must be signed in to change notification settings - Fork 729
Prevent overmapping on aarch32, aarch64, x86 #1526
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
Signed-off-by: Alwin Joshy <[email protected]>
Signed-off-by: Alwin Joshy <[email protected]>
a5d907e to
70bcc54
Compare
Signed-off-by: Krishnan Winter <[email protected]>
Signed-off-by: Krishnan Winter <[email protected]>
70bcc54 to
4a31f6a
Compare
Indanz
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not convinced that we need is_remap and think it should be enough to check the page table entry we want to update for an existing valid mapping. Removing is_remap would reduce the diff a fair bit. The whole point of this is to prevent remapping, so when would is_remap be true and allowed?
Conceptually, all that is needed to prevent overmapping is one extra check on the destination PTE to see if the slot is free or already used.
|
This still needs at least a TSC discussion if not an RFC. It breaks the API for systems that currently use overmapping. Just because the RISC-V implementation follows the manual does not mean that the manual was correct. The ARM and x86 implementations both predate RISC-V and we have fixed so many misunderstandings in both the RISC-V implementation and in the manual over the years that it is absolutely open what the actual intention should be. Currently, it's just inconsistent and we should consciously decide what we want. There is also still the question of whether anything should be done at all to the code. The manual can just state what the correct behaviour is for each architecture. There is no actual requirement for them to be the same even if consistency is generally preferable -- the question is who is going to come up with the funding for the verification of this change, it's too large to just do on the side. |
I'm in the process of writing an RFC up for this change, and will make a PR to the rfc repo for that soon.
My understanding of remap is that it essentially allows a permissions update, so if the supplied frame cap is mapped into the current address space, and doesn't exist in a different mapping within it, then we allow a remap of it (with potentially new permissions). This PR prevents overmapping, which is when we are attempting to over-write an existing mapping with an unmapped frame. So if re-map is true, then the check for over-mapping should be ignored (I believe that was the original intention behind Alwin's original PR). |
Indanz
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So really, the changes can be limited to just an extra check per mapping invocation that checks the info in the current page table entry for presence and current physical address. It's just unfortunate that on some archs this requires a check per page type.
| #ifndef CONFIG_ARM_HYPERVISOR_SUPPORT | ||
| if (pte_ptr_get_pteType(ret.pte_entries.base) == pte_pte_large) { | ||
| #else | ||
| if (pte_ptr_get_pteType(ret.pte_entries.base) == pte_pte_small) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is this missing && pte_pte_small_ptr_get_contiguous_hint(ret.pte_entries.base)))?
| if (!is_remap) { | ||
| userError("Virtual address (0x%"SEL4_PRIx_word") already mapped", vaddr); | ||
| current_syscall_error.type = seL4_DeleteFirst; | ||
| ret.status = EXCEPTION_SYSCALL_ERROR; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is repeated so often, what about putting it in a separate function?
| frame_asid = generic_frame_cap_get_capFMappedASID(cap); | ||
|
|
||
| if (generic_frame_cap_get_capFIsMapped(cap)) { | ||
| if (generic_frame_cap_get_capFMappedASID(cap) != asid) { | ||
| if (frame_asid != asid) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps nicer, but you're not re-using frame_asid, so this change is unnecessary.
| return EXCEPTION_SYSCALL_ERROR; | ||
| } | ||
|
|
||
| is_remap = false; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You only need to set this once at the start of the if (generic_frame_cap_get_capFIsMapped(cap)) block.
| } else if (cap_frame_cap_get_capFMappedAddress(cap) != vaddr) { | ||
| } | ||
|
|
||
| /* The invoked frame cap is already mapped to a different address in this vspace */ | ||
| if (cap_frame_cap_get_capFMappedAddress(cap) != vaddr) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No actual logical change here, just looks like it because the comment was wedged in.
|
|
||
| exception_t decodeX86ModeMapPage(word_t label, vm_page_size_t page_size, cte_t *cte, cap_t cap, | ||
| vspace_root_t *vroot, vptr_t vaddr, paddr_t paddr, vm_rights_t vm_rights, vm_attributes_t vm_attr) | ||
| vspace_root_t *vroot, vptr_t vaddr, paddr_t paddr, vm_rights_t vm_rights, vm_attributes_t vm_attr, asid_t frame_asid) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Isn't that supposed to be an is_remap? Where did frame_asid come from?
| static create_mapping_pdpte_return_t createSafeMappingEntries_PDPTE(paddr_t base, word_t vaddr, vm_rights_t vmRights, | ||
| vm_attributes_t attr, | ||
| vspace_root_t *vspace) | ||
| vspace_root_t *vspace, asid_t frame_asid) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems to be actually is_remap, see other comment.
|
|
||
| /* Check that we are not overwriting an existing mapping */ | ||
| if (pdpte_ptr_get_page_size(ret.pdptSlot) == pdpte_pdpte_1g) { | ||
| if (pdpte_pdpte_1g_ptr_get_present(ret.pdptSlot) && frame_asid == asidInvalid) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Probably:
| if (pdpte_pdpte_1g_ptr_get_present(ret.pdptSlot) && frame_asid == asidInvalid) { | |
| if (pdpte_pdpte_1g_ptr_get_present(ret.pdptSlot) && !is_remap) { |
This is continuing the work as outlined in PR #967. The original branch has been rebased, and merge issues resolved related to the aarch64 page tables refactor.
Test with: seL4/sel4test#148