138032Speter/*-
2261370Sgshapiro * SPDX-License-Identifier: BSD-2-Clause
364562Sgshapiro *
438032Speter * Copyright (c) 2022 Alexander V. Chernikov
538032Speter *
638032Speter * Redistribution and use in source and binary forms, with or without
738032Speter * modification, are permitted provided that the following conditions
838032Speter * are met:
938032Speter * 1. Redistributions of source code must retain the above copyright
1038032Speter *    notice, this list of conditions and the following disclaimer.
1138032Speter * 2. Redistributions in binary form must reproduce the above copyright
1238032Speter *    notice, this list of conditions and the following disclaimer in the
1338032Speter *    documentation and/or other materials provided with the distribution.
1464562Sgshapiro *
15168515Sgshapiro * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1638032Speter * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17261370Sgshapiro * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1864562Sgshapiro * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1938032Speter * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2038032Speter * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2164562Sgshapiro * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2238032Speter * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2390792Sgshapiro * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2464562Sgshapiro * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2564562Sgshapiro * SUCH DAMAGE.
2664562Sgshapiro */
2738032Speter
2838032Speter#include <sys/param.h>
2938032Speter#include <sys/errno.h>
3064562Sgshapiro#include <sys/ktrace.h>
3164562Sgshapiro#include <sys/socket.h>
3290792Sgshapiro#include <sys/un.h>
3338032Speter
3490792Sgshapiro#include <netinet/in.h>
3590792Sgshapiro
3690792Sgshapiro#include <fcntl.h>
3738032Speter#include <poll.h>
38157001Sgshapiro#include <stdio.h>
3966494Sgshapiro#include <stdlib.h>
4090792Sgshapiro
4190792Sgshapiro#include <atf-c.h>
4290792Sgshapiro
4390792Sgshapirostatic void
4490792Sgshapirocheck_recvmsg(int cs, int ss, struct sockaddr *sa, const size_t sizes[],
4590792Sgshapiro    size_t nsizes)
4690792Sgshapiro{
4790792Sgshapiro	char buf[9000];
4890792Sgshapiro
4990792Sgshapiro	memset(buf, 0xFF, sizeof(buf));
5090792Sgshapiro	for (size_t i = 0; i < nsizes; i++) {
5190792Sgshapiro		ssize_t rc;
5290792Sgshapiro		size_t sz = sizes[i];
5390792Sgshapiro		char tbuf[1];
5490792Sgshapiro
5590792Sgshapiro		ATF_REQUIRE(sz <= sizeof(buf));
5690792Sgshapiro
5790792Sgshapiro		rc = sendto(cs, buf, sz, 0, sa, sa->sa_len);
5890792Sgshapiro		ATF_REQUIRE_MSG(rc != -1, "sendto failed: %s", strerror(errno));
5938032Speter		ATF_REQUIRE((size_t)rc == sz);
6090792Sgshapiro
6138032Speter		rc = recv(ss, NULL, 0, MSG_PEEK | MSG_TRUNC);
62168515Sgshapiro		ATF_REQUIRE_MSG(rc >= 0, "recv failed: %s", strerror(errno));
63168515Sgshapiro		ATF_REQUIRE((size_t)rc == sz);
6464562Sgshapiro
65141858Sgshapiro		rc = recv(ss, tbuf, sizeof(tbuf), MSG_PEEK | MSG_TRUNC);
6690792Sgshapiro		ATF_REQUIRE_MSG(rc >= 0, "recv failed: %s", strerror(errno));
6790792Sgshapiro		ATF_REQUIRE((size_t)rc == sz);
6890792Sgshapiro
69141858Sgshapiro		rc = recv(ss, tbuf, sizeof(tbuf), MSG_TRUNC);
70141858Sgshapiro		ATF_REQUIRE_MSG(rc >= 0, "recv failed: %s", strerror(errno));
71141858Sgshapiro		ATF_REQUIRE((size_t)rc == sz);
72141858Sgshapiro	}
73141858Sgshapiro
7464562Sgshapiro	ATF_REQUIRE(close(cs) == 0);
7538032Speter	ATF_REQUIRE(close(ss) == 0);
7638032Speter}
7738032Speter
7838032SpeterATF_TC_WITHOUT_HEAD(recv_trunc_afinet_udp);
7938032SpeterATF_TC_BODY(recv_trunc_afinet_udp, tc)
8038032Speter{
8138032Speter	struct sockaddr_in sin;
8238032Speter	struct sockaddr *sa;
8338032Speter	int ss, cs, rc;
8438032Speter
8538032Speter	ss = socket(PF_INET, SOCK_DGRAM, 0);
8638032Speter	ATF_REQUIRE(ss >= 0);
8738032Speter
8838032Speter	memset(&sin, 0, sizeof(sin));
8938032Speter	sin.sin_family = AF_INET;
9038032Speter	sin.sin_len = sizeof(sin);
9138032Speter	sin.sin_port = htons(6666);
9238032Speter	sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
9338032Speter	sa = (struct sockaddr *)&sin;
9438032Speter	rc = bind(ss, sa, sa->sa_len);
9590792Sgshapiro	ATF_REQUIRE_MSG(rc == 0, "bind failed: %s", strerror(errno));
9638032Speter
9790792Sgshapiro	cs = socket(PF_INET, SOCK_DGRAM, 0);
9890792Sgshapiro	ATF_REQUIRE(cs >= 0);
9938032Speter
10038032Speter	size_t sizes[] = {80, 255, 256, 1024, 4096, 9000};
10138032Speter	check_recvmsg(cs, ss, sa, sizes, nitems(sizes));
10264562Sgshapiro}
10390792Sgshapiro
10464562SgshapiroATF_TC_WITHOUT_HEAD(recv_trunc_afinet6_udp);
10590792SgshapiroATF_TC_BODY(recv_trunc_afinet6_udp, tc)
10664562Sgshapiro{
10790792Sgshapiro	struct sockaddr_in6 sin6;
10838032Speter	struct sockaddr *sa;
10938032Speter	int cs, ss, rc;
11038032Speter
11138032Speter	ss = socket(PF_INET6, SOCK_DGRAM, 0);
11238032Speter	ATF_REQUIRE(ss >= 0);
11338032Speter
11464562Sgshapiro	memset(&sin6, 0, sizeof(sin6));
11538032Speter	sin6.sin6_family = AF_INET6;
11638032Speter	sin6.sin6_len = sizeof(sin6);
11738032Speter	sin6.sin6_port = htons(6666);
11838032Speter	const struct in6_addr in6loopback = IN6ADDR_LOOPBACK_INIT;
11938032Speter	sin6.sin6_addr = in6loopback;
12038032Speter	sa = (struct sockaddr *)&sin6;
12138032Speter	rc = bind(ss, sa, sa->sa_len);
12238032Speter	ATF_REQUIRE_MSG(rc == 0, "bind failed: %s", strerror(errno));
12390792Sgshapiro
12490792Sgshapiro	cs = socket(PF_INET6, SOCK_DGRAM, 0);
12538032Speter	ATF_REQUIRE(cs >= 0);
12638032Speter
12764562Sgshapiro	size_t sizes[] = {80, 255, 256, 1024, 4096, 9000};
12838032Speter	check_recvmsg(cs, ss, sa, sizes, nitems(sizes));
12938032Speter}
13038032Speter
13138032SpeterATF_TC_WITHOUT_HEAD(recv_trunc_afunix_dgram);
13264562SgshapiroATF_TC_BODY(recv_trunc_afunix_dgram, tc)
13364562Sgshapiro{
13490792Sgshapiro	struct sockaddr_un sun;
13538032Speter	struct sockaddr *sa;
13690792Sgshapiro	int ss, cs, rc;
13742575Speter
13864562Sgshapiro	ss = socket(PF_UNIX, SOCK_DGRAM, 0);
139168515Sgshapiro	ATF_REQUIRE(ss >= 0);
14094334Sgshapiro
14194334Sgshapiro	bzero(&sun, sizeof(sun));
14294334Sgshapiro	sun.sun_family = AF_UNIX;
14364562Sgshapiro	strlcpy(sun.sun_path, "test_check_recvmsg_socket", sizeof(sun.sun_path));
14442575Speter	sun.sun_len = sizeof(sun);
14564562Sgshapiro	sa = (struct sockaddr *)&sun;
14664562Sgshapiro	rc = bind(ss, sa, sa->sa_len);
14738032Speter	ATF_REQUIRE_MSG(rc == 0, "bind failed: %s", strerror(errno));
14838032Speter
149125820Sgshapiro	cs = socket(PF_UNIX, SOCK_DGRAM, 0);
150125820Sgshapiro	ATF_REQUIRE(cs >= 0);
15190792Sgshapiro
15238032Speter	size_t sizes[] = {80, 255, 256, 1024, 2000};
15364562Sgshapiro	check_recvmsg(cs, ss, sa, sizes, nitems(sizes));
15490792Sgshapiro}
15564562Sgshapiro
15638032Speter/*
15771345Sgshapiro * Exercise the case where ktrace was used to dump a truncated buffer.
15838032Speter */
15938032SpeterATF_TC_WITHOUT_HEAD(recvmsg_trunc_ktrace_uio);
16038032SpeterATF_TC_BODY(recvmsg_trunc_ktrace_uio, tc)
16138032Speter{
16238032Speter	struct ktr_header ktr;
16364562Sgshapiro	struct msghdr msg;
16490792Sgshapiro	struct iovec iov;
16571345Sgshapiro	const char *tracepath;
16690792Sgshapiro	char buf[128];
16790792Sgshapiro	ssize_t nbytes;
16890792Sgshapiro	int error, fd, sd[2];
16971345Sgshapiro
17064562Sgshapiro	tracepath = "ktrace";
17138032Speter
17238032Speter	error = socketpair(AF_UNIX, SOCK_DGRAM, 0, sd);
17390792Sgshapiro	ATF_REQUIRE(error == 0);
17490792Sgshapiro
17538032Speter	memset(buf, 0, sizeof(buf));
17642575Speter	nbytes = send(sd[0], buf, sizeof(buf), 0);
17742575Speter	ATF_REQUIRE_MSG(nbytes >= 0, "send failed: %s", strerror(errno));
17843730Speter	ATF_REQUIRE((size_t)nbytes == sizeof(buf));
17990792Sgshapiro
18042575Speter	fd = open(tracepath, O_RDWR | O_CREAT | O_TRUNC, 0644);
18190792Sgshapiro	ATF_REQUIRE_MSG(fd >= 0, "open failed: %s", strerror(errno));
18290792Sgshapiro	error = ktrace(tracepath, KTROP_SET, KTRFAC_GENIO, getpid());
18338032Speter	ATF_REQUIRE_MSG(error == 0,
18490792Sgshapiro	    "ktrace(SET) failed: %s", strerror(errno));
18564562Sgshapiro
18638032Speter	iov.iov_base = buf;
18790792Sgshapiro	iov.iov_len = sizeof(buf) - 1; /* truncate */
18838032Speter	memset(&msg, 0, sizeof(msg));
18938032Speter	msg.msg_iov = &iov;
19038032Speter	msg.msg_iovlen = 1;
191168515Sgshapiro	nbytes = recvmsg(sd[1], &msg, MSG_TRUNC);
19238032Speter	ATF_REQUIRE_MSG(nbytes >= 0, "recvmsg failed: %s", strerror(errno));
19338032Speter	ATF_REQUIRE((size_t)nbytes == sizeof(buf));
19490792Sgshapiro	ATF_REQUIRE((msg.msg_flags & MSG_TRUNC) != 0);
19538032Speter
19642575Speter	error = ktrace(tracepath, KTROP_CLEARFILE, 0, getpid());
197132943Sgshapiro	ATF_REQUIRE_MSG(error == 0,
19842575Speter	    "ktrace(CLEARFILE) failed: %s", strerror(errno));
19938032Speter
20064562Sgshapiro	nbytes = read(fd, &ktr, sizeof(ktr));
20190792Sgshapiro	ATF_REQUIRE_MSG(nbytes >= 0, "read failed: %s", strerror(errno));
202203004Sgshapiro	ATF_REQUIRE((size_t)nbytes == sizeof(ktr));
20364562Sgshapiro	ATF_REQUIRE((ktr.ktr_type & ~KTR_TYPE) == KTR_GENIO);
20464562Sgshapiro
20564562Sgshapiro	ATF_REQUIRE(close(fd) == 0);
20638032Speter	ATF_REQUIRE(close(sd[0]) == 0);
20738032Speter	ATF_REQUIRE(close(sd[1]) == 0);
20838032Speter}
20938032Speter
21038032SpeterATF_TP_ADD_TCS(tp)
21190792Sgshapiro{
21290792Sgshapiro	ATF_TP_ADD_TC(tp, recv_trunc_afinet_udp);
21364562Sgshapiro	ATF_TP_ADD_TC(tp, recv_trunc_afinet6_udp);
21438032Speter	ATF_TP_ADD_TC(tp, recv_trunc_afunix_dgram);
21590792Sgshapiro	ATF_TP_ADD_TC(tp, recvmsg_trunc_ktrace_uio);
21690792Sgshapiro
21766494Sgshapiro	return (atf_no_error());
21890792Sgshapiro}
21938032Speter