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