// Socket syscalls. // // The kernel side is in kernel/net/unix.c; this file is only the translation // between a syscall's user-supplied `struct sockaddr` and the path string the // socket layer actually wants, plus the file-descriptor bookkeeping. // // Two families now. AF_UNIX is answered by kernel/net/unix.c, AF_INET by // kernel/net/inet.c on top of lwIP; the socket layer dispatches on the domain // the socket was created with, so this file's only extra job is to read the // right shape of sockaddr out of user memory. AF_INET6 is still refused with // EAFNOSUPPORT rather than EINVAL, because a program that probes for IPv6 and // falls back to IPv4 needs to tell "not here" from "you passed nonsense". #include "core/types.h" #include "core/defs.h" #include "core/param.h" #include "arch/mmu.h" #include "core/proc.h" #include "fs/fs.h" #include "core/spinlock.h" #include "core/sleeplock.h" #include "uapi/stat.h" #include "fs/file.h" #include "uapi/posix.h" #include "core/syscall.h" #include "core/uaccess.h" #include "core/kmem.h" #include "uapi/errno.h" #include "net/socket.h" // Pull the sun_path out of a user `struct sockaddr_un`, NUL-terminated. // // The length the caller gives is checked rather than trusted: musl passes // `offsetof(sockaddr_un, sun_path) + strlen(path) + 1`, which is shorter than // the full struct, so reading sizeof(struct sockaddr_un) from user memory // would fault on a path that sits near the end of a page. static int fetch_sun_path(addr_t uaddr, int ulen, char *out) { struct sockaddr_un sa; int plen; if (ulen < (int)sizeof(sa.sun_family) || ulen > (int)sizeof(sa)) return -EINVAL; memset(&sa, 0, sizeof(sa)); if (copy_from_user(&sa, uaddr, (uint64)ulen) < 0) return -EFAULT; if (sa.sun_family == AF_INET) return -EAFNOSUPPORT; if (sa.sun_family != AF_UNIX) return -EAFNOSUPPORT; plen = ulen - (int)sizeof(sa.sun_family); if (plen <= 0) return -EINVAL; if (plen > UNIX_PATH_MAX - 1) plen = UNIX_PATH_MAX - 1; memmove(out, sa.sun_path, (uint)plen); out[plen] = '\0'; // A NUL inside the copied region is fine -- it just ends the path early, // which is what a caller passing the full struct length does. out[UNIX_PATH_MAX - 1] = '\0'; return 0; } // For an abstract address -- sun_path[0] == 0 -- the name as a key, and 1. // The name is every byte after the NUL up to the length given, NULs included, // as Linux has it; FNV-1a, which is plenty for a table of NSOCK. static int sun_abstract(addr_t uaddr, int ulen, uint64 *key) { struct sockaddr_un sa; int plen = ulen - (int)sizeof(sa.sun_family); if (plen < 2 || ulen > (int)sizeof(sa)) return 0; if (copy_from_user(&sa, uaddr, (uint64)ulen) < 0 || sa.sun_path[0] != 0) return 0; uint64 h = 1469598103934665603ULL; for (int i = 1; i < plen; i++) { h ^= (uchar)sa.sun_path[i]; h *= 1099511628211ULL; } *key = h ? h : 1; return 1; } // Wrap an established socket in a file and a descriptor. Consumes the // socket's reference on success; on failure the caller still owns it. // // `sflags` carries SOCK_CLOEXEC and SOCK_NONBLOCK, which socket(), socketpair() // and accept4() all take and all used to discard. // // Discarding them is not harmless in either direction. A dropped SOCK_CLOEXEC // leaks the descriptor across every exec the process makes -- so a server that // forks a child holds its listening socket open in it, and the port stays bound // after the server dies. A dropped SOCK_NONBLOCK is worse: the caller believes // it has a non-blocking socket, does not select() first, and blocks forever in // what it thinks is a poll loop. // // Both are one line each, and they were masked off with a comment saying they // were not honoured -- which is exactly the class of quiet lie the rest of this // file has just been cleaned of. static int sock_to_fd(struct socket *s, int sflags) { struct file *f; int fd; if ((f = filealloc()) == 0) return -ENFILE; if ((fd = fdalloc(f)) < 0) { f->ref = 0; return -EMFILE; } f->type = FD_SOCKET; f->sock = s; f->readable = 1; f->writable = 1; f->off = 0; f->nonblock = (sflags & SOCK_NONBLOCK) != 0; if (sflags & SOCK_CLOEXEC) myproc()->files->flags[fd] |= FD_CLOEXEC; return fd; } // Resolve a descriptor to the socket behind it. static int argsock(int n, struct socket **ps) { int fd; struct file *f; if (argint(n, &fd) < 0) return -EBADF; if (fd < 0 || fd >= NOFILE || !(f = myproc()->files->ofile[fd])) return -EBADF; if (f->type != FD_SOCKET) return -ENOTSOCK; *ps = f->sock; return 0; } SYSCALL_DEFINE(socket) { int domain, type, protocol; struct socket *s; int fd; argint(0, &domain); argint(1, &type); argint(2, &protocol); if (domain != AF_UNIX && domain != AF_INET && domain != AF_NETLINK) return -EAFNOSUPPORT; // SOCK_CLOEXEC / SOCK_NONBLOCK ride in the high bits of `type`. Split them // off rather than discarding them: the type check below wants the low byte, // and sock_to_fd wants the flags. int sflags = type & (SOCK_CLOEXEC | SOCK_NONBLOCK); if (type & ~(0xFF | SOCK_CLOEXEC | SOCK_NONBLOCK)) return -EINVAL; type &= 0xFF; if (domain == AF_UNIX && type != SOCK_STREAM && type != SOCK_DGRAM && type != SOCK_SEQPACKET) return -EPROTOTYPE; if (domain == AF_INET && type != SOCK_STREAM && type != SOCK_DGRAM && type != SOCK_RAW) return -EPROTOTYPE; // AF_NETLINK takes SOCK_RAW or SOCK_DGRAM and its own protocol numbering; // socknew checks both, because which protocols exist is the socket layer's // business rather than this one's. if (domain == AF_NETLINK && type != SOCK_RAW && type != SOCK_DGRAM) return -EPROTOTYPE; // Protocol 0 means "the default for this type". The one non-default we // support is a ping socket -- SOCK_DGRAM with IPPROTO_ICMP, Linux's way of // letting an unprivileged process do the one thing raw sockets were used // for. Anything else is still refused rather than quietly given a socket // that speaks a different protocol than the caller asked for. // // IPPROTO_TCP with SOCK_STREAM and IPPROTO_UDP with SOCK_DGRAM name the // default rather than departing from it, and programs do write them out: // toybox's `nc` passes IPPROTO_TCP, and refusing it meant "Protocol not // supported" for TCP on a system whose whole network is TCP. if (protocol != 0 && domain != AF_NETLINK) { int redundant = (domain == AF_INET && type == SOCK_STREAM && protocol == IPPROTO_TCP) || (domain == AF_INET && type == SOCK_DGRAM && protocol == IPPROTO_UDP); if (redundant) protocol = 0; else if (!(domain == AF_INET && (type == SOCK_DGRAM || type == SOCK_RAW) && protocol == IPPROTO_ICMP)) return -EPROTONOSUPPORT; } // A raw socket is ICMP or nothing: it exists because busybox's ping, which // is /bin/ping on the Alpine root, opens SOCK_RAW and stops at // EPROTOTYPE. Raw TCP or UDP would be the stack handing over packets it is // also processing, and nothing has asked for that. if (domain == AF_INET && type == SOCK_RAW && protocol != IPPROTO_ICMP) return -EPROTONOSUPPORT; // ENETDOWN rather than ENFILE when the stack itself is not running: the // old blanket ENFILE said "file table overflow" for a machine with no // network, which is a long way from the truth and a longer way from the // fix. if (domain == AF_INET && !net_is_ready()) return -ENETDOWN; if ((s = socknew(domain, type, protocol)) == 0) return -ENFILE; if ((fd = sock_to_fd(s, sflags)) < 0) { sockclose(s); return fd; } return fd; } // Pull an address and port out of a user `struct sockaddr_in`. // // Both come back in network byte order and stay that way: lwIP wants them that // way, so converting here and back again would be two swaps that cancel. static int fetch_sin(addr_t uaddr, int ulen, uint *addr, ushort *port) { struct sockaddr_in sa; if (ulen < (int)sizeof(sa)) return -EINVAL; if (copy_from_user(&sa, uaddr, sizeof(sa)) < 0) return -EFAULT; if (sa.sin_family != AF_INET) return -EAFNOSUPPORT; *addr = sa.sin_addr; *port = sa.sin_port; return 0; } // Network byte order to host, for a port. The kernel is little-endian and the // wire is big-endian; lwIP's own ntohs is not reachable from here without // dragging its headers into the syscall layer. static ushort port_from_net(ushort p) { return (ushort)(((p & 0xFF) << 8) | ((p >> 8) & 0xFF)); } SYSCALL_DEFINE(bind) { struct socket *s; addr_t uaddr; int ulen, r; char path[UNIX_PATH_MAX]; if ((r = argsock(0, &s)) < 0) return r; argaddr(1, &uaddr); argint(2, &ulen); if (sock_domain(s) == AF_INET) { uint ip; ushort port; if ((r = fetch_sin(uaddr, ulen, &ip, &port)) < 0) return r; return sockbind_in(s, ip, port_from_net(port)); } // sockaddr_nl: family, pad, port id, groups. Only the groups matter here. if (sock_domain(s) == AF_NETLINK) { uint pid = 0, groups = 0; if (ulen < 12) return -EINVAL; if (copy_from_user(&pid, uaddr + 4, 4) < 0 || copy_from_user(&groups, uaddr + 8, 4) < 0) return -EFAULT; return sock_netlink_bind(s, pid, groups); } uint64 key; if (sun_abstract(uaddr, ulen, &key)) return sockbind_abstract(s, key); if ((r = fetch_sun_path(uaddr, ulen, path)) < 0) return r; // The node lives in the filesystem now, and it is made here rather than in // sockbind() because this is the layer that has both -- kernel/net/unix.c // knows about sockets and has no business calling create(). // // EADDRINUSE comes from the directory, not from a scan of the socket // table: the name being taken is a property of the filesystem, and a // socket file left behind by a crashed server has to refuse a rebind for // the same reason a running one does. Otherwise two servers both believe // they own it. { struct inode *ip; uint dev; uint64 ino; begin_op(); if ((ip = namei(path)) != 0) { iput(ip); end_op(); return -EADDRINUSE; } if ((ip = create_sock(path)) == 0) { end_op(); return -ENOENT; // the directory does not exist } dev = ip->dev; ino = ip->inum; iunlockput(ip); end_op(); r = sockbind(s, path, dev, ino); if (r < 0) { // Take the node back out, so a failed bind leaves nothing behind // for the next one to trip over. begin_op(); unlink_path(path); end_op(); } return r; } } SYSCALL_DEFINE(listen) { struct socket *s; int backlog, r; if ((r = argsock(0, &s)) < 0) return r; argint(1, &backlog); return socklisten(s, backlog); } SYSCALL_DEFINE(connect) { struct socket *s; addr_t uaddr; int ulen, r; char path[UNIX_PATH_MAX]; if ((r = argsock(0, &s)) < 0) return r; argaddr(1, &uaddr); argint(2, &ulen); if (sock_domain(s) == AF_INET) { uint ip; ushort port; if ((r = fetch_sin(uaddr, ulen, &ip, &port)) < 0) return r; return sockconnect_in(s, ip, port_from_net(port)); } uint64 key; if (sun_abstract(uaddr, ulen, &key)) return sockconnect(s, SOCK_ABSTRACT_DEV, key); if ((r = fetch_sun_path(uaddr, ulen, path)) < 0) return r; // Resolve the path here, for the same reason bind() creates here. A path // that names nothing, or names something that is not a socket, is // ECONNREFUSED -- which is what Linux says and what a client can act on. { struct inode *ip; uint dev; uint64 ino; short type; if ((ip = namei(path)) == 0) return -ECONNREFUSED; ilock(ip); dev = ip->dev; ino = ip->inum; type = ip->type; iunlockput(ip); if (type != T_SOCK) return -ECONNREFUSED; return sockconnect(s, dev, ino); } } // accept(2) and accept4(2) share everything but the flags word. // // They are two table entries rather than one with an alias, and the reason is // the argument count: accept takes three, so a handler that read a fourth // register would be reading whatever the caller happened to leave there and // would invent a SOCK_NONBLOCK out of stack litter. That is precisely the bug // the old `SYSCALL_ALIAS(288, accept)` would have grown the moment the flags // started being honoured. static addr_t do_accept(int sflags) { struct socket *s, *c; addr_t uaddr, ulenp; int r, fd; if ((r = argsock(0, &s)) < 0) return r; argaddr(1, &uaddr); argaddr(2, &ulenp); if ((c = sockaccept(s)) == 0) return -EINVAL; if ((fd = sock_to_fd(c, sflags)) < 0) { sockclose(c); return fd; } // The peer address of a Unix socket that never bound a name is the empty // one: family AF_UNIX and a zero-length path. Reporting it is optional // (both pointers may be null) but a caller that asks must not be left // with an uninitialised struct it then prints. if (uaddr && ulenp) { struct sockaddr_un sa; int len = (int)sizeof(sa.sun_family); int want = 0; memset(&sa, 0, sizeof(sa)); sa.sun_family = AF_UNIX; safestrcpy(sa.sun_path, sockname(c), UNIX_PATH_MAX); len += (int)strlen(sa.sun_path) + 1; if (get_user(want, ulenp) < 0) return fd; // the fd is already live; do not fail it if (want > len) want = len; if (want > 0) copy_to_user(uaddr, &sa, (uint64)want); put_user(len, ulenp); } return fd; } SYSCALL_DEFINE(accept) { return do_accept(0); } SYSCALL_DEFINE(accept4) { int flags = 0; argint(3, &flags); if (flags & ~(SOCK_CLOEXEC | SOCK_NONBLOCK)) return -EINVAL; return do_accept(flags); } SYSCALL_DEFINE(socketpair) { int domain, type, protocol; addr_t usv; struct socket *a, *b; int fd0, fd1, r; argint(0, &domain); argint(1, &type); argint(2, &protocol); argaddr(3, &usv); if (domain != AF_UNIX) return -EAFNOSUPPORT; int sflags = type & (SOCK_CLOEXEC | SOCK_NONBLOCK); type &= 0xFF; // Datagram and sequenced-packet pairs keep message boundaries (kernel/net/unix.c). if (type != SOCK_STREAM && type != SOCK_DGRAM && type != SOCK_SEQPACKET) return -EPROTOTYPE; if ((r = sockpair_type(&a, &b, type)) < 0) return r; if ((fd0 = sock_to_fd(a, sflags)) < 0) { sockclose(a); sockclose(b); return fd0; } if ((fd1 = sock_to_fd(b, sflags)) < 0) { myproc()->files->ofile[fd0] = 0; sockclose(a); sockclose(b); return fd1; } int sv[2] = { fd0, fd1 }; if (copy_to_user(usv, sv, sizeof(sv)) < 0) { myproc()->files->ofile[fd0] = 0; myproc()->files->ofile[fd1] = 0; sockclose(a); sockclose(b); return -EFAULT; } return 0; } // Host byte order to network, for a port on its way back to userland. The // inverse of port_from_net above, and the same two lines: a sockaddr always // carries the port big-endian, whichever direction it is travelling. static ushort port_to_net(ushort p) { return (ushort)(((p & 0xFF) << 8) | ((p >> 8) & 0xFF)); } // send/recv with no flags are read/write, and sendto/recvfrom are those plus an // address. Implementing them here rather than leaving them ENOSYS saves every // ported program from being rewritten to use read() and write(). SYSCALL_DEFINE(sendto) { struct socket *s; addr_t ubuf, uaddr; int len, flags, ulen, r; uint ip = 0; ushort port = 0; if ((r = argsock(0, &s)) < 0) return r; argaddr(1, &ubuf); argint(2, &len); argint(3, &flags); argaddr(4, &uaddr); argint(5, &ulen); if (len < 0) return -EINVAL; char *p = (char *)user_ptr(ubuf, (uint64)len); if (len && !p) return -EFAULT; // A null address is send(), not an error: the socket already knows where // it is pointed, which for TCP is the only possibility anyway. if (uaddr) { if ((r = fetch_sin(uaddr, ulen, &ip, &port)) < 0) return r; port = port_from_net(port); } return socksendto(s, p, len, ip, port); } static int argsockfile(int n, struct socket **sp, struct file **fp); SYSCALL_DEFINE(recvfrom) { struct socket *s; struct file *file; addr_t ubuf, uaddr, ulenp; int len, flags, r; uint ip = 0; ushort port = 0; if ((r = argsockfile(0, &s, &file)) < 0) return r; argaddr(1, &ubuf); argint(2, &len); argint(3, &flags); argaddr(4, &uaddr); argaddr(5, &ulenp); if (len < 0) return -EINVAL; char *p = (char *)user_ptr(ubuf, (uint64)len); if (len && !p) return -EFAULT; // As in recvmsg. This one blocked regardless, and musl's resolver -- which // sends the A and AAAA queries together and reads its non-blocking socket // until EAGAIN -- waited for ever after the first answer: NetSurf sat on // "Loading" with the reply in hand. if ((file->nonblock || (flags & MSG_DONTWAIT)) && !sockreadable(s)) return -EAGAIN; r = sockrecvfrom(s, p, len, &ip, &port); if (r < 0 || uaddr == 0) return r; // The address is reported only for the family that has one to report. A // Unix socket leaves ip at zero, and the honest answer there is a length of // zero rather than a sockaddr full of nothing that a caller would read as // 0.0.0.0:0 and believe. int alen = 0; if (sock_domain(s) == AF_INET) { struct sockaddr_in sa; memset(&sa, 0, sizeof(sa)); sa.sin_family = AF_INET; sa.sin_addr = ip; sa.sin_port = port_to_net(port); alen = (int)sizeof(sa); // Truncated rather than refused if the caller's buffer is smaller, // which is what accept() and getsockname() do everywhere: the length // written back tells them what they got. int cap = alen; if (ulenp && get_user(cap, ulenp) < 0) return -EFAULT; if (cap > alen) cap = alen; if (cap > 0 && copy_to_user(uaddr, &sa, (uint64)cap) < 0) return -EFAULT; } else if (sock_domain(s) == AF_NETLINK) { // Everything on a netlink socket here comes from the kernel: port id // 0, no groups. GLib's network monitor checks exactly that before it // believes a message, and with no address at all it hit an assertion // and every GNOME program that watches the network aborted. uint16 nl[6] = { AF_NETLINK, 0, 0, 0, 0, 0 }; uint g = sock_nl_groups(s), from = sock_nl_from(s); nl[2] = (uint16)from; nl[3] = (uint16)(from >> 16); nl[4] = (uint16)g; nl[5] = (uint16)(g >> 16); alen = (int)sizeof(nl); int cap = alen; if (ulenp && get_user(cap, ulenp) < 0) return -EFAULT; if (cap > alen) cap = alen; if (cap > 0 && copy_to_user(uaddr, nl, (uint64)cap) < 0) return -EFAULT; } if (ulenp && copy_to_user(ulenp, &alen, sizeof(alen)) < 0) return -EFAULT; return r; } // getsockname(2) and getpeername(2). // // Neither existed, and the first program to mind was every X client: libxcb // picks the cookie to send by the family of the connection's address, asked // with getpeername and then getsockname, and with both failing it sent none. // Xorg answered "Authorization required, but no authorization protocol // specified" and startx gave up. static int sock_name(int peer) { struct socket *s; addr_t uaddr, ulenp; int r, cap; if ((r = argsock(0, &s)) < 0) return r; argaddr(1, &uaddr); argaddr(2, &ulenp); if (get_user(cap, ulenp) < 0) return -EFAULT; if (cap < 0) return -EINVAL; union { struct sockaddr_in in; struct sockaddr_un un; } sa; int alen; memset(&sa, 0, sizeof(sa)); if (sock_domain(s) == AF_INET) { uint ip; ushort port; if ((r = sockname_inet(s, peer, &ip, &port)) < 0) return r; sa.in.sin_family = AF_INET; sa.in.sin_addr = ip; sa.in.sin_port = port_to_net(port); alen = (int)sizeof(sa.in); } else if (sock_domain(s) == AF_NETLINK) { // A sockaddr_nl of zeros: family, padding, port id 0 (the kernel), // no groups. sa.un.sun_family = AF_NETLINK; { // Port id and bound groups, at their offsets in sockaddr_nl. uint pid = sock_nl_pid(s), grp = sock_nl_bound_groups(s); memmove((char *)&sa + 4, &pid, 4); memmove((char *)&sa + 8, &grp, 4); } alen = 12; } else { if ((r = sockname_unix(s, peer, sa.un.sun_path)) < 0) return r; sa.un.sun_family = (uint16)sock_domain(s); // The family, the path and its NUL; an unnamed socket is the family // alone, as on Linux. alen = (int)sizeof(sa.un.sun_family); if (sa.un.sun_path[0]) alen += (int)strlen(sa.un.sun_path) + 1; } // Truncated to the caller's buffer, with the full length written back. if (cap > alen) cap = alen; if (cap > 0 && copy_to_user(uaddr, &sa, (uint64)cap) < 0) return -EFAULT; if (copy_to_user(ulenp, &alen, sizeof(alen)) < 0) return -EFAULT; return 0; } SYSCALL_DEFINE(getsockname) { return sock_name(0); } SYSCALL_DEFINE(getpeername) { return sock_name(1); } // shutdown(2). SHUT_WR is a half-close: the peer reads EOF and can still // write back (see sock_shutdown). SYSCALL_DEFINE(sockshutdown) { struct socket *s; int how, r; if ((r = argsock(0, &s)) < 0) return r; argint(1, &how); return sock_shutdown(s, how); } // setsockopt / getsockopt. // // These both used to succeed unconditionally -- setsockopt was `return 0;` and // getsockopt wrote a zero for every option asked about. The comment said it was // so that a server setting SO_REUSEADDR and treating failure as fatal would not // fail. // // That trade is the wrong way round, and it is worth being precise about why, // because "accept and ignore" looks like the kind thing to do. A caller that // gets ENOPROTOOPT knows the option did not take effect and can decide what to // do. A caller that gets success *changes its behaviour on the strength of it*: // it sets SO_RCVTIMEO and then blocks forever in a read it believes will time // out; it sets TCP_NODELAY and reports latency numbers that measure Nagle. The // failure is silent, remote from the call, and indistinguishable from a bug in // the protocol stack. // // So the rule here is the one the rest of this kernel already follows: do it, // or say you did not. The four options below are genuinely applied to lwIP's // pcb; the readable ones report the truth; everything else is ENOPROTOOPT. // // SO_REUSEADDR is honoured rather than refused precisely because of the // original comment's concern -- it is the one option a server really does set // and really does check. // Fetch the int a setsockopt call is passing. Every option handled here is an // int; anything wanting a struct (SO_RCVTIMEO and friends) is refused above. static int opt_in(addr_t uval, int ulen, int *out) { if (!uval || ulen < (int)sizeof(int)) return -EINVAL; return get_user(*out, uval) < 0 ? -EFAULT : 0; } // Hand one int back, and report how many bytes that was. static int opt_out(addr_t uval, addr_t ulenp, int val) { int want = 0; if (!uval || !ulenp) return -EFAULT; if (get_user(want, ulenp) < 0) return -EFAULT; if (want < (int)sizeof(int)) return -EINVAL; if (put_user(val, uval) < 0) return -EFAULT; want = sizeof(int); return put_user(want, ulenp) < 0 ? -EFAULT : 0; } SYSCALL_DEFINE(setsockopt) { struct socket *s; addr_t uval; int level, name, ulen, val, r; if ((r = argsock(0, &s)) < 0) return r; argint(1, &level); argint(2, &name); argaddr(3, &uval); argint(4, &ulen); if ((r = opt_in(uval, ulen, &val)) < 0) return r; return sockopt_set(s, level, name, val); } SYSCALL_DEFINE(getsockopt) { struct socket *s; addr_t uval, ulenp; int level, name, val = 0, r; if ((r = argsock(0, &s)) < 0) return r; argint(1, &level); argint(2, &name); argaddr(3, &uval); argaddr(4, &ulenp); // SO_PEERCRED: who is on the other end of a Unix socket. tmux asks its // client this and, told nothing, refuses it as a stranger. if (level == 1 && name == 17) { struct { int pid; uint uid, gid; } cr; int want; if (sock_peercred(s, &cr.pid, &cr.uid, &cr.gid) < 0) return -ENOTCONN; if (!uval || !ulenp || get_user(want, ulenp) < 0) return -EFAULT; if (want < (int)sizeof(cr)) return -EINVAL; if (copy_to_user(uval, &cr, sizeof(cr)) < 0) return -EFAULT; want = sizeof(cr); return put_user(want, ulenp) < 0 ? -EFAULT : 0; } if ((r = sockopt_get(s, level, name, &val)) < 0) return r; return opt_out(uval, ulenp, val); } // --------------------------------------------------------------------------- // sendmsg / recvmsg // // These exist for SCM_RIGHTS. Everything else they do -- scatter/gather over an // iovec, an address on the side -- sendto and recvfrom already did, and the // reason to build the general call rather than a `sendfd()` is that the // programs that need it are not ours: libwayland and toybox's ping both call // recvmsg with Linux's structures and would not notice a friendlier door. // // docs/architecture/kernel.md item 1, and docs/architecture/devices.md mechanism 1. // --------------------------------------------------------------------------- // Linux caps an iovec at UIO_MAXIOV = 1024, and so does this. It was 32, and // tmux met it on its first message: imsg hands sendmsg every queued buffer at // once, one iovec each, and a client announcing its environment has dozens. // Nothing is sized by the count -- each entry is fetched and copied on its own. #define SCH_IOV_MAX 1024 // The control buffer is copied onto the kernel stack, and that stack is 4 KB // (param.h, KSTACKSIZE). 256 bytes holds CMSG_SPACE(SCM_MAXFD * 4) six times // over; anything larger on the *send* side is a caller with a plan we do not // need to support. #define SCH_CMSG_MAX 256 // Resolve a descriptor to both the socket and the open file description -- // recvmsg needs the second because O_NONBLOCK lives there, not on the socket. static int argsockfile(int n, struct socket **ps, struct file **pf) { int fd; struct file *f; if (argint(n, &fd) < 0) return -EBADF; if (fd < 0 || fd >= NOFILE || !(f = myproc()->files->ofile[fd])) return -EBADF; if (f->type != FD_SOCKET) return -ENOTSOCK; *ps = f->sock; *pf = f; return 0; } static int fetch_msghdr(addr_t umsg, struct msghdr *m) { if (umsg == 0 || copy_from_user(m, umsg, sizeof(*m)) < 0) return -EFAULT; if (m->msg_iovlen > SCH_IOV_MAX) return -EMSGSIZE; return 0; } // One iovec, validated. Returns the byte count, 0 for an empty entry that the // caller should skip, or negative on a bad pointer. static int fetch_iov(struct msghdr *m, uint64 i, char **pp) { struct iovec iv; if (copy_from_user(&iv, (addr_t)&m->msg_iov[i], sizeof(iv)) < 0) return -EFAULT; if (iv.iov_len == 0) return 0; if (iv.iov_len > 0x7fffffff) return -EINVAL; if (!(*pp = (char *)user_ptr((addr_t)iv.iov_base, iv.iov_len))) return -EFAULT; return (int)iv.iov_len; } // Pull the descriptors out of a control buffer and take a kernel reference on // each. On any failure the ones already taken are released -- a half-gathered // message must not leave references behind for a call that returns an error. static int scm_gather(struct msghdr *m, struct file **fs, int *nfp) { char buf[SCH_CMSG_MAX]; uint64 off, payload, i; struct cmsghdr *c; struct file *f; int ufd, r; *nfp = 0; if (m->msg_control == 0 || m->msg_controllen < sizeof(struct cmsghdr)) return 0; if (m->msg_controllen > SCH_CMSG_MAX) return -EINVAL; if (copy_from_user(buf, (addr_t)m->msg_control, m->msg_controllen) < 0) return -EFAULT; for (off = 0; off + sizeof(struct cmsghdr) <= m->msg_controllen; ) { c = (struct cmsghdr *)(buf + off); if (c->cmsg_len < CMSG_LEN(0) || c->cmsg_len > m->msg_controllen - off) { r = -EINVAL; goto fail; } if (c->cmsg_level == SOL_SOCKET && c->cmsg_type == SCM_RIGHTS) { payload = c->cmsg_len - CMSG_LEN(0); for (i = 0; i + sizeof(int) <= payload; i += sizeof(int)) { memmove(&ufd, CMSG_DATA(c) + i, sizeof(int)); if (*nfp >= SCM_MAXFD) { r = -EINVAL; goto fail; } if (ufd < 0 || ufd >= NOFILE || !(f = myproc()->files->ofile[ufd])) { r = -EBADF; goto fail; } fs[(*nfp)++] = filedup(f); } } else if (c->cmsg_level == SOL_SOCKET && c->cmsg_type == 2 /* SCM_CREDENTIALS */) { // Credentials, which GDBus sends with the first byte of every // D-Bus connection. Checked as Linux checks them -- they must be // the sender's own, or the sender root -- and then not delivered: // nothing here sets SO_PASSCRED to receive them, and the D-Bus // daemon asks SO_PEERCRED instead, which answers the same question // from the kernel's side. Refusing them made every GNOME program // fail its D-Bus handshake ("Error sending credentials"). struct { int pid; uint uid, gid; } cr; struct proc *me = myproc(); if (c->cmsg_len < CMSG_LEN(sizeof(cr))) { r = -EINVAL; goto fail; } memmove(&cr, CMSG_DATA(c), sizeof(cr)); if (me->euid != 0 && (cr.pid != me->tgid || (cr.uid != me->uid && cr.uid != me->euid) || (cr.gid != me->gid && cr.gid != me->egid))) { r = -EPERM; goto fail; } } else if (c->cmsg_level == SOL_SOCKET) { // Anything else. Refused rather than ignored: a caller that asked // for something and was told yes would believe it happened. r = -EINVAL; goto fail; } off += CMSG_ALIGN(c->cmsg_len); } return 0; fail: while (*nfp > 0) fileclose(fs[--*nfp]); return r; } SYSCALL_DEFINE(sendmsg) { struct socket *s; struct file *file; struct msghdr m; struct file *fs[SCM_MAXFD]; addr_t umsg; uint64 i; int flags, nf = 0, r; long sent = 0; uint ip = 0; ushort port = 0; int addressed = 0; int anydata = 0; if ((r = argsockfile(0, &s, &file)) < 0) return r; argaddr(1, &umsg); argint(2, &flags); if ((r = fetch_msghdr(umsg, &m)) < 0) return r; if ((r = scm_gather(&m, fs, &nf)) < 0) return r; // SCM_RIGHTS is an AF_UNIX facility and there is nothing to generalise: a // descriptor has no meaning on the far side of a wire. if (nf > 0 && sock_domain(s) != AF_UNIX) { r = -EINVAL; goto fail; } if (m.msg_name && sock_domain(s) == AF_INET) { if ((r = fetch_sin((addr_t)m.msg_name, (int)m.msg_namelen, &ip, &port)) < 0) goto fail; port = port_from_net(port); addressed = 1; } // A datagram socket sends the whole message as one datagram, however many // iovecs it is spread over -- udev's header and properties are two. if (sock_is_packet(s)) { char *buf = kalloc(); // a page: kmalloc has no 4 KB class int total = 0; if (!buf) { r = -ENOMEM; goto fail; } for (i = 0; i < m.msg_iovlen; i++) { char *p; int len; if ((len = fetch_iov(&m, i, &p)) < 0) { kfree(buf); r = len; goto fail; } if (total + len > 4096 - 8) { kfree(buf); r = -EMSGSIZE; goto fail; } memmove(buf + total, p, (uint)len); total += len; } if (sock_domain(s) == AF_NETLINK) { // sockaddr_nl: where it goes, by port id and/or multicast group. uint dpid = 0, dgrp = 0; if (m.msg_name && m.msg_namelen >= 12) { if (copy_from_user(&dpid, (addr_t)m.msg_name + 4, 4) < 0 || copy_from_user(&dgrp, (addr_t)m.msg_name + 8, 4) < 0) { kfree(buf); r = -EFAULT; goto fail; } } else { dgrp = UEVENT_GROUP_UDEV; } r = sock_uevent_send(s, buf, total, dpid, dgrp); } else if (nf > 0) { r = sockwrite_fds(s, buf, total, fs, nf); if (r < 0) { kfree(buf); goto fail; // not queued: the descriptors are still ours } nf = 0; } else { r = sockwrite(s, buf, total); } kfree(buf); if (r < 0) goto fail; return total; } for (i = 0; i < m.msg_iovlen; i++) { char *p; int len, w; if ((len = fetch_iov(&m, i, &p)) < 0) { r = len; goto fail; } if (len == 0) continue; anydata = 1; if (addressed) w = socksendto(s, p, len, ip, port); else if (nf > 0) w = sockwrite_fds(s, p, len, fs, nf); else w = sockwrite(s, p, len); if (w < 0) { if (sent > 0) break; // a short write is still a write r = w; goto fail; } // Any positive count means the descriptors are queued and no longer // ours; see the contract above sockwrite_fds. if (w > 0) nf = 0; sent += w; if (w < len) break; } // Descriptors with no bytes to ride on. The delivery rule pins them to the // position of a first byte that in this case never arrives, so there is no // position at which a receiver could ever be handed them. if (nf > 0) { r = -EINVAL; goto fail; } // A datagram with nothing in it is still a datagram: udev's workers say // "done" with exactly that, and the credentials it carries are the message. if (!anydata && sock_is_packet(s)) { if ((r = sockwrite(s, "", 0)) < 0) return r; } return (int)sent; fail: while (nf > 0) fileclose(fs[--nf]); return r; } SYSCALL_DEFINE(recvmsg) { int didread = 0; struct socket *s; struct file *file; struct msghdr m; struct file *fs[SCM_MAXFD]; char cbuf[CMSG_SPACE(SCM_MAXFD * sizeof(int)) + CMSG_SPACE(12)]; int ufd[SCM_MAXFD]; addr_t umsg; uint64 i, clen = 0; int flags, nf = 0, mflags = 0, r; long got = 0; uint ip = 0; ushort port = 0; if ((r = argsockfile(0, &s, &file)) < 0) return r; argaddr(1, &umsg); argint(2, &flags); if ((r = fetch_msghdr(umsg, &m)) < 0) return r; // O_NONBLOCK on the description and MSG_DONTWAIT on the call mean the same // thing and are both honoured, because a program that polls and then reads // uses whichever one its library happened to pick. if ((file->nonblock || (flags & MSG_DONTWAIT)) && !sockreadable(s)) return -EAGAIN; // Netlink is datagrams, and its readers size them before reading: // GLib's network monitor asks recvmsg(MSG_PEEK|MSG_TRUNC) with no buffer // at all and expects the datagram's length back. Answered 0, it read 0, // the answer stayed queued, poll said readable, and Epiphany's main // thread spun on that forever. // // A plain read shorter than what is waiting keeps the rest for the next // one rather than discarding it as Linux would: musl's getifaddrs reads // in chunks, and this whole queue is one "datagram" only by convention. int nlret = -1; if (sock_domain(s) == AF_NETLINK && !sock_is_packet(s)) { uint have = socknl_pending(s); if (have == 0) return -EAGAIN; // never blocks; see sockread for (i = 0; i < m.msg_iovlen; i++) { char *p; int len, rd; if ((len = fetch_iov(&m, i, &p)) < 0) return len; rd = socknl_copy(s, (uint)got, p, len); got += rd; if (rd < len) break; } if (!(flags & MSG_PEEK)) socknl_take(s, (uint)got); if ((uint)got < have && (flags & MSG_PEEK)) mflags |= MSG_TRUNC; nlret = (flags & MSG_TRUNC) ? (int)have : (int)got; m.msg_iovlen = 0; // the loop below has nothing left } for (i = 0; i < m.msg_iovlen; i++) { char *p; int len, rd; if ((len = fetch_iov(&m, i, &p)) < 0) return len; if (len == 0) continue; // Only the first read may block, and it stops for good once a message // carrying descriptors has been taken: the next iovec would be filled // from the message *after* it, and the caller has no way to say where // one ended and the next began. if (got > 0 && (nf > 0 || !sockreadable(s))) break; didread = 1; if (sock_domain(s) == AF_UNIX) rd = sockread_fds(s, p, len, fs, &nf); else if (m.msg_name && sock_domain(s) == AF_INET) rd = sockrecvfrom(s, p, len, &ip, &port); else rd = sockread(s, p, len); if (rd < 0) { if (got > 0) break; return rd; } got += rd; if (rd < len || sock_is_packet(s)) break; // one message per call } // A receive buffer of no bytes still takes a datagram off the queue (it is // truncated to nothing). udev's workers report in with empty datagrams and // read them this way; skipping the read left the message queued, the // socket readable and the manager looping on it. if (!didread && sock_is_packet(s)) { char z; int rd = sock_domain(s) == AF_UNIX ? sockread_fds(s, &z, 0, fs, &nf) : sockread(s, &z, 0); if (rd < 0) return rd; } if (nf > 0) { int room = 0, installed = 0, j; uint64 writelen; if (m.msg_control && m.msg_controllen >= CMSG_LEN(sizeof(int))) room = (int)((m.msg_controllen - CMSG_LEN(0)) / sizeof(int)); if (room > nf) room = nf; // How much will actually be written. CMSG_SPACE includes the padding // to where a *next* header would start, and there is no next header -- // so when the caller's buffer is not big enough for that padding the // message still fits without it. Writing CMSG_SPACE unconditionally // would overrun a buffer sized with CMSG_LEN, which is legal. writelen = CMSG_SPACE(room * sizeof(int)); if (writelen > m.msg_controllen) writelen = CMSG_LEN(room * sizeof(int)); // Check the control buffer is writable *before* installing anything. // A descriptor that has been put in the table and then reported to a // caller who never learned its number is unclosable. if (room > 0 && !user_ptr((addr_t)m.msg_control, writelen)) room = 0; for (j = 0; j < room; j++) { int d = fdalloc(fs[j]); if (d < 0) break; if (flags & MSG_CMSG_CLOEXEC) myproc()->files->flags[d] |= FD_CLOEXEC; ufd[installed++] = d; } // Whatever did not fit is closed here and nowhere else: the kernel // holds the last reference, and a receiver with no room is still a // delivery. MSG_CTRUNC is how the caller finds out. for (j = installed; j < nf; j++) fileclose(fs[j]); if (installed < nf) mflags |= MSG_CTRUNC; if (installed > 0) { struct cmsghdr *c = (struct cmsghdr *)cbuf; memset(cbuf, 0, sizeof(cbuf)); // pad bytes, not kernel stack c->cmsg_len = CMSG_LEN(installed * sizeof(int)); c->cmsg_level = SOL_SOCKET; c->cmsg_type = SCM_RIGHTS; memmove(CMSG_DATA(c), ufd, installed * sizeof(int)); clen = CMSG_SPACE(installed * sizeof(int)); if (clen > m.msg_controllen) clen = CMSG_LEN(installed * sizeof(int)); if (copy_to_user((addr_t)m.msg_control, cbuf, clen) < 0) return -EFAULT; // ruled out above, but not assumed } } // SO_PASSCRED: who sent it, after any descriptors. On a connected Unix // socket that is always the peer, so its recorded credentials are the // answer. WebKit sets the option on its IPC sockets and aborts if it is // refused. if (sock_passcred(s) && (got > 0 || sock_is_packet(s))) { struct { int pid; uint uid, gid; } cr; uint64 off = clen ? CMSG_SPACE(clen - CMSG_LEN(0)) : 0; if (sock_sendercred(s, &cr.pid, &cr.uid, &cr.gid) == 0) { if (m.msg_control && off + CMSG_LEN(sizeof(cr)) <= m.msg_controllen) { struct cmsghdr c; char tmp[CMSG_SPACE(sizeof(cr))]; memset(tmp, 0, sizeof(tmp)); c.cmsg_len = CMSG_LEN(sizeof(cr)); c.cmsg_level = SOL_SOCKET; c.cmsg_type = 2; // SCM_CREDENTIALS memmove(tmp, &c, sizeof(c)); memmove(CMSG_DATA((struct cmsghdr *)tmp), &cr, sizeof(cr)); uint64 n2 = CMSG_SPACE(sizeof(cr)); if (off + n2 > m.msg_controllen) n2 = CMSG_LEN(sizeof(cr)); if (copy_to_user((addr_t)m.msg_control + off, tmp, n2) < 0) return -EFAULT; clen = off + n2; } else { mflags |= MSG_CTRUNC; } } } // The address, for the family that has one. Same rule as recvfrom: a Unix // socket reports a length of zero rather than a sockaddr full of nothing. if (m.msg_name) { uint32 alen = 0; if (sock_domain(s) == AF_INET) { struct sockaddr_in sa; memset(&sa, 0, sizeof(sa)); sa.sin_family = AF_INET; sa.sin_addr = ip; sa.sin_port = port_to_net(port); alen = (uint32)sizeof(sa); if (alen > m.msg_namelen) alen = m.msg_namelen; if (alen && copy_to_user((addr_t)m.msg_name, &sa, alen) < 0) return -EFAULT; } else if (sock_domain(s) == AF_NETLINK) { // The kernel, as in recvfrom above. uint16 nl[6] = { AF_NETLINK, 0, 0, 0, 0, 0 }; uint g = sock_nl_groups(s), from = sock_nl_from(s); nl[2] = (uint16)from; nl[3] = (uint16)(from >> 16); nl[4] = (uint16)g; nl[5] = (uint16)(g >> 16); alen = (uint32)sizeof(nl); if (alen > m.msg_namelen) alen = m.msg_namelen; if (alen && copy_to_user((addr_t)m.msg_name, nl, alen) < 0) return -EFAULT; alen = (uint32)sizeof(nl); } if (copy_to_user(umsg + __builtin_offsetof(struct msghdr, msg_namelen), &alen, sizeof(alen)) < 0) return -EFAULT; } if (copy_to_user(umsg + __builtin_offsetof(struct msghdr, msg_controllen), &clen, sizeof(clen)) < 0) return -EFAULT; if (copy_to_user(umsg + __builtin_offsetof(struct msghdr, msg_flags), &mflags, sizeof(mflags)) < 0) return -EFAULT; return nlret >= 0 ? nlret : (int)got; }