Skip to content

Commit 2bdbf32

Browse files
committed
nitro: Write rootfs tar archive to enclave
Use krun to write the archived rootfs over vsock to the enclave. The enclave will read the archive over vsock and extract the rootfs from it. Signed-off-by: Tyler Fanelli <tfanelli@redhat.com>
1 parent 80fe4b0 commit 2bdbf32

5 files changed

Lines changed: 240 additions & 9 deletions

File tree

init/nitro/main.c

Lines changed: 61 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,11 @@
44
#include <errno.h>
55
#include <fcntl.h>
66
#include <signal.h>
7+
#include <stddef.h>
78
#include <stdint.h>
89
#include <stdio.h>
910
#include <stdlib.h>
11+
#include <string.h>
1012
#include <unistd.h>
1113
#include <sys/mount.h>
1214
#include <sys/reboot.h>
@@ -16,6 +18,8 @@
1618
#include <sys/syscall.h>
1719
#include <linux/vm_sockets.h>
1820

21+
#include "rootfs_archive.h"
22+
1923
#define finit_module(fd, param_values, flags) (int)syscall(__NR_finit_module, fd, param_values, flags)
2024

2125
#define HEART_BEAT 0xb7
@@ -177,32 +181,74 @@ krun_signal()
177181
// communication is established.
178182
ret = write(sock_fd, buf, 1);
179183
if (ret != 1) {
184+
close(sock_fd);
180185
perror("vsock write");
181186
return -errno;
182187
}
183188

184189
ret = read(sock_fd, buf, 1);
185190
if (ret != 1) {
191+
close(sock_fd);
186192
perror("vsock read");
187193
return -errno;
188194
}
189195

190-
if (buf[0] != HEART_BEAT)
196+
if (buf[0] != HEART_BEAT) {
197+
close(sock_fd);
191198
return -1;
199+
}
192200

193-
ret = close(sock_fd);
194-
if (ret < 0) {
195-
perror("vsock close");
196-
return -errno;
201+
return sock_fd;
202+
}
203+
204+
int
205+
rootfs_rcv(int sock_fd, void **buf_ptr, size_t *size)
206+
{
207+
uint8_t len_b[8], *rootfs_archive;
208+
ssize_t read_len;
209+
uint64_t len, idx = 0;
210+
211+
read_len = read(sock_fd, len_b, 8);
212+
if (read_len < 8) {
213+
close(sock_fd);
214+
perror("vsock rootfs archive length read");
215+
return -1;
216+
}
217+
218+
memcpy(&len, len_b, sizeof(uint64_t));
219+
220+
*size = len;
221+
222+
rootfs_archive = (uint8_t *) malloc(len);
223+
if (rootfs_archive == NULL) {
224+
close(sock_fd);
225+
perror("rootfs archive malloc");
226+
return -1;
227+
}
228+
229+
while (len) {
230+
read_len = read(sock_fd, &rootfs_archive[idx], len);
231+
if (read_len <= 0) {
232+
close(sock_fd);
233+
free((void *) rootfs_archive);
234+
perror("vsock rootfs archive read");
235+
return -1;
236+
}
237+
idx += read_len;
238+
len -= read_len;
197239
}
198240

241+
*buf_ptr = (void *) rootfs_archive;
242+
199243
return 0;
200244
}
201245

