1use linux_api::errno::Errno;
2use linux_api::fcntl::DescriptorFlags;
3use linux_api::socket::Shutdown;
4use log::*;
5use nix::sys::socket::SockFlag;
6use shadow_shim_helper_rs::syscall_types::ForeignPtr;
7
8use crate::host::descriptor::descriptor_table::DescriptorHandle;
9use crate::host::descriptor::socket::inet::InetSocket;
10use crate::host::descriptor::socket::inet::legacy_tcp::LegacyTcpSocket;
11use crate::host::descriptor::socket::inet::tcp::TcpSocket;
12use crate::host::descriptor::socket::inet::udp::UdpSocket;
13use crate::host::descriptor::socket::netlink::{NetlinkFamily, NetlinkSocket, NetlinkSocketType};
14use crate::host::descriptor::socket::unix::{UnixSocket, UnixSocketType};
15use crate::host::descriptor::socket::{RecvmsgArgs, RecvmsgReturn, SendmsgArgs, Socket};
16use crate::host::descriptor::{CompatFile, Descriptor, File, FileState, FileStatus, OpenFile};
17use crate::host::syscall::handler::{SyscallContext, SyscallHandler};
18use crate::host::syscall::io::{self, IoVec};
19use crate::host::syscall::type_formatting::{SyscallBufferArg, SyscallSockAddrArg};
20use crate::host::syscall::types::ForeignArrayPtr;
21use crate::host::syscall::types::SyscallError;
22use crate::utility::callback_queue::CallbackQueue;
23use crate::utility::sockaddr::SockaddrStorage;
24
25impl SyscallHandler {
26 log_syscall!(
27 socket,
28 std::ffi::c_int,
29 linux_api::socket::AddressFamily,
30 std::ffi::c_int,
31 std::ffi::c_int,
32 );
33 pub fn socket(
34 ctx: &mut SyscallContext,
35 domain: std::ffi::c_int,
36 socket_type: std::ffi::c_int,
37 protocol: std::ffi::c_int,
38 ) -> Result<DescriptorHandle, Errno> {
39 let flags = socket_type & (libc::SOCK_NONBLOCK | libc::SOCK_CLOEXEC);
41 let socket_type = socket_type & !flags;
42
43 let mut file_flags = FileStatus::empty();
44 let mut descriptor_flags = DescriptorFlags::empty();
45
46 if flags & libc::SOCK_NONBLOCK != 0 {
47 file_flags.insert(FileStatus::NONBLOCK);
48 }
49
50 if flags & libc::SOCK_CLOEXEC != 0 {
51 descriptor_flags.insert(DescriptorFlags::FD_CLOEXEC);
52 }
53
54 let socket = match domain {
55 libc::AF_UNIX => {
56 let socket_type = match UnixSocketType::try_from(socket_type) {
57 Ok(x) => x,
58 Err(e) => {
59 warn!("{}", e);
60 return Err(Errno::EPROTONOSUPPORT);
61 }
62 };
63
64 if protocol != 0 {
66 warn!(
67 "Unsupported socket protocol {}, we only support default protocol 0",
68 protocol
69 );
70 return Err(Errno::EPROTONOSUPPORT);
71 }
72
73 Socket::Unix(UnixSocket::new(
74 file_flags,
75 socket_type,
76 &ctx.objs.host.abstract_unix_namespace(),
77 ))
78 }
79 libc::AF_INET => match socket_type {
80 libc::SOCK_STREAM => {
81 if protocol != 0 && protocol != libc::IPPROTO_TCP {
82 log::debug!("Unsupported inet stream socket protocol {protocol}");
83 return Err(Errno::EPROTONOSUPPORT);
84 }
85
86 if ctx.objs.host.params.use_new_tcp {
87 Socket::Inet(InetSocket::Tcp(TcpSocket::new(file_flags)))
88 } else {
89 Socket::Inet(InetSocket::LegacyTcp(LegacyTcpSocket::new(
90 file_flags,
91 ctx.objs.host,
92 )))
93 }
94 }
95 libc::SOCK_DGRAM => {
96 if protocol != 0 && protocol != libc::IPPROTO_UDP {
97 log::debug!("Unsupported inet dgram socket protocol {protocol}");
98 return Err(Errno::EPROTONOSUPPORT);
99 }
100 let send_buf_size = ctx.objs.host.params.init_sock_send_buf_size;
101 let recv_buf_size = ctx.objs.host.params.init_sock_recv_buf_size;
102 Socket::Inet(InetSocket::Udp(UdpSocket::new(
103 file_flags,
104 send_buf_size.try_into().unwrap(),
105 recv_buf_size.try_into().unwrap(),
106 )))
107 }
108 _ => return Err(Errno::ESOCKTNOSUPPORT),
109 },
110 libc::AF_NETLINK => {
111 let socket_type = match NetlinkSocketType::try_from(socket_type) {
112 Ok(x) => x,
113 Err(e) => {
114 warn!("{}", e);
115 return Err(Errno::EPROTONOSUPPORT);
116 }
117 };
118 let family = match NetlinkFamily::try_from(protocol) {
119 Ok(x) => x,
120 Err(e) => {
121 warn!("{}", e);
122 return Err(Errno::EPROTONOSUPPORT);
123 }
124 };
125 Socket::Netlink(NetlinkSocket::new(file_flags, socket_type, family))
126 }
127 _ => return Err(Errno::EAFNOSUPPORT),
128 };
129
130 let mut desc = Descriptor::new(CompatFile::New(OpenFile::new(File::Socket(socket))));
131 desc.set_flags(descriptor_flags);
132
133 let fd = ctx
134 .objs
135 .thread
136 .descriptor_table_borrow_mut(ctx.objs.host)
137 .register_descriptor(desc)
138 .or(Err(Errno::ENFILE))?;
139
140 log::trace!("Created socket fd {fd}");
141
142 Ok(fd)
143 }
144
145 log_syscall!(
146 bind,
147 std::ffi::c_int,
148 std::ffi::c_int,
149 SyscallSockAddrArg<2>,
150 libc::socklen_t,
151 );
152 pub fn bind(
153 ctx: &mut SyscallContext,
154 fd: std::ffi::c_int,
155 addr_ptr: ForeignPtr<u8>,
156 addr_len: libc::socklen_t,
157 ) -> Result<(), SyscallError> {
158 let file = {
159 let desc_table = ctx.objs.thread.descriptor_table_borrow(ctx.objs.host);
161 let desc = Self::get_descriptor(&desc_table, fd)?;
162
163 let CompatFile::New(file) = desc.file() else {
164 return Err(Errno::ENOTSOCK.into());
166 };
167
168 file.inner_file().clone()
169 };
170
171 let File::Socket(socket) = file else {
172 return Err(Errno::ENOTSOCK.into());
173 };
174
175 let addr = io::read_sockaddr(&ctx.objs.process.memory_borrow(), addr_ptr, addr_len)?;
176
177 log::trace!("Attempting to bind fd {} to {:?}", fd, addr);
178
179 let mut rng = ctx.objs.host.random_mut();
180 let net_ns = ctx.objs.host.network_namespace_borrow();
181 Socket::bind(&socket, addr.as_ref(), &net_ns, &mut *rng)
182 }
183
184 log_syscall!(
185 sendto,
186 libc::ssize_t,
187 std::ffi::c_int,
188 SyscallBufferArg<2>,
189 libc::size_t,
190 nix::sys::socket::MsgFlags,
191 SyscallSockAddrArg<5>,
192 libc::socklen_t,
193 );
194 pub fn sendto(
195 ctx: &mut SyscallContext,
196 fd: std::ffi::c_int,
197 buf_ptr: ForeignPtr<u8>,
198 buf_len: libc::size_t,
199 flags: std::ffi::c_int,
200 addr_ptr: ForeignPtr<u8>,
201 addr_len: libc::socklen_t,
202 ) -> Result<libc::ssize_t, SyscallError> {
203 let file = ctx
206 .objs
207 .thread
208 .syscall_condition()
209 .and_then(|x| x.active_file().cloned());
211
212 let file = match file {
213 Some(x) => x,
215 None => {
217 let desc_table = ctx.objs.thread.descriptor_table_borrow(ctx.objs.host);
218 let CompatFile::New(file) = Self::get_descriptor(&desc_table, fd)?.file() else {
219 return Err(Errno::ENOTSOCK.into());
221 };
222 file.clone()
223 }
224 };
225
226 let File::Socket(socket) = file.inner_file() else {
227 return Err(Errno::ENOTSOCK.into());
228 };
229
230 let mut mem = ctx.objs.process.memory_borrow_mut();
231 let mut rng = ctx.objs.host.random_mut();
232 let net_ns = ctx.objs.host.network_namespace_borrow();
233
234 let addr = io::read_sockaddr(&mem, addr_ptr, addr_len)?;
235
236 log::trace!("Attempting to send {} bytes to {:?}", buf_len, addr);
237
238 let iov = IoVec {
239 base: buf_ptr,
240 len: buf_len,
241 };
242
243 let args = SendmsgArgs {
244 addr,
245 iovs: &[iov],
246 control_ptr: ForeignArrayPtr::new(ForeignPtr::null(), 0),
247 flags,
248 };
249
250 let mut result = CallbackQueue::queue_and_run_with_legacy(|cb_queue| {
252 Socket::sendmsg(socket, args, &mut mem, &net_ns, &mut *rng, cb_queue)
253 });
254
255 if let Some(err) = result.as_mut().err() {
257 if let Some(cond) = err.blocked_condition() {
258 cond.set_active_file(file);
259 }
260 }
261
262 let bytes_sent = result?;
263 Ok(bytes_sent)
264 }
265
266 log_syscall!(
267 sendmsg,
268 libc::ssize_t,
269 std::ffi::c_int,
270 *const libc::msghdr,
271 nix::sys::socket::MsgFlags,
272 );
273 pub fn sendmsg(
274 ctx: &mut SyscallContext,
275 fd: std::ffi::c_int,
276 msg_ptr: ForeignPtr<libc::msghdr>,
277 flags: std::ffi::c_int,
278 ) -> Result<libc::ssize_t, SyscallError> {
279 let file = ctx
282 .objs
283 .thread
284 .syscall_condition()
285 .and_then(|x| x.active_file().cloned());
287
288 let file = match file {
289 Some(x) => x,
291 None => {
293 let desc_table = ctx.objs.thread.descriptor_table_borrow(ctx.objs.host);
294 match Self::get_descriptor(&desc_table, fd)?.file() {
295 CompatFile::New(file) => file.clone(),
296 CompatFile::Legacy(_file) => {
297 return Err(Errno::ENOTSOCK.into());
298 }
299 }
300 }
301 };
302
303 let File::Socket(socket) = file.inner_file() else {
304 return Err(Errno::ENOTSOCK.into());
305 };
306
307 let mut mem = ctx.objs.process.memory_borrow_mut();
308 let mut rng = ctx.objs.host.random_mut();
309 let net_ns = ctx.objs.host.network_namespace_borrow();
310
311 let msg = io::read_msghdr(&mem, msg_ptr)?;
312
313 let args = SendmsgArgs {
314 addr: io::read_sockaddr(&mem, msg.name, msg.name_len)?,
315 iovs: &msg.iovs,
316 control_ptr: ForeignArrayPtr::new(msg.control, msg.control_len),
317 flags,
319 };
320
321 let mut result = CallbackQueue::queue_and_run_with_legacy(|cb_queue| {
323 Socket::sendmsg(socket, args, &mut mem, &net_ns, &mut *rng, cb_queue)
324 });
325
326 if let Some(err) = result.as_mut().err() {
328 if let Some(cond) = err.blocked_condition() {
329 cond.set_active_file(file);
330 }
331 }
332
333 let bytes_written = result?;
334 Ok(bytes_written)
335 }
336
337 log_syscall!(
338 recvfrom,
339 libc::ssize_t,
340 std::ffi::c_int,
341 *const std::ffi::c_void,
342 libc::size_t,
343 nix::sys::socket::MsgFlags,
344 *const libc::sockaddr,
345 *const libc::socklen_t,
346 );
347 pub fn recvfrom(
348 ctx: &mut SyscallContext,
349 fd: std::ffi::c_int,
350 buf_ptr: ForeignPtr<u8>,
351 buf_len: libc::size_t,
352 flags: std::ffi::c_int,
353 addr_ptr: ForeignPtr<u8>,
354 addr_len_ptr: ForeignPtr<libc::socklen_t>,
355 ) -> Result<libc::ssize_t, SyscallError> {
356 let file = ctx
359 .objs
360 .thread
361 .syscall_condition()
362 .and_then(|x| x.active_file().cloned());
364
365 let file = match file {
366 Some(x) => x,
368 None => {
370 let desc_table = ctx.objs.thread.descriptor_table_borrow(ctx.objs.host);
371 let CompatFile::New(file) = Self::get_descriptor(&desc_table, fd)?.file() else {
372 return Err(Errno::ENOTSOCK.into());
374 };
375 file.clone()
376 }
377 };
378
379 let File::Socket(socket) = file.inner_file() else {
380 return Err(Errno::ENOTSOCK.into());
381 };
382
383 let mut mem = ctx.objs.process.memory_borrow_mut();
384
385 log::trace!("Attempting to recv {} bytes", buf_len);
386
387 let iov = IoVec {
388 base: buf_ptr,
389 len: buf_len,
390 };
391
392 let args = RecvmsgArgs {
393 iovs: &[iov],
394 control_ptr: ForeignArrayPtr::new(ForeignPtr::null(), 0),
395 flags,
396 };
397
398 let mut result = CallbackQueue::queue_and_run_with_legacy(|cb_queue| {
400 Socket::recvmsg(socket, args, &mut mem, cb_queue)
401 });
402
403 if let Some(err) = result.as_mut().err() {
405 if let Some(cond) = err.blocked_condition() {
406 cond.set_active_file(file);
407 }
408 }
409
410 let RecvmsgReturn {
411 return_val,
412 addr: from_addr,
413 ..
414 } = result?;
415
416 if !addr_ptr.is_null() {
417 io::write_sockaddr_and_len(&mut mem, from_addr.as_ref(), addr_ptr, addr_len_ptr)?;
418 }
419
420 Ok(return_val)
421 }
422
423 log_syscall!(
424 recvmsg,
425 libc::ssize_t,
426 std::ffi::c_int,
427 *const libc::msghdr,
428 nix::sys::socket::MsgFlags,
429 );
430 pub fn recvmsg(
431 ctx: &mut SyscallContext,
432 fd: std::ffi::c_int,
433 msg_ptr: ForeignPtr<libc::msghdr>,
434 flags: std::ffi::c_int,
435 ) -> Result<libc::ssize_t, SyscallError> {
436 let file = ctx
439 .objs
440 .thread
441 .syscall_condition()
442 .and_then(|x| x.active_file().cloned());
444
445 let file = match file {
446 Some(x) => x,
448 None => {
450 let desc_table = ctx.objs.thread.descriptor_table_borrow(ctx.objs.host);
451 match Self::get_descriptor(&desc_table, fd)?.file() {
452 CompatFile::New(file) => file.clone(),
453 CompatFile::Legacy(_file) => {
454 return Err(Errno::ENOTSOCK.into());
455 }
456 }
457 }
458 };
459
460 let File::Socket(socket) = file.inner_file() else {
461 return Err(Errno::ENOTSOCK.into());
462 };
463
464 let mut mem = ctx.objs.process.memory_borrow_mut();
465
466 let mut msg = io::read_msghdr(&mem, msg_ptr)?;
467
468 let args = RecvmsgArgs {
469 iovs: &msg.iovs,
470 control_ptr: ForeignArrayPtr::new(msg.control, msg.control_len),
471 flags,
472 };
473
474 let mut result = CallbackQueue::queue_and_run_with_legacy(|cb_queue| {
476 Socket::recvmsg(socket, args, &mut mem, cb_queue)
477 });
478
479 if let Some(err) = result.as_mut().err() {
481 if let Some(cond) = err.blocked_condition() {
482 cond.set_active_file(file);
483 }
484 }
485
486 let result = result?;
487
488 if !msg.name.is_null() {
490 if let Some(from_addr) = result.addr.as_ref() {
491 msg.name_len = io::write_sockaddr(&mut mem, from_addr, msg.name, msg.name_len)?;
492 } else {
493 msg.name_len = 0;
494 }
495 }
496
497 msg.control_len = result.control_len;
499 msg.flags = result.msg_flags;
500
501 io::update_msghdr(&mut mem, msg_ptr, msg)?;
503
504 Ok(result.return_val)
505 }
506
507 log_syscall!(
508 getsockname,
509 std::ffi::c_int,
510 std::ffi::c_int,
511 *const libc::sockaddr,
512 *const libc::socklen_t,
513 );
514 pub fn getsockname(
515 ctx: &mut SyscallContext,
516 fd: std::ffi::c_int,
517 addr_ptr: ForeignPtr<u8>,
518 addr_len_ptr: ForeignPtr<libc::socklen_t>,
519 ) -> Result<(), Errno> {
520 let addr_to_write: Option<SockaddrStorage> = {
521 let desc_table = ctx.objs.thread.descriptor_table_borrow(ctx.objs.host);
523 let desc = Self::get_descriptor(&desc_table, fd)?;
524
525 let CompatFile::New(file) = desc.file() else {
526 return Err(Errno::ENOTSOCK);
528 };
529
530 let File::Socket(socket) = file.inner_file() else {
531 return Err(Errno::ENOTSOCK);
532 };
533
534 if addr_ptr.is_null() || addr_len_ptr.is_null() {
536 return Err(Errno::EFAULT);
537 }
538
539 let socket = socket.borrow();
540 socket.getsockname()?
541 };
542
543 debug!("Returning socket address of {:?}", addr_to_write);
544 io::write_sockaddr_and_len(
545 &mut ctx.objs.process.memory_borrow_mut(),
546 addr_to_write.as_ref(),
547 addr_ptr,
548 addr_len_ptr,
549 )?;
550
551 Ok(())
552 }
553
554 log_syscall!(
555 getpeername,
556 std::ffi::c_int,
557 std::ffi::c_int,
558 *const libc::sockaddr,
559 *const libc::socklen_t,
560 );
561 pub fn getpeername(
562 ctx: &mut SyscallContext,
563 fd: std::ffi::c_int,
564 addr_ptr: ForeignPtr<u8>,
565 addr_len_ptr: ForeignPtr<libc::socklen_t>,
566 ) -> Result<(), Errno> {
567 let addr_to_write = {
568 let desc_table = ctx.objs.thread.descriptor_table_borrow(ctx.objs.host);
570 let desc = Self::get_descriptor(&desc_table, fd)?;
571
572 let CompatFile::New(file) = desc.file() else {
573 return Err(Errno::ENOTSOCK);
575 };
576
577 let File::Socket(socket) = file.inner_file() else {
578 return Err(Errno::ENOTSOCK);
579 };
580
581 if addr_ptr.is_null() || addr_len_ptr.is_null() {
583 return Err(Errno::EFAULT);
584 }
585
586 #[allow(clippy::let_and_return)]
588 let addr_to_write = socket.borrow().getpeername()?;
589 addr_to_write
590 };
591
592 debug!("Returning peer address of {:?}", addr_to_write);
593 io::write_sockaddr_and_len(
594 &mut ctx.objs.process.memory_borrow_mut(),
595 addr_to_write.as_ref(),
596 addr_ptr,
597 addr_len_ptr,
598 )?;
599
600 Ok(())
601 }
602
603 log_syscall!(
604 listen,
605 std::ffi::c_int,
606 std::ffi::c_int,
607 std::ffi::c_int,
608 );
609 pub fn listen(
610 ctx: &mut SyscallContext,
611 fd: std::ffi::c_int,
612 backlog: std::ffi::c_int,
613 ) -> Result<(), Errno> {
614 let desc_table = ctx.objs.thread.descriptor_table_borrow(ctx.objs.host);
616 let desc = Self::get_descriptor(&desc_table, fd)?;
617
618 let CompatFile::New(file) = desc.file() else {
619 return Err(Errno::ENOTSOCK);
621 };
622
623 let File::Socket(socket) = file.inner_file() else {
624 return Err(Errno::ENOTSOCK);
625 };
626
627 let mut rng = ctx.objs.host.random_mut();
628 let net_ns = ctx.objs.host.network_namespace_borrow();
629
630 CallbackQueue::queue_and_run_with_legacy(|cb_queue| {
631 Socket::listen(socket, backlog, &net_ns, &mut *rng, cb_queue)
632 })?;
633
634 Ok(())
635 }
636
637 log_syscall!(
638 accept,
639 std::ffi::c_int,
640 std::ffi::c_int,
641 *const libc::sockaddr,
642 *const libc::socklen_t,
643 );
644 pub fn accept(
645 ctx: &mut SyscallContext,
646 fd: std::ffi::c_int,
647 addr_ptr: ForeignPtr<u8>,
648 addr_len_ptr: ForeignPtr<libc::socklen_t>,
649 ) -> Result<DescriptorHandle, SyscallError> {
650 let file = ctx
653 .objs
654 .thread
655 .syscall_condition()
656 .and_then(|x| x.active_file().cloned());
658
659 let file = match file {
660 Some(x) => x,
662 None => {
664 let desc_table = ctx.objs.thread.descriptor_table_borrow(ctx.objs.host);
665 let CompatFile::New(file) = Self::get_descriptor(&desc_table, fd)?.file() else {
666 return Err(Errno::ENOTSOCK.into());
668 };
669 file.clone()
670 }
671 };
672
673 let mut result = Self::accept_helper(ctx, file.inner_file(), addr_ptr, addr_len_ptr, 0);
674
675 if let Some(err) = result.as_mut().err() {
677 if let Some(cond) = err.blocked_condition() {
678 cond.set_active_file(file);
679 }
680 }
681
682 result
683 }
684
685 log_syscall!(
686 accept4,
687 std::ffi::c_int,
688 std::ffi::c_int,
689 *const libc::sockaddr,
690 *const libc::socklen_t,
691 std::ffi::c_int,
692 );
693 pub fn accept4(
694 ctx: &mut SyscallContext,
695 fd: std::ffi::c_int,
696 addr_ptr: ForeignPtr<u8>,
697 addr_len_ptr: ForeignPtr<libc::socklen_t>,
698 flags: std::ffi::c_int,
699 ) -> Result<DescriptorHandle, SyscallError> {
700 let file = ctx
703 .objs
704 .thread
705 .syscall_condition()
706 .and_then(|x| x.active_file().cloned());
708
709 let file = match file {
710 Some(x) => x,
712 None => {
714 let desc_table = ctx.objs.thread.descriptor_table_borrow(ctx.objs.host);
715 let CompatFile::New(file) = Self::get_descriptor(&desc_table, fd)?.file() else {
716 return Err(Errno::ENOTSOCK.into());
718 };
719 file.clone()
720 }
721 };
722
723 let mut result = Self::accept_helper(ctx, file.inner_file(), addr_ptr, addr_len_ptr, flags);
724
725 if let Some(err) = result.as_mut().err() {
727 if let Some(cond) = err.blocked_condition() {
728 cond.set_active_file(file);
729 }
730 }
731
732 result
733 }
734
735 fn accept_helper(
736 ctx: &mut SyscallContext,
737 file: &File,
738 addr_ptr: ForeignPtr<u8>,
739 addr_len_ptr: ForeignPtr<libc::socklen_t>,
740 flags: std::ffi::c_int,
741 ) -> Result<DescriptorHandle, SyscallError> {
742 let File::Socket(socket) = file else {
743 return Err(Errno::ENOTSOCK.into());
744 };
745
746 let flags = match SockFlag::from_bits(flags) {
748 Some(x) => x,
749 None => {
750 warn!("Invalid recvfrom flags: {}", flags);
752 SockFlag::from_bits_truncate(flags)
753 }
754 };
755
756 let mut rng = ctx.objs.host.random_mut();
757 let net_ns = ctx.objs.host.network_namespace_borrow();
758
759 let result = CallbackQueue::queue_and_run_with_legacy(|cb_queue| {
760 socket.borrow_mut().accept(&net_ns, &mut *rng, cb_queue)
761 });
762
763 let file_status = socket.borrow().status();
764
765 if result.as_ref().err() == Some(&Errno::EWOULDBLOCK.into())
767 && !file_status.contains(FileStatus::NONBLOCK)
768 {
769 return Err(SyscallError::new_blocked_on_file(
770 file.clone(),
771 FileState::READABLE,
772 socket.borrow().supports_sa_restart(),
773 ));
774 }
775
776 let new_socket = result?;
777
778 let from_addr = {
779 let File::Socket(new_socket) = new_socket.inner_file() else {
780 panic!("Accepted file should be a socket");
781 };
782 new_socket.borrow().getpeername().unwrap()
783 };
784
785 if !addr_ptr.is_null() {
786 io::write_sockaddr_and_len(
787 &mut ctx.objs.process.memory_borrow_mut(),
788 from_addr.as_ref(),
789 addr_ptr,
790 addr_len_ptr,
791 )?;
792 }
793
794 if flags.contains(SockFlag::SOCK_NONBLOCK) {
795 new_socket
796 .inner_file()
797 .borrow_mut()
798 .set_status(FileStatus::NONBLOCK);
799 }
800
801 let mut new_desc = Descriptor::new(CompatFile::New(new_socket));
802
803 if flags.contains(SockFlag::SOCK_CLOEXEC) {
804 new_desc.set_flags(DescriptorFlags::FD_CLOEXEC);
805 }
806
807 Ok(ctx
808 .objs
809 .thread
810 .descriptor_table_borrow_mut(ctx.objs.host)
811 .register_descriptor(new_desc)
812 .or(Err(Errno::ENFILE))?)
813 }
814
815 log_syscall!(
816 connect,
817 std::ffi::c_int,
818 std::ffi::c_int,
819 SyscallSockAddrArg<2>,
820 libc::socklen_t,
821 );
822 pub fn connect(
823 ctx: &mut SyscallContext,
824 fd: std::ffi::c_int,
825 addr_ptr: ForeignPtr<u8>,
826 addr_len: libc::socklen_t,
827 ) -> Result<(), SyscallError> {
828 let file = ctx
831 .objs
832 .thread
833 .syscall_condition()
834 .and_then(|x| x.active_file().cloned());
836
837 let file = match file {
838 Some(x) => x,
840 None => {
842 let desc_table = ctx.objs.thread.descriptor_table_borrow(ctx.objs.host);
843 let CompatFile::New(file) = Self::get_descriptor(&desc_table, fd)?.file() else {
844 return Err(Errno::ENOTSOCK.into());
846 };
847 file.clone()
848 }
849 };
850
851 let File::Socket(socket) = file.inner_file() else {
852 return Err(Errno::ENOTSOCK.into());
853 };
854
855 let addr = io::read_sockaddr(&ctx.objs.process.memory_borrow(), addr_ptr, addr_len)?
856 .ok_or(Errno::EFAULT)?;
857
858 let mut rng = ctx.objs.host.random_mut();
859 let net_ns = ctx.objs.host.network_namespace_borrow();
860
861 let mut result = CallbackQueue::queue_and_run_with_legacy(|cb_queue| {
862 Socket::connect(socket, &addr, &net_ns, &mut *rng, cb_queue)
863 });
864
865 if let Some(err) = result.as_mut().err() {
867 if let Some(cond) = err.blocked_condition() {
868 cond.set_active_file(file);
869 }
870 }
871
872 result?;
873
874 Ok(())
875 }
876
877 log_syscall!(
878 shutdown,
879 std::ffi::c_int,
880 std::ffi::c_int,
881 std::ffi::c_uint,
882 );
883 pub fn shutdown(
884 ctx: &mut SyscallContext,
885 fd: std::ffi::c_int,
886 how: std::ffi::c_uint,
887 ) -> Result<(), SyscallError> {
888 let desc_table = ctx.objs.thread.descriptor_table_borrow(ctx.objs.host);
890 let desc = Self::get_descriptor(&desc_table, fd)?;
891
892 let CompatFile::New(file) = desc.file() else {
893 return Err(Errno::ENOTSOCK.into());
895 };
896
897 let how = Shutdown::try_from(how).or(Err(Errno::EINVAL))?;
898
899 let File::Socket(socket) = file.inner_file() else {
900 return Err(Errno::ENOTSOCK.into());
901 };
902
903 CallbackQueue::queue_and_run_with_legacy(|cb_queue| {
904 socket.borrow_mut().shutdown(how, cb_queue)
905 })?;
906
907 Ok(())
908 }
909
910 log_syscall!(
911 socketpair,
912 std::ffi::c_int,
913 linux_api::socket::AddressFamily,
914 std::ffi::c_int,
915 std::ffi::c_int,
916 [std::ffi::c_int; 2],
917 );
918 pub fn socketpair(
919 ctx: &mut SyscallContext,
920 domain: std::ffi::c_int,
921 socket_type: std::ffi::c_int,
922 protocol: std::ffi::c_int,
923 fd_ptr: ForeignPtr<[std::ffi::c_int; 2]>,
924 ) -> Result<(), SyscallError> {
925 let flags = socket_type & (libc::SOCK_NONBLOCK | libc::SOCK_CLOEXEC);
927 let socket_type = socket_type & !flags;
928
929 if domain != libc::AF_UNIX {
931 warn!("Domain {domain} is not supported for socketpair()");
932 return Err(Errno::EOPNOTSUPP.into());
933 }
934
935 let socket_type = match UnixSocketType::try_from(socket_type) {
936 Ok(x) => x,
937 Err(e) => {
938 warn!("Not a unix socket type: {e}");
939 return Err(Errno::EPROTONOSUPPORT.into());
940 }
941 };
942
943 if protocol != 0 {
945 warn!("Unsupported socket protocol {protocol}, we only support default protocol 0");
946 return Err(Errno::EPROTONOSUPPORT.into());
947 }
948
949 let mut file_flags = FileStatus::empty();
950 let mut descriptor_flags = DescriptorFlags::empty();
951
952 if flags & libc::SOCK_NONBLOCK != 0 {
953 file_flags.insert(FileStatus::NONBLOCK);
954 }
955
956 if flags & libc::SOCK_CLOEXEC != 0 {
957 descriptor_flags.insert(DescriptorFlags::FD_CLOEXEC);
958 }
959
960 let (socket_1, socket_2) = CallbackQueue::queue_and_run_with_legacy(|cb_queue| {
961 UnixSocket::pair(
962 file_flags,
963 socket_type,
964 &ctx.objs.host.abstract_unix_namespace(),
965 cb_queue,
966 )
967 });
968
969 let mut desc_1 = Descriptor::new(CompatFile::New(OpenFile::new(File::Socket(
971 Socket::Unix(socket_1),
972 ))));
973 let mut desc_2 = Descriptor::new(CompatFile::New(OpenFile::new(File::Socket(
974 Socket::Unix(socket_2),
975 ))));
976
977 desc_1.set_flags(descriptor_flags);
979 desc_2.set_flags(descriptor_flags);
980
981 let mut dt = ctx.objs.thread.descriptor_table_borrow_mut(ctx.objs.host);
983 let fd_1 = dt.register_descriptor(desc_1).unwrap();
986 let fd_2 = dt.register_descriptor(desc_2).unwrap();
987
988 let fds = [i32::from(fd_1), i32::from(fd_2)];
990 let write_res = ctx.objs.process.memory_borrow_mut().write(fd_ptr, &fds);
991
992 match write_res {
994 Ok(_) => Ok(()),
995 Err(e) => {
996 CallbackQueue::queue_and_run_with_legacy(|cb_queue| {
997 dt.deregister_descriptor(fd_1)
999 .unwrap()
1000 .close(ctx.objs.host, cb_queue);
1001 dt.deregister_descriptor(fd_2)
1002 .unwrap()
1003 .close(ctx.objs.host, cb_queue);
1004 });
1005 Err(e.into())
1006 }
1007 }
1008 }
1009
1010 log_syscall!(
1011 getsockopt,
1012 std::ffi::c_int,
1013 std::ffi::c_int,
1014 std::ffi::c_int,
1015 std::ffi::c_int,
1016 *const std::ffi::c_void,
1017 *const libc::socklen_t,
1018 );
1019 pub fn getsockopt(
1020 ctx: &mut SyscallContext,
1021 fd: std::ffi::c_int,
1022 level: std::ffi::c_int,
1023 optname: std::ffi::c_int,
1024 optval_ptr: ForeignPtr<()>,
1025 optlen_ptr: ForeignPtr<libc::socklen_t>,
1026 ) -> Result<(), SyscallError> {
1027 let desc_table = ctx.objs.thread.descriptor_table_borrow(ctx.objs.host);
1029 let desc = Self::get_descriptor(&desc_table, fd)?;
1030
1031 let CompatFile::New(file) = desc.file() else {
1032 return Err(Errno::ENOTSOCK.into());
1034 };
1035
1036 let File::Socket(socket) = file.inner_file() else {
1037 return Err(Errno::ENOTSOCK.into());
1038 };
1039
1040 let mut mem = ctx.objs.process.memory_borrow_mut();
1041
1042 let optlen = mem.read(optlen_ptr)?;
1044
1045 let mut optlen_new = CallbackQueue::queue_and_run_with_legacy(|cb_queue| {
1046 socket
1047 .borrow_mut()
1048 .getsockopt(level, optname, optval_ptr, optlen, &mut mem, cb_queue)
1049 })?;
1050
1051 if optlen_new > optlen {
1052 log::warn!(
1054 "Attempting to return an optlen {} that's greater than the provided optlen {}",
1055 optlen_new,
1056 optlen
1057 );
1058 optlen_new = optlen;
1059 }
1060
1061 mem.write(optlen_ptr, &optlen_new)?;
1063
1064 Ok(())
1065 }
1066
1067 log_syscall!(
1068 setsockopt,
1069 std::ffi::c_int,
1070 std::ffi::c_int,
1071 std::ffi::c_int,
1072 std::ffi::c_int,
1073 *const std::ffi::c_void,
1074 libc::socklen_t,
1075 );
1076 pub fn setsockopt(
1077 ctx: &mut SyscallContext,
1078 fd: std::ffi::c_int,
1079 level: std::ffi::c_int,
1080 optname: std::ffi::c_int,
1081 optval_ptr: ForeignPtr<()>,
1082 optlen: libc::socklen_t,
1083 ) -> Result<(), SyscallError> {
1084 let desc_table = ctx.objs.thread.descriptor_table_borrow(ctx.objs.host);
1086 let desc = Self::get_descriptor(&desc_table, fd)?;
1087
1088 let CompatFile::New(file) = desc.file() else {
1089 return Err(Errno::ENOTSOCK.into());
1091 };
1092
1093 let File::Socket(socket) = file.inner_file() else {
1094 return Err(Errno::ENOTSOCK.into());
1095 };
1096
1097 let mem = ctx.objs.process.memory_borrow();
1098
1099 socket
1100 .borrow_mut()
1101 .setsockopt(level, optname, optval_ptr, optlen, &mem)?;
1102
1103 Ok(())
1104 }
1105}