1use std::cell::{Cell, RefCell};
2use std::io::Read;
3use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6};
4use std::{io, iter};
5
6use mio::Interest;
7use mio::event::Source;
8use mio::net::{TcpListener, TcpStream};
9use rand::Rng;
10use rustc_abi::Size;
11use rustc_const_eval::interpret::{InterpResult, interp_ok};
12use rustc_middle::throw_unsup_format;
13use rustc_target::spec::Os;
14
15use crate::shims::files::{EvalContextExt as _, FdId, FileDescription, FileDescriptionRef};
16use crate::{OpTy, Scalar, *};
17
18#[derive(Debug, PartialEq)]
19enum SocketFamily {
20 IPv4,
22 IPv6,
24}
25
26enum SocketIoError {
27 NotReady,
29 Other(io::Error),
31}
32
33impl From<io::Error> for SocketIoError {
34 fn from(value: io::Error) -> Self {
35 match value.kind() {
36 io::ErrorKind::InProgress | io::ErrorKind::NotConnected => Self::NotReady,
37 _ => Self::Other(value),
38 }
39 }
40}
41
42#[derive(Debug)]
43enum SocketState {
44 Initial,
46 Bound(SocketAddr),
49 Listening(TcpListener),
52 Connecting(TcpStream),
56 Connected(TcpStream),
62}
63
64impl SocketState {
65 pub fn try_set_connected(&mut self) -> Result<(), SocketIoError> {
76 let SocketState::Connecting(stream) = self else { return Ok(()) };
82
83 if let Ok(Some(e)) = stream.take_error() {
84 let e = SocketIoError::from(e);
86 assert!(matches!(e, SocketIoError::Other(_)));
89 *self = SocketState::Initial;
92 return Err(e);
93 }
94
95 if let Err(e) = stream.peer_addr() {
96 let e = SocketIoError::from(e);
97 if let SocketIoError::Other(_) = &e {
98 *self = SocketState::Initial;
100 }
101 return Err(e);
102 };
103
104 let SocketState::Connecting(stream) = std::mem::replace(self, SocketState::Initial) else {
109 unreachable!()
111 };
112 *self = SocketState::Connected(stream);
113 Ok(())
114 }
115}
116
117#[derive(Debug)]
118struct Socket {
119 family: SocketFamily,
122 state: RefCell<SocketState>,
124 is_non_block: Cell<bool>,
126}
127
128impl FileDescription for Socket {
129 fn name(&self) -> &'static str {
130 "socket"
131 }
132
133 fn destroy<'tcx>(
134 self,
135 _self_id: FdId,
136 communicate_allowed: bool,
137 _ecx: &mut MiriInterpCx<'tcx>,
138 ) -> InterpResult<'tcx, std::io::Result<()>> {
139 assert!(communicate_allowed, "cannot have `Socket` with isolation enabled!");
140
141 interp_ok(Ok(()))
142 }
143
144 fn read<'tcx>(
145 self: FileDescriptionRef<Self>,
146 communicate_allowed: bool,
147 ptr: Pointer,
148 len: usize,
149 ecx: &mut MiriInterpCx<'tcx>,
150 finish: DynMachineCallback<'tcx, Result<usize, IoError>>,
151 ) -> InterpResult<'tcx> {
152 assert!(communicate_allowed, "cannot have `Socket` with isolation enabled!");
153
154 if !matches!(&*self.state.borrow(), SocketState::Connected(_)) {
155 return finish.call(ecx, Err(LibcError("ENOTCONN")));
158 }
159
160 ecx.block_for_recv(self, ptr, len, false, finish);
163
164 interp_ok(())
165 }
166
167 fn write<'tcx>(
168 self: FileDescriptionRef<Self>,
169 communicate_allowed: bool,
170 ptr: Pointer,
171 len: usize,
172 ecx: &mut MiriInterpCx<'tcx>,
173 finish: DynMachineCallback<'tcx, Result<usize, IoError>>,
174 ) -> InterpResult<'tcx> {
175 assert!(communicate_allowed, "cannot have `Socket` with isolation enabled!");
176
177 if !matches!(&*self.state.borrow(), SocketState::Connected(_)) {
178 return finish.call(ecx, Err(LibcError("ENOTCONN")));
181 }
182
183 ecx.block_for_send(self, ptr, len, finish);
186
187 interp_ok(())
188 }
189
190 fn short_fd_operations(&self) -> bool {
191 true
193 }
194
195 fn get_flags<'tcx>(&self, ecx: &mut MiriInterpCx<'tcx>) -> InterpResult<'tcx, Scalar> {
196 let mut flags = ecx.eval_libc_i32("O_RDWR");
197
198 if self.is_non_block.get() {
199 flags |= ecx.eval_libc_i32("O_NONBLOCK");
200 }
201
202 interp_ok(Scalar::from_i32(flags))
203 }
204
205 fn set_flags<'tcx>(
206 &self,
207 mut _flag: i32,
208 _ecx: &mut MiriInterpCx<'tcx>,
209 ) -> InterpResult<'tcx, Scalar> {
210 throw_unsup_format!("fcntl: socket flags aren't supported")
211 }
212}
213
214impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {}
215pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
216 fn socket(
219 &mut self,
220 domain: &OpTy<'tcx>,
221 type_: &OpTy<'tcx>,
222 protocol: &OpTy<'tcx>,
223 ) -> InterpResult<'tcx, Scalar> {
224 let this = self.eval_context_mut();
225
226 let domain = this.read_scalar(domain)?.to_i32()?;
227 let mut flags = this.read_scalar(type_)?.to_i32()?;
228 let protocol = this.read_scalar(protocol)?.to_i32()?;
229
230 if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
232 this.reject_in_isolation("`socket`", reject_with)?;
233 return this.set_last_error_and_return_i32(LibcError("EACCES"));
234 }
235
236 let mut is_sock_nonblock = false;
237
238 if matches!(
241 this.tcx.sess.target.os,
242 Os::Linux | Os::Android | Os::FreeBsd | Os::Solaris | Os::Illumos
243 ) {
244 let sock_nonblock = this.eval_libc_i32("SOCK_NONBLOCK");
247 let sock_cloexec = this.eval_libc_i32("SOCK_CLOEXEC");
248 if flags & sock_nonblock == sock_nonblock {
249 is_sock_nonblock = true;
250 flags &= !sock_nonblock;
251 }
252 if flags & sock_cloexec == sock_cloexec {
253 flags &= !sock_cloexec;
255 }
256 }
257
258 let family = if domain == this.eval_libc_i32("AF_INET") {
259 SocketFamily::IPv4
260 } else if domain == this.eval_libc_i32("AF_INET6") {
261 SocketFamily::IPv6
262 } else {
263 throw_unsup_format!(
264 "socket: domain {:#x} is unsupported, only AF_INET and \
265 AF_INET6 are allowed.",
266 domain
267 );
268 };
269
270 if flags != this.eval_libc_i32("SOCK_STREAM") {
271 throw_unsup_format!(
272 "socket: type {:#x} is unsupported, only SOCK_STREAM, \
273 SOCK_CLOEXEC and SOCK_NONBLOCK are allowed",
274 flags
275 );
276 }
277 if protocol != 0 {
278 throw_unsup_format!(
279 "socket: socket protocol {protocol} is unsupported, \
280 only 0 is allowed"
281 );
282 }
283
284 let fds = &mut this.machine.fds;
285 let fd = fds.new_ref(Socket {
286 family,
287 state: RefCell::new(SocketState::Initial),
288 is_non_block: Cell::new(is_sock_nonblock),
289 });
290
291 interp_ok(Scalar::from_i32(fds.insert(fd)))
292 }
293
294 fn bind(
295 &mut self,
296 socket: &OpTy<'tcx>,
297 address: &OpTy<'tcx>,
298 address_len: &OpTy<'tcx>,
299 ) -> InterpResult<'tcx, Scalar> {
300 let this = self.eval_context_mut();
301
302 let socket = this.read_scalar(socket)?.to_i32()?;
303 let address = match this.socket_address(address, address_len, "bind")? {
304 Ok(addr) => addr,
305 Err(e) => return this.set_last_error_and_return_i32(e),
306 };
307
308 let Some(fd) = this.machine.fds.get(socket) else {
310 return this.set_last_error_and_return_i32(LibcError("EBADF"));
311 };
312
313 let Some(socket) = fd.downcast::<Socket>() else {
314 return this.set_last_error_and_return_i32(LibcError("ENOTSOCK"));
316 };
317
318 assert!(this.machine.communicate(), "cannot have `Socket` with isolation enabled!");
319
320 let mut state = socket.state.borrow_mut();
321
322 match *state {
323 SocketState::Initial => {
324 let address_family = match &address {
325 SocketAddr::V4(_) => SocketFamily::IPv4,
326 SocketAddr::V6(_) => SocketFamily::IPv6,
327 };
328
329 if socket.family != address_family {
330 let err = if matches!(this.tcx.sess.target.os, Os::Linux | Os::Android) {
333 LibcError("EINVAL")
336 } else {
337 LibcError("EAFNOSUPPORT")
341 };
342 return this.set_last_error_and_return_i32(err);
343 }
344
345 *state = SocketState::Bound(address);
346 }
347 SocketState::Connecting(_) | SocketState::Connected(_) =>
348 throw_unsup_format!(
349 "bind: socket is already connected and binding a
350 connected socket is unsupported"
351 ),
352 SocketState::Bound(_) | SocketState::Listening(_) =>
353 throw_unsup_format!(
354 "bind: socket is already bound and binding a socket \
355 multiple times is unsupported"
356 ),
357 }
358
359 interp_ok(Scalar::from_i32(0))
360 }
361
362 fn listen(&mut self, socket: &OpTy<'tcx>, backlog: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> {
363 let this = self.eval_context_mut();
364
365 let socket = this.read_scalar(socket)?.to_i32()?;
366 let _backlog = this.read_scalar(backlog)?.to_i32()?;
368
369 let Some(fd) = this.machine.fds.get(socket) else {
371 return this.set_last_error_and_return_i32(LibcError("EBADF"));
372 };
373
374 let Some(socket) = fd.downcast::<Socket>() else {
375 return this.set_last_error_and_return_i32(LibcError("ENOTSOCK"));
377 };
378
379 assert!(this.machine.communicate(), "cannot have `Socket` with isolation enabled!");
380
381 let mut state = socket.state.borrow_mut();
382
383 match *state {
384 SocketState::Bound(socket_addr) =>
385 match TcpListener::bind(socket_addr) {
386 Ok(listener) => *state = SocketState::Listening(listener),
387 Err(e) => return this.set_last_error_and_return_i32(e),
388 },
389 SocketState::Initial => {
390 throw_unsup_format!(
391 "listen: listening on a socket which isn't bound is unsupported"
392 )
393 }
394 SocketState::Listening(_) => {
395 throw_unsup_format!("listen: listening on a socket multiple times is unsupported")
396 }
397 SocketState::Connecting(_) | SocketState::Connected(_) => {
398 throw_unsup_format!("listen: listening on a connected socket is unsupported")
399 }
400 }
401
402 interp_ok(Scalar::from_i32(0))
403 }
404
405 fn accept4(
408 &mut self,
409 socket: &OpTy<'tcx>,
410 address: &OpTy<'tcx>,
411 address_len: &OpTy<'tcx>,
412 flags: Option<&OpTy<'tcx>>,
413 dest: &MPlaceTy<'tcx>,
415 ) -> InterpResult<'tcx> {
416 let this = self.eval_context_mut();
417
418 let socket = this.read_scalar(socket)?.to_i32()?;
419 let address_ptr = this.read_pointer(address)?;
420 let address_len_ptr = this.read_pointer(address_len)?;
421 let mut flags =
422 if let Some(flags) = flags { this.read_scalar(flags)?.to_i32()? } else { 0 };
423
424 let Some(fd) = this.machine.fds.get(socket) else {
426 return this.set_last_error_and_return(LibcError("EBADF"), dest);
427 };
428
429 let Some(socket) = fd.downcast::<Socket>() else {
430 return this.set_last_error_and_return(LibcError("ENOTSOCK"), dest);
432 };
433
434 assert!(this.machine.communicate(), "cannot have `Socket` with isolation enabled!");
435
436 if !matches!(*socket.state.borrow(), SocketState::Listening(_)) {
437 throw_unsup_format!(
438 "accept4: accepting incoming connections is only allowed when socket is listening"
439 )
440 };
441
442 let mut is_client_sock_nonblock = false;
443
444 if matches!(
447 this.tcx.sess.target.os,
448 Os::Linux | Os::Android | Os::FreeBsd | Os::Solaris | Os::Illumos
449 ) {
450 let sock_nonblock = this.eval_libc_i32("SOCK_NONBLOCK");
453 let sock_cloexec = this.eval_libc_i32("SOCK_CLOEXEC");
454 if flags & sock_nonblock == sock_nonblock {
455 is_client_sock_nonblock = true;
456 flags &= !sock_nonblock;
457 }
458 if flags & sock_cloexec == sock_cloexec {
459 flags &= !sock_cloexec;
461 }
462 }
463
464 if flags != 0 {
465 throw_unsup_format!(
466 "accept4: flag {flags:#x} is unsupported, only SOCK_CLOEXEC \
467 and SOCK_NONBLOCK are allowed",
468 );
469 }
470
471 if socket.is_non_block.get() {
472 throw_unsup_format!("accept4: non-blocking accept is unsupported")
473 }
474
475 this.block_for_accept(
478 address_ptr,
479 address_len_ptr,
480 is_client_sock_nonblock,
481 socket,
482 dest.clone(),
483 );
484 interp_ok(())
485 }
486
487 fn connect(
488 &mut self,
489 socket: &OpTy<'tcx>,
490 address: &OpTy<'tcx>,
491 address_len: &OpTy<'tcx>,
492 dest: &MPlaceTy<'tcx>,
494 ) -> InterpResult<'tcx> {
495 let this = self.eval_context_mut();
496
497 let socket = this.read_scalar(socket)?.to_i32()?;
498 let address = match this.socket_address(address, address_len, "connect")? {
499 Ok(address) => address,
500 Err(e) => return this.set_last_error_and_return(e, dest),
501 };
502
503 let Some(fd) = this.machine.fds.get(socket) else {
505 return this.set_last_error_and_return(LibcError("EBADF"), dest);
506 };
507
508 let Some(socket) = fd.downcast::<Socket>() else {
509 return this.set_last_error_and_return(LibcError("ENOTSOCK"), dest);
511 };
512
513 assert!(this.machine.communicate(), "cannot have `Socket` with isolation enabled!");
514
515 match &*socket.state.borrow() {
516 SocketState::Initial => { }
517 SocketState::Connecting(_) =>
519 return this.set_last_error_and_return(LibcError("EALREADY"), dest),
520 _ =>
524 throw_unsup_format!(
525 "connect: connecting is only supported for sockets which are neither \
526 bound, listening nor already connected"
527 ),
528 }
529
530 match TcpStream::connect(address) {
537 Ok(stream) => *socket.state.borrow_mut() = SocketState::Connecting(stream),
538 Err(e) => return this.set_last_error_and_return(e, dest),
539 };
540
541 if socket.is_non_block.get() {
542 throw_unsup_format!("connect: non-blocking connect is unsupported");
543 }
544
545 this.block_for_connect(socket, dest.clone());
548 interp_ok(())
549 }
550
551 fn send(
552 &mut self,
553 socket: &OpTy<'tcx>,
554 buffer: &OpTy<'tcx>,
555 length: &OpTy<'tcx>,
556 flags: &OpTy<'tcx>,
557 dest: &MPlaceTy<'tcx>,
559 ) -> InterpResult<'tcx> {
560 let this = self.eval_context_mut();
561
562 let socket = this.read_scalar(socket)?.to_i32()?;
563 let buffer_ptr = this.read_pointer(buffer)?;
564 let size_layout = this.libc_ty_layout("size_t");
565 let length: usize =
566 this.read_scalar(length)?.to_uint(size_layout.size)?.try_into().unwrap();
567 let mut flags = this.read_scalar(flags)?.to_i32()?;
568
569 let Some(fd) = this.machine.fds.get(socket) else {
571 return this.set_last_error_and_return(LibcError("EBADF"), dest);
572 };
573
574 let Some(socket) = fd.downcast::<Socket>() else {
575 return this.set_last_error_and_return(LibcError("ENOTSOCK"), dest);
577 };
578
579 if !matches!(&*socket.state.borrow(), SocketState::Connected(_)) {
580 return this.set_last_error_and_return(LibcError("ENOTCONN"), dest);
583 }
584
585 let length = if this.machine.short_fd_operations
589 && length >= 2
590 && this.machine.rng.get_mut().random()
591 {
592 length / 2
593 } else {
594 length
595 };
596
597 if matches!(
600 this.tcx.sess.target.os,
601 Os::Linux | Os::Android | Os::FreeBsd | Os::Solaris | Os::Illumos
602 ) {
603 let msg_nosignal = this.eval_libc_i32("MSG_NOSIGNAL");
606 if flags & msg_nosignal == msg_nosignal {
607 flags &= !msg_nosignal;
611 }
612 }
613
614 if flags != 0 {
615 throw_unsup_format!(
616 "send: flag {flags:#x} is unsupported, only MSG_NOSIGNAL is allowed",
617 );
618 }
619
620 let dest = dest.clone();
621
622 this.block_for_send(
623 socket,
624 buffer_ptr,
625 length,
626 callback!(@capture<'tcx> {
627 dest: MPlaceTy<'tcx>
628 } |this, result: Result<usize, IoError>| {
629 match result {
630 Ok(read_size) => {
631 let read_size: u64 = read_size.try_into().unwrap();
632 let ssize_layout = this.libc_ty_layout("ssize_t");
633 this.write_scalar(Scalar::from_int(read_size, ssize_layout.size), &dest)
634 }
635 Err(e) => this.set_last_error_and_return(e, &dest)
636 }
637 }),
638 );
639
640 interp_ok(())
641 }
642
643 fn recv(
644 &mut self,
645 socket: &OpTy<'tcx>,
646 buffer: &OpTy<'tcx>,
647 length: &OpTy<'tcx>,
648 flags: &OpTy<'tcx>,
649 dest: &MPlaceTy<'tcx>,
651 ) -> InterpResult<'tcx> {
652 let this = self.eval_context_mut();
653
654 let socket = this.read_scalar(socket)?.to_i32()?;
655 let buffer_ptr = this.read_pointer(buffer)?;
656 let size_layout = this.libc_ty_layout("size_t");
657 let length: usize =
658 this.read_scalar(length)?.to_uint(size_layout.size)?.try_into().unwrap();
659 let mut flags = this.read_scalar(flags)?.to_i32()?;
660
661 let Some(fd) = this.machine.fds.get(socket) else {
663 return this.set_last_error_and_return(LibcError("EBADF"), dest);
664 };
665
666 let Some(socket) = fd.downcast::<Socket>() else {
667 return this.set_last_error_and_return(LibcError("ENOTSOCK"), dest);
669 };
670
671 if !matches!(&*socket.state.borrow(), SocketState::Connected(_)) {
672 return this.set_last_error_and_return(LibcError("ENOTCONN"), dest);
675 }
676
677 let length = if this.machine.short_fd_operations
684 && length >= 2
685 && this.machine.rng.get_mut().random()
686 {
687 length / 2 } else {
689 length
690 };
691
692 let mut should_peek = false;
693
694 let msg_peek = this.eval_libc_i32("MSG_PEEK");
698 if flags & msg_peek == msg_peek {
699 should_peek = true;
700 flags &= !msg_peek;
701 }
702
703 if matches!(this.tcx.sess.target.os, Os::Linux | Os::Android | Os::FreeBsd | Os::Illumos) {
704 let msg_cmsg_cloexec = this.eval_libc_i32("MSG_CMSG_CLOEXEC");
707 if flags & msg_cmsg_cloexec == msg_cmsg_cloexec {
708 flags &= !msg_cmsg_cloexec;
710 }
711 }
712
713 if flags != 0 {
714 throw_unsup_format!(
715 "recv: flag {flags:#x} is unsupported, only MSG_PEEK \
716 and MSG_CMSG_CLOEXEC are allowed",
717 );
718 }
719
720 let dest = dest.clone();
721
722 this.block_for_recv(
723 socket,
724 buffer_ptr,
725 length,
726 should_peek,
727 callback!(@capture<'tcx> {
728 dest: MPlaceTy<'tcx>
729 } |this, result: Result<usize, IoError>| {
730 match result {
731 Ok(read_size) => {
732 let read_size: u64 = read_size.try_into().unwrap();
733 let ssize_layout = this.libc_ty_layout("ssize_t");
734 this.write_scalar(Scalar::from_int(read_size, ssize_layout.size), &dest)
735 }
736 Err(e) => this.set_last_error_and_return(e, &dest)
737 }
738 }),
739 );
740
741 interp_ok(())
742 }
743
744 fn setsockopt(
745 &mut self,
746 socket: &OpTy<'tcx>,
747 level: &OpTy<'tcx>,
748 option_name: &OpTy<'tcx>,
749 option_value: &OpTy<'tcx>,
750 option_len: &OpTy<'tcx>,
751 ) -> InterpResult<'tcx, Scalar> {
752 let this = self.eval_context_mut();
753
754 let socket = this.read_scalar(socket)?.to_i32()?;
755 let level = this.read_scalar(level)?.to_i32()?;
756 let option_name = this.read_scalar(option_name)?.to_i32()?;
757 let socklen_layout = this.libc_ty_layout("socklen_t");
758 let option_len = this.read_scalar(option_len)?.to_int(socklen_layout.size)?;
759
760 let Some(fd) = this.machine.fds.get(socket) else {
762 return this.set_last_error_and_return_i32(LibcError("EBADF"));
763 };
764
765 let Some(_socket) = fd.downcast::<Socket>() else {
766 return this.set_last_error_and_return_i32(LibcError("ENOTSOCK"));
768 };
769
770 if level == this.eval_libc_i32("SOL_SOCKET") {
771 let opt_so_reuseaddr = this.eval_libc_i32("SO_REUSEADDR");
772
773 if matches!(this.tcx.sess.target.os, Os::MacOs | Os::FreeBsd | Os::NetBsd) {
774 let opt_so_nosigpipe = this.eval_libc_i32("SO_NOSIGPIPE");
776
777 if option_name == opt_so_nosigpipe {
778 if option_len != 4 {
779 return this.set_last_error_and_return_i32(LibcError("EINVAL"));
781 }
782 let option_value =
783 this.deref_pointer_as(option_value, this.machine.layouts.i32)?;
784 let _val = this.read_scalar(&option_value)?.to_i32()?;
785 return interp_ok(Scalar::from_i32(0));
788 }
789 }
790
791 if option_name == opt_so_reuseaddr {
792 if option_len != 4 {
793 return this.set_last_error_and_return_i32(LibcError("EINVAL"));
795 }
796 let option_value = this.deref_pointer_as(option_value, this.machine.layouts.i32)?;
797 let _val = this.read_scalar(&option_value)?.to_i32()?;
798 return interp_ok(Scalar::from_i32(0));
801 } else {
802 throw_unsup_format!(
803 "setsockopt: option {option_name:#x} is unsupported for level SOL_SOCKET",
804 );
805 }
806 }
807
808 throw_unsup_format!(
809 "setsockopt: level {level:#x} is unsupported, only SOL_SOCKET is allowed"
810 );
811 }
812
813 fn getsockname(
814 &mut self,
815 socket: &OpTy<'tcx>,
816 address: &OpTy<'tcx>,
817 address_len: &OpTy<'tcx>,
818 ) -> InterpResult<'tcx, Scalar> {
819 let this = self.eval_context_mut();
820
821 let socket = this.read_scalar(socket)?.to_i32()?;
822 let address_ptr = this.read_pointer(address)?;
823 let address_len_ptr = this.read_pointer(address_len)?;
824
825 let Some(fd) = this.machine.fds.get(socket) else {
827 return this.set_last_error_and_return_i32(LibcError("EBADF"));
828 };
829
830 let Some(socket) = fd.downcast::<Socket>() else {
831 return this.set_last_error_and_return_i32(LibcError("ENOTSOCK"));
833 };
834
835 assert!(this.machine.communicate(), "cannot have `Socket` with isolation enabled!");
836
837 let state = socket.state.borrow();
838
839 let address = match &*state {
840 SocketState::Bound(address) => {
841 if address.port() == 0 {
842 throw_unsup_format!(
846 "getsockname: when the port is 0, getting the socket address before \
847 calling `listen` or `connect` is unsupported"
848 )
849 }
850
851 *address
852 }
853 SocketState::Listening(listener) =>
854 match listener.local_addr() {
855 Ok(address) => address,
856 Err(e) => return this.set_last_error_and_return_i32(e),
857 },
858 _ => SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::UNSPECIFIED, 0)),
861 };
862
863 match this.write_socket_address(&address, address_ptr, address_len_ptr, "getsockname")? {
864 Ok(_) => interp_ok(Scalar::from_i32(0)),
865 Err(e) => this.set_last_error_and_return_i32(e),
866 }
867 }
868
869 fn getpeername(
870 &mut self,
871 socket: &OpTy<'tcx>,
872 address: &OpTy<'tcx>,
873 address_len: &OpTy<'tcx>,
874 ) -> InterpResult<'tcx, Scalar> {
875 let this = self.eval_context_mut();
876
877 let socket = this.read_scalar(socket)?.to_i32()?;
878 let address_ptr = this.read_pointer(address)?;
879 let address_len_ptr = this.read_pointer(address_len)?;
880
881 let Some(fd) = this.machine.fds.get(socket) else {
883 return this.set_last_error_and_return_i32(LibcError("EBADF"));
884 };
885
886 let Some(socket) = fd.downcast::<Socket>() else {
887 return this.set_last_error_and_return_i32(LibcError("ENOTSOCK"));
889 };
890
891 assert!(this.machine.communicate(), "cannot have `Socket` with isolation enabled!");
892
893 let state = socket.state.borrow();
894
895 let SocketState::Connected(stream) = &*state else {
896 return this.set_last_error_and_return_i32(LibcError("ENOTCONN"));
898 };
899
900 let address = match stream.peer_addr() {
901 Ok(address) => address,
902 Err(e) => return this.set_last_error_and_return_i32(e),
903 };
904
905 match this.write_socket_address(&address, address_ptr, address_len_ptr, "getpeername")? {
906 Ok(_) => interp_ok(Scalar::from_i32(0)),
907 Err(e) => this.set_last_error_and_return_i32(e),
908 }
909 }
910}
911
912impl<'tcx> EvalContextPrivExt<'tcx> for crate::MiriInterpCx<'tcx> {}
913trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
914 fn socket_address(
918 &self,
919 address: &OpTy<'tcx>,
920 address_len: &OpTy<'tcx>,
921 foreign_name: &'static str,
922 ) -> InterpResult<'tcx, Result<SocketAddr, IoError>> {
923 let this = self.eval_context_ref();
924
925 let socklen_layout = this.libc_ty_layout("socklen_t");
926 let address_len: u64 =
929 this.read_scalar(address_len)?.to_int(socklen_layout.size)?.try_into().unwrap();
930
931 let sockaddr_layout = this.libc_ty_layout("sockaddr");
933 if address_len < sockaddr_layout.size.bytes() {
934 return interp_ok(Err(LibcError("EINVAL")));
936 }
937 let address = this.deref_pointer_as(address, sockaddr_layout)?;
938
939 let family_field = this.project_field_named(&address, "sa_family")?;
940 let family_layout = this.libc_ty_layout("sa_family_t");
941 let family = this.read_scalar(&family_field)?.to_int(family_layout.size)?;
942
943 let socket_addr = if family == this.eval_libc_i32("AF_INET").into() {
946 let sockaddr_in_layout = this.libc_ty_layout("sockaddr_in");
947 if address_len != sockaddr_in_layout.size.bytes() {
948 return interp_ok(Err(LibcError("EINVAL")));
950 }
951 let address = address.transmute(sockaddr_in_layout, this)?;
952
953 let port_field = this.project_field_named(&address, "sin_port")?;
954 let port_bytes: [u8; 2] = this
956 .read_bytes_ptr_strip_provenance(port_field.ptr(), Size::from_bytes(2))?
957 .try_into()
958 .unwrap();
959 let port = u16::from_be_bytes(port_bytes);
960
961 let addr_field = this.project_field_named(&address, "sin_addr")?;
962 let s_addr_field = this.project_field_named(&addr_field, "s_addr")?;
963 let addr_bytes: [u8; 4] = this
965 .read_bytes_ptr_strip_provenance(s_addr_field.ptr(), Size::from_bytes(4))?
966 .try_into()
967 .unwrap();
968 let addr_bits = u32::from_be_bytes(addr_bytes);
969
970 SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::from_bits(addr_bits), port))
971 } else if family == this.eval_libc_i32("AF_INET6").into() {
972 let sockaddr_in6_layout = this.libc_ty_layout("sockaddr_in6");
973 if address_len != sockaddr_in6_layout.size.bytes() {
974 return interp_ok(Err(LibcError("EINVAL")));
976 }
977 let address = address.offset(Size::ZERO, sockaddr_in6_layout, this)?;
979
980 let port_field = this.project_field_named(&address, "sin6_port")?;
981 let port_bytes: [u8; 2] = this
983 .read_bytes_ptr_strip_provenance(port_field.ptr(), Size::from_bytes(2))?
984 .try_into()
985 .unwrap();
986 let port = u16::from_be_bytes(port_bytes);
987
988 let addr_field = this.project_field_named(&address, "sin6_addr")?;
989 let s_addr_field = this
990 .project_field_named(&addr_field, "s6_addr")?
991 .transmute(this.machine.layouts.u128, this)?;
992 let addr_bytes: [u8; 16] = this
994 .read_bytes_ptr_strip_provenance(s_addr_field.ptr(), Size::from_bytes(16))?
995 .try_into()
996 .unwrap();
997 let addr_bits = u128::from_be_bytes(addr_bytes);
998
999 let flowinfo_field = this.project_field_named(&address, "sin6_flowinfo")?;
1000 let flowinfo = this.read_scalar(&flowinfo_field)?.to_u32()?;
1003
1004 let scope_id_field = this.project_field_named(&address, "sin6_scope_id")?;
1005 let scope_id = this.read_scalar(&scope_id_field)?.to_u32()?;
1008
1009 SocketAddr::V6(SocketAddrV6::new(
1010 Ipv6Addr::from_bits(addr_bits),
1011 port,
1012 flowinfo,
1013 scope_id,
1014 ))
1015 } else {
1016 throw_unsup_format!(
1019 "{foreign_name}: address family {family:#x} is unsupported, \
1020 only AF_INET and AF_INET6 are allowed"
1021 );
1022 };
1023
1024 interp_ok(Ok(socket_addr))
1025 }
1026
1027 fn write_socket_address(
1037 &mut self,
1038 address: &SocketAddr,
1039 address_ptr: Pointer,
1040 address_len_ptr: Pointer,
1041 foreign_name: &'static str,
1042 ) -> InterpResult<'tcx, Result<(), IoError>> {
1043 let this = self.eval_context_mut();
1044
1045 if address_ptr == Pointer::null() || address_len_ptr == Pointer::null() {
1046 throw_ub_format!(
1049 "{foreign_name}: writing a socket address but the address or the length pointer is a null pointer"
1050 )
1051 }
1052
1053 let socklen_layout = this.libc_ty_layout("socklen_t");
1054 let address_buffer_len_place = this.ptr_to_mplace(address_len_ptr, socklen_layout);
1055 let address_buffer_len: u64 = this
1058 .read_scalar(&address_buffer_len_place)?
1059 .to_int(socklen_layout.size)?
1060 .try_into()
1061 .unwrap();
1062
1063 let (address_buffer, address_layout) = match address {
1064 SocketAddr::V4(address) => {
1065 let address_bytes = address.ip().octets();
1067 let port = address.port().to_be();
1069
1070 let sockaddr_in_layout = this.libc_ty_layout("sockaddr_in");
1071 let address_buffer = this.allocate(sockaddr_in_layout, MemoryKind::Stack)?;
1075 this.write_bytes_ptr(
1078 address_buffer.ptr(),
1079 iter::repeat_n(0, address_buffer.layout.size.bytes_usize()),
1080 )?;
1081
1082 let sin_family_field = this.project_field_named(&address_buffer, "sin_family")?;
1083 let af_inet = this.eval_libc("AF_INET");
1088 let address_family =
1089 Scalar::from_int(af_inet.to_int(af_inet.size())?, sin_family_field.layout.size);
1090 this.write_scalar(address_family, &sin_family_field)?;
1091
1092 let sin_port_field = this.project_field_named(&address_buffer, "sin_port")?;
1093 this.write_bytes_ptr(sin_port_field.ptr(), port.to_ne_bytes())?;
1096
1097 let sin_addr_field = this.project_field_named(&address_buffer, "sin_addr")?;
1098 let s_addr_field = this.project_field_named(&sin_addr_field, "s_addr")?;
1099 this.write_bytes_ptr(s_addr_field.ptr(), address_bytes)?;
1100
1101 (address_buffer, sockaddr_in_layout)
1102 }
1103 SocketAddr::V6(address) => {
1104 let address_bytes = address.ip().octets();
1106 let port = address.port().to_be();
1108 let flowinfo = address.flowinfo();
1110 let scope_id = address.scope_id();
1112
1113 let sockaddr_in6_layout = this.libc_ty_layout("sockaddr_in6");
1114 let address_buffer = this.allocate(sockaddr_in6_layout, MemoryKind::Stack)?;
1118 this.write_bytes_ptr(
1121 address_buffer.ptr(),
1122 iter::repeat_n(0, address_buffer.layout.size.bytes_usize()),
1123 )?;
1124
1125 let sin6_family_field = this.project_field_named(&address_buffer, "sin6_family")?;
1126 let af_inet6 = this.eval_libc("AF_INET6");
1131 let address_family = Scalar::from_int(
1132 af_inet6.to_int(af_inet6.size())?,
1133 sin6_family_field.layout.size,
1134 );
1135 this.write_scalar(address_family, &sin6_family_field)?;
1136
1137 let sin6_port_field = this.project_field_named(&address_buffer, "sin6_port")?;
1138 this.write_bytes_ptr(sin6_port_field.ptr(), port.to_ne_bytes())?;
1141
1142 let sin6_flowinfo_field =
1143 this.project_field_named(&address_buffer, "sin6_flowinfo")?;
1144 this.write_scalar(Scalar::from_u32(flowinfo), &sin6_flowinfo_field)?;
1145
1146 let sin6_scope_id_field =
1147 this.project_field_named(&address_buffer, "sin6_scope_id")?;
1148 this.write_scalar(Scalar::from_u32(scope_id), &sin6_scope_id_field)?;
1149
1150 let sin6_addr_field = this.project_field_named(&address_buffer, "sin6_addr")?;
1151 let s6_addr_field = this.project_field_named(&sin6_addr_field, "s6_addr")?;
1152 this.write_bytes_ptr(s6_addr_field.ptr(), address_bytes)?;
1153
1154 (address_buffer, sockaddr_in6_layout)
1155 }
1156 };
1157
1158 this.mem_copy(
1160 address_buffer.ptr(),
1161 address_ptr,
1162 address_layout.size.min(Size::from_bytes(address_buffer_len)),
1164 true,
1167 )?;
1168 this.deallocate_ptr(address_buffer.ptr(), None, MemoryKind::Stack)?;
1171 let address_len = address_layout.size.bytes();
1173
1174 this.write_scalar(
1175 Scalar::from_uint(address_len, socklen_layout.size),
1176 &address_buffer_len_place,
1177 )?;
1178
1179 interp_ok(Ok(()))
1180 }
1181
1182 fn block_for_accept(
1186 &mut self,
1187 address_ptr: Pointer,
1188 address_len_ptr: Pointer,
1189 is_client_sock_nonblock: bool,
1190 socket: FileDescriptionRef<Socket>,
1191 dest: MPlaceTy<'tcx>,
1192 ) {
1193 let this = self.eval_context_mut();
1194 this.block_thread_for_io(
1195 socket.clone(),
1196 Interest::READABLE,
1197 None,
1198 callback!(@capture<'tcx> {
1199 address_ptr: Pointer,
1200 address_len_ptr: Pointer,
1201 is_client_sock_nonblock: bool,
1202 socket: FileDescriptionRef<Socket>,
1203 dest: MPlaceTy<'tcx>,
1204 } |this, kind: UnblockKind| {
1205 assert_eq!(kind, UnblockKind::Ready);
1206
1207 let state = socket.state.borrow();
1208
1209 let SocketState::Listening(listener) = &*state else {
1210 unreachable!()
1214 };
1215
1216 let (stream, addr) = match listener.accept() {
1217 Ok(peer) => peer,
1218 Err(e) if e.kind() == io::ErrorKind::WouldBlock => {
1219 drop(state);
1221 this.block_for_accept(address_ptr, address_len_ptr, is_client_sock_nonblock, socket, dest);
1222 return interp_ok(())
1223 },
1224 Err(e) => return this.set_last_error_and_return(e, &dest),
1225 };
1226
1227 let family = match addr {
1228 SocketAddr::V4(_) => SocketFamily::IPv4,
1229 SocketAddr::V6(_) => SocketFamily::IPv6,
1230 };
1231
1232 if address_ptr != Pointer::null() {
1233 if let Err(e) = this.write_socket_address(&addr, address_ptr, address_len_ptr, "accept4")? {
1237 return this.set_last_error_and_return(e, &dest);
1238 };
1239 }
1240
1241 let fd = this.machine.fds.new_ref(Socket {
1242 family,
1243 state: RefCell::new(SocketState::Connected(stream)),
1244 is_non_block: Cell::new(is_client_sock_nonblock),
1245 });
1246 let sockfd = this.machine.fds.insert(fd);
1247 this.write_scalar(Scalar::from_int(sockfd, dest.layout.size), &dest)
1252 }),
1253 );
1254 }
1255
1256 fn block_for_connect(&mut self, socket: FileDescriptionRef<Socket>, dest: MPlaceTy<'tcx>) {
1258 let this = self.eval_context_mut();
1259 this.block_thread_for_io(
1260 socket.clone(),
1261 Interest::WRITABLE,
1262 None,
1263 callback!(@capture<'tcx> {
1264 socket: FileDescriptionRef<Socket>,
1265 dest: MPlaceTy<'tcx>,
1266 } |this, kind: UnblockKind| {
1267 assert_eq!(kind, UnblockKind::Ready);
1268
1269 let mut state = socket.state.borrow_mut();
1270
1271 match state.try_set_connected() {
1273 Ok(_) => this.write_scalar(Scalar::from_i32(0), &dest),
1274 Err(SocketIoError::NotReady) => {
1275 drop(state);
1277 this.block_for_connect(socket, dest);
1278 return interp_ok(())
1279 },
1280 Err(SocketIoError::Other(e)) => return this.set_last_error_and_return(e, &dest)
1281 }
1282 }),
1283 );
1284 }
1285
1286 fn block_for_send(
1291 &mut self,
1292 socket: FileDescriptionRef<Socket>,
1293 buffer_ptr: Pointer,
1294 length: usize,
1295 finish: DynMachineCallback<'tcx, Result<usize, IoError>>,
1296 ) {
1297 let this = self.eval_context_mut();
1298 this.block_thread_for_io(
1299 socket.clone(),
1300 Interest::WRITABLE,
1301 None,
1302 callback!(@capture<'tcx> {
1303 socket: FileDescriptionRef<Socket>,
1304 buffer_ptr: Pointer,
1305 length: usize,
1306 finish: DynMachineCallback<'tcx, Result<usize, IoError>>,
1307 } |this, kind: UnblockKind| {
1308 assert_eq!(kind, UnblockKind::Ready);
1309
1310 let mut state = socket.state.borrow_mut();
1311 let SocketState::Connected(stream) = &mut*state else {
1312 unreachable!()
1314 };
1315
1316 let result = this.write_to_host(stream, length, buffer_ptr)?;
1318 match result {
1319 Err(IoError::HostError(e)) if e.kind() == io::ErrorKind::WouldBlock => {
1320 drop(state);
1322 this.block_for_send(socket, buffer_ptr, length, finish);
1323 interp_ok(())
1324 },
1325 result => finish.call(this, result)
1326 }
1327 }),
1328 );
1329 }
1330
1331 fn block_for_recv(
1336 &mut self,
1337 socket: FileDescriptionRef<Socket>,
1338 buffer_ptr: Pointer,
1339 length: usize,
1340 should_peek: bool,
1341 finish: DynMachineCallback<'tcx, Result<usize, IoError>>,
1342 ) {
1343 let this = self.eval_context_mut();
1344 this.block_thread_for_io(
1345 socket.clone(),
1346 Interest::READABLE,
1347 None,
1348 callback!(@capture<'tcx> {
1349 socket: FileDescriptionRef<Socket>,
1350 buffer_ptr: Pointer,
1351 length: usize,
1352 should_peek: bool,
1353 finish: DynMachineCallback<'tcx, Result<usize, IoError>>,
1354 } |this, kind: UnblockKind| {
1355 assert_eq!(kind, UnblockKind::Ready);
1356
1357 let mut state = socket.state.borrow_mut();
1358 let SocketState::Connected(stream) = &mut*state else {
1359 unreachable!()
1361 };
1362
1363 let result = this.read_from_host(|buf| {
1365 if should_peek {
1366 stream.peek(buf)
1367 } else {
1368 stream.read(buf)
1369 }
1370 }, length, buffer_ptr)?;
1371 match result {
1372 Err(IoError::HostError(e)) if e.kind() == io::ErrorKind::WouldBlock => {
1373 drop(state);
1375 this.block_for_recv(socket, buffer_ptr, length, should_peek, finish);
1376 interp_ok(())
1377 },
1378 result => finish.call(this, result)
1379 }
1380 }),
1381 );
1382 }
1383}
1384
1385impl VisitProvenance for FileDescriptionRef<Socket> {
1386 fn visit_provenance(&self, _visit: &mut VisitWith<'_>) {}
1389}
1390
1391impl WithSource for FileDescriptionRef<Socket> {
1392 fn with_source(&self, f: &mut dyn FnMut(&mut dyn Source) -> io::Result<()>) -> io::Result<()> {
1393 let mut state = self.state.borrow_mut();
1394 match &mut *state {
1395 SocketState::Listening(listener) => f(listener),
1396 SocketState::Connecting(stream) | SocketState::Connected(stream) => f(stream),
1397 _ => unreachable!(),
1399 }
1400 }
1401}