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

Implement separate create process syscall in kernel #4918

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions enclave_apps/oak_echo_raw_enclave_app/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,9 @@ fn start_echo_server() -> ! {
let mut channel = FileDescriptorChannel::default();
loop {
let bytes = {
log::info!("about to allocate bytes");
let mut bytes: Vec<u8> = vec![0; MESSAGE_SIZE];
log::info!("allocated bytes");
channel.read_exact(&mut bytes).expect("couldn't read bytes");
bytes
};
Expand Down
6 changes: 4 additions & 2 deletions enclave_apps/oak_orchestrator/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,8 @@ fn entrypoint() -> ! {
.expect("failed to write dice data");
attested_app.dice_data.as_bytes_mut().zeroize();

log::info!("Exiting and launching application.");
syscall::unstable_switch_proccess(attested_app.elf_binary.as_slice())
let pid = syscall::unstable_create_proccess(attested_app.elf_binary.as_slice())
.expect("failed to create app process");
log::info!("created application with pid: {}", pid);
syscall::unstable_switch_proccess(pid)
}
30 changes: 26 additions & 4 deletions oak_restricted_kernel/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,30 @@ pub static VMA_ALLOCATOR: Spinlock<VirtualAddressAllocator<Size2MiB>> =
},
)));

static PROCCESSES: Processes = Processes { list: Spinlock::new(alloc::vec::Vec::new()) };

struct Processes {
list: Spinlock<alloc::vec::Vec<Process>>,
}

impl Processes {
/// # Safety
///
/// Caller must ensure to no lock is currently being held.
unsafe fn add(&self, process: Process) -> usize {
self.list.force_unlock();
let mut processes = self.list.lock();
let pid: usize = processes.len();
processes.push(process);
log::debug!("Created process (pid: {})", pid);
pid
}
fn execute(&self, pid: usize) -> ! {
log::debug!("Executing process (pid: {})", pid);
self.list.lock().get_mut(pid).expect("PID not mapped to a process").execute()
}
}

