Skip to content
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

Create backward sentries for function returns and add more checks in cjalr #54

Merged
merged 10 commits into from
May 25, 2024

Commits on May 20, 2024

  1. Based on discussions with David Chisnall:

    Background:
    A typical (non-malicious) function call is as follows:
    - caller saves callee-saved registers (tmp registers) in the caller stack
    - caller saves arguments in arg registers, and overflow arguments in the callee stack
    - caller stores the return address (i.e. address of the instruction next to the call) in the return-address register (or stack in x86)
    - caller jumps to the entry point of the callee function (stored in a register).
      (RISC-V stores return address and jumps to the address in the register via a single jalr instruction)
    - callee executes the function; it might spill registers in the stack as needed
    - callee jumps back to the caller using the return-address register (jr)
    
    Even if the callee code is bug-free, the caller can violate callee’s CFI in two ways:
    - Jump to an address different from the entry point of the callee:
      + For instance, if the callee’s code internally performs operations in a specific branch which the caller did not have access to originally (because of various checks by the callee), the caller can instead directly jump to that branch of the callee (bypassing the checks) and execute that privileged code.
        (Note that PMP or MMU will not protect against this attack as a caller that can execute a function will have access to execute any part of the function; RISC-V has, for instance, proposed a “landing pad” to protect against this)
    - Setting a return address different from the correct return address
      + The caller can make a callee jump to an arbitrary location in some other library that the caller has access to.
        (This is the basis for Return Oriented Programming (ROP) attack, the returned location called a "gadget")
      + The return address that is spilled in the stack in overwritten (either with a buffer overflow attack or directly by feeding a wrong return address), and such gadgets chained.
    
    How CHERI prevents CFI:
    - Cross-compartment and Library functions can be jumped only through sealed capabilities (sentries)
      + jalr instruction to sentry ensures that the offset is 0, so the caller can only jump to published entry point sentries that are accessible by the caller, not arbitrary code inside another library
      + This prevents jumping to a privileged portion of the callee code bypassing the callee’s checks
      + This also prevents most of the ROP attacks using gadgets, as gadgets must be published entry points
    - Return address can only be manipulated by the caller to contain one of the following:
      + Sentry representing the correct return address
      + Sentry that the caller has access to already (either a function call entry point that the caller has access to, or the return address sentry of its caller, or some other return address sentry the caller previously had access to)
      + Non-sealed capability to its own code
    
      (Note that in all the 3 cases above, the manipulated return address has no effect, because the caller could have just jumped to that return address in the code)
    
    CHERIoT inherits all the above benefits. However, because CHERIoT allows manipulating the status of the interrupt through a function call (and function return), by encoding the interrupt type of the callee in the otype of the calling sentry and the interrupt type of the caller in the otype of the return-to-caller sentry, the following attack can occur: A caller calling an interrupt-disabling callee X can set the return address of the callee to be the same interrupt-disabling sentry to X. This means, the callee, on return will call itself all the while operating with interrupts disabled. This will lead to infinite repeated calls to X with interrupts disabled, violating availability.
    
    This attack can be prevented in CHERIoT by adding two new "backwards-edge" sentries and adding more checks on cjalr:
    
    otype 4: Backwards-edge, interrupts-disabled sentry
    otype 5: Backwards-edge, interrupts-enabled sentry.
    
    cjalr with a non-cnull link register always creates otype 4 or 5, i.e. backward sentries. (Currently it always creates otype 2 or 3 (forward explicit interrupt control sentries), so this is just a slightly different constant, but in the same place).
    
    - cjr $cra (a.k.a. cjalr $cra, $cnull, 0) must take a backwards-edge sentry. Sealing violation exception for other otypes.
    - cjr with a non-$cra target may be used only with otypes 0 (unsealed) or 1 (inheriting sentry). Sealing violation exception for other otypes.
    - cjalr with a non-zero return link register will generate a sealing violation for otypes 4 or 5 (backward sentry).
    - cjalr with a target that is otype 2 or 3 (forward, explicit interrupt control) must use $cra as the link register. Any other link register generates a sealing violation.
    
    Note that this disallows tail calls optimization of functions that change interrupt state. (They’re currently disabled and there’s a FIXME in the compiler to enable them. The compiler change is now to remove the FIXME, and then document this for programmers).
    
    Note that cjal currently sets a forward edge sentry on the link register. This change makes cjal set an unsealed cap in the link register. This is okay because cjal is not used in cross-compartment calls, and hence the caller and callee are ostensibly in the same security domain.
    vmurali committed May 20, 2024
    Configuration menu
    Copy the full SHA
    971183c View commit details
    Browse the repository at this point in the history
  2. fixed names and comments

    vmurali committed May 20, 2024
    Configuration menu
    Copy the full SHA
    774e678 View commit details
    Browse the repository at this point in the history

Commits on May 21, 2024

  1. Configuration menu
    Copy the full SHA
    04aa9c3 View commit details
    Browse the repository at this point in the history
  2. fixed cjal

    vmurali committed May 21, 2024
    Configuration menu
    Copy the full SHA
    4de2462 View commit details
    Browse the repository at this point in the history
  3. Configuration menu
    Copy the full SHA
    bf2c5ea View commit details
    Browse the repository at this point in the history
  4. Configuration menu
    Copy the full SHA
    039b141 View commit details
    Browse the repository at this point in the history

Commits on May 22, 2024

  1. change quotes for latex

    vmurali committed May 22, 2024
    Configuration menu
    Copy the full SHA
    73b967e View commit details
    Browse the repository at this point in the history
  2. relaxed one more constraint

    vmurali committed May 22, 2024
    Configuration menu
    Copy the full SHA
    4829964 View commit details
    Browse the repository at this point in the history
  3. fixed english

    vmurali committed May 22, 2024
    Configuration menu
    Copy the full SHA
    d84c384 View commit details
    Browse the repository at this point in the history
  4. rearranged table

    vmurali committed May 22, 2024
    Configuration menu
    Copy the full SHA
    624103b View commit details
    Browse the repository at this point in the history