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

bind6_prog.c (4639B)


      1// SPDX-License-Identifier: GPL-2.0
      2
      3#include <string.h>
      4
      5#include <linux/stddef.h>
      6#include <linux/bpf.h>
      7#include <linux/in.h>
      8#include <linux/in6.h>
      9#include <sys/socket.h>
     10#include <netinet/tcp.h>
     11#include <linux/if.h>
     12#include <errno.h>
     13
     14#include <bpf/bpf_helpers.h>
     15#include <bpf/bpf_endian.h>
     16
     17#define SERV6_IP_0		0xfaceb00c /* face:b00c:1234:5678::abcd */
     18#define SERV6_IP_1		0x12345678
     19#define SERV6_IP_2		0x00000000
     20#define SERV6_IP_3		0x0000abcd
     21#define SERV6_PORT		6060
     22#define SERV6_REWRITE_IP_0	0x00000000
     23#define SERV6_REWRITE_IP_1	0x00000000
     24#define SERV6_REWRITE_IP_2	0x00000000
     25#define SERV6_REWRITE_IP_3	0x00000001
     26#define SERV6_REWRITE_PORT	6666
     27
     28#ifndef IFNAMSIZ
     29#define IFNAMSIZ 16
     30#endif
     31
     32static __inline int bind_to_device(struct bpf_sock_addr *ctx)
     33{
     34	char veth1[IFNAMSIZ] = "test_sock_addr1";
     35	char veth2[IFNAMSIZ] = "test_sock_addr2";
     36	char missing[IFNAMSIZ] = "nonexistent_dev";
     37	char del_bind[IFNAMSIZ] = "";
     38	int veth1_idx, veth2_idx;
     39
     40	if (bpf_setsockopt(ctx, SOL_SOCKET, SO_BINDTODEVICE,
     41			   &veth1, sizeof(veth1)))
     42		return 1;
     43	if (bpf_getsockopt(ctx, SOL_SOCKET, SO_BINDTOIFINDEX,
     44			   &veth1_idx, sizeof(veth1_idx)) || !veth1_idx)
     45		return 1;
     46	if (bpf_setsockopt(ctx, SOL_SOCKET, SO_BINDTODEVICE,
     47			   &veth2, sizeof(veth2)))
     48		return 1;
     49	if (bpf_getsockopt(ctx, SOL_SOCKET, SO_BINDTOIFINDEX,
     50			   &veth2_idx, sizeof(veth2_idx)) || !veth2_idx ||
     51	    veth1_idx == veth2_idx)
     52		return 1;
     53	if (bpf_setsockopt(ctx, SOL_SOCKET, SO_BINDTODEVICE,
     54			   &missing, sizeof(missing)) != -ENODEV)
     55		return 1;
     56	if (bpf_setsockopt(ctx, SOL_SOCKET, SO_BINDTOIFINDEX,
     57			   &veth1_idx, sizeof(veth1_idx)))
     58		return 1;
     59	if (bpf_setsockopt(ctx, SOL_SOCKET, SO_BINDTODEVICE,
     60			   &del_bind, sizeof(del_bind)))
     61		return 1;
     62
     63	return 0;
     64}
     65
     66static __inline int bind_reuseport(struct bpf_sock_addr *ctx)
     67{
     68	int val = 1;
     69
     70	if (bpf_setsockopt(ctx, SOL_SOCKET, SO_REUSEPORT,
     71			   &val, sizeof(val)))
     72		return 1;
     73	if (bpf_getsockopt(ctx, SOL_SOCKET, SO_REUSEPORT,
     74			   &val, sizeof(val)) || !val)
     75		return 1;
     76	val = 0;
     77	if (bpf_setsockopt(ctx, SOL_SOCKET, SO_REUSEPORT,
     78			   &val, sizeof(val)))
     79		return 1;
     80	if (bpf_getsockopt(ctx, SOL_SOCKET, SO_REUSEPORT,
     81			   &val, sizeof(val)) || val)
     82		return 1;
     83
     84	return 0;
     85}
     86
     87static __inline int misc_opts(struct bpf_sock_addr *ctx, int opt)
     88{
     89	int old, tmp, new = 0xeb9f;
     90
     91	/* Socket in test case has guarantee that old never equals to new. */
     92	if (bpf_getsockopt(ctx, SOL_SOCKET, opt, &old, sizeof(old)) ||
     93	    old == new)
     94		return 1;
     95	if (bpf_setsockopt(ctx, SOL_SOCKET, opt, &new, sizeof(new)))
     96		return 1;
     97	if (bpf_getsockopt(ctx, SOL_SOCKET, opt, &tmp, sizeof(tmp)) ||
     98	    tmp != new)
     99		return 1;
    100	if (bpf_setsockopt(ctx, SOL_SOCKET, opt, &old, sizeof(old)))
    101		return 1;
    102
    103	return 0;
    104}
    105
    106SEC("cgroup/bind6")
    107int bind_v6_prog(struct bpf_sock_addr *ctx)
    108{
    109	struct bpf_sock *sk;
    110	__u32 user_ip6;
    111	__u16 user_port;
    112	int i;
    113
    114	sk = ctx->sk;
    115	if (!sk)
    116		return 0;
    117
    118	if (sk->family != AF_INET6)
    119		return 0;
    120
    121	if (ctx->type != SOCK_STREAM && ctx->type != SOCK_DGRAM)
    122		return 0;
    123
    124	if (ctx->user_ip6[0] != bpf_htonl(SERV6_IP_0) ||
    125	    ctx->user_ip6[1] != bpf_htonl(SERV6_IP_1) ||
    126	    ctx->user_ip6[2] != bpf_htonl(SERV6_IP_2) ||
    127	    ctx->user_ip6[3] != bpf_htonl(SERV6_IP_3) ||
    128	    ctx->user_port != bpf_htons(SERV6_PORT))
    129		return 0;
    130
    131	// u8 narrow loads:
    132	for (i = 0; i < 4; i++) {
    133		user_ip6 = 0;
    134		user_ip6 |= ((volatile __u8 *)&ctx->user_ip6[i])[0] << 0;
    135		user_ip6 |= ((volatile __u8 *)&ctx->user_ip6[i])[1] << 8;
    136		user_ip6 |= ((volatile __u8 *)&ctx->user_ip6[i])[2] << 16;
    137		user_ip6 |= ((volatile __u8 *)&ctx->user_ip6[i])[3] << 24;
    138		if (ctx->user_ip6[i] != user_ip6)
    139			return 0;
    140	}
    141
    142	user_port = 0;
    143	user_port |= ((volatile __u8 *)&ctx->user_port)[0] << 0;
    144	user_port |= ((volatile __u8 *)&ctx->user_port)[1] << 8;
    145	if (ctx->user_port != user_port)
    146		return 0;
    147
    148	// u16 narrow loads:
    149	for (i = 0; i < 4; i++) {
    150		user_ip6 = 0;
    151		user_ip6 |= ((volatile __u16 *)&ctx->user_ip6[i])[0] << 0;
    152		user_ip6 |= ((volatile __u16 *)&ctx->user_ip6[i])[1] << 16;
    153		if (ctx->user_ip6[i] != user_ip6)
    154			return 0;
    155	}
    156
    157	/* Bind to device and unbind it. */
    158	if (bind_to_device(ctx))
    159		return 0;
    160
    161	/* Test for misc socket options. */
    162	if (misc_opts(ctx, SO_MARK) || misc_opts(ctx, SO_PRIORITY))
    163		return 0;
    164
    165	/* Set reuseport and unset */
    166	if (bind_reuseport(ctx))
    167		return 0;
    168
    169	ctx->user_ip6[0] = bpf_htonl(SERV6_REWRITE_IP_0);
    170	ctx->user_ip6[1] = bpf_htonl(SERV6_REWRITE_IP_1);
    171	ctx->user_ip6[2] = bpf_htonl(SERV6_REWRITE_IP_2);
    172	ctx->user_ip6[3] = bpf_htonl(SERV6_REWRITE_IP_3);
    173	ctx->user_port = bpf_htons(SERV6_REWRITE_PORT);
    174
    175	return 1;
    176}
    177
    178char _license[] SEC("license") = "GPL";