Skip to main content

starnix_core/vfs/socket/
syscalls.rs

1// Copyright 2021 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use 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
43/// A `msghdr` can be augmented with a `UserBuffer`. In that case, the `UserBuffer` is used for
44/// the I/O, instead of the `iovec` fields from the `msghdr`.
45pub 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/// A reference to a `msghdr`.
60///
61/// This enum is used to abstract over whether the `msghdr` is in user memory (and needs to be
62/// read) or has been constructed in the kernel. This is used by `io_uring` to provide a buffer
63/// for `recvmsg`.
64#[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    // Should we use parse_socket_protocol here?
118    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        /*kernel_private=*/ 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    // For AF_UNIX, SOCK_RAW sockets are treated as if they were SOCK_DGRAM.
156    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                // Should we have different behavior error when called by root?
173                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
214// See "Autobind feature" section of https://man7.org/linux/man-pages/man7/unix.7.html
215fn 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        // See <https://man7.org/linux/man-pages/man7/ip.7.html>:
245        //
246        //   The port numbers below 1024 are called privileged ports (or
247        //   sometimes: reserved ports).  Only a privileged process (on Linux:
248        //   a process that has the CAP_NET_BIND_SERVICE capability in the
249        //   user namespace governing its network namespace) may bind(2) to
250        //   these sockets.
251        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                // If the name is empty, then we're supposed to generate an
262                // autobind address, which is always abstract.
263                name = generate_autobind_address();
264            }
265            // If there is a null byte at the start of the sun_path, then the
266            // address is abstract.
267            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        /* kernel_private= */ 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        // TODO(https://fxbug.dev/445433238): Connect not available for AF_VSOCK
384        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        // EINPROGRESS may be returned for inet sockets when `connect()` is completed
407        // asynchronously.
408        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        // TODO(tbodt): Support blocking when the UNIX domain socket queue fills up. This one's
422        // weird because as far as I can tell, removing a socket from the queue does not actually
423        // trigger FdEvents on anything.
424        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    // TODO: Eventually this will need to allocate two fd numbers (each of which could
502    // potentially fail), and only populate the fd numbers (which can't fail) if both allocations
503    // succeed.
504    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    // In `CurrentTask::read_iovec()` the same check fails with `EINVAL`. This works for all
524    // syscalls that use `iovec`, except `sendmsg()` and `recvmsg()`, which need to fail with
525    // EMSGSIZE.
526    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            // Skip zero-byte ancillary data on the receiving end. Not doing this trips this
586            // assert:
587            // https://cs.android.com/android/platform/superproject/+/master:system/libbase/cmsg.cpp;l=144;drc=15ec2c7a23cda814351a064a345a8270ed8c83ab
588            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        // If the message is smaller than expected, set the MSG_CTRUNC flag, so the caller can tell
599        // some of the message is missing.
600        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            // Can't fit the header, so stop trying to write.
607            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
655/// Implementation of `recvmsg`.
656///
657/// This function is used by `sys_recvmsg`, but can also be called from other parts of the kernel
658/// that need to override the `iovec` from the `msghdr`. For example, when using `io_uring` with
659/// ring buffers.
660pub 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 the message header is not long enough to fit the required fields of the
804        // control data, return EINVAL.
805        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    // vlen is capped at UIO_MAXIOV.
862    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, &current_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    // Even if `getsockopt()` above returned an error we still need to run
936    // the eBPF program - it may handle the error.
937    let (optlen, error) = match result {
938        Ok(new_optval) => {
939            // Linux getsockopt allows the user to pass a buffer smaller than the option's
940            // actual size, in which case the kernel truncates the returned value to fit
941            // the buffer and returns success.
942            //
943            // On the other hand, if the option is smaller than the user provided buffer,
944            // the eBPF program can still use the entire user allocated buffer if needed.
945            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    // Run eBPF program if any.
984    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(()), // The option was handled by eBPF.
995    };
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// Syscalls for arch32 usage
1023#[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                    // Ok.
1133                }
1134                bad => {
1135                    panic!("bad byte: {bad}");
1136                }
1137            }
1138        }
1139    }
1140}