cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

reuseport_addr_any.c (7243B)


      1// SPDX-License-Identifier: GPL-2.0
      2
      3/* Test that sockets listening on a specific address are preferred
      4 * over sockets listening on addr_any.
      5 */
      6
      7#define _GNU_SOURCE
      8
      9#include <arpa/inet.h>
     10#include <errno.h>
     11#include <error.h>
     12#include <linux/dccp.h>
     13#include <linux/in.h>
     14#include <linux/unistd.h>
     15#include <stdbool.h>
     16#include <stdio.h>
     17#include <stdlib.h>
     18#include <string.h>
     19#include <sys/epoll.h>
     20#include <sys/types.h>
     21#include <sys/socket.h>
     22#include <unistd.h>
     23
     24#ifndef SOL_DCCP
     25#define SOL_DCCP 269
     26#endif
     27
     28static const char *IP4_ADDR = "127.0.0.1";
     29static const char *IP6_ADDR = "::1";
     30static const char *IP4_MAPPED6 = "::ffff:127.0.0.1";
     31
     32static const int PORT = 8888;
     33
     34static void build_rcv_fd(int family, int proto, int *rcv_fds, int count,
     35			 const char *addr_str)
     36{
     37	struct sockaddr_in  addr4 = {0};
     38	struct sockaddr_in6 addr6 = {0};
     39	struct sockaddr *addr;
     40	int opt, i, sz;
     41
     42	memset(&addr, 0, sizeof(addr));
     43
     44	switch (family) {
     45	case AF_INET:
     46		addr4.sin_family = family;
     47		if (!addr_str)
     48			addr4.sin_addr.s_addr = htonl(INADDR_ANY);
     49		else if (!inet_pton(family, addr_str, &addr4.sin_addr.s_addr))
     50			error(1, errno, "inet_pton failed: %s", addr_str);
     51		addr4.sin_port = htons(PORT);
     52		sz = sizeof(addr4);
     53		addr = (struct sockaddr *)&addr4;
     54		break;
     55	case AF_INET6:
     56		addr6.sin6_family = AF_INET6;
     57		if (!addr_str)
     58			addr6.sin6_addr = in6addr_any;
     59		else if (!inet_pton(family, addr_str, &addr6.sin6_addr))
     60			error(1, errno, "inet_pton failed: %s", addr_str);
     61		addr6.sin6_port = htons(PORT);
     62		sz = sizeof(addr6);
     63		addr = (struct sockaddr *)&addr6;
     64		break;
     65	default:
     66		error(1, 0, "Unsupported family %d", family);
     67		/* clang does not recognize error() above as terminating
     68		 * the program, so it complains that saddr, sz are
     69		 * not initialized when this code path is taken. Silence it.
     70		 */
     71		return;
     72	}
     73
     74	for (i = 0; i < count; ++i) {
     75		rcv_fds[i] = socket(family, proto, 0);
     76		if (rcv_fds[i] < 0)
     77			error(1, errno, "failed to create receive socket");
     78
     79		opt = 1;
     80		if (setsockopt(rcv_fds[i], SOL_SOCKET, SO_REUSEPORT, &opt,
     81			       sizeof(opt)))
     82			error(1, errno, "failed to set SO_REUSEPORT");
     83
     84		if (bind(rcv_fds[i], addr, sz))
     85			error(1, errno, "failed to bind receive socket");
     86
     87		if (proto == SOCK_STREAM && listen(rcv_fds[i], 10))
     88			error(1, errno, "tcp: failed to listen on receive port");
     89		else if (proto == SOCK_DCCP) {
     90			if (setsockopt(rcv_fds[i], SOL_DCCP,
     91					DCCP_SOCKOPT_SERVICE,
     92					&(int) {htonl(42)}, sizeof(int)))
     93				error(1, errno, "failed to setsockopt");
     94
     95			if (listen(rcv_fds[i], 10))
     96				error(1, errno, "dccp: failed to listen on receive port");
     97		}
     98	}
     99}
    100
    101static int connect_and_send(int family, int proto)
    102{
    103	struct sockaddr_in  saddr4 = {0};
    104	struct sockaddr_in  daddr4 = {0};
    105	struct sockaddr_in6 saddr6 = {0};
    106	struct sockaddr_in6 daddr6 = {0};
    107	struct sockaddr *saddr, *daddr;
    108	int fd, sz;
    109
    110	switch (family) {
    111	case AF_INET:
    112		saddr4.sin_family = AF_INET;
    113		saddr4.sin_addr.s_addr = htonl(INADDR_ANY);
    114		saddr4.sin_port = 0;
    115
    116		daddr4.sin_family = AF_INET;
    117		if (!inet_pton(family, IP4_ADDR, &daddr4.sin_addr.s_addr))
    118			error(1, errno, "inet_pton failed: %s", IP4_ADDR);
    119		daddr4.sin_port = htons(PORT);
    120
    121		sz = sizeof(saddr4);
    122		saddr = (struct sockaddr *)&saddr4;
    123		daddr = (struct sockaddr *)&daddr4;
    124	break;
    125	case AF_INET6:
    126		saddr6.sin6_family = AF_INET6;
    127		saddr6.sin6_addr = in6addr_any;
    128
    129		daddr6.sin6_family = AF_INET6;
    130		if (!inet_pton(family, IP6_ADDR, &daddr6.sin6_addr))
    131			error(1, errno, "inet_pton failed: %s", IP6_ADDR);
    132		daddr6.sin6_port = htons(PORT);
    133
    134		sz = sizeof(saddr6);
    135		saddr = (struct sockaddr *)&saddr6;
    136		daddr = (struct sockaddr *)&daddr6;
    137	break;
    138	default:
    139		error(1, 0, "Unsupported family %d", family);
    140		/* clang does not recognize error() above as terminating
    141		 * the program, so it complains that saddr, daddr, sz are
    142		 * not initialized when this code path is taken. Silence it.
    143		 */
    144		return -1;
    145	}
    146
    147	fd = socket(family, proto, 0);
    148	if (fd < 0)
    149		error(1, errno, "failed to create send socket");
    150
    151	if (proto == SOCK_DCCP &&
    152		setsockopt(fd, SOL_DCCP, DCCP_SOCKOPT_SERVICE,
    153				&(int){htonl(42)}, sizeof(int)))
    154		error(1, errno, "failed to setsockopt");
    155
    156	if (bind(fd, saddr, sz))
    157		error(1, errno, "failed to bind send socket");
    158
    159	if (connect(fd, daddr, sz))
    160		error(1, errno, "failed to connect send socket");
    161
    162	if (send(fd, "a", 1, 0) < 0)
    163		error(1, errno, "failed to send message");
    164
    165	return fd;
    166}
    167
    168static int receive_once(int epfd, int proto)
    169{
    170	struct epoll_event ev;
    171	int i, fd;
    172	char buf[8];
    173
    174	i = epoll_wait(epfd, &ev, 1, 3);
    175	if (i < 0)
    176		error(1, errno, "epoll_wait failed");
    177
    178	if (proto == SOCK_STREAM || proto == SOCK_DCCP) {
    179		fd = accept(ev.data.fd, NULL, NULL);
    180		if (fd < 0)
    181			error(1, errno, "failed to accept");
    182		i = recv(fd, buf, sizeof(buf), 0);
    183		close(fd);
    184	} else {
    185		i = recv(ev.data.fd, buf, sizeof(buf), 0);
    186	}
    187
    188	if (i < 0)
    189		error(1, errno, "failed to recv");
    190
    191	return ev.data.fd;
    192}
    193
    194static void test(int *rcv_fds, int count, int family, int proto, int fd)
    195{
    196	struct epoll_event ev;
    197	int epfd, i, send_fd, recv_fd;
    198
    199	epfd = epoll_create(1);
    200	if (epfd < 0)
    201		error(1, errno, "failed to create epoll");
    202
    203	ev.events = EPOLLIN;
    204	for (i = 0; i < count; ++i) {
    205		ev.data.fd = rcv_fds[i];
    206		if (epoll_ctl(epfd, EPOLL_CTL_ADD, rcv_fds[i], &ev))
    207			error(1, errno, "failed to register sock epoll");
    208	}
    209
    210	send_fd = connect_and_send(family, proto);
    211
    212	recv_fd = receive_once(epfd, proto);
    213	if (recv_fd != fd)
    214		error(1, 0, "received on an unexpected socket");
    215
    216	close(send_fd);
    217	close(epfd);
    218}
    219
    220
    221static void run_one_test(int fam_send, int fam_rcv, int proto,
    222			 const char *addr_str)
    223{
    224	/* Below we test that a socket listening on a specific address
    225	 * is always selected in preference over a socket listening
    226	 * on addr_any. Bugs where this is not the case often result
    227	 * in sockets created first or last to get picked. So below
    228	 * we make sure that there are always addr_any sockets created
    229	 * before and after a specific socket is created.
    230	 */
    231	int rcv_fds[10], i;
    232
    233	build_rcv_fd(AF_INET, proto, rcv_fds, 2, NULL);
    234	build_rcv_fd(AF_INET6, proto, rcv_fds + 2, 2, NULL);
    235	build_rcv_fd(fam_rcv, proto, rcv_fds + 4, 1, addr_str);
    236	build_rcv_fd(AF_INET, proto, rcv_fds + 5, 2, NULL);
    237	build_rcv_fd(AF_INET6, proto, rcv_fds + 7, 2, NULL);
    238	test(rcv_fds, 9, fam_send, proto, rcv_fds[4]);
    239	for (i = 0; i < 9; ++i)
    240		close(rcv_fds[i]);
    241	fprintf(stderr, "pass\n");
    242}
    243
    244static void test_proto(int proto, const char *proto_str)
    245{
    246	if (proto == SOCK_DCCP) {
    247		int test_fd;
    248
    249		test_fd = socket(AF_INET, proto, 0);
    250		if (test_fd < 0) {
    251			if (errno == ESOCKTNOSUPPORT) {
    252				fprintf(stderr, "DCCP not supported: skipping DCCP tests\n");
    253				return;
    254			} else
    255				error(1, errno, "failed to create a DCCP socket");
    256		}
    257		close(test_fd);
    258	}
    259
    260	fprintf(stderr, "%s IPv4 ... ", proto_str);
    261	run_one_test(AF_INET, AF_INET, proto, IP4_ADDR);
    262
    263	fprintf(stderr, "%s IPv6 ... ", proto_str);
    264	run_one_test(AF_INET6, AF_INET6, proto, IP6_ADDR);
    265
    266	fprintf(stderr, "%s IPv4 mapped to IPv6 ... ", proto_str);
    267	run_one_test(AF_INET, AF_INET6, proto, IP4_MAPPED6);
    268}
    269
    270int main(void)
    271{
    272	test_proto(SOCK_DGRAM, "UDP");
    273	test_proto(SOCK_STREAM, "TCP");
    274	test_proto(SOCK_DCCP, "DCCP");
    275
    276	fprintf(stderr, "SUCCESS\n");
    277	return 0;
    278}