Skip to content

Commit 99980a0

Browse files
committed
init: Define specific initramfs for nitro enclaves
Signed-off-by: Tyler Fanelli <tfanelli@redhat.com>
1 parent bea9fef commit 99980a0

1 file changed

Lines changed: 230 additions & 0 deletions

File tree

init/nitro/main.c

Lines changed: 230 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,230 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
3+
#define _GNU_SOURCE
4+
#include <errno.h>
5+
#include <fcntl.h>
6+
#include <signal.h>
7+
#include <stdint.h>
8+
#include <stdio.h>
9+
#include <stdlib.h>
10+
#include <unistd.h>
11+
#include <sys/mount.h>
12+
#include <sys/reboot.h>
13+
#include <sys/socket.h>
14+
#include <sys/stat.h>
15+
#include <sys/types.h>
16+
#include <sys/syscall.h>
17+
#include <linux/vm_sockets.h>
18+
19+
#define finit_module(fd, param_values, flags) (int)syscall(__NR_finit_module, fd, param_values, flags)
20+
21+
#define HEART_BEAT 0xb7
22+
#define VSOCK_CID 3
23+
#define VSOCK_PORT 9000
24+
25+
/*
26+
* Block or unblock signals.
27+
*
28+
* NOTE: All signals are blocked before the devies or console are set up.
29+
* Therefore, perror output may not be displayed if a failure occurs
30+
* during this setup.
31+
*/
32+
int
33+
sig_mask(int mask)
34+
{
35+
sigset_t set;
36+
int ret;
37+
38+
// Initialize the signal set to the complete set of supported signals.
39+
ret = sigfillset(&set);
40+
if (ret < 0) {
41+
perror("sigfillset");
42+
return ret;
43+
}
44+
45+
// Block/unblock the signals. This essentially blocks/unblocks all signals
46+
// to the process.
47+
ret = sigprocmask(mask, &set, 0);
48+
if (ret < 0) {
49+
perror("sigprocmask");
50+
return ret;
51+
}
52+
53+
return 0;
54+
}
55+
56+
/*
57+
* Initialize a devtpmfs at /dev.
58+
*/
59+
int
60+
dev_init()
61+
{
62+
int ret;
63+
64+
ret = mount("dev", "/dev", "devtmpfs", MS_NOSUID | MS_NOEXEC, NULL);
65+
if (ret < 0) {
66+
perror("mount");
67+
return ret;
68+
}
69+
70+
return 0;
71+
}
72+
73+
/*
74+
* Initialize /dev/console and redirect std{err, in, out} to it for early debug
75+
* output.
76+
*/
77+
int
78+
console_init()
79+
{
80+
const char *path = "/dev/console";
81+
FILE *file;
82+
int ret;
83+
84+
// Initialize /dev.
85+
ret = dev_init();
86+
if (ret < 0)
87+
return ret;
88+
89+
// Redirect stdin, stdout, and stderr to /dev/console.
90+
file = freopen(path, "r", stdin);
91+
if (file == NULL)
92+
return -1;
93+
94+
file = freopen(path, "w", stdout);
95+
if (file == NULL)
96+
return -1;
97+
98+
file = freopen(path, "w", stderr);
99+
if (file == NULL)
100+
return -1;
101+
102+
return 0;
103+
}
104+
105+
/*
106+
* Initialize/load the NSM kernel module.
107+
*/
108+
int
109+
nsm_init()
110+
{
111+
const char *file_name = "nsm.ko";
112+
int fd, ret;
113+
114+
fd = open(file_name, O_RDONLY | O_CLOEXEC);
115+
if (fd < 0 && errno == ENOENT)
116+
return 0;
117+
else if (fd < 0) {
118+
perror("nsm.ko open");
119+
return -errno;
120+
}
121+
122+
// Load the NSM module.
123+
ret = finit_module(fd, "", 0);
124+
if (ret < 0) {
125+
perror("nsm.ko finit_module");
126+
return -errno;
127+
}
128+
129+
// Close the file descriptor and remove the NSM module file.
130+
ret = close(fd);
131+
if (ret < 0) {
132+
perror("nsm.ko close");
133+
return -errno;
134+
}
135+
136+
ret = unlink(file_name);
137+
if (ret < 0) {
138+
perror("nsm.ko unlink");
139+
return -errno;
140+
}
141+
142+
return 0;
143+
}
144+
145+
/*
146+
* Signal to the host that the enclave is ready to receive the archived rootfs.
147+
*/
148+
int
149+
krun_signal()
150+
{
151+
uint8_t buf[1];
152+
struct sockaddr_vm saddr;
153+
int ret, sock_fd;
154+
155+
buf[0] = HEART_BEAT;
156+
errno = -EINVAL;
157+
158+
saddr.svm_family = AF_VSOCK;
159+
saddr.svm_cid = VSOCK_CID;
160+
saddr.svm_port = VSOCK_PORT;
161+
saddr.svm_reserved1 = 0;
162+
163+
sock_fd = socket(AF_VSOCK, SOCK_STREAM, 0);
164+
if (sock_fd < 0) {
165+
perror("vsock initialization");
166+
return -errno;
167+
}
168+
169+
// Connect to the host.
170+
ret = connect(sock_fd, (struct sockaddr *) &saddr, sizeof(saddr));
171+
if (ret < 0) {
172+
perror("vsock connect");
173+
return -errno;
174+
}
175+
176+
// Write the heartbeat to the host and read it back to ensure that the
177+
// communication is established.
178+
ret = write(sock_fd, buf, 1);
179+
if (ret != 1) {
180+
perror("vsock write");
181+
return -errno;
182+
}
183+
184+
ret = read(sock_fd, buf, 1);
185+
if (ret != 1) {
186+
perror("vsock read");
187+
return -errno;
188+
}
189+
190+
if (buf[0] != HEART_BEAT)
191+
return -1;
192+
193+
ret = close(sock_fd);
194+
if (ret < 0) {
195+
perror("vsock close");
196+
return -errno;
197+
}
198+
199+
return 0;
200+
}
201+
202+
int
203+
main(int argc, char *argv[])
204+
{
205+
int ret;
206+
207+
// Block all signals.
208+
ret = sig_mask(SIG_BLOCK);
209+
if (ret < 0)
210+
exit(ret);
211+
212+
// Initialize early debug output with /dev/console.
213+
ret = console_init();
214+
if (ret < 0)
215+
exit(ret);
216+
217+
// Initialize the NSM kernel module.
218+
ret = nsm_init();
219+
if (ret < 0)
220+
exit(ret);
221+
222+
ret = krun_signal();
223+
if (ret < 0)
224+
exit(ret);
225+
226+
reboot(RB_AUTOBOOT);
227+
228+
// Unreachable.
229+
return -1;
230+
}

0 commit comments

Comments
 (0)