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

test_tcp_check_syncookie_user.c (6299B)


      1// SPDX-License-Identifier: GPL-2.0
      2// Copyright (c) 2018 Facebook
      3// Copyright (c) 2019 Cloudflare
      4
      5#include <limits.h>
      6#include <string.h>
      7#include <stdlib.h>
      8#include <unistd.h>
      9
     10#include <arpa/inet.h>
     11#include <netinet/in.h>
     12#include <sys/types.h>
     13#include <sys/socket.h>
     14
     15#include <bpf/bpf.h>
     16#include <bpf/libbpf.h>
     17
     18#include "cgroup_helpers.h"
     19
     20static int start_server(const struct sockaddr *addr, socklen_t len, bool dual)
     21{
     22	int mode = !dual;
     23	int fd;
     24
     25	fd = socket(addr->sa_family, SOCK_STREAM, 0);
     26	if (fd == -1) {
     27		log_err("Failed to create server socket");
     28		goto out;
     29	}
     30
     31	if (addr->sa_family == AF_INET6) {
     32		if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&mode,
     33			       sizeof(mode)) == -1) {
     34			log_err("Failed to set the dual-stack mode");
     35			goto close_out;
     36		}
     37	}
     38
     39	if (bind(fd, addr, len) == -1) {
     40		log_err("Failed to bind server socket");
     41		goto close_out;
     42	}
     43
     44	if (listen(fd, 128) == -1) {
     45		log_err("Failed to listen on server socket");
     46		goto close_out;
     47	}
     48
     49	goto out;
     50
     51close_out:
     52	close(fd);
     53	fd = -1;
     54out:
     55	return fd;
     56}
     57
     58static int connect_to_server(const struct sockaddr *addr, socklen_t len)
     59{
     60	int fd = -1;
     61
     62	fd = socket(addr->sa_family, SOCK_STREAM, 0);
     63	if (fd == -1) {
     64		log_err("Failed to create client socket");
     65		goto out;
     66	}
     67
     68	if (connect(fd, (const struct sockaddr *)addr, len) == -1) {
     69		log_err("Fail to connect to server");
     70		goto close_out;
     71	}
     72
     73	goto out;
     74
     75close_out:
     76	close(fd);
     77	fd = -1;
     78out:
     79	return fd;
     80}
     81
     82static int get_map_fd_by_prog_id(int prog_id, bool *xdp)
     83{
     84	struct bpf_prog_info info = {};
     85	__u32 info_len = sizeof(info);
     86	__u32 map_ids[1];
     87	int prog_fd = -1;
     88	int map_fd = -1;
     89
     90	prog_fd = bpf_prog_get_fd_by_id(prog_id);
     91	if (prog_fd < 0) {
     92		log_err("Failed to get fd by prog id %d", prog_id);
     93		goto err;
     94	}
     95
     96	info.nr_map_ids = 1;
     97	info.map_ids = (__u64)(unsigned long)map_ids;
     98
     99	if (bpf_obj_get_info_by_fd(prog_fd, &info, &info_len)) {
    100		log_err("Failed to get info by prog fd %d", prog_fd);
    101		goto err;
    102	}
    103
    104	if (!info.nr_map_ids) {
    105		log_err("No maps found for prog fd %d", prog_fd);
    106		goto err;
    107	}
    108
    109	*xdp = info.type == BPF_PROG_TYPE_XDP;
    110
    111	map_fd = bpf_map_get_fd_by_id(map_ids[0]);
    112	if (map_fd < 0)
    113		log_err("Failed to get fd by map id %d", map_ids[0]);
    114err:
    115	if (prog_fd >= 0)
    116		close(prog_fd);
    117	return map_fd;
    118}
    119
    120static int run_test(int server_fd, int results_fd, bool xdp,
    121		    const struct sockaddr *addr, socklen_t len)
    122{
    123	int client = -1, srv_client = -1;
    124	int ret = 0;
    125	__u32 key = 0;
    126	__u32 key_gen = 1;
    127	__u32 key_mss = 2;
    128	__u32 value = 0;
    129	__u32 value_gen = 0;
    130	__u32 value_mss = 0;
    131
    132	if (bpf_map_update_elem(results_fd, &key, &value, 0) < 0) {
    133		log_err("Can't clear results");
    134		goto err;
    135	}
    136
    137	if (bpf_map_update_elem(results_fd, &key_gen, &value_gen, 0) < 0) {
    138		log_err("Can't clear results");
    139		goto err;
    140	}
    141
    142	if (bpf_map_update_elem(results_fd, &key_mss, &value_mss, 0) < 0) {
    143		log_err("Can't clear results");
    144		goto err;
    145	}
    146
    147	client = connect_to_server(addr, len);
    148	if (client == -1)
    149		goto err;
    150
    151	srv_client = accept(server_fd, NULL, 0);
    152	if (srv_client == -1) {
    153		log_err("Can't accept connection");
    154		goto err;
    155	}
    156
    157	if (bpf_map_lookup_elem(results_fd, &key, &value) < 0) {
    158		log_err("Can't lookup result");
    159		goto err;
    160	}
    161
    162	if (value == 0) {
    163		log_err("Didn't match syncookie: %u", value);
    164		goto err;
    165	}
    166
    167	if (bpf_map_lookup_elem(results_fd, &key_gen, &value_gen) < 0) {
    168		log_err("Can't lookup result");
    169		goto err;
    170	}
    171
    172	if (xdp && value_gen == 0) {
    173		// SYN packets do not get passed through generic XDP, skip the
    174		// rest of the test.
    175		printf("Skipping XDP cookie check\n");
    176		goto out;
    177	}
    178
    179	if (bpf_map_lookup_elem(results_fd, &key_mss, &value_mss) < 0) {
    180		log_err("Can't lookup result");
    181		goto err;
    182	}
    183
    184	if (value != value_gen) {
    185		log_err("BPF generated cookie does not match kernel one");
    186		goto err;
    187	}
    188
    189	if (value_mss < 536 || value_mss > USHRT_MAX) {
    190		log_err("Unexpected MSS retrieved");
    191		goto err;
    192	}
    193
    194	goto out;
    195
    196err:
    197	ret = 1;
    198out:
    199	close(client);
    200	close(srv_client);
    201	return ret;
    202}
    203
    204static bool get_port(int server_fd, in_port_t *port)
    205{
    206	struct sockaddr_in addr;
    207	socklen_t len = sizeof(addr);
    208
    209	if (getsockname(server_fd, (struct sockaddr *)&addr, &len)) {
    210		log_err("Failed to get server addr");
    211		return false;
    212	}
    213
    214	/* sin_port and sin6_port are located at the same offset. */
    215	*port = addr.sin_port;
    216	return true;
    217}
    218
    219int main(int argc, char **argv)
    220{
    221	struct sockaddr_in addr4;
    222	struct sockaddr_in6 addr6;
    223	struct sockaddr_in addr4dual;
    224	struct sockaddr_in6 addr6dual;
    225	int server = -1;
    226	int server_v6 = -1;
    227	int server_dual = -1;
    228	int results = -1;
    229	int err = 0;
    230	bool xdp;
    231
    232	if (argc < 2) {
    233		fprintf(stderr, "Usage: %s prog_id\n", argv[0]);
    234		exit(1);
    235	}
    236
    237	/* Use libbpf 1.0 API mode */
    238	libbpf_set_strict_mode(LIBBPF_STRICT_ALL);
    239
    240	results = get_map_fd_by_prog_id(atoi(argv[1]), &xdp);
    241	if (results < 0) {
    242		log_err("Can't get map");
    243		goto err;
    244	}
    245
    246	memset(&addr4, 0, sizeof(addr4));
    247	addr4.sin_family = AF_INET;
    248	addr4.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
    249	addr4.sin_port = 0;
    250	memcpy(&addr4dual, &addr4, sizeof(addr4dual));
    251
    252	memset(&addr6, 0, sizeof(addr6));
    253	addr6.sin6_family = AF_INET6;
    254	addr6.sin6_addr = in6addr_loopback;
    255	addr6.sin6_port = 0;
    256
    257	memset(&addr6dual, 0, sizeof(addr6dual));
    258	addr6dual.sin6_family = AF_INET6;
    259	addr6dual.sin6_addr = in6addr_any;
    260	addr6dual.sin6_port = 0;
    261
    262	server = start_server((const struct sockaddr *)&addr4, sizeof(addr4),
    263			      false);
    264	if (server == -1 || !get_port(server, &addr4.sin_port))
    265		goto err;
    266
    267	server_v6 = start_server((const struct sockaddr *)&addr6,
    268				 sizeof(addr6), false);
    269	if (server_v6 == -1 || !get_port(server_v6, &addr6.sin6_port))
    270		goto err;
    271
    272	server_dual = start_server((const struct sockaddr *)&addr6dual,
    273				   sizeof(addr6dual), true);
    274	if (server_dual == -1 || !get_port(server_dual, &addr4dual.sin_port))
    275		goto err;
    276
    277	if (run_test(server, results, xdp,
    278		     (const struct sockaddr *)&addr4, sizeof(addr4)))
    279		goto err;
    280
    281	if (run_test(server_v6, results, xdp,
    282		     (const struct sockaddr *)&addr6, sizeof(addr6)))
    283		goto err;
    284
    285	if (run_test(server_dual, results, xdp,
    286		     (const struct sockaddr *)&addr4dual, sizeof(addr4dual)))
    287		goto err;
    288
    289	printf("ok\n");
    290	goto out;
    291err:
    292	err = 1;
    293out:
    294	close(server);
    295	close(server_v6);
    296	close(server_dual);
    297	close(results);
    298	return err;
    299}