Skip to content

Commit

Permalink
Add linux kernel with protect payload policy.
Browse files Browse the repository at this point in the history
This commit gives the possibility to start Miralis with the linux kernel while the payload is isolated from the firmware through the protect payload policy.
  • Loading branch information
francois141 authored and CharlyCst committed Oct 21, 2024
1 parent 4267780 commit 8d767b6
Show file tree
Hide file tree
Showing 4 changed files with 52 additions and 127 deletions.
26 changes: 26 additions & 0 deletions config/lock_kernel.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
[policy]
name = "protect_payload"

[target.miralis]
# Build profile for Miralis (dev profile is set by default)
profile = "dev"

# Miralis binary will be compiled with this value as a start address
# Default to "0x80000000"
start_address = 0x80000000

# Size of the Miralis' stack for each hart (i.e. core)
# Default to 0x8000
stack_size = 0x8000

[target.firmware]
# Build profile for the firmware (dev profile is set by default)
profile = "dev"

# Firmware binary will be compiled with this value as a start address
# Default to "0x80200000"
start_address = 0x80200000

# Size of the firmware stack for each hart (i.e. core)
# Default to 0x8000
stack_size = 0x8000
17 changes: 0 additions & 17 deletions config/test/qemu-virt-test-protect-payload.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@
level = "info"
color = true

[debug]
max_firmware_exits = 2000

[vcpu]
max_pmp = 8
Expand Down Expand Up @@ -40,20 +38,5 @@ start_address = 0x80200000
# Default to 0x8000
stack_size = 0x8000

[target.payload]
# Name or path to the payload binary
name = "test_protect_payload_payload"

# Build profile for the payload (dev profile is set by default)
profile = "dev"

# Payload binary will be compiled with this value as a start address
# Default to "0x80400000"
start_address = 0x80400000

# Size of the payload stack for each hart (i.e. core)
# Default to 0x8000
stack_size = 0x8000

[policy]
name = "protect_payload"
9 changes: 4 additions & 5 deletions justfile
Original file line number Diff line number Diff line change
Expand Up @@ -75,14 +75,13 @@ test:
cargo run -- run --config {{qemu_virt_hello_world_payload}} --firmware opensbi-jump
cargo run -- run --config {{qemu_virt_u_boot_payload}} --firmware opensbi-jump

# Test benchmark code
# Testing with protect payload policy
cargo run -- run --config {{qemu_virt_test_protect_paylod}} --firmware linux

# Testing benchmark code
cargo run -- run --config {{qemu_virt_benchmark}} --firmware csr_write
cargo run -- run --config {{qemu_virt_benchmark}} --firmware ecall_benchmark

# Test with different policies
cargo run -- run --config {{qemu_virt_protect_payload}} --firmware opensbi
# cargo run -- run --config {{qemu_virt_test_protect_paylod}} --firmware test_protect_payload_firmware

# Test firmware build
just build-firmware default {{qemu_virt}}

Expand Down
127 changes: 22 additions & 105 deletions src/policy/protect_payload.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

use miralis_core::abi_protect_payload;

use crate::arch::pmp::{build_napot, pmpcfg};
use crate::arch::pmp::pmpcfg;
use crate::arch::{MCause, Register};
use crate::host::MiralisContext;
use crate::policy::{PolicyHookResult, PolicyModule};
Expand All @@ -12,35 +12,17 @@ use crate::virt::{RegisterContextGetter, VirtContext};
pub struct ProtectPayloadPolicy {
protected: bool,
general_register: [usize; 32],
confidential_values_firmware: ConfidentialCSRs,
confidential_values_payload: ConfidentialCSRs,
last_cause: MCause,
}

