From 48a55bbfe95bc7b32d37673839edc2f365ffc028 Mon Sep 17 00:00:00 2001 From: Gleb Smirnoff Date: Wed, 29 Jun 2022 09:42:58 -0700 Subject: [PATCH] unix: change error code for recvmsg() failed due to RLIMIT_NOFILE Instead of returning EMSGSIZE pass the error code from fdallocn() directly to userland. That would be EMFILE, which makes much more sense. This error code is not listed in the specification[1], but the specification doesn't cover such edge case at all. Meanwhile the specification lists EMSGSIZE as the error code for invalid value of msg_iovlen, and FreeBSD follows that, see sys_recmsg(). Differentiating these two cases will make a developer/admin life much easier when debugging. [1] https://pubs.opengroup.org/onlinepubs/9699919799/functions/recvmsg.html Reviewed by: markj Differential revision: https://reviews.freebsd.org/D35640 --- lib/libc/sys/recv.2 | 19 +++++++++++++++---- sys/kern/uipc_usrreq.c | 3 +-- tests/sys/kern/unix_passfd_test.c | 4 ++-- 3 files changed, 18 insertions(+), 8 deletions(-) diff --git a/lib/libc/sys/recv.2 b/lib/libc/sys/recv.2 index 46e0cf8163d..1f3bf531c3e 100644 --- a/lib/libc/sys/recv.2 +++ b/lib/libc/sys/recv.2 @@ -28,7 +28,7 @@ .\" @(#)recv.2 8.3 (Berkeley) 2/21/94 .\" $FreeBSD$ .\" -.Dd August 19, 2018 +.Dd June 29, 2022 .Dt RECV 2 .Os .Sh NAME @@ -332,7 +332,7 @@ and The argument .Fa s does not refer to a socket. -.It Bq Er EMSGSIZE +.It Bq Er EMFILE The .Fn recvmsg system call @@ -340,9 +340,20 @@ was used to receive rights (file descriptors) that were in flight on the connection. However, the receiving program did not have enough free file descriptor slots to accept them. -In this case the descriptors are -closed, any pending data can be returned by another call to +In this case the descriptors are closed, with pending data either discarded +in the case of the unreliable datagram protocol or preserved in the case of a +reliable protocol. +The pending data can be retrieved with another call to .Fn recvmsg . +.It Bq Er EMSGSIZE +The +.Fa msg_iovlen +member of the +.Fa msghdr +structure pointed to by +.Fa msg +is less than or equal to 0, or is greater than +.Va IOV_MAX . .It Bq Er EAGAIN The socket is marked non-blocking and the receive operation would block, or diff --git a/sys/kern/uipc_usrreq.c b/sys/kern/uipc_usrreq.c index 2eb9db632a1..b0661c0d0da 100644 --- a/sys/kern/uipc_usrreq.c +++ b/sys/kern/uipc_usrreq.c @@ -2547,9 +2547,8 @@ unp_externalize(struct mbuf *control, struct mbuf **controlp, int flags) fdp = (int *) CMSG_DATA(mtod(*controlp, struct cmsghdr *)); - if (fdallocn(td, 0, fdp, newfds) != 0) { + if ((error = fdallocn(td, 0, fdp, newfds))) { FILEDESC_XUNLOCK(fdesc); - error = EMSGSIZE; unp_freerights(fdep, newfds); m_freem(*controlp); *controlp = NULL; diff --git a/tests/sys/kern/unix_passfd_test.c b/tests/sys/kern/unix_passfd_test.c index bbd298f9a26..dc017db4f1c 100644 --- a/tests/sys/kern/unix_passfd_test.c +++ b/tests/sys/kern/unix_passfd_test.c @@ -428,8 +428,8 @@ ATF_TC_BODY(send_a_lot, tc) msghdr.msg_controllen = CMSG_LEN(sizeof(int)); ATF_REQUIRE(sendmsg(fd[0], &msghdr, 0) == 1); ATF_REQUIRE(recvmsg(fd[1], &msghdr, 0) == -1); - /* Such attempt shall fail with EMSGSIZE. */ - ATF_REQUIRE(errno == EMSGSIZE); + /* Such attempt shall fail with EMFILE. */ + ATF_REQUIRE(errno == EMFILE); ATF_REQUIRE(getnfds() == nfds); #if TEST_PROTO == SOCK_STREAM /*