Skip to content

Commit 982cbf8

Browse files
committed
nitro: Use cached EIF file if none configured
With the underlying application decoupled from the EIF file, create and cache a stock EIF file that can be used to run enclaves with. Applications that want to run "standard" containzerized applications can now do so without specifying an EIF file. Update the nitro example to not require an EIF file. Signed-off-by: Tyler Fanelli <[email protected]>
1 parent d838a0a commit 982cbf8

File tree

9 files changed

+63
-52
lines changed

9 files changed

+63
-52
lines changed

Cargo.lock

Lines changed: 16 additions & 8 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

examples/nitro

210 KB
Binary file not shown.

examples/nitro.c

Lines changed: 7 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@ static void print_help(char *const name)
3434
"OPTIONS: \n"
3535
" -h --help Show help\n"
3636
"\n"
37-
"ENCLAVE_IMAGE: The enclave image to run\n"
3837
"NEWROOT: The root directory of the VM\n"
3938
"NVCPUS: The amount of vCPUs for running the enclave\n"
4039
"RAM_MIB: The amount of RAM (MiB) allocated for enclave\n",
@@ -49,7 +48,6 @@ static const struct option long_options[] = {
4948

5049
struct cmdline {
5150
bool show_help;
52-
const char *eif_path;
5351
const char *new_root;
5452
unsigned int nvcpus;
5553
unsigned int ram_mib;
@@ -64,7 +62,6 @@ bool parse_cmdline(int argc, char *const argv[], struct cmdline *cmdline)
6462
// set the defaults
6563
*cmdline = (struct cmdline){
6664
.show_help = false,
67-
.eif_path = NULL,
6865
};
6966

7067
// the '+' in optstring is a GNU extension that disables permutating argv
@@ -81,22 +78,19 @@ bool parse_cmdline(int argc, char *const argv[], struct cmdline *cmdline)
8178
}
8279
}
8380

84-
if (optind < argc - 3) {
85-
cmdline->eif_path = argv[optind];
86-
cmdline->new_root = argv[optind + 1];
87-
cmdline->nvcpus = strtoul(argv[optind + 2], NULL, 10);
88-
cmdline->ram_mib = strtoul(argv[optind + 3], NULL, 10);
81+
if (optind < argc - 2) {
82+
cmdline->new_root = argv[optind];
83+
cmdline->nvcpus = strtoul(argv[optind + 1], NULL, 10);
84+
cmdline->ram_mib = strtoul(argv[optind + 2], NULL, 10);
8985
return true;
9086
}
9187

92-
if (optind >= argc - 3)
93-
fprintf(stderr, "Missing RAM_MIB argument\n");
9488
if (optind >= argc - 2)
95-
fprintf(stderr, "Missing VCPUS argument\n");
89+
fprintf(stderr, "Missing RAM_MIB argument\n");
9690
if (optind >= argc - 1)
97-
fprintf(stderr, "Missing NEWROOT argument\n");
91+
fprintf(stderr, "Missing VCPUS argument\n");
9892
if (optind == argc)
99-
fprintf(stderr, "Missing ENCLAVE_IMAGE argument\n");
93+
fprintf(stderr, "Missing NEWROOT argument\n");
10094

10195
return false;
10296
}
@@ -197,15 +191,6 @@ int main(int argc, char *const argv[])
197191
return -1;
198192
}
199193

