1use crate::bpf::attachments::SetSockOptProgramResult;
6use crate::mm::{IOVecPtr, MemoryAccessor, MemoryAccessorExt};
7use crate::security;
8use crate::syscalls::time::TimeSpecPtr;
9use crate::task::{CurrentTask, IpTables, Task, WaitCallback, Waiter};
10use crate::vfs::buffers::{
11 AncillaryData, ControlMsg, UserBuffersInputBuffer, UserBuffersOutputBuffer,
12};
13use crate::vfs::socket::{
14 SA_FAMILY_SIZE, SA_STORAGE_SIZE, Socket, SocketAddress, SocketDomain, SocketFile,
15 SocketMessageFlags, SocketPeer, SocketProtocol, SocketShutdownFlags, SocketType, UnixSocket,
16 resolve_unix_socket_address,
17};
18use crate::vfs::{FdFlags, FdNumber, FileHandle, FsString, LookupContext};
19use starnix_logging::{log_trace, track_stub};
20use starnix_types::augmented::Augmented;
21use starnix_types::time::duration_from_timespec;
22use starnix_types::user_buffer::{UserBuffer, UserBuffers};
23use starnix_uapi::auth::CAP_NET_BIND_SERVICE;
24use starnix_uapi::errors::{EEXIST, EINPROGRESS, Errno};
25use starnix_uapi::file_mode::FileMode;
26use starnix_uapi::math::round_up_to_increment;
27use starnix_uapi::open_flags::OpenFlags;
28use starnix_uapi::user_address::{
29 ArchSpecific, MappingMultiArchUserRef, MultiArchUserRef, UserAddress, UserRef,
30};
31use starnix_uapi::user_value::UserValue;
32use starnix_uapi::vfs::FdEvents;
33use starnix_uapi::{
34 MSG_CTRUNC, MSG_DONTWAIT, MSG_TRUNC, MSG_WAITFORONE, SHUT_RD, SHUT_RDWR, SHUT_WR, SOCK_CLOEXEC,
35 SOCK_NONBLOCK, UIO_MAXIOV, errno, error, socklen_t, uapi,
36};
37use std::ops::DerefMut;
38
39uapi::check_arch_independent_layout! {
40 socklen_t {}
41}
42
43pub type WithAlternateBuffer<T> = Augmented<T, UserBuffer>;
46pub type MsgHdrPtr = MappingMultiArchUserRef<MsgHdr, uapi::msghdr, uapi::arch32::msghdr>;
47
48#[derive(Debug, Clone)]
49pub struct MsgHdr {
50 pub name: UserAddress,
51 pub name_len: socklen_t,
52 pub iov: IOVecPtr,
53 pub iovlen: UserValue<usize>,
54 pub control: UserAddress,
55 pub control_len: usize,
56 pub flags: u32,
57}
58
59#[derive(Debug, Clone)]
65pub enum MsgHdrRef {
66 Ptr(MsgHdrPtr),
67 Value(WithAlternateBuffer<MsgHdr>),
68}
69
70impl From<MsgHdrPtr> for MsgHdrRef {
71 fn from(ptr: MsgHdrPtr) -> Self {
72 Self::Ptr(ptr)
73 }
74}
75
76impl From<WithAlternateBuffer<MsgHdr>> for MsgHdrRef {
77 fn from(value: WithAlternateBuffer<MsgHdr>) -> Self {
78 Self::Value(value)
79 }
80}
81
82pub type MMsgHdrPtr = MappingMultiArchUserRef<MMsgHdr, uapi::mmsghdr, uapi::arch32::mmsghdr>;
83
84pub struct MMsgHdr {
85 hdr: MsgHdr,
86 len: usize,
87}
88
89uapi::arch_map_data! {
90 BidiTryFrom<MsgHdr, msghdr> {
91 name = msg_name;
92 name_len = msg_namelen;
93 iov = msg_iov;
94 iovlen = msg_iovlen;
95 control = msg_control;
96 control_len = msg_controllen;
97 flags = msg_flags;
98 }
99
100 BidiTryFrom<MMsgHdr, mmsghdr> {
101 hdr = msg_hdr;
102 len = msg_len;
103 }
104}
105
106pub type CMsgHdrPtr = MultiArchUserRef<uapi::cmsghdr, uapi::arch32::cmsghdr>;
107
108pub fn sys_socket(
109 current_task: &CurrentTask,
110 domain: u32,
111 socket_type: u32,
112 protocol: u32,
113) -> Result<FdNumber, Errno> {
114 let flags = socket_type & (SOCK_NONBLOCK | SOCK_CLOEXEC);
115 let domain = parse_socket_domain(domain)?;
116 let socket_type = parse_socket_type(domain, socket_type)?;
117 let protocol = SocketProtocol::from_raw(protocol);
119 let open_flags = socket_flags_to_open_flags(flags);
120 let socket_file = SocketFile::new_socket(
121 current_task,
122 domain,
123 socket_type,
124 open_flags,
125 protocol,
126 false,
127 )?;
128
129 let fd_flags = socket_flags_to_fd_flags(flags);
130 let fd = current_task.add_file(socket_file, fd_flags)?;
131 Ok(fd)
132}
133
134fn socket_flags_to_open_flags(flags: u32) -> OpenFlags {
135 OpenFlags::RDWR
136 | if flags & SOCK_NONBLOCK != 0 { OpenFlags::NONBLOCK } else { OpenFlags::empty() }
137}
138
139fn socket_flags_to_fd_flags(flags: u32) -> FdFlags {
140 if flags & SOCK_CLOEXEC != 0 { FdFlags::CLOEXEC } else { FdFlags::empty() }
141}
142
143fn parse_socket_domain(domain: u32) -> Result<SocketDomain, Errno> {
144 SocketDomain::from_raw(domain.try_into().map_err(|_| errno!(EAFNOSUPPORT))?).ok_or_else(|| {
145 track_stub!(TODO("https://fxbug.dev/322875074"), "parse socket domain", domain);
146 errno!(EAFNOSUPPORT)
147 })
148}
149
150fn parse_socket_type(domain: SocketDomain, socket_type: u32) -> Result<SocketType, Errno> {
151 let socket_type = SocketType::from_raw(socket_type & 0xf).ok_or_else(|| {
152 track_stub!(TODO("https://fxbug.dev/322875418"), "parse socket type", socket_type);
153 errno!(EINVAL)
154 })?;
155 Ok(if domain == SocketDomain::Unix && socket_type == SocketType::Raw {
157 SocketType::Datagram
158 } else {
159 socket_type
160 })
161}
162
163fn parse_socket_protocol(
164 domain: SocketDomain,
165 socket_type: SocketType,
166 protocol: u32,
167) -> Result<SocketProtocol, Errno> {
168 let protocol = SocketProtocol::from_raw(protocol);
169 if domain == SocketDomain::Inet {
170 match (socket_type, protocol) {
171 (SocketType::Raw, _) => {
172 return error!(EPROTONOSUPPORT);
174 }
175 (SocketType::Datagram, SocketProtocol::UDP) => (),
176 (SocketType::Datagram, _) => return error!(EPROTONOSUPPORT),
177 (SocketType::Stream, SocketProtocol::TCP) => (),
178 (SocketType::Stream, _) => return error!(EPROTONOSUPPORT),
179 _ => (),
180 }
181 }
182 Ok(protocol)
183}
184
185fn parse_socket_address(
186 task: &Task,
187 user_socket_address: UserAddress,
188 user_address_length: usize,
189) -> Result<SocketAddress, Errno> {
190 if user_address_length < SA_FAMILY_SIZE || user_address_length > SA_STORAGE_SIZE {
191 return error!(EINVAL);
192 }
193
194 let address = task.read_memory_to_vec(user_socket_address, user_address_length)?;
195
196 SocketAddress::from_bytes(address)
197}
198
199fn maybe_parse_socket_address(
200 task: &Task,
201 user_socket_address: UserAddress,
202 user_address_length: usize,
203) -> Result<Option<SocketAddress>, Errno> {
204 if user_address_length > i32::MAX as usize {
205 return error!(EINVAL);
206 }
207 Ok(if user_socket_address.is_null() {
208 None
209 } else {
210 Some(parse_socket_address(task, user_socket_address, user_address_length)?)
211 })
212}
213
214fn generate_autobind_address() -> FsString {
216 let mut bytes = [0u8; 4];
217 starnix_crypto::cprng_draw(&mut bytes);
218 let value = u32::from_ne_bytes(bytes) & 0xFFFFF;
219 format!("\0{value:05x}").into()
220}
221
222pub fn sys_bind(
223 current_task: &CurrentTask,
224 fd: FdNumber,
225 user_socket_address: UserAddress,
226 user_address_length: usize,
227) -> Result<(), Errno> {
228 let file = current_task.files().get(fd)?;
229 let socket = Socket::get_from_file(&file)?;
230 let address = parse_socket_address(current_task, user_socket_address, user_address_length)?;
231 if !address.valid_for_domain(socket.domain) {
232 if socket.domain == SocketDomain::Inet && address == SocketAddress::Unspecified {
233 if let Ok(local_addr) = socket.getsockname() {
234 if local_addr.maybe_inet_port().unwrap_or(0) != 0 {
235 return Ok(());
236 }
237 }
238 }
239 return match socket.domain {
240 SocketDomain::Unix
241 | SocketDomain::Vsock
242 | SocketDomain::Inet6
243 | SocketDomain::Netlink
244 | SocketDomain::Key
245 | SocketDomain::Packet
246 | SocketDomain::Qipcrtr => error!(EINVAL),
247 SocketDomain::Inet => error!(EAFNOSUPPORT),
248 };
249 }
250 if let Some(port) = address.maybe_inet_port() {
251 if port != 0 && port < 1024 {
259 security::check_task_capable(current_task, CAP_NET_BIND_SERVICE)
260 .map_err(|_| errno!(EACCES))?;
261 }
262 }
263 security::check_socket_bind_access(current_task, socket, &address)?;
264 match address {
265 SocketAddress::Unspecified => return error!(EINVAL),
266 SocketAddress::Unix(mut name) => {
267 if name.is_empty() {
268 name = generate_autobind_address();
271 }
272 if name[0] == b'\0' {
275 current_task.running_state().abstract_socket_namespace.bind(
276 current_task,
277 name,
278 socket,
279 )?;
280 } else {
281 let mode = file.node().info().mode;
282 let mode = current_task.fs().apply_umask(mode).with_type(FileMode::IFSOCK);
283 let (parent, basename) = current_task.lookup_parent_at(
284 &mut LookupContext::default(),
285 FdNumber::AT_FDCWD,
286 name.as_ref(),
287 )?;
288
289 parent
290 .bind_socket(
291 current_task,
292 basename,
293 socket.clone(),
294 SocketAddress::Unix(name.clone()),
295 mode,
296 )
297 .map_err(|errno| if errno == EEXIST { errno!(EADDRINUSE) } else { errno })?;
298 }
299 }
300 SocketAddress::Vsock { port, .. } => {
301 current_task.running_state().abstract_vsock_namespace.bind(
302 current_task,
303 port,
304 socket,
305 )?;
306 }
307 SocketAddress::Inet(_)
308 | SocketAddress::Inet6(_)
309 | SocketAddress::Netlink(_)
310 | SocketAddress::Packet(_)
311 | SocketAddress::Qipcrtr(_) => socket.bind(current_task, address)?,
312 }
313
314 Ok(())
315}
316
317pub fn sys_listen(current_task: &CurrentTask, fd: FdNumber, backlog: i32) -> Result<(), Errno> {
318 let file = current_task.files().get(fd)?;
319 let socket = Socket::get_from_file(&file)?;
320 socket.listen(current_task, backlog)?;
321 Ok(())
322}
323
324pub fn sys_accept(
325 current_task: &CurrentTask,
326 fd: FdNumber,
327 user_socket_address: UserAddress,
328 user_address_length: UserRef<socklen_t>,
329) -> Result<FdNumber, Errno> {
330 sys_accept4(current_task, fd, user_socket_address, user_address_length, 0)
331}
332
333pub fn sys_accept4(
334 current_task: &CurrentTask,
335 fd: FdNumber,
336 user_socket_address: UserAddress,
337 user_address_length: UserRef<socklen_t>,
338 flags: u32,
339) -> Result<FdNumber, Errno> {
340 let file = current_task.files().get(fd)?;
341 let listening_socket = Socket::get_from_file(&file)?;
342 let accepted_socket =
343 file.blocking_op(current_task, FdEvents::POLLIN | FdEvents::POLLHUP, None, || {
344 listening_socket.accept(current_task)
345 })?;
346
347 if !user_socket_address.is_null() {
348 let address_bytes = accepted_socket.getpeername()?.to_bytes();
349 write_socket_address(
350 current_task,
351 user_socket_address,
352 user_address_length,
353 &address_bytes,
354 )?;
355 }
356
357 let open_flags = socket_flags_to_open_flags(flags);
358 let accepted_socket_file = SocketFile::from_socket(
359 current_task,
360 accepted_socket,
361 open_flags,
362 false,
363 )?;
364 let listening_socket = SocketFile::get_from_file(&file)?;
365 let accepted_socket = SocketFile::get_from_file(&accepted_socket_file)?;
366 security::socket_accept(current_task, listening_socket, accepted_socket)?;
367 let fd_flags = if flags & SOCK_CLOEXEC != 0 { FdFlags::CLOEXEC } else { FdFlags::empty() };
368 let accepted_fd = current_task.add_file(accepted_socket_file, fd_flags)?;
369 Ok(accepted_fd)
370}
371
372pub fn sys_connect(
373 current_task: &CurrentTask,
374 fd: FdNumber,
375 user_socket_address: UserAddress,
376 user_address_length: usize,
377) -> Result<(), Errno> {
378 let client = current_task.files().get(fd)?;
379 let client = SocketFile::get_from_file(&client)?;
380 let address = parse_socket_address(current_task, user_socket_address, user_address_length)?;
381 let peer = match address {
382 SocketAddress::Unspecified => SocketPeer::Address(address),
383 SocketAddress::Unix(ref name) => {
384 log_trace!("connect to unix socket named \"{name}\"");
385 if name.is_empty() {
386 return error!(ECONNREFUSED);
387 }
388 SocketPeer::Handle(resolve_unix_socket_address(current_task, name.as_ref())?)
389 }
390 SocketAddress::Vsock { .. } => return error!(ENOSYS),
392 SocketAddress::Inet(ref addr) | SocketAddress::Inet6(ref addr) => {
393 log_trace!("connect to inet socket named {:?}", addr);
394 SocketPeer::Address(address)
395 }
396 SocketAddress::Netlink(_) => SocketPeer::Address(address),
397 SocketAddress::Packet(ref addr) => {
398 log_trace!("connect to packet socket named {:?}", addr);
399 SocketPeer::Address(address)
400 }
401 SocketAddress::Qipcrtr(ref addr) => {
402 log_trace!("connect to qipcrtr socket named {:?}", addr);
403 SocketPeer::Address(address)
404 }
405 };
406 let result = client.connect(current_task, peer.clone());
407
408 if client.file().is_non_blocking() {
409 return result;
410 }
411
412 match result {
413 Err(errno) if errno.code == EINPROGRESS => {
416 let waiter = Waiter::new();
417 client.file().wait_async(
418 current_task,
419 &waiter,
420 FdEvents::POLLOUT,
421 WaitCallback::none(),
422 );
423 if !client.file().query_events(current_task)?.contains(FdEvents::POLLOUT) {
424 waiter.wait(current_task)?;
425 }
426 client.connect(current_task, peer)
427 }
428 result => result,
432 }
433}
434
435fn write_socket_address(
436 current_task: &CurrentTask,
437 user_socket_address: UserAddress,
438 user_address_length: UserRef<socklen_t>,
439 address_bytes: &[u8],
440) -> Result<(), Errno> {
441 let capacity = current_task.read_object(user_address_length)?;
442 if capacity > i32::MAX as socklen_t {
443 return error!(EINVAL);
444 }
445 let length = address_bytes.len() as socklen_t;
446 if length > 0 {
447 let actual = std::cmp::min(length, capacity) as usize;
448 current_task.write_memory(user_socket_address, &address_bytes[..actual])?;
449 }
450 current_task.write_object(user_address_length, &length)?;
451 Ok(())
452}
453
454pub fn sys_getsockname(
455 current_task: &CurrentTask,
456 fd: FdNumber,
457 user_socket_address: UserAddress,
458 user_address_length: UserRef<socklen_t>,
459) -> Result<(), Errno> {
460 let file = current_task.files().get(fd)?;
461 let socket = Socket::get_from_file(&file)?;
462 security::check_socket_getsockname_access(current_task, socket)?;
463 let address_bytes = socket.getsockname()?.to_bytes();
464
465 write_socket_address(current_task, user_socket_address, user_address_length, &address_bytes)?;
466
467 Ok(())
468}
469
470pub fn sys_getpeername(
471 current_task: &CurrentTask,
472 fd: FdNumber,
473 user_socket_address: UserAddress,
474 user_address_length: UserRef<socklen_t>,
475) -> Result<(), Errno> {
476 let file = current_task.files().get(fd)?;
477 let socket = Socket::get_from_file(&file)?;
478 security::check_socket_getpeername_access(current_task, socket)?;
479 let address_bytes = socket.getpeername()?.to_bytes();
480
481 write_socket_address(current_task, user_socket_address, user_address_length, &address_bytes)?;
482
483 Ok(())
484}
485
486pub fn sys_socketpair(
487 current_task: &CurrentTask,
488 domain: u32,
489 socket_type: u32,
490 protocol: u32,
491 user_sockets: UserRef<[FdNumber; 2]>,
492) -> Result<(), Errno> {
493 let flags = socket_type & (SOCK_NONBLOCK | SOCK_CLOEXEC);
494 let domain = parse_socket_domain(domain)?;
495 if !matches!(domain, SocketDomain::Unix | SocketDomain::Inet) {
496 return error!(EAFNOSUPPORT);
497 }
498 let socket_type = parse_socket_type(domain, socket_type)?;
499 let _protocol = parse_socket_protocol(domain, socket_type, protocol)?;
500 if domain != SocketDomain::Unix {
501 return error!(EOPNOTSUPP);
502 }
503 let open_flags = socket_flags_to_open_flags(flags);
504
505 let (left, right) = UnixSocket::new_pair(current_task, domain, socket_type, open_flags)?;
506
507 let fd_flags = socket_flags_to_fd_flags(flags);
508 let left_fd = current_task.add_file(left, fd_flags)?;
512 let right_fd = current_task.add_file(right, fd_flags)?;
513
514 let fds = [left_fd, right_fd];
515 log_trace!("socketpair -> [{:#x}, {:#x}]", fds[0].raw(), fds[1].raw());
516 current_task.write_object(user_sockets, &fds)?;
517
518 Ok(())
519}
520
521fn read_iovec_from_msghdr(
522 current_task: &CurrentTask,
523 message_header: WithAlternateBuffer<&MsgHdr>,
524) -> Result<UserBuffers, Errno> {
525 if let WithAlternateBuffer::WithAux(_, b) = message_header {
526 return Ok(UserBuffers::from_buf([b]));
527 }
528 let iovec_count = message_header.iovlen;
529
530 if iovec_count.raw() > UIO_MAXIOV as usize {
534 return error!(EMSGSIZE);
535 }
536
537 current_task.read_iovec(message_header.iov, iovec_count)
538}
539
540fn recvmsg_internal(
541 current_task: &CurrentTask,
542 file: &FileHandle,
543 user_message_header: &mut MsgHdrRef,
544 flags: u32,
545 deadline: Option<zx::MonotonicInstant>,
546) -> Result<usize, Errno> {
547 let mut message_header = match *user_message_header {
548 MsgHdrRef::Ptr(ptr) => current_task.read_multi_arch_object(ptr)?.into(),
549 MsgHdrRef::Value(ref value) => value.clone(),
550 };
551 let result =
552 recvmsg_internal_with_header(current_task, file, message_header.as_mut(), flags, deadline)?;
553 match *user_message_header {
554 MsgHdrRef::Ptr(ptr) => {
555 current_task.write_multi_arch_object(ptr, message_header.extract())?;
556 }
557 MsgHdrRef::Value(ref mut value) => {
558 *value.deref_mut() = message_header.extract();
559 }
560 }
561 Ok(result)
562}
563
564fn recvmsg_internal_with_header(
565 current_task: &CurrentTask,
566 file: &FileHandle,
567 mut message_header: WithAlternateBuffer<&mut MsgHdr>,
568 flags: u32,
569 deadline: Option<zx::MonotonicInstant>,
570) -> Result<usize, Errno> {
571 let iovec = read_iovec_from_msghdr(current_task, message_header.as_unmut())?;
572
573 let flags = SocketMessageFlags::from_bits(flags).ok_or_else(|| errno!(EINVAL))?;
574 let socket_ops = file.downcast_file::<SocketFile>().unwrap();
575 let info = socket_ops.recvmsg(
576 current_task,
577 file,
578 &mut UserBuffersOutputBuffer::unified_new(current_task, iovec)?,
579 flags,
580 deadline,
581 )?;
582
583 message_header.flags = 0;
584
585 let cmsg_buffer_size = message_header.control_len;
586
587 let mut cmsg_bytes_written = 0;
588 let header_size = CMsgHdrPtr::size_of_object_for(current_task);
589
590 for ancillary_data in info.ancillary_data {
591 if ancillary_data.total_size(current_task) == 0 {
592 continue;
596 }
597
598 let aligned_offset = cmsg_align(current_task, cmsg_bytes_written)?;
600 let space_available = cmsg_buffer_size.saturating_sub(aligned_offset);
601
602 if space_available < header_size {
603 message_header.flags |= MSG_CTRUNC;
605 break;
606 }
607
608 let conversion = ancillary_data.into_bytes(current_task, flags, space_available)?;
609
610 if conversion.truncated {
611 message_header.flags |= MSG_CTRUNC;
612 }
613
614 assert!(aligned_offset + conversion.bytes.len() <= cmsg_buffer_size);
615 current_task.write_memory((message_header.control + aligned_offset)?, &conversion.bytes)?;
617 cmsg_bytes_written = std::cmp::min(
619 cmsg_align(current_task, aligned_offset + conversion.bytes.len())?,
620 cmsg_buffer_size,
621 );
622 }
623
624 message_header.control_len = cmsg_bytes_written;
625
626 let msg_name = message_header.name;
627 if !msg_name.is_null() {
628 if message_header.name_len > i32::MAX as u32 {
629 return error!(EINVAL);
630 }
631 let bytes = info.address.map(|a| a.to_bytes()).unwrap_or_else(|| vec![]);
632 let num_bytes = std::cmp::min(message_header.name_len as usize, bytes.len());
633 message_header.name_len = bytes.len() as u32;
634 if num_bytes > 0 {
635 current_task.write_memory(msg_name, &bytes[..num_bytes])?;
636 }
637 }
638
639 if socket_ops.socket.socket_type != SocketType::Stream && info.bytes_read != info.message_length
640 {
641 message_header.flags |= MSG_TRUNC;
642 }
643
644 if flags.contains(SocketMessageFlags::TRUNC)
645 && socket_ops.socket.socket_type != SocketType::Stream
646 {
647 Ok(info.message_length)
648 } else {
649 Ok(info.bytes_read)
650 }
651}
652
653pub fn sys_recvmsg(
654 current_task: &CurrentTask,
655 fd: FdNumber,
656 user_message_header: MsgHdrPtr,
657 flags: u32,
658) -> Result<usize, Errno> {
659 recvmsg_impl(current_task, fd, &mut user_message_header.into(), flags)
660}
661
662pub fn recvmsg_impl(
668 current_task: &CurrentTask,
669 fd: FdNumber,
670 user_message_header: &mut MsgHdrRef,
671 flags: u32,
672) -> Result<usize, Errno> {
673 let file = current_task.files().get(fd)?;
674 if !file.node().is_sock() {
675 return error!(ENOTSOCK);
676 }
677 recvmsg_internal(current_task, &file, user_message_header, flags, None)
678}
679
680pub fn sys_recvmmsg(
681 current_task: &CurrentTask,
682 fd: FdNumber,
683 user_mmsgvec: MMsgHdrPtr,
684 vlen: u32,
685 mut flags: u32,
686 user_timeout: TimeSpecPtr,
687) -> Result<usize, Errno> {
688 let file = current_task.files().get(fd)?;
689 if !file.node().is_sock() {
690 return error!(ENOTSOCK);
691 }
692
693 if vlen > UIO_MAXIOV {
694 return error!(EINVAL);
695 }
696
697 let deadline = if user_timeout.is_null() {
698 None
699 } else {
700 let ts = current_task.read_multi_arch_object(user_timeout)?;
701 Some(zx::MonotonicInstant::after(duration_from_timespec(ts)?))
702 };
703
704 let mut index = 0usize;
705 while index < vlen as usize {
706 let current_ptr = user_mmsgvec.at(index)?;
707 let mut current_mmsghdr = current_task.read_multi_arch_object(current_ptr)?;
708 match recvmsg_internal_with_header(
709 current_task,
710 &file,
711 (&mut current_mmsghdr.hdr).into(),
712 flags,
713 deadline,
714 ) {
715 Err(error) => {
716 if index == 0 {
717 return Err(error);
718 }
719 break;
720 }
721 Ok(bytes_read) => {
722 current_mmsghdr.len = bytes_read;
723 current_task.write_multi_arch_object(current_ptr, current_mmsghdr)?;
724 }
725 }
726 index += 1;
727 if flags & MSG_WAITFORONE != 0 {
728 flags |= MSG_DONTWAIT;
729 }
730 }
731 Ok(index)
732}
733
734pub fn sys_recvfrom(
735 current_task: &CurrentTask,
736 fd: FdNumber,
737 user_buffer: UserAddress,
738 buffer_length: usize,
739 flags: u32,
740 user_src_address: UserAddress,
741 user_src_address_length: UserRef<socklen_t>,
742) -> Result<usize, Errno> {
743 let file = current_task.files().get(fd)?;
744 if !file.node().is_sock() {
745 return error!(ENOTSOCK);
746 }
747
748 let flags = SocketMessageFlags::from_bits(flags).ok_or_else(|| errno!(EINVAL))?;
749 let socket_ops = file.downcast_file::<SocketFile>().unwrap();
750 let info = socket_ops.recvmsg(
751 current_task,
752 &file,
753 &mut UserBuffersOutputBuffer::unified_new_at(current_task, user_buffer, buffer_length)?,
754 flags,
755 None,
756 )?;
757
758 if !user_src_address.is_null() {
759 let bytes = info.address.map(|a| a.to_bytes()).unwrap_or_else(|| vec![]);
760 write_socket_address(current_task, user_src_address, user_src_address_length, &bytes)?;
761 }
762
763 if flags.contains(SocketMessageFlags::TRUNC)
764 && socket_ops.socket.socket_type != SocketType::Stream
765 {
766 Ok(info.message_length)
767 } else {
768 Ok(info.bytes_read)
769 }
770}
771
772fn sendmsg_internal(
773 current_task: &CurrentTask,
774 file: &FileHandle,
775 user_message_header: MsgHdrPtr,
776 flags: u32,
777) -> Result<usize, Errno> {
778 let message_header = current_task.read_multi_arch_object(user_message_header)?;
779 sendmsg_internal_with_header(current_task, file, &message_header, flags)
780}
781
782fn sendmsg_internal_with_header(
783 current_task: &CurrentTask,
784 file: &FileHandle,
785 message_header: &MsgHdr,
786 flags: u32,
787) -> Result<usize, Errno> {
788 if message_header.name_len > i32::MAX as u32 {
789 return error!(EINVAL);
790 }
791 if message_header.control_len > 20480 {
792 return error!(ENOBUFS);
793 }
794 let dest_address = maybe_parse_socket_address(
795 current_task,
796 message_header.name,
797 message_header.name_len as usize,
798 )?;
799 let iovec = read_iovec_from_msghdr(current_task, message_header.into())?;
800
801 let mut next_message_offset: usize = 0;
802 let mut ancillary_data = Vec::new();
803 let header_size = CMsgHdrPtr::size_of_object_for(current_task);
804 loop {
805 let space = message_header.control_len.saturating_sub(next_message_offset);
806 if space < header_size {
807 break;
808 }
809 let cmsg_ref =
810 CMsgHdrPtr::new(current_task, (message_header.control + next_message_offset)?);
811 let cmsg = current_task.read_multi_arch_object(cmsg_ref)?;
812 if (cmsg.cmsg_len as usize) < header_size {
815 return error!(EINVAL);
816 }
817
818 let data_size = std::cmp::min(cmsg.cmsg_len as usize - header_size, space);
819 let next_data_offset = next_message_offset + header_size;
820 let data = current_task
821 .read_memory_to_vec((message_header.control + next_data_offset)?, data_size)?;
822 next_message_offset += cmsg_align(current_task, header_size + data.len())?;
823 let data = AncillaryData::from_cmsg(
824 current_task,
825 ControlMsg::new(cmsg.cmsg_level, cmsg.cmsg_type, data),
826 )?;
827 if data.total_size(current_task) == 0 {
828 continue;
829 }
830 ancillary_data.push(data);
831 }
832
833 let flags = SocketMessageFlags::from_bits(flags).ok_or_else(|| errno!(EOPNOTSUPP))?;
834 let socket_ops = file.downcast_file::<SocketFile>().unwrap();
835 socket_ops.sendmsg(
836 current_task,
837 file,
838 &mut UserBuffersInputBuffer::unified_new(current_task, iovec)?,
839 dest_address,
840 ancillary_data,
841 flags,
842 )
843}
844
845pub fn sys_sendmsg(
846 current_task: &CurrentTask,
847 fd: FdNumber,
848 user_message_header: MsgHdrPtr,
849 flags: u32,
850) -> Result<usize, Errno> {
851 let file = current_task.files().get(fd)?;
852 if !file.node().is_sock() {
853 return error!(ENOTSOCK);
854 }
855 sendmsg_internal(current_task, &file, user_message_header, flags)
856}
857
858pub fn sys_sendmmsg(
859 current_task: &CurrentTask,
860 fd: FdNumber,
861 user_mmsgvec: MMsgHdrPtr,
862 mut vlen: u32,
863 flags: u32,
864) -> Result<usize, Errno> {
865 let file = current_task.files().get(fd)?;
866 if !file.node().is_sock() {
867 return error!(ENOTSOCK);
868 }
869
870 if vlen > UIO_MAXIOV {
872 vlen = UIO_MAXIOV;
873 }
874
875 let mut index = 0usize;
876 while index < vlen as usize {
877 let current_ptr = user_mmsgvec.at(index)?;
878 let mut current_mmsghdr = current_task.read_multi_arch_object(current_ptr)?;
879 match sendmsg_internal_with_header(current_task, &file, ¤t_mmsghdr.hdr, flags) {
880 Err(error) => {
881 if index == 0 {
882 return Err(error);
883 }
884 break;
885 }
886 Ok(bytes_read) => {
887 current_mmsghdr.len = bytes_read;
888 current_task.write_multi_arch_object(current_ptr, current_mmsghdr)?;
889 }
890 }
891 index += 1;
892 }
893 Ok(index)
894}
895
896pub fn sys_sendto(
897 current_task: &CurrentTask,
898 fd: FdNumber,
899 user_buffer: UserAddress,
900 user_buffer_length: usize,
901 flags: u32,
902 user_dest_address: UserAddress,
903 user_dest_address_length: socklen_t,
904) -> Result<usize, Errno> {
905 let file = current_task.files().get(fd)?;
906 if !file.node().is_sock() {
907 return error!(ENOTSOCK);
908 }
909
910 let dest_address = maybe_parse_socket_address(
911 current_task,
912 user_dest_address,
913 user_dest_address_length as usize,
914 )?;
915 let mut data =
916 UserBuffersInputBuffer::unified_new_at(current_task, user_buffer, user_buffer_length)?;
917
918 let flags = SocketMessageFlags::from_bits(flags).ok_or_else(|| errno!(EOPNOTSUPP))?;
919 let socket_file = file.downcast_file::<SocketFile>().unwrap();
920 socket_file.sendmsg(current_task, &file, &mut data, dest_address, vec![], flags)
921}
922
923pub fn sys_getsockopt(
924 current_task: &CurrentTask,
925 fd: FdNumber,
926 level: u32,
927 optname: u32,
928 user_optval: UserAddress,
929 user_optlen: UserRef<socklen_t>,
930) -> Result<(), Errno> {
931 let file = current_task.files().get(fd)?;
932 let socket = Socket::get_from_file(&file)?;
933
934 let optlen = current_task.read_object(user_optlen)? as usize;
935 let optval_buffer_len = optlen;
936 let mut optval = current_task.read_memory_to_vec(user_optval, optlen as usize)?;
937
938 let result = if socket.domain.is_inet() && IpTables::can_handle_getsockopt(level, optname) {
939 current_task.kernel().iptables().getsockopt(current_task, socket, optname, optval.clone())
940 } else {
941 socket.getsockopt(current_task, level, optname, optlen as u32)
942 };
943
944 let (optlen, error) = match result {
947 Ok(new_optval) => {
948 let len = std::cmp::min(new_optval.len(), optval.len());
955 optval[..len].copy_from_slice(&new_optval[..len]);
956 (len, None)
957 }
958 Err(e) => (optlen, Some(e)),
959 };
960
961 let root_cgroup = current_task.kernel().ebpf_state.attachments.root_cgroup();
962 let (optval, optlen) = root_cgroup.run_getsockopt_prog(
963 current_task,
964 level,
965 optname,
966 optval,
967 optlen,
968 error,
969 socket,
970 )?;
971
972 assert!(optlen <= optval_buffer_len);
973 current_task.write_memory(user_optval, &optval[..optlen])?;
974 current_task.write_object(user_optlen, &(optlen as u32))?;
975
976 Ok(())
977}
978
979pub fn sys_setsockopt(
980 current_task: &CurrentTask,
981 fd: FdNumber,
982 level: u32,
983 optname: u32,
984 user_optval: UserAddress,
985 optlen: socklen_t,
986) -> Result<(), Errno> {
987 let file = current_task.files().get(fd)?;
988 let socket = Socket::get_from_file(&file)?;
989
990 let user_opt = UserBuffer { address: user_optval, length: optlen as usize };
991
992 let root_cgroup = current_task.kernel().ebpf_state.attachments.root_cgroup();
994 let optval = match root_cgroup.run_setsockopt_prog(
995 current_task,
996 level,
997 optname,
998 user_opt.into(),
999 socket,
1000 ) {
1001 SetSockOptProgramResult::Allow(value) => value,
1002 SetSockOptProgramResult::Fail(errno) => return Err(errno),
1003 SetSockOptProgramResult::Bypass => return Ok(()), };
1005
1006 if socket.domain.is_inet() && IpTables::can_handle_setsockopt(level, optname) {
1007 current_task.kernel().iptables().setsockopt(current_task, socket, optname, optval)
1008 } else {
1009 socket.setsockopt(current_task, level, optname, optval)
1010 }
1011}
1012
1013pub fn sys_shutdown(current_task: &CurrentTask, fd: FdNumber, how: u32) -> Result<(), Errno> {
1014 let file = current_task.files().get(fd)?;
1015 let socket = Socket::get_from_file(&file)?;
1016 let how = match how {
1017 SHUT_RD => SocketShutdownFlags::READ,
1018 SHUT_WR => SocketShutdownFlags::WRITE,
1019 SHUT_RDWR => SocketShutdownFlags::READ | SocketShutdownFlags::WRITE,
1020 _ => return error!(EINVAL),
1021 };
1022 socket.shutdown(current_task, how)?;
1023 Ok(())
1024}
1025
1026pub fn cmsg_align(current_task: &CurrentTask, value: usize) -> Result<usize, Errno> {
1027 let alignment = if current_task.is_arch32() { 4 } else { 8 };
1028 round_up_to_increment(value, alignment)
1029}
1030
1031#[cfg(target_arch = "aarch64")]
1033mod arch32 {
1034 use crate::task::CurrentTask;
1035 use crate::vfs::FdNumber;
1036 use starnix_uapi::errors::Errno;
1037 use starnix_uapi::user_address::UserAddress;
1038
1039 pub use super::{
1040 sys_accept as sys_arch32_accept, sys_accept4 as sys_arch32_accept4,
1041 sys_bind as sys_arch32_bind, sys_getpeername as sys_arch32_getpeername,
1042 sys_getsockname as sys_arch32_getsockname, sys_getsockopt as sys_arch32_getsockopt,
1043 sys_listen as sys_arch32_listen, sys_recvfrom as sys_arch32_recvfrom,
1044 sys_recvmmsg as sys_arch32_recvmmsg, sys_recvmsg as sys_arch32_recvmsg,
1045 sys_sendmsg as sys_arch32_sendmsg, sys_sendto as sys_arch32_sendto,
1046 sys_setsockopt as sys_arch32_setsockopt, sys_shutdown as sys_arch32_shutdown,
1047 sys_socketpair as sys_arch32_socketpair,
1048 };
1049
1050 pub fn sys_arch32_send(
1051 current_task: &CurrentTask,
1052 fd: FdNumber,
1053 user_buffer: UserAddress,
1054 user_buffer_length: usize,
1055 flags: u32,
1056 ) -> Result<usize, Errno> {
1057 super::sys_sendto(
1058 current_task,
1059 fd,
1060 user_buffer,
1061 user_buffer_length,
1062 flags,
1063 Default::default(),
1064 Default::default(),
1065 )
1066 }
1067
1068 pub fn sys_arch32_recv(
1069 current_task: &CurrentTask,
1070 fd: FdNumber,
1071 user_buffer: UserAddress,
1072 buffer_length: usize,
1073 flags: u32,
1074 ) -> Result<usize, Errno> {
1075 super::sys_recvfrom(
1076 current_task,
1077 fd,
1078 user_buffer,
1079 buffer_length,
1080 flags,
1081 Default::default(),
1082 Default::default(),
1083 )
1084 }
1085}
1086
1087#[cfg(target_arch = "aarch64")]
1088pub use arch32::*;
1089
1090#[cfg(test)]
1091mod tests {
1092 use super::*;
1093 use crate::testing::spawn_kernel_and_run;
1094 use starnix_uapi::{AF_INET, AF_UNIX, SOCK_STREAM};
1095
1096 #[::fuchsia::test]
1097 async fn test_socketpair_invalid_arguments() {
1098 spawn_kernel_and_run(async |current_task| {
1099 assert_eq!(
1100 sys_socketpair(
1101 current_task,
1102 AF_INET as u32,
1103 SOCK_STREAM,
1104 0,
1105 UserRef::new(UserAddress::default())
1106 ),
1107 error!(EPROTONOSUPPORT)
1108 );
1109 assert_eq!(
1110 sys_socketpair(
1111 current_task,
1112 AF_UNIX as u32,
1113 7,
1114 0,
1115 UserRef::new(UserAddress::default())
1116 ),
1117 error!(EINVAL)
1118 );
1119 assert_eq!(
1120 sys_socketpair(
1121 current_task,
1122 AF_UNIX as u32,
1123 SOCK_STREAM,
1124 0,
1125 UserRef::new(UserAddress::default())
1126 ),
1127 error!(EFAULT)
1128 );
1129 })
1130 .await;
1131 }
1132
1133 #[::fuchsia::test]
1134 fn test_generate_autobind_address() {
1135 let address = generate_autobind_address();
1136 assert_eq!(address.len(), 6);
1137 assert_eq!(address[0], 0);
1138 for byte in address[1..].iter() {
1139 match byte {
1140 b'0'..=b'9' | b'a'..=b'f' => {
1141 }
1143 bad => {
1144 panic!("bad byte: {bad}");
1145 }
1146 }
1147 }
1148 }
1149}