/// Main entry point for the kernel, to be called from bootloader.
pub fn start_kernel(info: &BootParams) -> ! {
avx::enable_avx();
Expand Down Expand Up @@ -471,11 +495,9 @@ pub fn start_kernel(info: &BootParams) -> ! {

// Ensure new process is not dropped.
// Safety: The application is assumed to be a valid ELF file.
let process = Box::leak(Box::new(unsafe {
Process::from_application(&application).expect("failed to create process")
}));
let pid = unsafe { Process::from_application(&application).expect("failed to create process") };

process.execute()
PROCCESSES.execute(pid)
}

#[derive(EnumIter, EnumString)]
Expand Down
1 change: 1 addition & 0 deletions oak_restricted_kernel/src/mm/page_tables.rs
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,7 @@ impl CurrentRootPageTable {
/// Safety: The new page tables must keep the identity mapping at -2GB
/// (kernel space) intact.
pub unsafe fn replace(&mut self, pml4_frame: PhysFrame) -> Option<RootPageTable> {
log::info!("Writing new pml4 to Cr3: {:?}", pml4_frame);
// This validates any references that expect boot page tables to be valid!
// Safety: Caller must ensure that the new page tables are safe.
unsafe {
Expand Down
20 changes: 10 additions & 10 deletions oak_restricted_kernel/src/payload.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,11 @@ use goblin::{
use oak_restricted_kernel_interface::syscalls::{MmapFlags, MmapProtection};
use self_cell::self_cell;
use x86_64::{
structures::paging::{PageSize, Size2MiB},
structures::paging::{PageSize, PhysFrame, Size2MiB},
VirtAddr,
};

use crate::syscall::mmap::mmap;
use crate::{syscall::mmap::mmap, PROCCESSES};

// Set up the userspace stack at the end of the lower half of the virtual
// address space. Well... almost. It's one page lower than the very end, as
Expand Down Expand Up @@ -160,19 +160,21 @@ pub fn identify_pml4_frame(
}

pub struct Process {
pml4: x86_64::structures::paging::PageTable,
pml4_frame: PhysFrame,
entry: VirtAddr,
}

impl Process {
/// Creates a process from the application, without executing it.
/// Creates a process from the application, without executing it. Returns
/// the PID of the new process.
///
/// # Safety
///
/// The application must be built from a valid ELF file representing an Oak
/// Restricted Application.
pub unsafe fn from_application(application: &Application) -> Result<Self, anyhow::Error> {
pub unsafe fn from_application(application: &Application) -> Result<usize, anyhow::Error> {
let pml4 = crate::BASE_L4_PAGE_TABLE.get().context("base l4 table should be set")?.clone();
let pml4_frame: PhysFrame = identify_pml4_frame(&pml4)?;
Comment on lines 162 to +177
Copy link
Contributor Author

@jul-sh jul-sh Mar 25, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Storing the pml4_frame (instead of the rust struct it holds) in Process is the change to that brought us from failing as soon as the new application is being executed, to failing only once it attempts to allocate memory.

To recap, the prior logs had a confusing number of pml4 physical addresses:

# kernel loads the pml4 that is created as a process is created from an ELF file
[2024-03-19T20:55:26Z INFO  oak_launcher_utils::launcher] console: "kernel DEBUG: replacing current pml4 with: 0x0000000001075000"
# kernel switches back to the initial pml4, at the end of this function
[2024-03-19T20:55:26Z INFO  oak_launcher_utils::launcher] console: "kernel DEBUG: replacing current pml4 with: 0x0000000001200000"
[2024-03-19T20:55:26Z INFO  oak_launcher_utils::launcher] console: "kernel DEBUG: Created process (pid: 0)"
[2024-03-19T20:55:26Z INFO  oak_launcher_utils::launcher] console: "kernel DEBUG: Executing process (pid: 0)"
# Here the kernel again loaded the pml4 created in the first step, now to execute the application. Somehow this now is a different address. One would expect it to be 0x0000000001075000 
[2024-03-19T20:55:26Z INFO  oak_launcher_utils::launcher] console: "kernel DEBUG: replacing current pml4 with: 0x0000000001964000"

In this state this sequence would work for loading the orchestrator, but fail when it loads the application.

The change highlighted above fixed that. Now we get the expected sequence of logs:

[2024-03-25T19:08:24Z INFO  oak_launcher_utils::launcher] console: "kernel INFO: Writing new pml4 to Cr3: PhysFrame[4KiB](0x1075000)"
[2024-03-25T19:08:24Z INFO  oak_launcher_utils::launcher] console: "kernel INFO: Writing new pml4 to Cr3: PhysFrame[4KiB](0x1200000)"
[2024-03-25T19:08:24Z INFO  oak_launcher_utils::launcher] console: "kernel DEBUG: Created process (pid: 0)"
[2024-03-25T19:08:24Z INFO  oak_launcher_utils::launcher] console: "kernel DEBUG: Executing process (pid: 0)"
[2024-03-25T19:08:24Z INFO  oak_launcher_utils::launcher] console: "kernel INFO: Writing new pml4 to Cr3: PhysFrame[4KiB](0x1075000)"

It's not clear to me exactly why this led to different behavior. And either way, we still crash as soon as the enclave application attempts to allocate, as seen in the full logs:

[2024-03-25T19:08:24Z INFO  oak_launcher_utils::launcher] executing: Command { std: "/nix/store/hb3zh2dk3rxpsdy51ik52iwprfirsr7y-qemu-host-cpu-only-8.2.2/bin/qemu-system-x86_64" "-enable-kvm" "-cpu" "IvyBridge-IBRS,enforce" "-m" "8G" "-nodefaults" "-nographic" "-no-reboot" "-machine" "microvm,acpi=on" "-chardev" "socket,id=consock,fd=9" "-serial" "chardev:consock" "-chardev" "socket,id=commsock,fd=11" "-device" "virtio-serial-device,max_ports=1" "-device" "virtconsole,chardev=commsock" "-bios" "stage0_bin/target/x86_64-unknown-none/release/stage0_bin" "-kernel" "oak_restricted_kernel_wrapper/target/x86_64-unknown-none/release/oak_restricted_kernel_wrapper_bin" "-initrd" "enclave_apps/target/x86_64-unknown-none/release/oak_orchestrator", kill_on_drop: false }
[2024-03-25T19:08:24Z INFO  oak_launcher_utils::launcher] console: "stage0 INFO: starting..."
[2024-03-25T19:08:24Z INFO  oak_launcher_utils::launcher] console: "stage0 INFO: Enabled SEV features: SevStatus(0x0)"
[2024-03-25T19:08:24Z INFO  oak_launcher_utils::launcher] console: "stage0 DEBUG: early E820 entry: [0x0000000000000000-0x0000000000080000), len 524288, type RAM"
[2024-03-25T19:08:24Z INFO  oak_launcher_utils::launcher] console: "stage0 DEBUG: early E820 entry: [0x0000000000080000-0x00000000000a0000), len 131072, type ACPI"
[2024-03-25T19:08:24Z INFO  oak_launcher_utils::launcher] console: "stage0 DEBUG: early E820 entry: [0x0000000000100000-0x00000000c0000000), len 3220176896, type RAM"
[2024-03-25T19:08:24Z INFO  oak_launcher_utils::launcher] console: "stage0 DEBUG: early E820 entry: [0x00000000feffc000-0x00000000ff000000), len 16384, type RESERVED"
[2024-03-25T19:08:24Z INFO  oak_launcher_utils::launcher] console: "stage0 DEBUG: early E820 entry: [0x0000000100000000-0x0000000240000000), len 5368709120, type RAM"
[2024-03-25T19:08:24Z INFO  oak_launcher_utils::launcher] console: "stage0 DEBUG: Kernel cmdline: "
[2024-03-25T19:08:24Z INFO  oak_launcher_utils::launcher] console: "stage0 DEBUG: Kernel image size 3297440"
[2024-03-25T19:08:24Z INFO  oak_launcher_utils::launcher] console: "stage0 DEBUG: Kernel image start address 0x0000000002000000"
[2024-03-25T19:08:24Z INFO  oak_launcher_utils::launcher] console: "stage0 DEBUG: Kernel entry point 0x0000000002000200"
[2024-03-25T19:08:24Z INFO  oak_launcher_utils::launcher] console: "stage0 INFO: Using x2APIC for AP initialization."
[2024-03-25T19:08:24Z INFO  oak_launcher_utils::launcher] console: "stage0 DEBUG: Local APIC: ProcessorLocalApic { header: ControllerHeader { structure_type: 0, len: 8 }, processor_uid: 0, apic_id: 0, flags: LocalApicFlags(ENABLED) }"
[2024-03-25T19:08:24Z INFO  oak_launcher_utils::launcher] console: "stage0 DEBUG: uninteresting structure: 1"
[2024-03-25T19:08:24Z INFO  oak_launcher_utils::launcher] console: "stage0 DEBUG: uninteresting structure: 1"
[2024-03-25T19:08:24Z INFO  oak_launcher_utils::launcher] console: "stage0 DEBUG: uninteresting structure: 4"
[2024-03-25T19:08:24Z INFO  oak_launcher_utils::launcher] console: "stage0 INFO: Expected number of APs: 0, started number of APs: 0"
[2024-03-25T19:08:24Z INFO  oak_launcher_utils::launcher] console: "stage0 DEBUG: Initial RAM disk size 1434256"
[2024-03-25T19:08:24Z INFO  oak_launcher_utils::launcher] console: "stage0 DEBUG: Initial RAM disk address 0x000000003fea1000"
[2024-03-25T19:08:24Z INFO  oak_launcher_utils::launcher] console: "stage0 DEBUG: Kernel image digest: sha2-256:a5d5f252ae19644ca2aa0c7bc5acdf99d2d9d134ee21f150380d0d6bd1bfe4c7"
[2024-03-25T19:08:24Z INFO  oak_launcher_utils::launcher] console: "stage0 DEBUG: Kernel setup data digest: sha2-256:ebd71745942f79eec4687dd1c2773363cefa00c42d1578040e1150bfeb8ff3e1"
[2024-03-25T19:08:24Z INFO  oak_launcher_utils::launcher] console: "stage0 DEBUG: Kernel command-line: "
[2024-03-25T19:08:24Z INFO  oak_launcher_utils::launcher] console: "stage0 DEBUG: Initial RAM disk digest: sha2-256:e8491f147b64557b1d57a4edfbb2a1036f64e0e30c88977a4280978299ee90a0"
[2024-03-25T19:08:24Z INFO  oak_launcher_utils::launcher] console: "stage0 DEBUG: ACPI table generation digest: sha2-256:8460c6eaf5f2facb20bbb3ca639d9b5970f1e224f344b1dd3007e7aac34b80c1"
[2024-03-25T19:08:24Z INFO  oak_launcher_utils::launcher] console: "stage0 DEBUG: E820 table digest: sha2-256:7272421a29871fe5e8420f86ac4bdb7da92e5527d6bf5f1ba61b75a4280b3960"
[2024-03-25T19:08:24Z INFO  oak_launcher_utils::launcher] console: "stage0 INFO: jumping to kernel at 0x0000000002000200"
[2024-03-25T19:08:24Z INFO  oak_launcher_utils::launcher] console: "kernel INFO: Logging initialised."
[2024-03-25T19:08:24Z INFO  oak_launcher_utils::launcher] console: "kernel INFO: Kernel boot args: --oak-dice=0x16000"
[2024-03-25T19:08:24Z INFO  oak_launcher_utils::launcher] console: "kernel INFO: Boot protocol:  Linux Boot Protocol"
[2024-03-25T19:08:24Z INFO  oak_launcher_utils::launcher] console: "kernel INFO: E820 entry: [0x0000000000000000..0x0000000000016000) (90112), type RAM"
[2024-03-25T19:08:24Z INFO  oak_launcher_utils::launcher] console: "kernel INFO: E820 entry: [0x0000000000016000..0x0000000000017000) (4096), type RESERVED"
[2024-03-25T19:08:24Z INFO  oak_launcher_utils::launcher] console: "kernel INFO: E820 entry: [0x0000000000017000..0x0000000000080000) (430080), type RAM"
[2024-03-25T19:08:24Z INFO  oak_launcher_utils::launcher] console: "kernel INFO: E820 entry: [0x0000000000080000..0x00000000000a0000) (131072), type ACPI"
[2024-03-25T19:08:24Z INFO  oak_launcher_utils::launcher] console: "kernel INFO: E820 entry: [0x0000000000100000..0x00000000c0000000) (3220176896), type RAM"
[2024-03-25T19:08:24Z INFO  oak_launcher_utils::launcher] console: "kernel INFO: E820 entry: [0x00000000feffc000..0x00000000ff000000) (16384), type RESERVED"
[2024-03-25T19:08:24Z INFO  oak_launcher_utils::launcher] console: "kernel INFO: E820 entry: [0x0000000100000000..0x0000000240000000) (5368709120), type RAM"
[2024-03-25T19:08:24Z INFO  oak_launcher_utils::launcher] console: "kernel INFO: marking [0x0000000000200000..0x0000000000400000) as reserved"
[2024-03-25T19:08:24Z INFO  oak_launcher_utils::launcher] console: "kernel INFO: marking [0x0000000000200000..0x0000000000400000) as reserved"
[2024-03-25T19:08:24Z INFO  oak_launcher_utils::launcher] console: "kernel INFO: marking [0x0000000000400000..0x0000000000600000) as reserved"
[2024-03-25T19:08:24Z INFO  oak_launcher_utils::launcher] console: "kernel INFO: marking [0x0000000000600000..0x0000000000800000) as reserved"
[2024-03-25T19:08:24Z INFO  oak_launcher_utils::launcher] console: "kernel INFO: marking [0x0000000000800000..0x0000000000a00000) as reserved"
[2024-03-25T19:08:24Z INFO  oak_launcher_utils::launcher] console: "kernel INFO: marking [0x0000000000a00000..0x0000000001200000) as reserved"
[2024-03-25T19:08:24Z INFO  oak_launcher_utils::launcher] console: "kernel INFO: marking [0x000000003fe00000..0x0000000040000000) as reserved (ramdisk)"
[2024-03-25T19:08:24Z INFO  oak_launcher_utils::launcher] console: "kernel INFO: Writing new pml4 to Cr3: PhysFrame[4KiB](0x1200000)"
[2024-03-25T19:08:24Z INFO  oak_launcher_utils::launcher] console: "kernel INFO: Marking [0xffff880001400000..0xffff880001800000) for guest-host communication."
[2024-03-25T19:08:24Z INFO  oak_launcher_utils::launcher] console: "kernel DEBUG: Extending kernel heap to [0xffffc90000000000..0xffffc90000200000)."
[2024-03-25T19:08:24Z INFO  oak_launcher_utils::launcher] console: "kernel INFO: ACPI device: \\_SB_.COM1 PNP0501 16550A-compatible COM Serial Port"
[2024-03-25T19:08:24Z INFO  oak_launcher_utils::launcher] console: "kernel INFO:   IO port: IOPortDescriptor { decodes_full_address: true, memory_range: (1016, 1016), base_alignment: 0, range_length: 8 }"
[2024-03-25T19:08:24Z INFO  oak_launcher_utils::launcher] console: "kernel INFO:   IRQ: 16"
[2024-03-25T19:08:24Z INFO  oak_launcher_utils::launcher] console: "kernel INFO: ACPI device: \\_SB_.FWCF QEMU0002 QEMU fw_cfg Device"
[2024-03-25T19:08:24Z INFO  oak_launcher_utils::launcher] console: "kernel INFO:   IO port: IOPortDescriptor { decodes_full_address: true, memory_range: (1296, 1296), base_alignment: 1, range_length: 12 }"
[2024-03-25T19:08:24Z INFO  oak_launcher_utils::launcher] console: "kernel INFO: ACPI device: \\_SB_.GED_ ACPI0013 ACPI Generic Event Device"
[2024-03-25T19:08:24Z INFO  oak_launcher_utils::launcher] console: "kernel INFO:   IRQ: 9"
[2024-03-25T19:08:24Z INFO  oak_launcher_utils::launcher] console: "kernel INFO: ACPI device: \\_SB_.PWRB PNP0C0C Power Button Device"
[2024-03-25T19:08:24Z INFO  oak_launcher_utils::launcher] console: "kernel INFO: ACPI device: \\_SB_.VR23 LNRO0005 Memory-mapped virtio device bus"
[2024-03-25T19:08:24Z INFO  oak_launcher_utils::launcher] console: "kernel INFO:   Memory range: [0x00000000feb02e00..0x00000000feb03000)"
[2024-03-25T19:08:24Z INFO  oak_launcher_utils::launcher] console: "kernel INFO:   IRQ: 47"
[2024-03-25T19:08:24Z INFO  oak_launcher_utils::launcher] console: "kernel INFO: Using virtio console over MMIO; ACPI device name \\_SB_.VR23, vendor ID: 554d4551"
[2024-03-25T19:08:24Z INFO  oak_launcher_utils::launcher] console: "kernel DEBUG: Device features: Features(EMERG_WRITE | NOTIFY_ON_EMPTY | ANY_LAYOUT | RING_INDIRECT_DESC | RING_EVENT_IDX)"
[2024-03-25T19:08:24Z INFO  oak_launcher_utils::launcher] console: "kernel INFO: Copying application from ramdisk..."
[2024-03-25T19:08:24Z INFO  oak_launcher_utils::launcher] console: "kernel INFO: marking [0x000000003fe00000..0x0000000040000000) as available"
[2024-03-25T19:08:24Z INFO  oak_launcher_utils::launcher] console: "kernel INFO: Binary loaded, size: 1434256"
[2024-03-25T19:08:24Z INFO  oak_launcher_utils::launcher] console: "kernel INFO: Writing new pml4 to Cr3: PhysFrame[4KiB](0x1075000)"
[2024-03-25T19:08:24Z INFO  oak_launcher_utils::launcher] console: "kernel INFO: Writing new pml4 to Cr3: PhysFrame[4KiB](0x1200000)"
[2024-03-25T19:08:24Z INFO  oak_launcher_utils::launcher] console: "kernel DEBUG: Created process (pid: 0)"
[2024-03-25T19:08:24Z INFO  oak_launcher_utils::launcher] console: "kernel DEBUG: Executing process (pid: 0)"
[2024-03-25T19:08:24Z INFO  oak_launcher_utils::launcher] console: "kernel INFO: Writing new pml4 to Cr3: PhysFrame[4KiB](0x1075000)"
[2024-03-25T19:08:25Z INFO  oak_launcher_utils::launcher] console: "orchestrator INFO: Binary loaded, size: 1020272"
[2024-03-25T19:08:25Z INFO  oak_launcher_utils::launcher] console: "orchestrator INFO: Application digest (sha2-256): 90af89d0dcd5cd971b942b4743422fbe6ea3ee84a8b8cbe676ee6fb9a6df6c40"
[2024-03-25T19:08:25Z INFO  oak_launcher_utils::launcher] connecting to guest instance
[2024-03-25T19:08:25Z INFO  oak_launcher_utils::launcher] waiting for guest instance to terminate
[2024-03-25T19:08:25Z INFO  oak_launcher_utils::launcher] console: "kernel DEBUG: Extending kernel heap to [0xffffc90000000000..0xffffc90000400000)."
[2024-03-25T19:08:25Z INFO  oak_launcher_utils::launcher] console: "kernel INFO: Writing new pml4 to Cr3: PhysFrame[4KiB](0x1ffd000)"
[2024-03-25T19:08:25Z INFO  oak_launcher_utils::launcher] console: "kernel INFO: Writing new pml4 to Cr3: PhysFrame[4KiB](0x1075000)"
[2024-03-25T19:08:25Z INFO  oak_launcher_utils::launcher] console: "kernel DEBUG: Created process (pid: 1)"
[2024-03-25T19:08:25Z INFO  oak_launcher_utils::launcher] console: "orchestrator INFO: created application with pid: 1"
[2024-03-25T19:08:25Z INFO  oak_launcher_utils::launcher] console: "kernel DEBUG: Switching to a different process (pid: 1)"
[2024-03-25T19:08:25Z INFO  oak_launcher_utils::launcher] console: "kernel DEBUG: Executing process (pid: 1)"
[2024-03-25T19:08:25Z INFO  oak_launcher_utils::launcher] console: "kernel INFO: Writing new pml4 to Cr3: PhysFrame[4KiB](0x1ffd000)"
[2024-03-25T19:08:25Z INFO  oak_launcher_utils::launcher] console: "INFO: In main!"
[2024-03-25T19:08:25Z INFO  oak_launcher_utils::launcher] console: "INFO: about to allocate bytes"
[2024-03-25T19:08:25Z ERROR oak_restricted_kernel_launcher] Unexpected VMM exit, status: Ok(ExitStatus(unix_wait_status(0)))

@conradgrobler @andrisaar can you help debug? I'm pretty much at my wits end

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Command to obtain the logs is

just stage0_bin oak_restricted_kernel_wrapper oak_orchestrator oak_echo_raw_enclave_app && RUST_LOG=DEBUG cargo run --package=oak_restricted_kernel_launcher -- --kernel=oak_restricted_kernel_wrapper/target/x86_64-unknown-none/release/oak_restricted_kernel_wrapper_bin --vmm-binary=$(which qemu-system-x86_64) --memory-size=8G --bios-binary=stage0_bin/target/x86_64-unknown-none/release/stage0_bin --initrd=enclave_apps/target/x86_64-unknown-none/release/oak_orchestrator --app-binary=enclave_apps/target/x86_64-unknown-none/release/oak_echo_raw_enclave_app

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also backported just this change onto main, where it results in the same behavior: panic upon allocating in the enclave application (though strangely not in the orchestrator)

#4957

// Load the process's page table, so the application can be loaded into its
// memory. Hold onto the previous PT, so we can revert to it once the
// application has been mapped into the process pt.
Expand All @@ -198,17 +200,15 @@ impl Process {
// Safety: the new page table maintains the same mappings for kernel space.
unsafe { crate::PAGE_TABLES.lock().replace(pml4_frame) };
}

Ok(Self { pml4, entry })
let pid = PROCCESSES.add(Self { pml4_frame, entry });
Ok(pid)
}
/// Executes the process.
pub fn execute(&self) -> ! {
let pml4_frame = identify_pml4_frame(&self.pml4).expect("could not get pml4 frame");
// Safety: the new page table maintains the same mappings for kernel space.
unsafe { crate::PAGE_TABLES.lock().replace(pml4_frame) };
unsafe { crate::PAGE_TABLES.lock().replace(self.pml4_frame) };

let entry = self.entry;
log::info!("Running application");
// Enter Ring 3 and jump to user code.
// Safety: by now, if we're here, we've loaded a valid ELF file. It's up to the
// user to guarantee that the file made sense.
Expand Down
49 changes: 49 additions & 0 deletions oak_restricted_kernel/src/syscall/create_process.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
//
// Copyright 2024 The Project Oak Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

use core::{
ffi::{c_size_t, c_ssize_t, c_void},
slice,
};

use oak_restricted_kernel_interface::Errno;

use crate::payload::Process;

pub fn syscall_unstable_create_proccess(buf: *mut c_void, count: c_size_t) -> c_ssize_t {
// We should validate that the pointer and count are valid, as these come from
// userspace and therefore are not to be trusted, but right now everything
// is in kernel space so there is nothing to check.
let elf_binary_buffer = unsafe { slice::from_raw_parts(buf as *mut u8, count) };
match unstable_create_proccess(elf_binary_buffer) {
Ok(pid) => pid.try_into().expect("pid so large, it could not be represented as isize"),
Err(err) => err as isize,
}
}

fn unstable_create_proccess(buf: &[u8]) -> Result<usize, Errno> {
// Copy the ELF file into kernel space.
let copied_elf_binary: alloc::vec::Vec<u8> = buf.to_vec();

let application = crate::payload::Application::new(copied_elf_binary.into_boxed_slice())
.inspect_err(|err| log::error!("failed to create application: {:?}", err))
.map_err(|_| Errno::EINVAL)?;

Ok(
// Safety: application is assumed to be a valid ELF file.
unsafe { Process::from_application(&application).expect("failed to create process") },
)
}
15 changes: 12 additions & 3 deletions oak_restricted_kernel/src/syscall/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ pub mod mmap;
mod process;
mod stdio;

#[cfg(feature = "initrd")]
mod create_process;
#[cfg(feature = "initrd")]
mod switch_process;

Expand All @@ -44,7 +46,10 @@ use x86_64::{
};

#[cfg(feature = "initrd")]
use self::switch_process::syscall_unstable_switch_proccess;
use self::{
create_process::syscall_unstable_create_proccess,
switch_process::syscall_unstable_switch_proccess,
};
use self::{
fd::{syscall_fsync, syscall_read, syscall_write},
mmap::syscall_mmap,
Expand Down Expand Up @@ -131,9 +136,13 @@ extern "sysv64" fn syscall_handler(
}
Some(Syscall::Fsync) => syscall_fsync(arg1 as i32),
#[cfg(feature = "initrd")]
Some(Syscall::UnstableSwitchProcess) => {
syscall_unstable_switch_proccess(arg1 as *mut c_void, arg2)
Some(Syscall::UnstableCreateProcess) => {
syscall_unstable_create_proccess(arg1 as *mut c_void, arg2)
}
#[cfg(feature = "initrd")]
Some(Syscall::UnstableSwitchProcess) => syscall_unstable_switch_proccess(arg1),
#[cfg(not(feature = "initrd"))]
Some(Syscall::UnstableCreateProcess) => Errno::ENOSYS as isize,
#[cfg(not(feature = "initrd"))]
Some(Syscall::UnstableSwitchProcess) => Errno::ENOSYS as isize,
None => Errno::ENOSYS as isize,
Expand Down
30 changes: 4 additions & 26 deletions oak_restricted_kernel/src/syscall/switch_process.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,31 +14,9 @@
// limitations under the License.
//

use alloc::boxed::Box;
use core::{
ffi::{c_size_t, c_void},
slice,
};
use core::ffi::c_size_t;

use crate::payload::Process;

pub fn syscall_unstable_switch_proccess(buf: *mut c_void, count: c_size_t) -> ! {
// We should validate that the pointer and count are valid, as these come from
// userspace and therefore are not to be trusted, but right now everything
// is in kernel space so there is nothing to check.
let elf_binary_buffer = unsafe { slice::from_raw_parts(buf as *mut u8, count) };

// Copy the ELF file into kernel space.
let copied_elf_binary = elf_binary_buffer.to_vec();

let application = crate::payload::Application::new(copied_elf_binary.into_boxed_slice())
.expect("failed to parse application");

// Ensure the new process is not dropped.
let process = Box::leak(Box::new(
// Safety: application is assumed to be a valid ELF file.
unsafe { Process::from_application(&application).expect("failed to create process") },
));

process.execute()
pub fn syscall_unstable_switch_proccess(pid: c_size_t) -> ! {
log::debug!("Switching to a different process (pid: {})", pid);
crate::PROCCESSES.execute(pid)
}
24 changes: 20 additions & 4 deletions oak_restricted_kernel_interface/src/syscall.rs
Original file line number Diff line number Diff line change
Expand Up @@ -121,12 +121,28 @@ pub fn exit(status: i32) -> ! {
}

#[no_mangle]
pub extern "C" fn sys_unstable_switch_proccess(buf: *const c_void, count: c_size_t) {
unsafe { syscall!(Syscall::UnstableSwitchProcess, buf, count) };
pub extern "C" fn sys_unstable_create_proccess(buf: *const c_void, count: c_size_t) -> c_ssize_t {
unsafe { syscall!(Syscall::UnstableCreateProcess, buf, count) }
}

pub fn unstable_switch_proccess(buf: &[u8]) -> ! {
sys_unstable_switch_proccess(buf.as_ptr() as *const c_void, buf.len());
pub fn unstable_create_proccess(buf: &[u8]) -> Result<usize, Errno> {
let ret = sys_unstable_create_proccess(buf.as_ptr() as *const c_void, buf.len());
if ret <= 0 {
Err(Errno::from_repr(ret).unwrap_or_else(|| {
panic!("unexpected error from unstable_create_proccess syscall: {}", ret)
}))
} else {
Ok(ret.try_into().expect("pid could not be represented as isize"))
}
}

#[no_mangle]
pub extern "C" fn sys_unstable_switch_proccess(pid: c_size_t) {
unsafe { syscall!(Syscall::UnstableSwitchProcess, pid) };
}

pub fn unstable_switch_proccess(pid: usize) -> ! {
sys_unstable_switch_proccess(pid);
unreachable!();
}

Expand Down
13 changes: 11 additions & 2 deletions oak_restricted_kernel_interface/src/syscalls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,13 +96,22 @@ pub enum Syscall {
/// a value of <errno::Errno> on failure; 0, otherwise.
Fsync = 74,

/// Terminates the calling process and executes the supplied ELF binary
/// instead.
/// Create new process from ELF file, without starting it.
///
/// Arguments:
/// - arg0 (*mut c_void): pointer to the a buffer holding an ELF file
/// - arg1 (c_size_t): size of the buffer
/// Returns:
/// a value of <errno::Errno> on failure; Otherwise the PID of the new
/// process.
UnstableCreateProcess = UNSTABLE_SYSCALL_SPACE,

/// Switch the active execution execution to the process with the provided
/// PID.
///
/// Arguments:
/// - arg0 (c_size_t): PID of the process.
/// Returns:
/// a value of <errno::Errno> on failure; 0, otherwise.
UnstableSwitchProcess = UNSTABLE_SYSCALL_SPACE + 1,
}
Expand Down
2 changes: 1 addition & 1 deletion oak_restricted_kernel_launcher/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ must be built.

```shell
# Stage0, the restricted kernel, and an enclave app may be built like so:
just stage0_bin oak_restricted_kernel_wrapper oak_orchestrator && \
just stage0_bin oak_restricted_kernel_wrapper oak_orchestrator oak_echo_raw_enclave_app && \

# After building dependencies, an enclave app may be run like so:
RUST_LOG=DEBUG \
Expand Down
Loading