Skip to content

Commit

Permalink
caprevoke: Handle a race between revokers
Browse files Browse the repository at this point in the history
Suppose a CAPSTORE page is mapped into multiple address spaces, so is
subject to parallel revocation.  Suppose two revokers race to scan the
page.  Suppose further that neither mapping has CDBM set (e.g., because
a third mapping which had set CAPSTORE has been destroyed).

The revokers are initially serialized by the page's object's write lock.
However, the following race is possible:

T1:
- calls pmap_caploadgen_update(), which busies the page and returns
  PMAP_CAPLOADGEN_SCAN_RW_XBUSIED
- drops VM object lock and calls vm_cheri_revoke_visit_rw() to scan the
  page

T2:
- calls pmap_caploadgen_update(), observes that PGA_CAPSTORE is set

T1:
- finds no capabilities in the page, calls pmap_caploadgen_update()
  again
- observes that no mappings has CDBM set, clears PGA_CAPSTORE and
  returns
- unbusies the page

T2:
- acquires the page busy lock
- calls vm_cheri_revoke_visit_rw(), finds no capabilities
- calls pmap_caploadgen_update(), which panics because PGA_CAPSTORE has
  already been cleared

Handle the race by permitting CAPSTORE to be clear in
pmap_caploadgen_update().  In this case, simply update the LCLG and move
on.
  • Loading branch information
markjdb committed Nov 15, 2023
1 parent fb2382d commit 3f8fae9
Show file tree
Hide file tree
Showing 2 changed files with 14 additions and 4 deletions.
9 changes: 7 additions & 2 deletions sys/arm64/arm64/pmap.c
Original file line number Diff line number Diff line change
Expand Up @@ -5590,9 +5590,14 @@ pmap_caploadgen_update(pmap_t pmap, vm_offset_t va, vm_page_t *mp, int flags)
if (mas.flags & PGA_CAPDIRTY) {
/* Page-level cleaning: -?> VACANT */
vm_page_aflag_clear(m, PGA_CAPDIRTY);
} else if (__predict_false(
(mas.flags & PGA_CAPSTORE) == 0)) {
/*
* We raced with another revoker, simply
* update the LCLG and keep going.
*/
;
} else {
KASSERT(mas.flags & PGA_CAPSTORE,
("Page already CAP-CLEAN?"));
/* PTE CAP-CLEAN; page -?> IDLE */

/*
Expand Down
9 changes: 7 additions & 2 deletions sys/riscv/riscv/pmap.c
Original file line number Diff line number Diff line change
Expand Up @@ -3912,9 +3912,14 @@ pmap_caploadgen_update(pmap_t pmap, vm_offset_t va, vm_page_t *mp, int flags)
if (mas.flags & PGA_CAPDIRTY) {
/* Page-level cleaning: -?> VACANT */
vm_page_aflag_clear(m, PGA_CAPDIRTY);
} else if (__predict_false(
(mas.flags & PGA_CAPSTORE) == 0)) {
/*
* We raced with another revoker, simply
* update the LCLG and keep going.
*/
;
} else {
KASSERT(mas.flags & PGA_CAPSTORE,
("Page already CAP-CLEAN?"));
/* PTE CAP-CLEAN; page -?> IDLE */

/*
Expand Down

0 comments on commit 3f8fae9

Please sign in to comment.