202246
int
203247
main(int argc, char *argv[])
204248
{
205-
int ret;
249+
void *rootfs_archive;
250+
size_t archive_size;
251+
int ret, sock_fd;
206252

207253
// Block all signals.
208254
ret = sig_mask(SIG_BLOCK);
@@ -219,7 +265,15 @@ main(int argc, char *argv[])
219265
if (ret < 0)
220266
exit(ret);
221267

222-
ret = krun_signal();
268+
sock_fd = krun_signal();
269+
if (sock_fd < 0)
270+
exit(ret);
271+
272+
ret = rootfs_rcv(sock_fd, &rootfs_archive, &archive_size);
273+
if (ret < 0)
274+
exit(ret);
275+
276+
ret = archive_extract(rootfs_archive, archive_size);
223277
if (ret < 0)
224278
exit(ret);
225279

init/nitro/rootfs_archive.c

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
3+
#include <stddef.h>
4+
#include <stdlib.h>
5+
6+
#include <archive.h>
7+
#include <archive_entry.h>
8+
9+
#include "rootfs_archive.h"
10+
11+
static
12+
struct archive *
13+
reader_init(void *buf, size_t size)
14+
{
15+
struct archive *r;
16+
int ret;
17+
18+
r = archive_read_new();
19+
if (r == NULL) {
20+
printf("init reader failed\n");
21+
return NULL;
22+
}
23+
24+
ret = archive_read_support_format_tar(r);
25+
if (ret != ARCHIVE_OK) {
26+
printf("reader cannot support tar format\n");
27+
return NULL;
28+
}
29+
30+
ret = archive_read_open_memory(r, buf, size);
31+
if (ret != ARCHIVE_OK) {
32+
printf("reader cannot open file\ncause: %s\n", archive_error_string(r));
33+
return NULL;
34+
}
35+
36+
return r;
37+
}
38+
39+
static
40+
struct archive *
41+
writer_init()
42+
{
43+
struct archive *w;
44+
int ret;
45+
46+
w = archive_write_disk_new();
47+
if (w == NULL) {
48+
printf("init writer failed\n");
49+
return NULL;
50+
}
51+
52+
ret = archive_write_disk_set_options(w, ARCHIVE_EXTRACT_TIME);
53+
if (ret < 0) {
54+
printf("error setting writer disk options\n");
55+
return NULL;
56+
}
57+
58+
return w;
59+
}
60+
61+
static
62+
int
63+
extract(struct archive *r, struct archive *w)
64+
{
65+
struct archive_entry *entry;
66+
const void *buf;
67+
int64_t offset;
68+
size_t size;
69+
int ret;
70+
71+
while ((ret = archive_read_next_header(r, &entry)) != ARCHIVE_EOF) {
72+
if (ret != ARCHIVE_OK) {
73+
printf("error reading archive entry\ncause: %s\n", archive_error_string(r));
74+
return -1;
75+
}
76+
77+
ret = archive_write_header(w, entry);
78+
if (ret != ARCHIVE_OK) {
79+
printf("error writing %s entry\ncause: %s\n", archive_entry_pathname(entry), archive_error_string(w));
80+
return -1;
81+
}
82+
83+
while ((ret = archive_read_data_block(r, &buf, &size, &offset)) != ARCHIVE_EOF) {
84+
if (ret != ARCHIVE_OK) {
85+
printf("error reading archive data block\ncause: %s\n", archive_error_string(r));
86+
return -1;
87+
}
88+
89+
ret = archive_write_data_block(w, buf, size, offset);
90+
if (ret != ARCHIVE_OK) {
91+
printf("error writing archive data block\ncause: %s\n", archive_error_string(w));
92+
return -1;
93+
}
94+
}
95+
96+
ret = archive_write_finish_entry(w);
97+
if (ret != ARCHIVE_OK) {
98+
printf("error finishing %s entry\ncause: %s\n", archive_entry_pathname(entry), archive_error_string(w));
99+
return -1;
100+
}
101+
}
102+
103+
return 0;
104+
}
105+
106+
static
107+
void
108+
archive_cleanup(struct archive *r, struct archive *w)
109+
{
110+
archive_read_close(r);
111+
archive_read_free(r);
112+
113+
archive_write_close(w);
114+
archive_write_free(w);
115+
}
116+
117+
int
118+
archive_extract(void *buf, size_t size)
119+
{
120+
struct archive *reader, *writer;
121+
int ret;
122+
123+
reader = reader_init(buf, size);
124+
if (reader == NULL)
125+
return -1;
126+
127+
writer = writer_init();
128+
if (writer == NULL)
129+
return -1;
130+
131+
ret = extract(reader, writer);
132+
if (ret < 0)
133+
return -1;
134+
135+
archive_cleanup(reader, writer);
136+
137+
return 0;
138+
}

init/nitro/rootfs_archive.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
3+
#ifndef _ROOTFS_ARCHIVE_H
4+
#define _ROOTFS_ARCHIVE_H
5+
6+
#include <stddef.h>
7+
8+
int archive_extract(void *, size_t);
9+
10+
#endif // _ROOTFS_ARCHIVE_H

src/nitro/src/enclaves.rs

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,11 @@ pub struct NitroEnclave {
4040
impl NitroEnclave {
4141
/// Run the enclave.
4242
pub fn run(&mut self) -> Result<u32> {
43-
let _rootfs_archive = self.rootfs_archive()?;
43+
let rootfs_archive = self.rootfs_archive()?;
4444

45-
let (cid, _stream) = self.start()?;
45+
let (cid, stream) = self.start()?;
46+
47+
self.write_rootfs(rootfs_archive, stream)?;
4648

4749
Ok(cid)
4850
}
@@ -124,4 +126,21 @@ impl NitroEnclave {
124126

125127
Ok((cid, stream.0))
126128
}
129+
130+
fn write_rootfs(&self, archive: Vec<u8>, mut stream: VsockStream) -> Result<()> {
131+
let len: u64 = archive
132+
.len()
133+
.try_into()
134+
.or(Err(NitroError::RootFsTooLarge))?;
135+
136+
stream
137+
.write_all(&len.to_ne_bytes())
138+
.map_err(NitroError::RootFsLenWrite)?;
139+
140+
stream
141+
.write_all(&archive)
142+
.map_err(NitroError::RootFsWrite)?;
143+
144+
Ok(())
145+
}
127146
}

src/nitro/src/error.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ pub enum NitroError {
2323
VsockSetTimeout,
2424
VsockConnect,
2525
IpcWrite(io::Error),
26+
RootFsLenWrite(io::Error),
27+
RootFsWrite(io::Error),
28+
RootFsTooLarge,
2629
}
2730

2831
impl fmt::Display for NitroError {
@@ -64,6 +67,13 @@ impl fmt::Display for NitroError {
6467
NitroError::IpcWrite(e) => {
6568
format!("unable to write enclave vsock data to UNIX IPC socket: {e}")
6669
}
70+
NitroError::RootFsLenWrite(e) => {
71+
format!("unable to write rootfs archive length to enclave: {e}")
72+
}
73+
NitroError::RootFsWrite(e) => {
74+
format!("unable to write rootfs archive to enclave: {e}")
75+
}
76+
NitroError::RootFsTooLarge => "rootfs size is larger than 64 bytes".to_string(),
6777
};
6878

6979
write!(f, "{}", msg)

0 commit comments

Comments
 (0)