brintos

brintos / linux-shallow public Read only

0
0
Text · 14.9 KiB · 3ed3882 Raw
758 lines · c
1// SPDX-License-Identifier: GPL-2.02/* Copyright Amazon.com Inc. or its affiliates. */3 4#include <fcntl.h>5#include <string.h>6#include <unistd.h>7 8#include <netinet/in.h>9#include <sys/epoll.h>10#include <sys/ioctl.h>11#include <sys/signalfd.h>12#include <sys/socket.h>13 14#include "../../kselftest_harness.h"15 16#define BUF_SZ	3217 18FIXTURE(msg_oob)19{20	int fd[4];		/* 0: AF_UNIX sender21				 * 1: AF_UNIX receiver22				 * 2: TCP sender23				 * 3: TCP receiver24				 */25	int signal_fd;26	int epoll_fd[2];	/* 0: AF_UNIX receiver27				 * 1: TCP receiver28				 */29	bool tcp_compliant;30};31 32FIXTURE_VARIANT(msg_oob)33{34	bool peek;35};36 37FIXTURE_VARIANT_ADD(msg_oob, no_peek)38{39	.peek = false,40};41 42FIXTURE_VARIANT_ADD(msg_oob, peek)43{44	.peek = true45};46 47static void create_unix_socketpair(struct __test_metadata *_metadata,48				   FIXTURE_DATA(msg_oob) *self)49{50	int ret;51 52	ret = socketpair(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, 0, self->fd);53	ASSERT_EQ(ret, 0);54}55 56static void create_tcp_socketpair(struct __test_metadata *_metadata,57				  FIXTURE_DATA(msg_oob) *self)58{59	struct sockaddr_in addr;60	socklen_t addrlen;61	int listen_fd;62	int ret;63 64	listen_fd = socket(AF_INET, SOCK_STREAM, 0);65	ASSERT_GE(listen_fd, 0);66 67	ret = listen(listen_fd, -1);68	ASSERT_EQ(ret, 0);69 70	addrlen = sizeof(addr);71	ret = getsockname(listen_fd, (struct sockaddr *)&addr, &addrlen);72	ASSERT_EQ(ret, 0);73 74	self->fd[2] = socket(AF_INET, SOCK_STREAM, 0);75	ASSERT_GE(self->fd[2], 0);76 77	ret = connect(self->fd[2], (struct sockaddr *)&addr, addrlen);78	ASSERT_EQ(ret, 0);79 80	self->fd[3] = accept(listen_fd, (struct sockaddr *)&addr, &addrlen);81	ASSERT_GE(self->fd[3], 0);82 83	ret = fcntl(self->fd[3], F_SETFL, O_NONBLOCK);84	ASSERT_EQ(ret, 0);85}86 87static void setup_sigurg(struct __test_metadata *_metadata,88			 FIXTURE_DATA(msg_oob) *self)89{90	struct signalfd_siginfo siginfo;91	int pid = getpid();92	sigset_t mask;93	int i, ret;94 95	for (i = 0; i < 2; i++) {96		ret = ioctl(self->fd[i * 2 + 1], FIOSETOWN, &pid);97		ASSERT_EQ(ret, 0);98	}99 100	ret = sigemptyset(&mask);101	ASSERT_EQ(ret, 0);102 103	ret = sigaddset(&mask, SIGURG);104	ASSERT_EQ(ret, 0);105 106	ret = sigprocmask(SIG_BLOCK, &mask, NULL);107	ASSERT_EQ(ret, 0);108 109	self->signal_fd = signalfd(-1, &mask, SFD_NONBLOCK);110	ASSERT_GE(self->signal_fd, 0);111 112	ret = read(self->signal_fd, &siginfo, sizeof(siginfo));113	ASSERT_EQ(ret, -1);114}115 116static void setup_epollpri(struct __test_metadata *_metadata,117			   FIXTURE_DATA(msg_oob) *self)118{119	struct epoll_event event = {120		.events = EPOLLPRI,121	};122	int i;123 124	for (i = 0; i < 2; i++) {125		int ret;126 127		self->epoll_fd[i] = epoll_create1(0);128		ASSERT_GE(self->epoll_fd[i], 0);129 130		ret = epoll_ctl(self->epoll_fd[i], EPOLL_CTL_ADD, self->fd[i * 2 + 1], &event);131		ASSERT_EQ(ret, 0);132	}133}134 135static void close_sockets(FIXTURE_DATA(msg_oob) *self)136{137	int i;138 139	for (i = 0; i < 4; i++)140		close(self->fd[i]);141}142 143FIXTURE_SETUP(msg_oob)144{145	create_unix_socketpair(_metadata, self);146	create_tcp_socketpair(_metadata, self);147 148	setup_sigurg(_metadata, self);149	setup_epollpri(_metadata, self);150 151	self->tcp_compliant = true;152}153 154FIXTURE_TEARDOWN(msg_oob)155{156	close_sockets(self);157}158 159static void __epollpair(struct __test_metadata *_metadata,160			FIXTURE_DATA(msg_oob) *self,161			bool oob_remaining)162{163	struct epoll_event event[2] = {};164	int i, ret[2];165 166	for (i = 0; i < 2; i++)167		ret[i] = epoll_wait(self->epoll_fd[i], &event[i], 1, 0);168 169	ASSERT_EQ(ret[0], oob_remaining);170 171	if (self->tcp_compliant)172		ASSERT_EQ(ret[0], ret[1]);173 174	if (oob_remaining) {175		ASSERT_EQ(event[0].events, EPOLLPRI);176 177		if (self->tcp_compliant)178			ASSERT_EQ(event[0].events, event[1].events);179	}180}181 182static void __sendpair(struct __test_metadata *_metadata,183		       FIXTURE_DATA(msg_oob) *self,184		       const void *buf, size_t len, int flags)185{186	int i, ret[2];187 188	for (i = 0; i < 2; i++) {189		struct signalfd_siginfo siginfo = {};190		int bytes;191 192		ret[i] = send(self->fd[i * 2], buf, len, flags);193 194		bytes = read(self->signal_fd, &siginfo, sizeof(siginfo));195 196		if (flags & MSG_OOB) {197			ASSERT_EQ(bytes, sizeof(siginfo));198			ASSERT_EQ(siginfo.ssi_signo, SIGURG);199 200			bytes = read(self->signal_fd, &siginfo, sizeof(siginfo));201		}202 203		ASSERT_EQ(bytes, -1);204	}205 206	ASSERT_EQ(ret[0], len);207	ASSERT_EQ(ret[0], ret[1]);208}209 210static void __recvpair(struct __test_metadata *_metadata,211		       FIXTURE_DATA(msg_oob) *self,212		       const char *expected_buf, int expected_len,213		       int buf_len, int flags)214{215	int i, ret[2], recv_errno[2], expected_errno = 0;216	char recv_buf[2][BUF_SZ] = {};217	bool printed = false;218 219	ASSERT_GE(BUF_SZ, buf_len);220 221	errno = 0;222 223	for (i = 0; i < 2; i++) {224		ret[i] = recv(self->fd[i * 2 + 1], recv_buf[i], buf_len, flags);225		recv_errno[i] = errno;226	}227 228	if (expected_len < 0) {229		expected_errno = -expected_len;230		expected_len = -1;231	}232 233	if (ret[0] != expected_len || recv_errno[0] != expected_errno) {234		TH_LOG("AF_UNIX :%s", ret[0] < 0 ? strerror(recv_errno[0]) : recv_buf[0]);235		TH_LOG("Expected:%s", expected_errno ? strerror(expected_errno) : expected_buf);236 237		ASSERT_EQ(ret[0], expected_len);238		ASSERT_EQ(recv_errno[0], expected_errno);239	}240 241	if (ret[0] != ret[1] || recv_errno[0] != recv_errno[1]) {242		TH_LOG("AF_UNIX :%s", ret[0] < 0 ? strerror(recv_errno[0]) : recv_buf[0]);243		TH_LOG("TCP     :%s", ret[1] < 0 ? strerror(recv_errno[1]) : recv_buf[1]);244 245		printed = true;246 247		if (self->tcp_compliant) {248			ASSERT_EQ(ret[0], ret[1]);249			ASSERT_EQ(recv_errno[0], recv_errno[1]);250		}251	}252 253	if (expected_len >= 0) {254		int cmp;255 256		cmp = strncmp(expected_buf, recv_buf[0], expected_len);257		if (cmp) {258			TH_LOG("AF_UNIX :%s", ret[0] < 0 ? strerror(recv_errno[0]) : recv_buf[0]);259			TH_LOG("Expected:%s", expected_errno ? strerror(expected_errno) : expected_buf);260 261			ASSERT_EQ(cmp, 0);262		}263 264		cmp = strncmp(recv_buf[0], recv_buf[1], expected_len);265		if (cmp) {266			if (!printed) {267				TH_LOG("AF_UNIX :%s", ret[0] < 0 ? strerror(recv_errno[0]) : recv_buf[0]);268				TH_LOG("TCP     :%s", ret[1] < 0 ? strerror(recv_errno[1]) : recv_buf[1]);269			}270 271			if (self->tcp_compliant)272				ASSERT_EQ(cmp, 0);273		}274	}275}276 277static void __setinlinepair(struct __test_metadata *_metadata,278			    FIXTURE_DATA(msg_oob) *self)279{280	int i, oob_inline = 1;281 282	for (i = 0; i < 2; i++) {283		int ret;284 285		ret = setsockopt(self->fd[i * 2 + 1], SOL_SOCKET, SO_OOBINLINE,286				 &oob_inline, sizeof(oob_inline));287		ASSERT_EQ(ret, 0);288	}289}290 291static void __siocatmarkpair(struct __test_metadata *_metadata,292			     FIXTURE_DATA(msg_oob) *self,293			     bool oob_head)294{295	int answ[2] = {};296	int i;297 298	for (i = 0; i < 2; i++) {299		int ret;300 301		ret = ioctl(self->fd[i * 2 + 1], SIOCATMARK, &answ[i]);302		ASSERT_EQ(ret, 0);303	}304 305	ASSERT_EQ(answ[0], oob_head);306 307	if (self->tcp_compliant)308		ASSERT_EQ(answ[0], answ[1]);309}310 311#define sendpair(buf, len, flags)					\312	__sendpair(_metadata, self, buf, len, flags)313 314#define recvpair(expected_buf, expected_len, buf_len, flags)		\315	do {								\316		if (variant->peek)					\317			__recvpair(_metadata, self,			\318				   expected_buf, expected_len,		\319				   buf_len, (flags) | MSG_PEEK);	\320		__recvpair(_metadata, self,				\321			   expected_buf, expected_len, buf_len, flags);	\322	} while (0)323 324#define epollpair(oob_remaining)					\325	__epollpair(_metadata, self, oob_remaining)326 327#define siocatmarkpair(oob_head)					\328	__siocatmarkpair(_metadata, self, oob_head)329 330#define setinlinepair()							\331	__setinlinepair(_metadata, self)332 333#define tcp_incompliant							\334	for (self->tcp_compliant = false;				\335	     self->tcp_compliant == false;				\336	     self->tcp_compliant = true)337 338TEST_F(msg_oob, non_oob)339{340	sendpair("x", 1, 0);341	epollpair(false);342	siocatmarkpair(false);343 344	recvpair("", -EINVAL, 1, MSG_OOB);345	epollpair(false);346	siocatmarkpair(false);347}348 349TEST_F(msg_oob, oob)350{351	sendpair("x", 1, MSG_OOB);352	epollpair(true);353	siocatmarkpair(true);354 355	recvpair("x", 1, 1, MSG_OOB);356	epollpair(false);357	siocatmarkpair(true);358}359 360TEST_F(msg_oob, oob_drop)361{362	sendpair("x", 1, MSG_OOB);363	epollpair(true);364	siocatmarkpair(true);365 366	recvpair("", -EAGAIN, 1, 0);		/* Drop OOB. */367	epollpair(false);368	siocatmarkpair(false);369 370	recvpair("", -EINVAL, 1, MSG_OOB);371	epollpair(false);372	siocatmarkpair(false);373}374 375TEST_F(msg_oob, oob_ahead)376{377	sendpair("hello", 5, MSG_OOB);378	epollpair(true);379	siocatmarkpair(false);380 381	recvpair("o", 1, 1, MSG_OOB);382	epollpair(false);383	siocatmarkpair(false);384 385	recvpair("hell", 4, 4, 0);386	epollpair(false);387	siocatmarkpair(true);388}389 390TEST_F(msg_oob, oob_break)391{392	sendpair("hello", 5, MSG_OOB);393	epollpair(true);394	siocatmarkpair(false);395 396	recvpair("hell", 4, 5, 0);		/* Break at OOB even with enough buffer. */397	epollpair(true);398	siocatmarkpair(true);399 400	recvpair("o", 1, 1, MSG_OOB);401	epollpair(false);402	siocatmarkpair(true);403 404	recvpair("", -EAGAIN, 1, 0);405	siocatmarkpair(false);406}407 408TEST_F(msg_oob, oob_ahead_break)409{410	sendpair("hello", 5, MSG_OOB);411	epollpair(true);412	siocatmarkpair(false);413 414	sendpair("world", 5, 0);415	epollpair(true);416	siocatmarkpair(false);417 418	recvpair("o", 1, 1, MSG_OOB);419	epollpair(false);420	siocatmarkpair(false);421 422	recvpair("hell", 4, 9, 0);		/* Break at OOB even after it's recv()ed. */423	epollpair(false);424	siocatmarkpair(true);425 426	recvpair("world", 5, 5, 0);427	epollpair(false);428	siocatmarkpair(false);429}430 431TEST_F(msg_oob, oob_break_drop)432{433	sendpair("hello", 5, MSG_OOB);434	epollpair(true);435	siocatmarkpair(false);436 437	sendpair("world", 5, 0);438	epollpair(true);439	siocatmarkpair(false);440 441	recvpair("hell", 4, 10, 0);		/* Break at OOB even with enough buffer. */442	epollpair(true);443	siocatmarkpair(true);444 445	recvpair("world", 5, 10, 0);		/* Drop OOB and recv() the next skb. */446	epollpair(false);447	siocatmarkpair(false);448 449	recvpair("", -EINVAL, 1, MSG_OOB);450	epollpair(false);451	siocatmarkpair(false);452}453 454TEST_F(msg_oob, ex_oob_break)455{456	sendpair("hello", 5, MSG_OOB);457	epollpair(true);458	siocatmarkpair(false);459 460	sendpair("wor", 3, MSG_OOB);461	epollpair(true);462	siocatmarkpair(false);463 464	sendpair("ld", 2, 0);465	epollpair(true);466	siocatmarkpair(false);467 468	recvpair("hellowo", 7, 10, 0);		/* Break at OOB but not at ex-OOB. */469	epollpair(true);470	siocatmarkpair(true);471 472	recvpair("r", 1, 1, MSG_OOB);473	epollpair(false);474	siocatmarkpair(true);475 476	recvpair("ld", 2, 2, 0);477	epollpair(false);478	siocatmarkpair(false);479}480 481TEST_F(msg_oob, ex_oob_drop)482{483	sendpair("x", 1, MSG_OOB);484	epollpair(true);485	siocatmarkpair(true);486 487	sendpair("y", 1, MSG_OOB);		/* TCP drops "x" at this moment. */488	epollpair(true);489 490	tcp_incompliant {491		siocatmarkpair(false);492 493		recvpair("x", 1, 1, 0);		/* TCP drops "y" by passing through it. */494		epollpair(true);495		siocatmarkpair(true);496 497		recvpair("y", 1, 1, MSG_OOB);	/* TCP returns -EINVAL. */498		epollpair(false);499		siocatmarkpair(true);500	}501}502 503TEST_F(msg_oob, ex_oob_drop_2)504{505	sendpair("x", 1, MSG_OOB);506	epollpair(true);507	siocatmarkpair(true);508 509	sendpair("y", 1, MSG_OOB);		/* TCP drops "x" at this moment. */510	epollpair(true);511 512	tcp_incompliant {513		siocatmarkpair(false);514	}515 516	recvpair("y", 1, 1, MSG_OOB);517	epollpair(false);518 519	tcp_incompliant {520		siocatmarkpair(false);521 522		recvpair("x", 1, 1, 0);		/* TCP returns -EAGAIN. */523		epollpair(false);524		siocatmarkpair(true);525	}526}527 528TEST_F(msg_oob, ex_oob_oob)529{530	sendpair("x", 1, MSG_OOB);531	epollpair(true);532	siocatmarkpair(true);533 534	recvpair("x", 1, 1, MSG_OOB);535	epollpair(false);536	siocatmarkpair(true);537 538	sendpair("y", 1, MSG_OOB);539	epollpair(true);540	siocatmarkpair(true);541 542	recvpair("", -EAGAIN, 1, 0);543	epollpair(false);544	siocatmarkpair(false);545 546	recvpair("", -EINVAL, 1, MSG_OOB);547	epollpair(false);548	siocatmarkpair(false);549}550 551TEST_F(msg_oob, ex_oob_ahead_break)552{553	sendpair("hello", 5, MSG_OOB);554	epollpair(true);555	siocatmarkpair(false);556 557	sendpair("wor", 3, MSG_OOB);558	epollpair(true);559	siocatmarkpair(false);560 561	recvpair("r", 1, 1, MSG_OOB);562	epollpair(false);563	siocatmarkpair(false);564 565	sendpair("ld", 2, MSG_OOB);566	epollpair(true);567	siocatmarkpair(false);568 569	tcp_incompliant {570		recvpair("hellowol", 8, 10, 0);	/* TCP recv()s "helloworl", why "r" ?? */571	}572 573	epollpair(true);574	siocatmarkpair(true);575 576	recvpair("d", 1, 1, MSG_OOB);577	epollpair(false);578	siocatmarkpair(true);579}580 581TEST_F(msg_oob, ex_oob_siocatmark)582{583	sendpair("hello", 5, MSG_OOB);584	epollpair(true);585	siocatmarkpair(false);586 587	recvpair("o", 1, 1, MSG_OOB);588	epollpair(false);589	siocatmarkpair(false);590 591	sendpair("world", 5, MSG_OOB);592	epollpair(true);593	siocatmarkpair(false);594 595	recvpair("hell", 4, 4, 0);		/* Intentionally stop at ex-OOB. */596	epollpair(true);597	siocatmarkpair(false);598}599 600TEST_F(msg_oob, inline_oob)601{602	setinlinepair();603 604	sendpair("x", 1, MSG_OOB);605	epollpair(true);606	siocatmarkpair(true);607 608	recvpair("", -EINVAL, 1, MSG_OOB);609	epollpair(true);610	siocatmarkpair(true);611 612	recvpair("x", 1, 1, 0);613	epollpair(false);614	siocatmarkpair(false);615}616 617TEST_F(msg_oob, inline_oob_break)618{619	setinlinepair();620 621	sendpair("hello", 5, MSG_OOB);622	epollpair(true);623	siocatmarkpair(false);624 625	recvpair("", -EINVAL, 1, MSG_OOB);626	epollpair(true);627	siocatmarkpair(false);628 629	recvpair("hell", 4, 5, 0);		/* Break at OOB but not at ex-OOB. */630	epollpair(true);631	siocatmarkpair(true);632 633	recvpair("o", 1, 1, 0);634	epollpair(false);635	siocatmarkpair(false);636}637 638TEST_F(msg_oob, inline_oob_ahead_break)639{640	sendpair("hello", 5, MSG_OOB);641	epollpair(true);642	siocatmarkpair(false);643 644	sendpair("world", 5, 0);645	epollpair(true);646	siocatmarkpair(false);647 648	recvpair("o", 1, 1, MSG_OOB);649	epollpair(false);650	siocatmarkpair(false);651 652	setinlinepair();653 654	recvpair("hell", 4, 9, 0);		/* Break at OOB even with enough buffer. */655	epollpair(false);656	siocatmarkpair(true);657 658	tcp_incompliant {659		recvpair("world", 5, 6, 0);	/* TCP recv()s "oworld", ... "o" ??? */660	}661 662	epollpair(false);663	siocatmarkpair(false);664}665 666TEST_F(msg_oob, inline_ex_oob_break)667{668	sendpair("hello", 5, MSG_OOB);669	epollpair(true);670	siocatmarkpair(false);671 672	sendpair("wor", 3, MSG_OOB);673	epollpair(true);674	siocatmarkpair(false);675 676	sendpair("ld", 2, 0);677	epollpair(true);678	siocatmarkpair(false);679 680	setinlinepair();681 682	recvpair("hellowo", 7, 10, 0);		/* Break at OOB but not at ex-OOB. */683	epollpair(true);684	siocatmarkpair(true);685 686	recvpair("rld", 3, 3, 0);687	epollpair(false);688	siocatmarkpair(false);689}690 691TEST_F(msg_oob, inline_ex_oob_no_drop)692{693	sendpair("x", 1, MSG_OOB);694	epollpair(true);695	siocatmarkpair(true);696 697	setinlinepair();698 699	sendpair("y", 1, MSG_OOB);		/* TCP does NOT drops "x" at this moment. */700	epollpair(true);701	siocatmarkpair(false);702 703	recvpair("x", 1, 1, 0);704	epollpair(true);705	siocatmarkpair(true);706 707	recvpair("y", 1, 1, 0);708	epollpair(false);709	siocatmarkpair(false);710}711 712TEST_F(msg_oob, inline_ex_oob_drop)713{714	sendpair("x", 1, MSG_OOB);715	epollpair(true);716	siocatmarkpair(true);717 718	sendpair("y", 1, MSG_OOB);		/* TCP drops "x" at this moment. */719	epollpair(true);720 721	setinlinepair();722 723	tcp_incompliant {724		siocatmarkpair(false);725 726		recvpair("x", 1, 1, 0);		/* TCP recv()s "y". */727		epollpair(true);728		siocatmarkpair(true);729 730		recvpair("y", 1, 1, 0);		/* TCP returns -EAGAIN. */731		epollpair(false);732		siocatmarkpair(false);733	}734}735 736TEST_F(msg_oob, inline_ex_oob_siocatmark)737{738	sendpair("hello", 5, MSG_OOB);739	epollpair(true);740	siocatmarkpair(false);741 742	recvpair("o", 1, 1, MSG_OOB);743	epollpair(false);744	siocatmarkpair(false);745 746	setinlinepair();747 748	sendpair("world", 5, MSG_OOB);749	epollpair(true);750	siocatmarkpair(false);751 752	recvpair("hell", 4, 4, 0);		/* Intentionally stop at ex-OOB. */753	epollpair(true);754	siocatmarkpair(false);755}756 757TEST_HARNESS_MAIN758