impl PolicyModule for ProtectPayloadPolicy {
fn init() -> Self {
ProtectPayloadPolicy {
protected: false,
general_register: [0; 32],
confidential_values_firmware: ConfidentialCSRs {
stvec: 0,
scounteren: 0,
senvcfg: 0,
sscratch: 0,
sepc: 0,
scause: 0,
stval: 0,
satp: 0,
},
confidential_values_payload: ConfidentialCSRs {
stvec: 0,
scounteren: 0,
senvcfg: 0,
sscratch: 0,
sepc: 0,
scause: 0,
stval: 0,
satp: 0,
},
// It is important to let the first mode be EcallFromSMode as the firmware passes some information to the OS.
// Setting this last_cause allows to pass the arguments during the first call.
last_cause: MCause::EcallFromSMode,
}
}
fn name() -> &'static str {
Expand Down Expand Up @@ -90,11 +72,7 @@ impl PolicyModule for ProtectPayloadPolicy {
ctx: &mut VirtContext,
mctx: &mut MiralisContext,
) {
if !self.protected {
return;
}

// Step 1: Clear general purpose registers
// Restore general purpose registers
for i in 0..32 {
self.general_register[i] = ctx.regs[i];
// We don't clear ecall registers
Expand All @@ -103,78 +81,39 @@ impl PolicyModule for ProtectPayloadPolicy {
}
}

// Step 2: Save sensitives privileged registers
self.confidential_values_payload = get_confidential_values(ctx);
self.write_confidential_registers(ctx, false);

// Step 3: Lock memory
// Lock memory
mctx.pmp
.set_from_policy(0, build_napot(0x80400000, 0x80000).unwrap(), pmpcfg::NAPOT);
.set_from_policy(0, 0x80400000 / 4, pmpcfg::INACTIVE);
mctx.pmp.set_from_policy(1, usize::MAX / 4, pmpcfg::TOR);

self.last_cause = ctx.trap_info.get_cause();
}

fn switch_from_firmware_to_payload(
&mut self,
ctx: &mut VirtContext,
mctx: &mut MiralisContext,
) {
if !self.protected {
return;
}

// Step 1: Restore general purpose registers
// Restore general purpose registers
for i in 0..32 {
// 10 & 11 are return registers
if self.restore_register(i, ctx) {
ctx.regs[i] = self.general_register[i];
}
}

// Step 2: Restore sensitives privileged registers
self.write_confidential_registers(ctx, true);

// Step 3: Unlock memory
mctx.pmp.set_from_policy(0, 0, pmpcfg::INACTIVE);
// Unlock memory
mctx.pmp
.set_from_policy(0, 0x80400000 / 4, pmpcfg::INACTIVE);
mctx.pmp
.set_from_policy(1, usize::MAX / 4, pmpcfg::TOR | pmpcfg::RWX);
}

const NUMBER_PMPS: usize = 1;
}

// TODO: Check what to do with fcsr & sip & cycle
pub struct ConfidentialCSRs {
pub stvec: usize,
pub scounteren: usize,
pub senvcfg: usize,
pub sscratch: usize,
pub sepc: usize,
pub scause: usize,
pub stval: usize,
pub satp: usize,
}

fn get_confidential_values(ctx: &mut VirtContext) -> ConfidentialCSRs {
ConfidentialCSRs {
stvec: ctx.csr.stvec,
scounteren: ctx.csr.scounteren,
senvcfg: ctx.csr.senvcfg,
sscratch: ctx.csr.sscratch,
sepc: ctx.csr.sepc,
scause: ctx.csr.scause,
stval: ctx.csr.stval,
satp: ctx.csr.satp,
}
const NUMBER_PMPS: usize = 2;
}

impl ProtectPayloadPolicy {
fn lock(&mut self, mctx: &mut MiralisContext, ctx: &mut VirtContext) {
// Step 1: Get view of confidential registers
self.confidential_values_firmware = get_confidential_values(ctx);
self.confidential_values_payload = get_confidential_values(ctx);
// TODO: Make it dynamic in the future
// First set pmp entry protection
mctx.pmp
.set_from_policy(0, build_napot(0x80400000, 0x80000).unwrap(), pmpcfg::NAPOT);

// Step 2: Mark as protected
fn lock(&mut self, _mctx: &mut MiralisContext, _ctx: &mut VirtContext) {
self.protected = true;
}

Expand All @@ -183,32 +122,10 @@ impl ProtectPayloadPolicy {
}

fn clear_register(&mut self, idx: usize, ctx: &mut VirtContext) -> bool {
!(ctx.trap_info.get_cause() == MCause::EcallFromSMode && (10..18).contains(&idx))
}

fn restore_register(&mut self, idx: usize, ctx: &mut VirtContext) -> bool {
!(ctx.trap_info.get_cause() == MCause::EcallFromSMode && (10..12).contains(&idx))
!(10..18).contains(&idx) || ctx.trap_info.get_cause() != MCause::EcallFromSMode
}

fn write_confidential_registers(&mut self, ctx: &mut VirtContext, restore: bool) {
if restore {
ctx.csr.stvec = self.confidential_values_payload.stvec;
ctx.csr.scounteren = self.confidential_values_payload.scounteren;
ctx.csr.senvcfg = self.confidential_values_payload.senvcfg;
ctx.csr.sscratch = self.confidential_values_payload.sscratch;
ctx.csr.sepc = self.confidential_values_payload.sepc;
ctx.csr.scause = self.confidential_values_payload.scause;
ctx.csr.stval = self.confidential_values_payload.stval;
ctx.csr.satp = self.confidential_values_payload.satp;
} else {
ctx.csr.stvec = self.confidential_values_firmware.stvec;
ctx.csr.scounteren = self.confidential_values_firmware.scounteren;
ctx.csr.senvcfg = self.confidential_values_firmware.senvcfg;
ctx.csr.sscratch = self.confidential_values_firmware.sscratch;
ctx.csr.sepc = self.confidential_values_firmware.sepc;
ctx.csr.scause = self.confidential_values_firmware.scause;
ctx.csr.stval = self.confidential_values_firmware.stval;
ctx.csr.satp = self.confidential_values_firmware.satp;
}
fn restore_register(&mut self, idx: usize, _ctx: &mut VirtContext) -> bool {
!(10..12).contains(&idx) || self.last_cause != MCause::EcallFromSMode
}
}

0 comments on commit 8d767b6

Please sign in to comment.