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
222const SIN6_LEN_RFC2133: usize = 24;
224
225pub fn sys_bind(
226 current_task: &CurrentTask,
227 fd: FdNumber,
228 user_socket_address: UserAddress,
229 user_address_length: usize,
230) -> Result<(), Errno> {
231 let file = current_task.get_file(fd)?;
232 let socket = Socket::get_from_file(&file)?;
233 let address = parse_socket_address(current_task, user_socket_address, user_address_length)?;
234 if !address.valid_for_domain(socket.domain) {
235 return match socket.domain {
236 SocketDomain::Unix
237 | SocketDomain::Vsock
238 | SocketDomain::Netlink
239 | SocketDomain::Key
240 | SocketDomain::Packet
241 | SocketDomain::Qipcrtr => error!(EINVAL),
242 SocketDomain::Inet => {
243 if user_address_length < std::mem::size_of::<uapi::sockaddr_in>() {
244 return error!(EINVAL);
245 }
246 if address == SocketAddress::Unspecified {
247 if let Ok(local_addr) = socket.getsockname() {
248 if local_addr.maybe_inet_port().unwrap_or(0) != 0 {
249 return Ok(());
250 }
251 }
252 }
253 error!(EAFNOSUPPORT)
254 }
255 SocketDomain::Inet6 => {
256 if user_address_length < SIN6_LEN_RFC2133 {
257 error!(EINVAL)
258 } else {
259 error!(EAFNOSUPPORT)
260 }
261 }
262 };
263 }
264 if let Some(port) = address.maybe_inet_port() {
265 if port != 0 && port < 1024 {
273 security::check_task_capable(current_task, CAP_NET_BIND_SERVICE)
274 .map_err(|_| errno!(EACCES))?;
275 }
276 }
277 security::check_socket_bind_access(current_task, socket, &address)?;
278 match address {
279 SocketAddress::Unspecified => return error!(EINVAL),
280 SocketAddress::Unix(mut name) => {
281 if name.is_empty() {
282 name = generate_autobind_address();
285 }
286 if name[0] == b'\0' {
289 current_task.running_state().abstract_socket_namespace.bind(
290 current_task,
291 name,
292 socket,
293 )?;
294 } else {
295 let mode = file.node().info().mode;
296 let mode = current_task.fs().apply_umask(mode).with_type(FileMode::IFSOCK);
297 let (parent, basename) = current_task.lookup_parent_at(
298 &mut LookupContext::default(),
299 FdNumber::AT_FDCWD,
300 name.as_ref(),
301 )?;
302
303 parent
304 .bind_socket(
305 current_task,
306 basename,
307 socket.clone(),
308 SocketAddress::Unix(name.clone()),
309 mode,
310 )
311 .map_err(|errno| if errno == EEXIST { errno!(EADDRINUSE) } else { errno })?;
312 }
313 }
314 SocketAddress::Vsock { port, .. } => {
315 current_task.running_state().abstract_vsock_namespace.bind(
316 current_task,
317 port,
318 socket,
319 )?;
320 }
321 SocketAddress::Inet(_)
322 | SocketAddress::Inet6(_)
323 | SocketAddress::Netlink(_)
324 | SocketAddress::Packet(_)
325 | SocketAddress::Qipcrtr(_) => socket.bind(current_task, address)?,
326 }
327
328 Ok(())
329}
330
331pub fn sys_listen(current_task: &CurrentTask, fd: FdNumber, backlog: i32) -> Result<(), Errno> {
332 let file = current_task.get_file(fd)?;
333 let socket = Socket::get_from_file(&file)?;
334 socket.listen(current_task, backlog)?;
335 Ok(())
336}
337
338pub fn sys_accept(
339 current_task: &CurrentTask,
340 fd: FdNumber,
341 user_socket_address: UserAddress,
342 user_address_length: UserRef<socklen_t>,
343) -> Result<FdNumber, Errno> {
344 sys_accept4(current_task, fd, user_socket_address, user_address_length, 0)
345}
346
347pub fn sys_accept4(
348 current_task: &CurrentTask,
349 fd: FdNumber,
350 user_socket_address: UserAddress,
351 user_address_length: UserRef<socklen_t>,
352 flags: u32,
353) -> Result<FdNumber, Errno> {
354 let file = current_task.get_file(fd)?;
355 let listening_socket = Socket::get_from_file(&file)?;
356 let accepted_socket =
357 file.blocking_op(current_task, FdEvents::POLLIN | FdEvents::POLLHUP, None, || {
358 listening_socket.accept(current_task)
359 })?;
360
361 if !user_socket_address.is_null() {
362 let address_bytes = accepted_socket.getpeername()?.to_bytes();
363 write_socket_address(
364 current_task,
365 user_socket_address,
366 user_address_length,
367 &address_bytes,
368 )?;
369 }
370
371 let open_flags = socket_flags_to_open_flags(flags);
372 let accepted_socket_file = SocketFile::from_socket(
373 current_task,
374 accepted_socket,
375 open_flags,
376 false,
377 )?;
378 let listening_socket = SocketFile::get_from_file(&file)?;
379 let accepted_socket = SocketFile::get_from_file(&accepted_socket_file)?;
380 security::socket_accept(current_task, listening_socket, accepted_socket)?;
381 let fd_flags = if flags & SOCK_CLOEXEC != 0 { FdFlags::CLOEXEC } else { FdFlags::empty() };
382 let accepted_fd = current_task.add_file(accepted_socket_file, fd_flags)?;
383 Ok(accepted_fd)
384}
385
386pub fn sys_connect(
387 current_task: &CurrentTask,
388 fd: FdNumber,
389 user_socket_address: UserAddress,
390 user_address_length: usize,
391) -> Result<(), Errno> {
392 let client = current_task.get_file(fd)?;
393 let client = SocketFile::get_from_file(&client)?;
394 let address = parse_socket_address(current_task, user_socket_address, user_address_length)?;
395 let domain = client.socket().domain;
396 if address != SocketAddress::Unspecified && !address.valid_for_domain(domain) {
397 match domain {
398 SocketDomain::Inet => {
399 if user_address_length < std::mem::size_of::<uapi::sockaddr_in>() {
400 return error!(EINVAL);
401 }
402 return error!(EAFNOSUPPORT);
403 }
404 SocketDomain::Inet6 => {
405 if !(matches!(address, SocketAddress::Inet(_))
406 && client.socket().socket_type == SocketType::Datagram)
407 {
408 if user_address_length < SIN6_LEN_RFC2133 {
409 return error!(EINVAL);
410 }
411 return error!(EAFNOSUPPORT);
412 }
413 }
414 SocketDomain::Unix => return error!(EINVAL),
415 _ => {}
416 }
417 }
418 let peer = match address {
419 SocketAddress::Unspecified => SocketPeer::Address(address),
420 SocketAddress::Unix(ref name) => {
421 log_trace!("connect to unix socket named \"{name}\"");
422 if name.is_empty() {
423 return error!(ECONNREFUSED);
424 }
425 SocketPeer::Handle(resolve_unix_socket_address(current_task, name.as_ref())?)
426 }
427 SocketAddress::Vsock { .. } => return error!(ENOSYS),
429 SocketAddress::Inet(ref addr) | SocketAddress::Inet6(ref addr) => {
430 log_trace!("connect to inet socket named {:?}", addr);
431 SocketPeer::Address(address)
432 }
433 SocketAddress::Netlink(_) => SocketPeer::Address(address),
434 SocketAddress::Packet(ref addr) => {
435 log_trace!("connect to packet socket named {:?}", addr);
436 SocketPeer::Address(address)
437 }
438 SocketAddress::Qipcrtr(ref addr) => {
439 log_trace!("connect to qipcrtr socket named {:?}", addr);
440 SocketPeer::Address(address)
441 }
442 };
443 let result = client.connect(current_task, peer.clone());
444
445 if client.file().is_non_blocking() {
446 return result;
447 }
448
449 match result {
450 Err(errno) if errno.code == EINPROGRESS => {
453 let waiter = Waiter::new();
454 client.file().wait_async(
455 current_task,
456 &waiter,
457 FdEvents::POLLOUT,
458 WaitCallback::none(),
459 );
460 if !client.file().query_events(current_task)?.contains(FdEvents::POLLOUT) {
461 waiter.wait(current_task)?;
462 }
463 client.connect(current_task, peer)
464 }
465 result => result,
469 }
470}
471
472fn write_socket_address(
473 current_task: &CurrentTask,
474 user_socket_address: UserAddress,
475 user_address_length: UserRef<socklen_t>,
476 address_bytes: &[u8],
477) -> Result<(), Errno> {
478 let capacity = current_task.read_object(user_address_length)?;
479 if capacity > i32::MAX as socklen_t {
480 return error!(EINVAL);
481 }
482 let length = address_bytes.len() as socklen_t;
483 if length > 0 {
484 let actual = std::cmp::min(length, capacity) as usize;
485 current_task.write_memory(user_socket_address, &address_bytes[..actual])?;
486 }
487 current_task.write_object(user_address_length, &length)?;
488 Ok(())
489}
490
491pub fn sys_getsockname(
492 current_task: &CurrentTask,
493 fd: FdNumber,
494 user_socket_address: UserAddress,
495 user_address_length: UserRef<socklen_t>,
496) -> Result<(), Errno> {
497 let file = current_task.get_file(fd)?;
498 let socket = Socket::get_from_file(&file)?;
499 security::check_socket_getsockname_access(current_task, socket)?;
500 let address_bytes = socket.getsockname()?.to_bytes();
501
502 write_socket_address(current_task, user_socket_address, user_address_length, &address_bytes)?;
503
504 Ok(())
505}
506
507pub fn sys_getpeername(
508 current_task: &CurrentTask,
509 fd: FdNumber,
510 user_socket_address: UserAddress,
511 user_address_length: UserRef<socklen_t>,
512) -> Result<(), Errno> {
513 let file = current_task.get_file(fd)?;
514 let socket = Socket::get_from_file(&file)?;
515 security::check_socket_getpeername_access(current_task, socket)?;
516 let address_bytes = socket.getpeername()?.to_bytes();
517
518 write_socket_address(current_task, user_socket_address, user_address_length, &address_bytes)?;
519
520 Ok(())
521}
522
523pub fn sys_socketpair(
524 current_task: &CurrentTask,
525 domain: u32,
526 socket_type: u32,
527 protocol: u32,
528 user_sockets: UserRef<[FdNumber; 2]>,
529) -> Result<(), Errno> {
530 let flags = socket_type & (SOCK_NONBLOCK | SOCK_CLOEXEC);
531 let domain = parse_socket_domain(domain)?;
532 if !matches!(domain, SocketDomain::Unix | SocketDomain::Inet) {
533 return error!(EAFNOSUPPORT);
534 }
535 let socket_type = parse_socket_type(domain, socket_type)?;
536 let _protocol = parse_socket_protocol(domain, socket_type, protocol)?;
537 if domain != SocketDomain::Unix {
538 return error!(EOPNOTSUPP);
539 }
540 let open_flags = socket_flags_to_open_flags(flags);
541
542 let (left, right) = UnixSocket::new_pair(current_task, domain, socket_type, open_flags)?;
543
544 let fd_flags = socket_flags_to_fd_flags(flags);
545 let left_fd = current_task.add_file(left, fd_flags)?;
549 let right_fd = current_task.add_file(right, fd_flags)?;
550
551 let fds = [left_fd, right_fd];
552 log_trace!("socketpair -> [{:#x}, {:#x}]", fds[0].raw(), fds[1].raw());
553 current_task.write_object(user_sockets, &fds)?;
554
555 Ok(())
556}
557
558fn read_iovec_from_msghdr(
559 current_task: &CurrentTask,
560 message_header: WithAlternateBuffer<&MsgHdr>,
561) -> Result<UserBuffers, Errno> {
562 if let WithAlternateBuffer::WithAux(_, b) = message_header {
563 return Ok(UserBuffers::from_buf([b]));
564 }
565 let iovec_count = message_header.iovlen;
566
567 if iovec_count.raw() > UIO_MAXIOV as usize {
571 return error!(EMSGSIZE);
572 }
573
574 current_task.read_iovec(message_header.iov, iovec_count)
575}
576
577fn recvmsg_internal(
578 current_task: &CurrentTask,
579 file: &FileHandle,
580 user_message_header: &mut MsgHdrRef,
581 flags: u32,
582 deadline: Option<zx::MonotonicInstant>,
583) -> Result<usize, Errno> {
584 let mut message_header = match *user_message_header {
585 MsgHdrRef::Ptr(ptr) => current_task.read_multi_arch_object(ptr)?.into(),
586 MsgHdrRef::Value(ref value) => value.clone(),
587 };
588 let result =
589 recvmsg_internal_with_header(current_task, file, message_header.as_mut(), flags, deadline)?;
590 match *user_message_header {
591 MsgHdrRef::Ptr(ptr) => {
592 current_task.write_multi_arch_object(ptr, message_header.extract())?;
593 }
594 MsgHdrRef::Value(ref mut value) => {
595 *value.deref_mut() = message_header.extract();
596 }
597 }
598 Ok(result)
599}
600
601fn recvmsg_internal_with_header(
602 current_task: &CurrentTask,
603 file: &FileHandle,
604 mut message_header: WithAlternateBuffer<&mut MsgHdr>,
605 flags: u32,
606 deadline: Option<zx::MonotonicInstant>,
607) -> Result<usize, Errno> {
608 let iovec = read_iovec_from_msghdr(current_task, message_header.as_unmut())?;
609
610 let flags = SocketMessageFlags::from_bits(flags).ok_or_else(|| errno!(EINVAL))?;
611 let socket_ops = file.downcast_file::<SocketFile>().unwrap();
612 let info = socket_ops.recvmsg(
613 current_task,
614 file,
615 &mut UserBuffersOutputBuffer::unified_new(current_task, iovec)?,
616 flags,
617 deadline,
618 )?;
619
620 message_header.flags = 0;
621
622 let cmsg_buffer_size = message_header.control_len;
623
624 let mut cmsg_bytes_written = 0;
625 let header_size = CMsgHdrPtr::size_of_object_for(current_task);
626
627 for ancillary_data in info.ancillary_data {
628 if ancillary_data.total_size(current_task) == 0 {
629 continue;
633 }
634
635 let aligned_offset = cmsg_align(current_task, cmsg_bytes_written)?;
637 let space_available = cmsg_buffer_size.saturating_sub(aligned_offset);
638
639 if space_available < header_size {
640 message_header.flags |= MSG_CTRUNC;
642 break;
643 }
644
645 let conversion = ancillary_data.into_bytes(current_task, flags, space_available)?;
646
647 if conversion.truncated {
648 message_header.flags |= MSG_CTRUNC;
649 }
650
651 assert!(aligned_offset + conversion.bytes.len() <= cmsg_buffer_size);
652 current_task.write_memory((message_header.control + aligned_offset)?, &conversion.bytes)?;
654 cmsg_bytes_written = std::cmp::min(
656 cmsg_align(current_task, aligned_offset + conversion.bytes.len())?,
657 cmsg_buffer_size,
658 );
659 }
660
661 message_header.control_len = cmsg_bytes_written;
662
663 let msg_name = message_header.name;
664 if !msg_name.is_null() {
665 if message_header.name_len > i32::MAX as u32 {
666 return error!(EINVAL);
667 }
668 let bytes = info.address.map(|a| a.to_bytes()).unwrap_or_else(|| vec![]);
669 let num_bytes = std::cmp::min(message_header.name_len as usize, bytes.len());
670 message_header.name_len = bytes.len() as u32;
671 if num_bytes > 0 {
672 current_task.write_memory(msg_name, &bytes[..num_bytes])?;
673 }
674 }
675
676 if socket_ops.socket.socket_type != SocketType::Stream && info.bytes_read != info.message_length
677 {
678 message_header.flags |= MSG_TRUNC;
679 }
680
681 if flags.contains(SocketMessageFlags::TRUNC)
682 && socket_ops.socket.socket_type != SocketType::Stream
683 {
684 Ok(info.message_length)
685 } else {
686 Ok(info.bytes_read)
687 }
688}
689
690pub fn sys_recvmsg(
691 current_task: &CurrentTask,
692 fd: FdNumber,
693 user_message_header: MsgHdrPtr,
694 flags: u32,
695) -> Result<usize, Errno> {
696 recvmsg_impl(current_task, fd, &mut user_message_header.into(), flags)
697}
698
699pub fn recvmsg_impl(
705 current_task: &CurrentTask,
706 fd: FdNumber,
707 user_message_header: &mut MsgHdrRef,
708 flags: u32,
709) -> Result<usize, Errno> {
710 let file = current_task.get_file(fd)?;
711 if !file.node().is_sock() {
712 return error!(ENOTSOCK);
713 }
714 recvmsg_internal(current_task, &file, user_message_header, flags, None)
715}
716
717pub fn sys_recvmmsg(
718 current_task: &CurrentTask,
719 fd: FdNumber,
720 user_mmsgvec: MMsgHdrPtr,
721 vlen: u32,
722 mut flags: u32,
723 user_timeout: TimeSpecPtr,
724) -> Result<usize, Errno> {
725 let file = current_task.get_file(fd)?;
726 if !file.node().is_sock() {
727 return error!(ENOTSOCK);
728 }
729
730 if vlen > UIO_MAXIOV {
731 return error!(EINVAL);
732 }
733
734 let deadline = if user_timeout.is_null() {
735 None
736 } else {
737 let ts = current_task.read_multi_arch_object(user_timeout)?;
738 Some(zx::MonotonicInstant::after(duration_from_timespec(ts)?))
739 };
740
741 let mut index = 0usize;
742 while index < vlen as usize {
743 let current_ptr = user_mmsgvec.at(index)?;
744 let mut current_mmsghdr = current_task.read_multi_arch_object(current_ptr)?;
745 match recvmsg_internal_with_header(
746 current_task,
747 &file,
748 (&mut current_mmsghdr.hdr).into(),
749 flags,
750 deadline,
751 ) {
752 Err(error) => {
753 if index == 0 {
754 return Err(error);
755 }
756 break;
757 }
758 Ok(bytes_read) => {
759 current_mmsghdr.len = bytes_read;
760 current_task.write_multi_arch_object(current_ptr, current_mmsghdr)?;
761 }
762 }
763 index += 1;
764 if flags & MSG_WAITFORONE != 0 {
765 flags |= MSG_DONTWAIT;
766 }
767 }
768 Ok(index)
769}
770
771pub fn sys_recvfrom(
772 current_task: &CurrentTask,
773 fd: FdNumber,
774 user_buffer: UserAddress,
775 buffer_length: usize,
776 flags: u32,
777 user_src_address: UserAddress,
778 user_src_address_length: UserRef<socklen_t>,
779) -> Result<usize, Errno> {
780 let file = current_task.get_file(fd)?;
781 if !file.node().is_sock() {
782 return error!(ENOTSOCK);
783 }
784
785 let flags = SocketMessageFlags::from_bits(flags).ok_or_else(|| errno!(EINVAL))?;
786 let socket_ops = file.downcast_file::<SocketFile>().unwrap();
787 let info = socket_ops.recvmsg(
788 current_task,
789 &file,
790 &mut UserBuffersOutputBuffer::unified_new_at(current_task, user_buffer, buffer_length)?,
791 flags,
792 None,
793 )?;
794
795 if !user_src_address.is_null() {
796 let bytes = info.address.map(|a| a.to_bytes()).unwrap_or_else(|| vec![]);
797 write_socket_address(current_task, user_src_address, user_src_address_length, &bytes)?;
798 }
799
800 if flags.contains(SocketMessageFlags::TRUNC)
801 && socket_ops.socket.socket_type != SocketType::Stream
802 {
803 Ok(info.message_length)
804 } else {
805 Ok(info.bytes_read)
806 }
807}
808
809fn sendmsg_internal(
810 current_task: &CurrentTask,
811 file: &FileHandle,
812 user_message_header: MsgHdrPtr,
813 flags: u32,
814) -> Result<usize, Errno> {
815 let message_header = current_task.read_multi_arch_object(user_message_header)?;
816 sendmsg_internal_with_header(current_task, file, &message_header, flags)
817}
818
819fn sendmsg_internal_with_header(
820 current_task: &CurrentTask,
821 file: &FileHandle,
822 message_header: &MsgHdr,
823 flags: u32,
824) -> Result<usize, Errno> {
825 if message_header.name_len > i32::MAX as u32 {
826 return error!(EINVAL);
827 }
828 if message_header.control_len > 20480 {
829 return error!(ENOBUFS);
830 }
831 let dest_address = maybe_parse_socket_address(
832 current_task,
833 message_header.name,
834 message_header.name_len as usize,
835 )?;
836 let iovec = read_iovec_from_msghdr(current_task, message_header.into())?;
837
838 let mut next_message_offset: usize = 0;
839 let mut ancillary_data = Vec::new();
840 let header_size = CMsgHdrPtr::size_of_object_for(current_task);
841 loop {
842 let space = message_header.control_len.saturating_sub(next_message_offset);
843 if space < header_size {
844 break;
845 }
846 let cmsg_ref =
847 CMsgHdrPtr::new(current_task, (message_header.control + next_message_offset)?);
848 let cmsg = current_task.read_multi_arch_object(cmsg_ref)?;
849 if (cmsg.cmsg_len as usize) < header_size {
852 return error!(EINVAL);
853 }
854
855 let data_size = std::cmp::min(cmsg.cmsg_len as usize - header_size, space);
856 let next_data_offset = next_message_offset + header_size;
857 let data = current_task
858 .read_memory_to_vec((message_header.control + next_data_offset)?, data_size)?;
859 next_message_offset += cmsg_align(current_task, header_size + data.len())?;
860 let data = AncillaryData::from_cmsg(
861 current_task,
862 ControlMsg::new(cmsg.cmsg_level, cmsg.cmsg_type, data),
863 )?;
864 if data.total_size(current_task) == 0 {
865 continue;
866 }
867 ancillary_data.push(data);
868 }
869
870 let flags = SocketMessageFlags::from_bits(flags).ok_or_else(|| errno!(EOPNOTSUPP))?;
871 let socket_ops = file.downcast_file::<SocketFile>().unwrap();
872 if dest_address.is_some()
873 && socket_ops.socket.domain == SocketDomain::Inet
874 && socket_ops.socket.socket_type != SocketType::Stream
875 && (message_header.name_len as usize) < std::mem::size_of::<uapi::sockaddr_in>()
876 {
877 return error!(EINVAL);
878 }
879 socket_ops.sendmsg(
880 current_task,
881 file,
882 &mut UserBuffersInputBuffer::unified_new(current_task, iovec)?,
883 dest_address,
884 ancillary_data,
885 flags,
886 )
887}
888
889pub fn sys_sendmsg(
890 current_task: &CurrentTask,
891 fd: FdNumber,
892 user_message_header: MsgHdrPtr,
893 flags: u32,
894) -> Result<usize, Errno> {
895 let file = current_task.get_file(fd)?;
896 if !file.node().is_sock() {
897 return error!(ENOTSOCK);
898 }
899 sendmsg_internal(current_task, &file, user_message_header, flags)
900}
901
902pub fn sys_sendmmsg(
903 current_task: &CurrentTask,
904 fd: FdNumber,
905 user_mmsgvec: MMsgHdrPtr,
906 mut vlen: u32,
907 flags: u32,
908) -> Result<usize, Errno> {
909 let file = current_task.get_file(fd)?;
910 if !file.node().is_sock() {
911 return error!(ENOTSOCK);
912 }
913
914 if vlen > UIO_MAXIOV {
916 vlen = UIO_MAXIOV;
917 }
918
919 let mut index = 0usize;
920 while index < vlen as usize {
921 let current_ptr = user_mmsgvec.at(index)?;
922 let mut current_mmsghdr = current_task.read_multi_arch_object(current_ptr)?;
923 match sendmsg_internal_with_header(current_task, &file, ¤t_mmsghdr.hdr, flags) {
924 Err(error) => {
925 if index == 0 {
926 return Err(error);
927 }
928 break;
929 }
930 Ok(bytes_read) => {
931 current_mmsghdr.len = bytes_read;
932 current_task.write_multi_arch_object(current_ptr, current_mmsghdr)?;
933 }
934 }
935 index += 1;
936 }
937 Ok(index)
938}
939
940pub fn sys_sendto(
941 current_task: &CurrentTask,
942 fd: FdNumber,
943 user_buffer: UserAddress,
944 user_buffer_length: usize,
945 flags: u32,
946 user_dest_address: UserAddress,
947 user_dest_address_length: socklen_t,
948) -> Result<usize, Errno> {
949 let file = current_task.get_file(fd)?;
950 if !file.node().is_sock() {
951 return error!(ENOTSOCK);
952 }
953
954 let dest_address = maybe_parse_socket_address(
955 current_task,
956 user_dest_address,
957 user_dest_address_length as usize,
958 )?;
959 let mut data =
960 UserBuffersInputBuffer::unified_new_at(current_task, user_buffer, user_buffer_length)?;
961
962 let flags = SocketMessageFlags::from_bits(flags).ok_or_else(|| errno!(EOPNOTSUPP))?;
963 let socket_file = file.downcast_file::<SocketFile>().unwrap();
964 if dest_address.is_some()
965 && socket_file.socket.domain == SocketDomain::Inet
966 && socket_file.socket.socket_type != SocketType::Stream
967 && (user_dest_address_length as usize) < std::mem::size_of::<uapi::sockaddr_in>()
968 {
969 return error!(EINVAL);
970 }
971 socket_file.sendmsg(current_task, &file, &mut data, dest_address, vec![], flags)
972}
973
974pub fn sys_getsockopt(
975 current_task: &CurrentTask,
976 fd: FdNumber,
977 level: u32,
978 optname: u32,
979 user_optval: UserAddress,
980 user_optlen: UserRef<socklen_t>,
981) -> Result<(), Errno> {
982 let file = current_task.get_file(fd)?;
983 let socket = Socket::get_from_file(&file)?;
984
985 let optlen = current_task.read_object(user_optlen)? as usize;
986 let optval_buffer_len = optlen;
987 let mut optval = current_task.read_memory_to_vec(user_optval, optlen as usize)?;
988
989 let result = if socket.domain.is_inet() && IpTables::can_handle_getsockopt(level, optname) {
990 current_task.kernel().iptables().getsockopt(current_task, socket, optname, optval.clone())
991 } else {
992 socket.getsockopt(current_task, level, optname, optlen as u32)
993 };
994
995 let (optlen, error) = match result {
998 Ok(new_optval) => {
999 let len = std::cmp::min(new_optval.len(), optval.len());
1006 optval[..len].copy_from_slice(&new_optval[..len]);
1007 (len, None)
1008 }
1009 Err(e) => (optlen, Some(e)),
1010 };
1011
1012 let root_cgroup = current_task.kernel().ebpf_state.attachments.root_cgroup();
1013 let (optval, optlen) = root_cgroup.run_getsockopt_prog(
1014 current_task,
1015 level,
1016 optname,
1017 optval,
1018 optlen,
1019 error,
1020 socket,
1021 )?;
1022
1023 assert!(optlen <= optval_buffer_len);
1024 current_task.write_memory(user_optval, &optval[..optlen])?;
1025 current_task.write_object(user_optlen, &(optlen as u32))?;
1026
1027 Ok(())
1028}
1029
1030pub fn sys_setsockopt(
1031 current_task: &CurrentTask,
1032 fd: FdNumber,
1033 level: u32,
1034 optname: u32,
1035 user_optval: UserAddress,
1036 optlen: socklen_t,
1037) -> Result<(), Errno> {
1038 let file = current_task.get_file(fd)?;
1039 let socket = Socket::get_from_file(&file)?;
1040
1041 let user_opt = UserBuffer { address: user_optval, length: optlen as usize };
1042
1043 let root_cgroup = current_task.kernel().ebpf_state.attachments.root_cgroup();
1045 let optval = match root_cgroup.run_setsockopt_prog(
1046 current_task,
1047 level,
1048 optname,
1049 user_opt.into(),
1050 socket,
1051 ) {
1052 SetSockOptProgramResult::Allow(value) => value,
1053 SetSockOptProgramResult::Fail(errno) => return Err(errno),
1054 SetSockOptProgramResult::Bypass => return Ok(()), };
1056
1057 if socket.domain.is_inet() && IpTables::can_handle_setsockopt(level, optname) {
1058 current_task.kernel().iptables().setsockopt(current_task, socket, optname, optval)
1059 } else {
1060 socket.setsockopt(current_task, level, optname, optval)
1061 }
1062}
1063
1064pub fn sys_shutdown(current_task: &CurrentTask, fd: FdNumber, how: u32) -> Result<(), Errno> {
1065 let file = current_task.get_file(fd)?;
1066 let socket = Socket::get_from_file(&file)?;
1067 let how = match how {
1068 SHUT_RD => SocketShutdownFlags::READ,
1069 SHUT_WR => SocketShutdownFlags::WRITE,
1070 SHUT_RDWR => SocketShutdownFlags::READ | SocketShutdownFlags::WRITE,
1071 _ => return error!(EINVAL),
1072 };
1073 socket.shutdown(current_task, how)?;
1074 Ok(())
1075}
1076
1077pub fn cmsg_align(current_task: &CurrentTask, value: usize) -> Result<usize, Errno> {
1078 let alignment = if current_task.is_arch32() { 4 } else { 8 };
1079 round_up_to_increment(value, alignment)
1080}
1081
1082#[cfg(target_arch = "aarch64")]
1084mod arch32 {
1085 use crate::task::CurrentTask;
1086 use crate::vfs::FdNumber;
1087 use starnix_uapi::errors::Errno;
1088 use starnix_uapi::user_address::UserAddress;
1089
1090 pub use super::{
1091 sys_accept as sys_arch32_accept, sys_accept4 as sys_arch32_accept4,
1092 sys_bind as sys_arch32_bind, sys_getpeername as sys_arch32_getpeername,
1093 sys_getsockname as sys_arch32_getsockname, sys_getsockopt as sys_arch32_getsockopt,
1094 sys_listen as sys_arch32_listen, sys_recvfrom as sys_arch32_recvfrom,
1095 sys_recvmmsg as sys_arch32_recvmmsg, sys_recvmsg as sys_arch32_recvmsg,
1096 sys_sendmsg as sys_arch32_sendmsg, sys_sendto as sys_arch32_sendto,
1097 sys_setsockopt as sys_arch32_setsockopt, sys_shutdown as sys_arch32_shutdown,
1098 sys_socketpair as sys_arch32_socketpair,
1099 };
1100
1101 pub fn sys_arch32_send(
1102 current_task: &CurrentTask,
1103 fd: FdNumber,
1104 user_buffer: UserAddress,
1105 user_buffer_length: usize,
1106 flags: u32,
1107 ) -> Result<usize, Errno> {
1108 super::sys_sendto(
1109 current_task,
1110 fd,
1111 user_buffer,
1112 user_buffer_length,
1113 flags,
1114 Default::default(),
1115 Default::default(),
1116 )
1117 }
1118
1119 pub fn sys_arch32_recv(
1120 current_task: &CurrentTask,
1121 fd: FdNumber,
1122 user_buffer: UserAddress,
1123 buffer_length: usize,
1124 flags: u32,
1125 ) -> Result<usize, Errno> {
1126 super::sys_recvfrom(
1127 current_task,
1128 fd,
1129 user_buffer,
1130 buffer_length,
1131 flags,
1132 Default::default(),
1133 Default::default(),
1134 )
1135 }
1136}
1137
1138#[cfg(target_arch = "aarch64")]
1139pub use arch32::*;
1140
1141#[cfg(test)]
1142mod tests {
1143 use super::*;
1144 use crate::testing::spawn_kernel_and_run;
1145 use starnix_uapi::{AF_INET, AF_UNIX, SOCK_STREAM};
1146
1147 #[::fuchsia::test]
1148 async fn test_socketpair_invalid_arguments() {
1149 spawn_kernel_and_run(async |current_task| {
1150 assert_eq!(
1151 sys_socketpair(
1152 current_task,
1153 AF_INET as u32,
1154 SOCK_STREAM,
1155 0,
1156 UserRef::new(UserAddress::default())
1157 ),
1158 error!(EPROTONOSUPPORT)
1159 );
1160 assert_eq!(
1161 sys_socketpair(
1162 current_task,
1163 AF_UNIX as u32,
1164 7,
1165 0,
1166 UserRef::new(UserAddress::default())
1167 ),
1168 error!(EINVAL)
1169 );
1170 assert_eq!(
1171 sys_socketpair(
1172 current_task,
1173 AF_UNIX as u32,
1174 SOCK_STREAM,
1175 0,
1176 UserRef::new(UserAddress::default())
1177 ),
1178 error!(EFAULT)
1179 );
1180 })
1181 .await;
1182 }
1183
1184 #[::fuchsia::test]
1185 fn test_generate_autobind_address() {
1186 let address = generate_autobind_address();
1187 assert_eq!(address.len(), 6);
1188 assert_eq!(address[0], 0);
1189 for byte in address[1..].iter() {
1190 match byte {
1191 b'0'..=b'9' | b'a'..=b'f' => {
1192 }
1194 bad => {
1195 panic!("bad byte: {bad}");
1196 }
1197 }
1198 }
1199 }
1200}