200-
// Set the nitro enclave image specified on the command line.
201-
if (err = krun_nitro_set_image(ctx_id, cmdline.eif_path,
202-
KRUN_NITRO_IMG_TYPE_EIF)) {
203-
errno = -err;
204-
perror("Error configuring nitro enclave image");
205-
return -1;
206-
207-
}
208-
209194
// Configure the nitro enclave to run in debug mode.
210195
if (err = krun_nitro_set_start_flags(ctx_id, KRUN_NITRO_START_FLAG_DEBUG)) {
211196
errno = -err;

examples/test_data/hello.eif

-14.7 MB
Binary file not shown.

src/libkrun/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ hvf = { path = "../hvf" }
4141
kvm-bindings = { version = ">=0.11", features = ["fam-wrappers"] }
4242
kvm-ioctls = ">=0.21"
4343
nitro = { path = "../nitro", optional = true }
44-
nitro-enclaves = { version = "0.3.0", optional = true }
44+
nitro-enclaves = { version = "0.5.0", optional = true }
4545
vm-memory = { version = ">=0.13", features = ["backend-mmap"] }
4646

4747
[lib]

src/libkrun/src/lib.rs

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -363,16 +363,6 @@ impl TryFrom<ContextConfig> for NitroEnclave {
363363
return Err(-libc::EINVAL);
364364
};
365365

366-
let Some(image_path) = ctx.nitro_image_path else {
367-
error!("nitro image not configured");
368-
return Err(-libc::EINVAL);
369-
};
370-
371-
let Ok(image) = File::open(&image_path) else {
372-
error!("unable to open {}", image_path.display());
373-
return Err(-libc::EINVAL);
374-
};
375-
376366
let rootfs = {
377367
if ctx.vmr.fs.len() != 1 {
378368
error!("one rootfs path required");
@@ -407,7 +397,7 @@ impl TryFrom<ContextConfig> for NitroEnclave {
407397
};
408398

409399
Ok(Self {
410-
image,
400+
_image_path: ctx.nitro_image_path,
411401
mem_size_mib,
412402
vcpus,
413403
rootfs,

src/nitro/Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,11 @@ edition = "2021"
77
nitro = []
88

99
[dependencies]
10+
flate2 = "1.1.5"
1011
libc = "0.2.171"
1112
nix = { version = "0.30.1", features = ["ioctl", "poll"] }
1213
tar = "0.4.44"
1314
vsock = "0.5.1"
1415

1516
[target.'cfg(target_os = "linux")'.dependencies]
16-
nitro-enclaves = "0.3.0"
17+
nitro-enclaves = "0.5.0"

src/nitro/src/enclaves.rs

Lines changed: 36 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// SPDX-License-Identifier: Apache-2.0
22

33
use super::error::NitroError;
4+
use flate2::read::GzDecoder;
45
use libc::c_int;
56
use nitro_enclaves::{
67
launch::{ImageType, Launcher, MemoryInfo, PollTimeout, StartFlags},
@@ -9,16 +10,19 @@ use nitro_enclaves::{
910
use nix::poll::{poll, PollFd, PollFlags, PollTimeout as NixPollTimeout};
1011
use std::{
1112
ffi::CString,
12-
fs::File,
1313
io::{Read, Write},
1414
os::fd::AsFd,
1515
path::PathBuf,
1616
str::FromStr,
1717
};
18+
use tar::Archive;
1819
use vsock::{VsockAddr, VsockListener, VsockStream};
1920

2021
type Result<T> = std::result::Result<T, NitroError>;
2122

23+
const KRUN_NITRO_EIF_TAR: &[u8] = include_bytes!("runtime-data/eif.tar.gz");
24+
const KRUN_NITRO_EIF_FILE_NAME: &str = "krun-nitro.eif";
25+
2226
const ENCLAVE_READY_VSOCK_PORT: u32 = 9000;
2327

2428
const VMADDR_CID_PARENT: u32 = 3;
@@ -27,8 +31,9 @@ const HEART_BEAT: u8 = 0xb7;
2731

2832
/// Nitro Enclave data.
2933
pub struct NitroEnclave {
30-
/// Enclave image.
31-
pub image: File,
34+
/// Path to configurable enclave image. Will default to KRUN_NITRO_ENCLAVE_EIF if one external
35+
/// enclave provided.
36+
pub _image_path: Option<PathBuf>,
3237
/// Amount of RAM (in MiB).
3338
pub mem_size_mib: usize,
3439
/// Number of vCPUs.
@@ -93,12 +98,12 @@ impl NitroEnclave {
9398
Ok(())
9499
}
95100

96-
fn launch(&mut self) -> Result<u32> {
101+
fn launch(&mut self, eif: &[u8]) -> Result<u32> {
97102
let device = Device::open().map_err(NitroError::DeviceOpen)?;
98103

99104
let mut launcher = Launcher::new(&device).map_err(NitroError::VmCreate)?;
100105

101-
let mem = MemoryInfo::new(ImageType::Eif(&mut self.image), self.mem_size_mib);
106+
let mem = MemoryInfo::new(ImageType::Eif(eif), self.mem_size_mib);
102107
launcher.set_memory(mem).map_err(NitroError::VmMemorySet)?;
103108

104109
for _ in 0..self.vcpus {
@@ -112,8 +117,8 @@ impl NitroEnclave {
112117
Ok(cid.try_into().unwrap()) // Safe to unwrap.
113118
}
114119

115-
fn poll(&self, listener: &VsockListener) -> Result<()> {
116-
let poll_timeout = PollTimeout::try_from((&self.image, self.mem_size_mib << 20))
120+
fn poll(&self, listener: &VsockListener, eif: &[u8]) -> Result<()> {
121+
let poll_timeout = PollTimeout::try_from((eif, self.mem_size_mib << 20))
117122
.map_err(NitroError::PollTimeoutCalculate)?;
118123

119124
let mut poll_fds = [PollFd::new(listener.as_fd(), PollFlags::POLLIN)];
@@ -136,9 +141,10 @@ impl NitroEnclave {
136141
fn start(&mut self) -> Result<(u32, VsockStream)> {
137142
let sockaddr = VsockAddr::new(VMADDR_CID_PARENT, ENCLAVE_READY_VSOCK_PORT);
138143
let listener = VsockListener::bind(&sockaddr).map_err(NitroError::HeartbeatBind)?;
144+
let eif = eif()?;
139145

140-
let cid = self.launch()?;
141-
self.poll(&listener)?;
146+
let cid = self.launch(&eif)?;
147+
self.poll(&listener, &eif)?;
142148

143149
let mut stream = listener.accept().map_err(NitroError::HeartbeatAccept)?;
144150

@@ -205,3 +211,24 @@ fn vsock_write_bytes(bytes: &[u8], stream: &mut VsockStream) -> Result<()> {
205211

206212
Ok(())
207213
}
214+
215+
fn eif() -> Result<Vec<u8>> {
216+
let gz = GzDecoder::new(KRUN_NITRO_EIF_TAR);
217+
let mut archive = Archive::new(gz);
218+
219+
let mut buf = Vec::new();
220+
221+
for entry_result in archive.entries().unwrap() {
222+
let mut entry = entry_result.unwrap();
223+
224+
let path = entry.path().unwrap();
225+
let path_str = path.to_string_lossy();
226+
227+
if path_str == KRUN_NITRO_EIF_FILE_NAME {
228+
entry.read_to_end(&mut buf).unwrap();
229+
break;
230+
}
231+
}
232+
233+
Ok(buf)
234+
}
61.2 MB
Binary file not shown.

0 commit comments

Comments
 (0)