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