Skip to content

refactor(mem): make permissions kind-dependent on AddressSpaceRegion #782

@JonasKruckenberg

Description

@JonasKruckenberg

Problem

AddressSpaceRegion stores permissions: Permissions as an unconditional sibling field next to vmo: Arc<Vmo>, regardless of the VMO kind:

// sys/kernel/src/mem/address_space_region.rs
pub struct AddressSpaceRegion {
    pub range: Range<VirtualAddress>,
    pub permissions: Permissions,   // ← always present
    pub name: Option<String>,
    pub vmo: Arc<Vmo>,              // ← Wired | Phys | Paged
    pub vmo_offset: usize,
    ...
}

For Vmo::Wired regions, this field is dead state. Every operation that would consult it bails out before reading it:

  • AddressSpaceRegion::commit()Vmo::Wired => unreachable!()
  • AddressSpaceRegion::page_fault()Vmo::Wired => unreachable!("Wired VMO can never page fault")
  • AddressSpaceRegion::unmap()Vmo::Wired => panic!("cannot unmap wired frames")

The only live consumer for wired-region perms is AddressSpace::reserve() itself, which today eagerly drives arch::update_flags() / arch::unmap() on the hardware:

// sys/kernel/src/mem/address_space.rs, inside `reserve()`
if permissions.is_empty() {
    self.arch.unmap(range.start, ..., flush)?;
} else {
    self.arch.update_flags(range.start, ..., permissions.into(), flush)?;
}

After the UEFI boot rework (#732), the loader becomes the sole source of truth for wired-region hardware perms — it maps each PT_LOAD segment with the right RX/RO/RW perms before handoff, and reserve() becomes purely logical bookkeeping (no update_flags / unmap). At that point the permissions field on wired regions has no meaningful value at all.

Today, this means a wired region could be constructed carrying Permissions::READ | Permissions::WRITE | Permissions::EXECUTE and the type system would happily accept it. We rely on a runtime assert!(perms.is_valid()) (W^X check) to catch illegal combinations — but for wired regions, any perms value is equally meaningless / equally lying about what's actually mapped. Making invalid states representable when they're meaningless is a security-hygiene problem in a microkernel.

Proposed change

Move permissions from a sibling field on AddressSpaceRegion into the VMO-kind branches that actually use it. Sketch:

pub enum Vmo {
    Wired,                                          // no perms — owned by loader
    Phys  { permissions: MemoryAttributes, ... },
    Paged { permissions: MemoryAttributes, ... },
}

(Field placement is illustrative — could be a wrapping struct, a new enum that pairs perms with non-Wired VMOs, or a refactor of AddressSpaceRegion itself. The shape we want is: perms only exist where they have meaning.)

Benefits

  • Invalid states unrepresentable. A wired region simply cannot carry perms — there's no place to put them. Reading the type makes this obvious.
  • No more dead state. The unconditional perms field becomes the conditional one it always semantically was.
  • Pairs naturally with W^X-by-typing. While touching this code, migrating from the bitflags-based Permissions (sys/kernel/src/mem/mod.rs, can represent W+E, enforced via runtime assert!(perms.is_valid())) to the type-safe MemoryAttributes (enum WriteOrExecute { Neither, Write, Execute } — W^X enforced by construction) is the same kind of states-unrepresentable improvement on the perms type itself. MemoryAttributes already exists in lib/mem-core but isn't adopted by AddressSpace.

Touch points

  • sys/kernel/src/mem/address_space_region.rs — restructure the type, update all match arms (commit, page_fault, unmap, new_wired / new_phys / new_zeroed, Display).
  • sys/kernel/src/mem/address_space.rsreserve(), protect(), commit(), page_fault() callsites; Display impl that prints region.permissions.
  • sys/kernel/src/mem/mmap.rs — userspace mmap path uses region.permissions = new_permissions.
  • sys/kernel/src/mem/mod.rsreserve_wired_regions (already being rewritten by loader: finish UEFI boot path #732 to drop the ELF walk).

Sequencing

  • Sequenced after loader: finish UEFI boot path #732 lands, since that work also touches reserve_wired_regions and is the change that makes wired-region perms genuinely dead state.
  • The MemoryAttributes adoption can be a follow-up (or done together — they're complementary but independent).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions