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

sockopt_sk.c (4968B)


      1// SPDX-License-Identifier: GPL-2.0
      2#include <string.h>
      3#include <linux/tcp.h>
      4#include <linux/bpf.h>
      5#include <netinet/in.h>
      6#include <bpf/bpf_helpers.h>
      7
      8char _license[] SEC("license") = "GPL";
      9
     10int page_size = 0; /* userspace should set it */
     11
     12#ifndef SOL_TCP
     13#define SOL_TCP IPPROTO_TCP
     14#endif
     15
     16#define SOL_CUSTOM			0xdeadbeef
     17
     18struct sockopt_sk {
     19	__u8 val;
     20};
     21
     22struct {
     23	__uint(type, BPF_MAP_TYPE_SK_STORAGE);
     24	__uint(map_flags, BPF_F_NO_PREALLOC);
     25	__type(key, int);
     26	__type(value, struct sockopt_sk);
     27} socket_storage_map SEC(".maps");
     28
     29SEC("cgroup/getsockopt")
     30int _getsockopt(struct bpf_sockopt *ctx)
     31{
     32	__u8 *optval_end = ctx->optval_end;
     33	__u8 *optval = ctx->optval;
     34	struct sockopt_sk *storage;
     35
     36	/* Make sure bpf_get_netns_cookie is callable.
     37	 */
     38	if (bpf_get_netns_cookie(NULL) == 0)
     39		return 0;
     40
     41	if (bpf_get_netns_cookie(ctx) == 0)
     42		return 0;
     43
     44	if (ctx->level == SOL_IP && ctx->optname == IP_TOS) {
     45		/* Not interested in SOL_IP:IP_TOS;
     46		 * let next BPF program in the cgroup chain or kernel
     47		 * handle it.
     48		 */
     49		ctx->optlen = 0; /* bypass optval>PAGE_SIZE */
     50		return 1;
     51	}
     52
     53	if (ctx->level == SOL_SOCKET && ctx->optname == SO_SNDBUF) {
     54		/* Not interested in SOL_SOCKET:SO_SNDBUF;
     55		 * let next BPF program in the cgroup chain or kernel
     56		 * handle it.
     57		 */
     58		return 1;
     59	}
     60
     61	if (ctx->level == SOL_TCP && ctx->optname == TCP_CONGESTION) {
     62		/* Not interested in SOL_TCP:TCP_CONGESTION;
     63		 * let next BPF program in the cgroup chain or kernel
     64		 * handle it.
     65		 */
     66		return 1;
     67	}
     68
     69	if (ctx->level == SOL_TCP && ctx->optname == TCP_ZEROCOPY_RECEIVE) {
     70		/* Verify that TCP_ZEROCOPY_RECEIVE triggers.
     71		 * It has a custom implementation for performance
     72		 * reasons.
     73		 */
     74
     75		/* Check that optval contains address (__u64) */
     76		if (optval + sizeof(__u64) > optval_end)
     77			return 0; /* bounds check */
     78
     79		if (((struct tcp_zerocopy_receive *)optval)->address != 0)
     80			return 0; /* unexpected data */
     81
     82		return 1;
     83	}
     84
     85	if (ctx->level == SOL_IP && ctx->optname == IP_FREEBIND) {
     86		if (optval + 1 > optval_end)
     87			return 0; /* bounds check */
     88
     89		ctx->retval = 0; /* Reset system call return value to zero */
     90
     91		/* Always export 0x55 */
     92		optval[0] = 0x55;
     93		ctx->optlen = 1;
     94
     95		/* Userspace buffer is PAGE_SIZE * 2, but BPF
     96		 * program can only see the first PAGE_SIZE
     97		 * bytes of data.
     98		 */
     99		if (optval_end - optval != page_size)
    100			return 0; /* unexpected data size */
    101
    102		return 1;
    103	}
    104
    105	if (ctx->level != SOL_CUSTOM)
    106		return 0; /* deny everything except custom level */
    107
    108	if (optval + 1 > optval_end)
    109		return 0; /* bounds check */
    110
    111	storage = bpf_sk_storage_get(&socket_storage_map, ctx->sk, 0,
    112				     BPF_SK_STORAGE_GET_F_CREATE);
    113	if (!storage)
    114		return 0; /* couldn't get sk storage */
    115
    116	if (!ctx->retval)
    117		return 0; /* kernel should not have handled
    118			   * SOL_CUSTOM, something is wrong!
    119			   */
    120	ctx->retval = 0; /* Reset system call return value to zero */
    121
    122	optval[0] = storage->val;
    123	ctx->optlen = 1;
    124
    125	return 1;
    126}
    127
    128SEC("cgroup/setsockopt")
    129int _setsockopt(struct bpf_sockopt *ctx)
    130{
    131	__u8 *optval_end = ctx->optval_end;
    132	__u8 *optval = ctx->optval;
    133	struct sockopt_sk *storage;
    134
    135	/* Make sure bpf_get_netns_cookie is callable.
    136	 */
    137	if (bpf_get_netns_cookie(NULL) == 0)
    138		return 0;
    139
    140	if (bpf_get_netns_cookie(ctx) == 0)
    141		return 0;
    142
    143	if (ctx->level == SOL_IP && ctx->optname == IP_TOS) {
    144		/* Not interested in SOL_IP:IP_TOS;
    145		 * let next BPF program in the cgroup chain or kernel
    146		 * handle it.
    147		 */
    148		ctx->optlen = 0; /* bypass optval>PAGE_SIZE */
    149		return 1;
    150	}
    151
    152	if (ctx->level == SOL_SOCKET && ctx->optname == SO_SNDBUF) {
    153		/* Overwrite SO_SNDBUF value */
    154
    155		if (optval + sizeof(__u32) > optval_end)
    156			return 0; /* bounds check */
    157
    158		*(__u32 *)optval = 0x55AA;
    159		ctx->optlen = 4;
    160
    161		return 1;
    162	}
    163
    164	if (ctx->level == SOL_TCP && ctx->optname == TCP_CONGESTION) {
    165		/* Always use cubic */
    166
    167		if (optval + 5 > optval_end)
    168			return 0; /* bounds check */
    169
    170		memcpy(optval, "cubic", 5);
    171		ctx->optlen = 5;
    172
    173		return 1;
    174	}
    175
    176	if (ctx->level == SOL_IP && ctx->optname == IP_FREEBIND) {
    177		/* Original optlen is larger than PAGE_SIZE. */
    178		if (ctx->optlen != page_size * 2)
    179			return 0; /* unexpected data size */
    180
    181		if (optval + 1 > optval_end)
    182			return 0; /* bounds check */
    183
    184		/* Make sure we can trim the buffer. */
    185		optval[0] = 0;
    186		ctx->optlen = 1;
    187
    188		/* Usepace buffer is PAGE_SIZE * 2, but BPF
    189		 * program can only see the first PAGE_SIZE
    190		 * bytes of data.
    191		 */
    192		if (optval_end - optval != page_size)
    193			return 0; /* unexpected data size */
    194
    195		return 1;
    196	}
    197
    198	if (ctx->level != SOL_CUSTOM)
    199		return 0; /* deny everything except custom level */
    200
    201	if (optval + 1 > optval_end)
    202		return 0; /* bounds check */
    203
    204	storage = bpf_sk_storage_get(&socket_storage_map, ctx->sk, 0,
    205				     BPF_SK_STORAGE_GET_F_CREATE);
    206	if (!storage)
    207		return 0; /* couldn't get sk storage */
    208
    209	storage->val = optval[0];
    210	ctx->optlen = -1; /* BPF has consumed this option, don't call kernel
    211			   * setsockopt handler.
    212			   */
    213
    214	return 1;
    215}