mirror of
https://github.com/freebsd/freebsd-src
synced 2024-07-22 18:56:38 +00:00
152a6d410e
The PF_UNIX/SOCK_SEQPACKET was marked as PR_ATOMIC and that made soreceive_generic() to treat it pretty much as a datagram socket. However, POSIX says: The SOCK_SEQPACKET socket type is similar to the SOCK_STREAM type, and is also connection-oriented. The only difference between these types is that record boundaries are maintained using the SOCK_SEQPACKET type. A record can be sent using one or more output operations and received using one or more input operations, but a single operation never transfers parts of more than one record. Record boundaries are visible to the receiver via the MSG_EOR flag in the received message flags returned by the recvmsg() function. It is protocol-specific whether a maximum record size is imposed. What the test was doing is checking if MSG_TRUNC would report the space required to return up the end of next mbuf record in the socket buffer. Apparently the test assumed that this boundary is defined by the write(2) size on the peer socket. This was true in test conditions, but I'm not sure it would always be true - sbcompress() may merge mbufs. Anyway, the mbuf boundaries are internal socket buffer implementation, they are not SOCK_SEQPACKET records. The records need to be explicitly marked with MSG_EOR by sender, and the test definitely wasn't doing that. Reviewed by: tuexen, markj Differential Revision: https://reviews.freebsd.org/D43707
219 lines
6.4 KiB
C
219 lines
6.4 KiB
C
/*-
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
*
|
|
* Copyright (c) 2022 Alexander V. Chernikov
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
* SUCH DAMAGE.
|
|
*/
|
|
|
|
#include <sys/param.h>
|
|
#include <sys/errno.h>
|
|
#include <sys/ktrace.h>
|
|
#include <sys/socket.h>
|
|
#include <sys/un.h>
|
|
|
|
#include <netinet/in.h>
|
|
|
|
#include <fcntl.h>
|
|
#include <poll.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
|
|
#include <atf-c.h>
|
|
|
|
static void
|
|
check_recvmsg(int cs, int ss, struct sockaddr *sa, const size_t sizes[],
|
|
size_t nsizes)
|
|
{
|
|
char buf[9000];
|
|
|
|
memset(buf, 0xFF, sizeof(buf));
|
|
for (size_t i = 0; i < nsizes; i++) {
|
|
ssize_t rc;
|
|
size_t sz = sizes[i];
|
|
char tbuf[1];
|
|
|
|
ATF_REQUIRE(sz <= sizeof(buf));
|
|
|
|
rc = sendto(cs, buf, sz, 0, sa, sa->sa_len);
|
|
ATF_REQUIRE_MSG(rc != -1, "sendto failed: %s", strerror(errno));
|
|
ATF_REQUIRE((size_t)rc == sz);
|
|
|
|
rc = recv(ss, NULL, 0, MSG_PEEK | MSG_TRUNC);
|
|
ATF_REQUIRE_MSG(rc >= 0, "recv failed: %s", strerror(errno));
|
|
ATF_REQUIRE((size_t)rc == sz);
|
|
|
|
rc = recv(ss, tbuf, sizeof(tbuf), MSG_PEEK | MSG_TRUNC);
|
|
ATF_REQUIRE_MSG(rc >= 0, "recv failed: %s", strerror(errno));
|
|
ATF_REQUIRE((size_t)rc == sz);
|
|
|
|
rc = recv(ss, tbuf, sizeof(tbuf), MSG_TRUNC);
|
|
ATF_REQUIRE_MSG(rc >= 0, "recv failed: %s", strerror(errno));
|
|
ATF_REQUIRE((size_t)rc == sz);
|
|
}
|
|
|
|
ATF_REQUIRE(close(cs) == 0);
|
|
ATF_REQUIRE(close(ss) == 0);
|
|
}
|
|
|
|
ATF_TC_WITHOUT_HEAD(recv_trunc_afinet_udp);
|
|
ATF_TC_BODY(recv_trunc_afinet_udp, tc)
|
|
{
|
|
struct sockaddr_in sin;
|
|
struct sockaddr *sa;
|
|
int ss, cs, rc;
|
|
|
|
ss = socket(PF_INET, SOCK_DGRAM, 0);
|
|
ATF_REQUIRE(ss >= 0);
|
|
|
|
memset(&sin, 0, sizeof(sin));
|
|
sin.sin_family = AF_INET;
|
|
sin.sin_len = sizeof(sin);
|
|
sin.sin_port = htons(6666);
|
|
sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
|
|
sa = (struct sockaddr *)&sin;
|
|
rc = bind(ss, sa, sa->sa_len);
|
|
ATF_REQUIRE_MSG(rc == 0, "bind failed: %s", strerror(errno));
|
|
|
|
cs = socket(PF_INET, SOCK_DGRAM, 0);
|
|
ATF_REQUIRE(cs >= 0);
|
|
|
|
size_t sizes[] = {80, 255, 256, 1024, 4096, 9000};
|
|
check_recvmsg(cs, ss, sa, sizes, nitems(sizes));
|
|
}
|
|
|
|
ATF_TC_WITHOUT_HEAD(recv_trunc_afinet6_udp);
|
|
ATF_TC_BODY(recv_trunc_afinet6_udp, tc)
|
|
{
|
|
struct sockaddr_in6 sin6;
|
|
struct sockaddr *sa;
|
|
int cs, ss, rc;
|
|
|
|
ss = socket(PF_INET6, SOCK_DGRAM, 0);
|
|
ATF_REQUIRE(ss >= 0);
|
|
|
|
memset(&sin6, 0, sizeof(sin6));
|
|
sin6.sin6_family = AF_INET6;
|
|
sin6.sin6_len = sizeof(sin6);
|
|
sin6.sin6_port = htons(6666);
|
|
const struct in6_addr in6loopback = IN6ADDR_LOOPBACK_INIT;
|
|
sin6.sin6_addr = in6loopback;
|
|
sa = (struct sockaddr *)&sin6;
|
|
rc = bind(ss, sa, sa->sa_len);
|
|
ATF_REQUIRE_MSG(rc == 0, "bind failed: %s", strerror(errno));
|
|
|
|
cs = socket(PF_INET6, SOCK_DGRAM, 0);
|
|
ATF_REQUIRE(cs >= 0);
|
|
|
|
size_t sizes[] = {80, 255, 256, 1024, 4096, 9000};
|
|
check_recvmsg(cs, ss, sa, sizes, nitems(sizes));
|
|
}
|
|
|
|
ATF_TC_WITHOUT_HEAD(recv_trunc_afunix_dgram);
|
|
ATF_TC_BODY(recv_trunc_afunix_dgram, tc)
|
|
{
|
|
struct sockaddr_un sun;
|
|
struct sockaddr *sa;
|
|
int ss, cs, rc;
|
|
|
|
ss = socket(PF_UNIX, SOCK_DGRAM, 0);
|
|
ATF_REQUIRE(ss >= 0);
|
|
|
|
bzero(&sun, sizeof(sun));
|
|
sun.sun_family = AF_UNIX;
|
|
strlcpy(sun.sun_path, "test_check_recvmsg_socket", sizeof(sun.sun_path));
|
|
sun.sun_len = sizeof(sun);
|
|
sa = (struct sockaddr *)&sun;
|
|
rc = bind(ss, sa, sa->sa_len);
|
|
ATF_REQUIRE_MSG(rc == 0, "bind failed: %s", strerror(errno));
|
|
|
|
cs = socket(PF_UNIX, SOCK_DGRAM, 0);
|
|
ATF_REQUIRE(cs >= 0);
|
|
|
|
size_t sizes[] = {80, 255, 256, 1024, 2000};
|
|
check_recvmsg(cs, ss, sa, sizes, nitems(sizes));
|
|
}
|
|
|
|
/*
|
|
* Exercise the case where ktrace was used to dump a truncated buffer.
|
|
*/
|
|
ATF_TC_WITHOUT_HEAD(recvmsg_trunc_ktrace_uio);
|
|
ATF_TC_BODY(recvmsg_trunc_ktrace_uio, tc)
|
|
{
|
|
struct ktr_header ktr;
|
|
struct msghdr msg;
|
|
struct iovec iov;
|
|
const char *tracepath;
|
|
char buf[128];
|
|
ssize_t nbytes;
|
|
int error, fd, sd[2];
|
|
|
|
tracepath = "ktrace";
|
|
|
|
error = socketpair(AF_UNIX, SOCK_DGRAM, 0, sd);
|
|
ATF_REQUIRE(error == 0);
|
|
|
|
memset(buf, 0, sizeof(buf));
|
|
nbytes = send(sd[0], buf, sizeof(buf), 0);
|
|
ATF_REQUIRE_MSG(nbytes >= 0, "send failed: %s", strerror(errno));
|
|
ATF_REQUIRE((size_t)nbytes == sizeof(buf));
|
|
|
|
fd = open(tracepath, O_RDWR | O_CREAT | O_TRUNC, 0644);
|
|
ATF_REQUIRE_MSG(fd >= 0, "open failed: %s", strerror(errno));
|
|
error = ktrace(tracepath, KTROP_SET, KTRFAC_GENIO, getpid());
|
|
ATF_REQUIRE_MSG(error == 0,
|
|
"ktrace(SET) failed: %s", strerror(errno));
|
|
|
|
iov.iov_base = buf;
|
|
iov.iov_len = sizeof(buf) - 1; /* truncate */
|
|
memset(&msg, 0, sizeof(msg));
|
|
msg.msg_iov = &iov;
|
|
msg.msg_iovlen = 1;
|
|
nbytes = recvmsg(sd[1], &msg, MSG_TRUNC);
|
|
ATF_REQUIRE_MSG(nbytes >= 0, "recvmsg failed: %s", strerror(errno));
|
|
ATF_REQUIRE((size_t)nbytes == sizeof(buf));
|
|
ATF_REQUIRE((msg.msg_flags & MSG_TRUNC) != 0);
|
|
|
|
error = ktrace(tracepath, KTROP_CLEARFILE, 0, getpid());
|
|
ATF_REQUIRE_MSG(error == 0,
|
|
"ktrace(CLEARFILE) failed: %s", strerror(errno));
|
|
|
|
nbytes = read(fd, &ktr, sizeof(ktr));
|
|
ATF_REQUIRE_MSG(nbytes >= 0, "read failed: %s", strerror(errno));
|
|
ATF_REQUIRE((size_t)nbytes == sizeof(ktr));
|
|
ATF_REQUIRE((ktr.ktr_type & ~KTR_TYPE) == KTR_GENIO);
|
|
|
|
ATF_REQUIRE(close(fd) == 0);
|
|
ATF_REQUIRE(close(sd[0]) == 0);
|
|
ATF_REQUIRE(close(sd[1]) == 0);
|
|
}
|
|
|
|
ATF_TP_ADD_TCS(tp)
|
|
{
|
|
ATF_TP_ADD_TC(tp, recv_trunc_afinet_udp);
|
|
ATF_TP_ADD_TC(tp, recv_trunc_afinet6_udp);
|
|
ATF_TP_ADD_TC(tp, recv_trunc_afunix_dgram);
|
|
ATF_TP_ADD_TC(tp, recvmsg_trunc_ktrace_uio);
|
|
|
|
return (atf_no_error());
|
|
}
|