nitro_enclaves/launch/
linux.rs1use super::{error::*, types::*};
4
5use std::{
6 cmp::min,
7 fs::File,
8 io::{Read, Seek},
9};
10
11pub const NE_MAGIC: u64 = 0xAE;
12
13pub const NE_CREATE_VM: u64 = nix::request_code_read!(NE_MAGIC, 0x20, size_of::<u64>()) as _;
15
16pub const NE_ADD_VCPU: u64 = nix::request_code_readwrite!(NE_MAGIC, 0x21, size_of::<u32>()) as _;
18
19pub const NE_GET_IMAGE_LOAD_INFO: u64 =
21 nix::request_code_readwrite!(NE_MAGIC, 0x22, size_of::<ImageLoadInfo>()) as _;
22
23pub const NE_SET_USER_MEMORY_REGION: u64 =
25 nix::request_code_write!(NE_MAGIC, 0x23, size_of::<UserMemoryRegion>()) as _;
26
27pub const NE_START_ENCLAVE: u64 =
29 nix::request_code_readwrite!(NE_MAGIC, 0x24, size_of::<StartInfo>()) as _;
30
31const NE_DEFAULT_MEMORY_REGION: u64 = 0;
33
34const HUGE_FLAG_SIZE: [(libc::c_int, usize); 9] = [
35 (libc::MAP_HUGE_16GB, 16 << 30),
36 (libc::MAP_HUGE_2GB, 2 << 30),
37 (libc::MAP_HUGE_1GB, 1 << 30),
38 (libc::MAP_HUGE_512MB, 512 << 20),
39 (libc::MAP_HUGE_256MB, 256 << 20),
40 (libc::MAP_HUGE_32MB, 32 << 20),
41 (libc::MAP_HUGE_16MB, 16 << 20),
42 (libc::MAP_HUGE_8MB, 8 << 20),
43 (libc::MAP_HUGE_2MB, 2 << 20),
44];
45
46#[derive(Debug, Default)]
48#[repr(C)]
49pub struct ImageLoadInfo {
50 flags: u64,
52
53 pub memory_offset: u64,
55}
56
57impl From<&ImageType<'_>> for ImageLoadInfo {
58 fn from(image_type: &ImageType) -> Self {
59 let flags = match image_type {
60 ImageType::Eif(_) => 0x01,
61 };
62
63 Self {
64 flags,
65 ..Default::default()
66 }
67 }
68}
69
70#[derive(Debug, Default)]
72#[repr(C)]
73pub struct UserMemoryRegion {
74 pub flags: u64,
76
77 pub size: u64,
79
80 pub uaddr: u64,
82}
83
84impl UserMemoryRegion {
85 pub fn image_fill(
86 &mut self,
87 image: &mut File,
88 offset: usize,
89 image_size: usize,
90 written: &mut usize,
91 ) -> Result<(), MemInitError> {
92 let Some(location) = written.checked_add(self.size as usize) else {
93 return Err(MemInitError::OffsetCheckOverflow);
94 };
95
96 if location > offset {
97 let region_offset = offset.saturating_sub(*written);
100 let image_offset = written.saturating_sub(offset);
101
102 let write_amount = min(
105 self.size as usize - region_offset,
106 image_size - image_offset,
107 );
108
109 let bytes = unsafe {
110 std::slice::from_raw_parts_mut(self.uaddr as *mut u8, self.size as usize)
111 };
112
113 image
114 .read_exact(&mut bytes[region_offset..region_offset + write_amount])
115 .map_err(MemInitError::ImageRead)?;
116 }
117
118 *written += self.size as usize;
119
120 Ok(())
121 }
122}
123
124pub struct UserMemoryRegions(Vec<UserMemoryRegion>);
126
127impl UserMemoryRegions {
128 pub fn new(size_mib: usize) -> Result<Self, MemInitError> {
130 let mut regions = Vec::new();
131 let mut size = size_mib << 20;
132 let mut found: bool;
133
134 while size > 0 {
135 found = false;
136 for (hp_flag, reg_size) in HUGE_FLAG_SIZE {
137 if size < reg_size {
140 continue;
141 }
142
143 let addr = unsafe {
144 libc::mmap(
145 std::ptr::null_mut(),
146 reg_size,
147 libc::PROT_READ | libc::PROT_WRITE,
148 libc::MAP_PRIVATE | libc::MAP_ANONYMOUS | libc::MAP_HUGETLB | hp_flag,
149 -1,
150 0,
151 )
152 };
153
154 if addr == libc::MAP_FAILED {
155 continue;
156 }
157
158 let region = UserMemoryRegion {
159 flags: NE_DEFAULT_MEMORY_REGION,
160 size: reg_size as _,
161 uaddr: addr as _,
162 };
163
164 regions.push(region);
165 size -= reg_size;
166 found = true;
167 }
168
169 if !found {
171 return Err(MemInitError::NoHugePageFound);
172 }
173 }
174
175 Ok(Self(regions))
176 }
177
178 pub fn image_fill(&mut self, offset: usize, image: ImageType) -> Result<(), MemInitError> {
180 let ImageType::Eif(image) = image;
182
183 let metadata = image.metadata().map_err(MemInitError::ImageMetadata)?;
185 let image_size = metadata.len() as usize;
186 image.rewind().map_err(MemInitError::ImageRewind)?;
187
188 let Some(limit) = offset.checked_add(image_size) else {
190 return Err(MemInitError::ImagePlacementOverflow);
191 };
192
193 let mut written: usize = 0;
195 for region in &mut self.0 {
196 region.image_fill(image, offset, image_size, &mut written)?;
197 if written >= limit {
198 break;
199 }
200 }
201
202 if written < limit {
204 return Err(MemInitError::ImageWriteIncomplete);
205 }
206
207 Ok(())
208 }
209
210 pub fn inner_ref(&self) -> &Vec<UserMemoryRegion> {
212 &self.0
213 }
214}
215
216#[repr(C)]
218pub struct StartInfo {
219 flags: u64,
221
222 pub cid: u64,
224}
225
226impl StartInfo {
227 pub fn new(flags: StartFlags, cid: u64) -> Self {
228 let flags = flags.bits();
229
230 Self { flags, cid }
231 }
232}