1use std::ffi::CString;
2use std::mem::MaybeUninit;
3
4use linux_api::errno::Errno;
5use shadow_shim_helper_rs::syscall_types::ForeignPtr;
6
7use crate::host::memory_manager::MemoryManager;
8use crate::host::syscall::types::ForeignArrayPtr;
9use crate::utility::sockaddr::SockaddrStorage;
10
11pub fn write_sockaddr_and_len(
19 mem: &mut MemoryManager,
20 addr: Option<&SockaddrStorage>,
21 plugin_addr: ForeignPtr<u8>,
22 plugin_addr_len_ptr: ForeignPtr<libc::socklen_t>,
23) -> Result<(), Errno> {
24 let addr = match addr {
25 Some(x) => x,
26 None => {
27 mem.write(plugin_addr_len_ptr, &0)?;
28 return Ok(());
29 }
30 };
31
32 let from_addr_slice = addr.as_slice();
33 let from_len: u32 = from_addr_slice.len().try_into().unwrap();
34
35 let plugin_addr_len = mem.read(plugin_addr_len_ptr)?;
37 mem.write(plugin_addr_len_ptr, &from_len)?;
38
39 if plugin_addr_len == 0 {
41 return Ok(());
42 }
43
44 let len_to_copy = std::cmp::min(from_len, plugin_addr_len).try_into().unwrap();
46
47 let plugin_addr = ForeignArrayPtr::new(plugin_addr.cast::<MaybeUninit<u8>>(), len_to_copy);
48 mem.copy_to_ptr(plugin_addr, &from_addr_slice[..len_to_copy])?;
49
50 Ok(())
51}
52
53pub fn write_sockaddr(
58 mem: &mut MemoryManager,
59 addr: &SockaddrStorage,
60 plugin_addr: ForeignPtr<u8>,
61 plugin_addr_len: libc::socklen_t,
62) -> Result<libc::socklen_t, Errno> {
63 let from_addr_slice = addr.as_slice();
64 let from_len: u32 = from_addr_slice.len().try_into().unwrap();
65
66 if plugin_addr_len == 0 {
68 return Ok(from_len);
69 }
70
71 let len_to_copy = std::cmp::min(from_len, plugin_addr_len).try_into().unwrap();
73
74 let plugin_addr = ForeignArrayPtr::new(plugin_addr.cast::<MaybeUninit<u8>>(), len_to_copy);
75 mem.copy_to_ptr(plugin_addr, &from_addr_slice[..len_to_copy])?;
76
77 Ok(from_len)
78}
79
80pub fn read_sockaddr(
81 mem: &MemoryManager,
82 addr_ptr: ForeignPtr<u8>,
83 addr_len: libc::socklen_t,
84) -> Result<Option<SockaddrStorage>, Errno> {
85 if addr_ptr.is_null() {
86 return Ok(None);
87 }
88
89 let addr_len_usize: usize = addr_len.try_into().unwrap();
90
91 let mut addr_buf = [MaybeUninit::new(0u8); std::mem::size_of::<libc::sockaddr_storage>()];
94
95 if addr_len_usize > std::mem::size_of_val(&addr_buf) {
97 log::warn!(
98 "Shadow does not support the address length {}, which is larger than {}",
99 addr_len,
100 std::mem::size_of_val(&addr_buf),
101 );
102 return Err(Errno::EINVAL);
103 }
104
105 let addr_buf = &mut addr_buf[..addr_len_usize];
106
107 mem.copy_from_ptr(
108 addr_buf,
109 ForeignArrayPtr::new(addr_ptr.cast::<MaybeUninit<u8>>(), addr_len_usize),
110 )?;
111
112 let addr = unsafe { SockaddrStorage::from_bytes(addr_buf).ok_or(Errno::EINVAL)? };
113
114 Ok(Some(addr))
115}
116
117pub fn write_partial<T: shadow_pod::Pod>(
135 mem: &mut MemoryManager,
136 val: &T,
137 val_ptr: ForeignPtr<T>,
138 val_len_bytes: usize,
139) -> Result<usize, Errno> {
140 let val_len_bytes = std::cmp::min(val_len_bytes, std::mem::size_of_val(val));
141
142 let val = &shadow_pod::as_u8_slice(val)[..val_len_bytes];
143
144 let val_ptr = val_ptr.cast::<MaybeUninit<u8>>();
145 let val_ptr = ForeignArrayPtr::new(val_ptr, val_len_bytes);
146
147 mem.copy_to_ptr(val_ptr, val)?;
148
149 Ok(val_len_bytes)
150}
151
152pub struct MsgHdr {
154 pub name: ForeignPtr<u8>,
155 pub name_len: libc::socklen_t,
156 pub iovs: Vec<IoVec>,
157 pub control: ForeignPtr<u8>,
158 pub control_len: libc::size_t,
159 pub flags: std::ffi::c_int,
160}
161
162#[derive(Copy, Clone, PartialEq, Eq)]
164pub struct IoVec {
165 pub base: ForeignPtr<u8>,
166 pub len: libc::size_t,
167}
168
169impl From<IoVec> for ForeignArrayPtr<u8> {
170 fn from(iov: IoVec) -> Self {
171 Self::new(iov.base, iov.len)
172 }
173}
174
175impl From<ForeignArrayPtr<u8>> for IoVec {
176 fn from(ptr: ForeignArrayPtr<u8>) -> Self {
177 IoVec {
178 base: ptr.ptr(),
179 len: ptr.len(),
180 }
181 }
182}
183
184pub struct IoVecReader<'a, I> {
194 iovs: I,
195 mem: &'a MemoryManager,
196 current_src: Option<ForeignArrayPtr<u8>>,
198}
199
200impl<'a, I> IoVecReader<'a, I> {
201 pub fn new<'b>(
202 iovs: impl IntoIterator<Item = &'b IoVec, IntoIter = I>,
203 mem: &'a MemoryManager,
204 ) -> Self {
205 Self {
206 iovs: iovs.into_iter(),
207 mem,
208 current_src: None,
209 }
210 }
211}
212
213impl<'a, I: Iterator<Item = &'a IoVec>> std::io::Read for IoVecReader<'a, I> {
214 fn read(&mut self, mut buf: &mut [u8]) -> std::io::Result<usize> {
215 let mut bytes_read = 0;
216
217 loop {
218 if buf.is_empty() {
220 break;
221 }
222
223 if let Some(ref mut src) = self.current_src {
224 let num_to_read = std::cmp::min(src.len(), buf.len());
225 let result = self
226 .mem
227 .copy_from_ptr(&mut buf[..num_to_read], src.slice(..num_to_read));
228
229 match (result, bytes_read) {
230 (Ok(()), _) => {}
232 (Err(e), 0) => return Err(e.into()),
234 (Err(_), _) => break,
236 }
237
238 bytes_read += num_to_read;
239 buf = &mut buf[num_to_read..];
240 *src = src.slice(num_to_read..);
241
242 if src.is_empty() {
243 self.current_src = None;
245 }
246 } else {
247 let Some(next_iov) = self.iovs.next() else {
248 break;
250 };
251 self.current_src = Some((*next_iov).into());
252 }
253 }
254
255 Ok(bytes_read)
256 }
257}
258
259pub struct IoVecWriter<'a, I> {
269 iovs: I,
270 mem: &'a mut MemoryManager,
271 current_dst: Option<ForeignArrayPtr<u8>>,
273}
274
275impl<'a, I> IoVecWriter<'a, I> {
276 pub fn new<'b>(
277 iovs: impl IntoIterator<Item = &'b IoVec, IntoIter = I>,
278 mem: &'a mut MemoryManager,
279 ) -> Self {
280 Self {
281 iovs: iovs.into_iter(),
282 mem,
283 current_dst: None,
284 }
285 }
286}
287
288impl<'a, I: Iterator<Item = &'a IoVec>> std::io::Write for IoVecWriter<'a, I> {
289 fn write(&mut self, mut buf: &[u8]) -> std::io::Result<usize> {
290 let mut bytes_written = 0;
291
292 loop {
293 if buf.is_empty() {
295 break;
296 }
297
298 if let Some(ref mut dst) = self.current_dst {
299 let num_to_write = std::cmp::min(dst.len(), buf.len());
300 let result = self
301 .mem
302 .copy_to_ptr(dst.slice(..num_to_write), &buf[..num_to_write]);
303
304 match (result, bytes_written) {
305 (Ok(()), _) => {}
307 (Err(e), 0) => return Err(e.into()),
309 (Err(_), _) => break,
311 }
312
313 bytes_written += num_to_write;
314 buf = &buf[num_to_write..];
315 *dst = dst.slice(num_to_write..);
316
317 if dst.is_empty() {
318 self.current_dst = None;
320 }
321 } else {
322 let Some(next_iov) = self.iovs.next() else {
323 break;
325 };
326 self.current_dst = Some((*next_iov).into());
327 }
328 }
329
330 Ok(bytes_written)
331 }
332
333 fn flush(&mut self) -> std::io::Result<()> {
334 Ok(())
335 }
336}
337
338pub fn read_iovecs(
340 mem: &MemoryManager,
341 iov_ptr: ForeignPtr<libc::iovec>,
342 count: usize,
343) -> Result<Vec<IoVec>, Errno> {
344 if count > libc::UIO_MAXIOV.try_into().unwrap() {
345 return Err(Errno::EINVAL);
346 }
347
348 let plugin_iovs = mem.read_vec(ForeignArrayPtr::new(iov_ptr, count))?;
349 let iovs = plugin_iovs
350 .into_iter()
351 .map(|plugin_iov| IoVec {
352 base: ForeignPtr::from_raw_ptr(plugin_iov.iov_base as *mut u8),
353 len: plugin_iov.iov_len,
354 })
355 .collect();
356
357 Ok(iovs)
358}
359
360pub fn read_msghdr(
362 mem: &MemoryManager,
363 msg_ptr: ForeignPtr<libc::msghdr>,
364) -> Result<MsgHdr, Errno> {
365 let plugin_msg = mem.read(msg_ptr)?;
366 msghdr_to_rust(&plugin_msg, mem)
367}
368
369pub fn update_msghdr(
373 mem: &mut MemoryManager,
374 msg_ptr: ForeignPtr<libc::msghdr>,
375 msg: MsgHdr,
376) -> Result<(), Errno> {
377 let mut plugin_msg = mem.read(msg_ptr)?;
378
379 plugin_msg.msg_namelen = msg.name_len;
381 plugin_msg.msg_controllen = msg.control_len;
382 plugin_msg.msg_flags = msg.flags;
383
384 mem.write(msg_ptr, &plugin_msg)
385}
386
387fn msghdr_to_rust(msg: &libc::msghdr, mem: &MemoryManager) -> Result<MsgHdr, Errno> {
391 let iovs = read_iovecs(mem, ForeignPtr::from_raw_ptr(msg.msg_iov), msg.msg_iovlen)?;
392 assert_eq!(iovs.len(), msg.msg_iovlen);
393
394 Ok(MsgHdr {
395 name: ForeignPtr::from_raw_ptr(msg.msg_name as *mut u8),
396 name_len: msg.msg_namelen,
397 iovs,
398 control: ForeignPtr::from_raw_ptr(msg.msg_control as *mut u8),
399 control_len: msg.msg_controllen,
400 flags: msg.msg_flags,
401 })
402}
403
404pub fn read_cstring_vec(
408 mem: &MemoryManager,
409 mut ptr_ptr: ForeignPtr<ForeignPtr<i8>>,
410) -> Result<Vec<CString>, Errno> {
411 let mut res = Vec::new();
412
413 let mut arg_buf = [0; linux_api::limits::ARG_MAX];
419
420 loop {
421 let ptr = mem.read(ptr_ptr)?;
422 ptr_ptr = ptr_ptr.add(1);
423 if ptr.is_null() {
424 break;
425 }
426 let cstr = mem.copy_str_from_ptr(
427 &mut arg_buf,
428 ForeignArrayPtr::new(ptr.cast::<u8>(), linux_api::limits::ARG_MAX),
429 )?;
430 res.push(cstr.to_owned());
431 }
432 Ok(res)
433}