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