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_estats.c (7137B)


      1/* Copyright (c) 2017 Facebook
      2 *
      3 * This program is free software; you can redistribute it and/or
      4 * modify it under the terms of version 2 of the GNU General Public
      5 * License as published by the Free Software Foundation.
      6 */
      7
      8/* This program shows clang/llvm is able to generate code pattern
      9 * like:
     10 *   _tcp_send_active_reset:
     11 *      0:       bf 16 00 00 00 00 00 00         r6 = r1
     12 *    ......
     13 *    335:       b7 01 00 00 0f 00 00 00         r1 = 15
     14 *    336:       05 00 48 00 00 00 00 00         goto 72
     15 *
     16 *   LBB0_3:
     17 *    337:       b7 01 00 00 01 00 00 00         r1 = 1
     18 *    338:       63 1a d0 ff 00 00 00 00         *(u32 *)(r10 - 48) = r1
     19 *    408:       b7 01 00 00 03 00 00 00         r1 = 3
     20 *
     21 *   LBB0_4:
     22 *    409:       71 a2 fe ff 00 00 00 00         r2 = *(u8 *)(r10 - 2)
     23 *    410:       bf a7 00 00 00 00 00 00         r7 = r10
     24 *    411:       07 07 00 00 b8 ff ff ff         r7 += -72
     25 *    412:       bf 73 00 00 00 00 00 00         r3 = r7
     26 *    413:       0f 13 00 00 00 00 00 00         r3 += r1
     27 *    414:       73 23 2d 00 00 00 00 00         *(u8 *)(r3 + 45) = r2
     28 *
     29 * From the above code snippet, the code generated by the compiler
     30 * is reasonable. The "r1" is assigned to different values in basic
     31 * blocks "_tcp_send_active_reset" and "LBB0_3", and used in "LBB0_4".
     32 * The verifier should be able to handle such code patterns.
     33 */
     34#include <string.h>
     35#include <linux/bpf.h>
     36#include <linux/ipv6.h>
     37#include <linux/version.h>
     38#include <sys/socket.h>
     39#include <bpf/bpf_helpers.h>
     40
     41#define _(P) ({typeof(P) val = 0; bpf_probe_read_kernel(&val, sizeof(val), &P); val;})
     42#define TCP_ESTATS_MAGIC 0xBAADBEEF
     43
     44/* This test case needs "sock" and "pt_regs" data structure.
     45 * Recursively, "sock" needs "sock_common" and "inet_sock".
     46 * However, this is a unit test case only for
     47 * verifier purpose without bpf program execution.
     48 * We can safely mock much simpler data structures, basically
     49 * only taking the necessary fields from kernel headers.
     50 */
     51typedef __u32 __bitwise __portpair;
     52typedef __u64 __bitwise __addrpair;
     53
     54struct sock_common {
     55	unsigned short		skc_family;
     56	union {
     57		__addrpair	skc_addrpair;
     58		struct {
     59			__be32	skc_daddr;
     60			__be32	skc_rcv_saddr;
     61		};
     62	};
     63	union {
     64		__portpair	skc_portpair;
     65		struct {
     66			__be16	skc_dport;
     67			__u16	skc_num;
     68		};
     69	};
     70	struct in6_addr		skc_v6_daddr;
     71	struct in6_addr		skc_v6_rcv_saddr;
     72};
     73
     74struct sock {
     75	struct sock_common	__sk_common;
     76#define sk_family		__sk_common.skc_family
     77#define sk_v6_daddr		__sk_common.skc_v6_daddr
     78#define sk_v6_rcv_saddr		__sk_common.skc_v6_rcv_saddr
     79};
     80
     81struct inet_sock {
     82	struct sock		sk;
     83#define inet_daddr		sk.__sk_common.skc_daddr
     84#define inet_dport		sk.__sk_common.skc_dport
     85	__be32			inet_saddr;
     86	__be16			inet_sport;
     87};
     88
     89struct pt_regs {
     90	long di;
     91};
     92
     93static inline struct inet_sock *inet_sk(const struct sock *sk)
     94{
     95	return (struct inet_sock *)sk;
     96}
     97
     98/* Define various data structures for state recording.
     99 * Some fields are not used due to test simplification.
    100 */
    101enum tcp_estats_addrtype {
    102	TCP_ESTATS_ADDRTYPE_IPV4 = 1,
    103	TCP_ESTATS_ADDRTYPE_IPV6 = 2
    104};
    105
    106enum tcp_estats_event_type {
    107	TCP_ESTATS_ESTABLISH,
    108	TCP_ESTATS_PERIODIC,
    109	TCP_ESTATS_TIMEOUT,
    110	TCP_ESTATS_RETRANSMIT_TIMEOUT,
    111	TCP_ESTATS_RETRANSMIT_OTHER,
    112	TCP_ESTATS_SYN_RETRANSMIT,
    113	TCP_ESTATS_SYNACK_RETRANSMIT,
    114	TCP_ESTATS_TERM,
    115	TCP_ESTATS_TX_RESET,
    116	TCP_ESTATS_RX_RESET,
    117	TCP_ESTATS_WRITE_TIMEOUT,
    118	TCP_ESTATS_CONN_TIMEOUT,
    119	TCP_ESTATS_ACK_LATENCY,
    120	TCP_ESTATS_NEVENTS,
    121};
    122
    123struct tcp_estats_event {
    124	int pid;
    125	int cpu;
    126	unsigned long ts;
    127	unsigned int magic;
    128	enum tcp_estats_event_type event_type;
    129};
    130
    131/* The below data structure is packed in order for
    132 * llvm compiler to generate expected code.
    133 */
    134struct tcp_estats_conn_id {
    135	unsigned int localaddressType;
    136	struct {
    137		unsigned char data[16];
    138	} localaddress;
    139	struct {
    140		unsigned char data[16];
    141	} remaddress;
    142	unsigned short    localport;
    143	unsigned short    remport;
    144} __attribute__((__packed__));
    145
    146struct tcp_estats_basic_event {
    147	struct tcp_estats_event event;
    148	struct tcp_estats_conn_id conn_id;
    149};
    150
    151struct {
    152	__uint(type, BPF_MAP_TYPE_HASH);
    153	__uint(max_entries, 1024);
    154	__type(key, __u32);
    155	__type(value, struct tcp_estats_basic_event);
    156} ev_record_map SEC(".maps");
    157
    158struct dummy_tracepoint_args {
    159	unsigned long long pad;
    160	struct sock *sock;
    161};
    162
    163static __always_inline void tcp_estats_ev_init(struct tcp_estats_event *event,
    164					       enum tcp_estats_event_type type)
    165{
    166	event->magic = TCP_ESTATS_MAGIC;
    167	event->ts = bpf_ktime_get_ns();
    168	event->event_type = type;
    169}
    170
    171static __always_inline void unaligned_u32_set(unsigned char *to, __u8 *from)
    172{
    173	to[0] = _(from[0]);
    174	to[1] = _(from[1]);
    175	to[2] = _(from[2]);
    176	to[3] = _(from[3]);
    177}
    178
    179static __always_inline void conn_id_ipv4_init(struct tcp_estats_conn_id *conn_id,
    180					      __be32 *saddr, __be32 *daddr)
    181{
    182	conn_id->localaddressType = TCP_ESTATS_ADDRTYPE_IPV4;
    183
    184	unaligned_u32_set(conn_id->localaddress.data, (__u8 *)saddr);
    185	unaligned_u32_set(conn_id->remaddress.data, (__u8 *)daddr);
    186}
    187
    188static __always_inline void conn_id_ipv6_init(struct tcp_estats_conn_id *conn_id,
    189					      __be32 *saddr, __be32 *daddr)
    190{
    191	conn_id->localaddressType = TCP_ESTATS_ADDRTYPE_IPV6;
    192
    193	unaligned_u32_set(conn_id->localaddress.data, (__u8 *)saddr);
    194	unaligned_u32_set(conn_id->localaddress.data + sizeof(__u32),
    195			  (__u8 *)(saddr + 1));
    196	unaligned_u32_set(conn_id->localaddress.data + sizeof(__u32) * 2,
    197			  (__u8 *)(saddr + 2));
    198	unaligned_u32_set(conn_id->localaddress.data + sizeof(__u32) * 3,
    199			  (__u8 *)(saddr + 3));
    200
    201	unaligned_u32_set(conn_id->remaddress.data,
    202			  (__u8 *)(daddr));
    203	unaligned_u32_set(conn_id->remaddress.data + sizeof(__u32),
    204			  (__u8 *)(daddr + 1));
    205	unaligned_u32_set(conn_id->remaddress.data + sizeof(__u32) * 2,
    206			  (__u8 *)(daddr + 2));
    207	unaligned_u32_set(conn_id->remaddress.data + sizeof(__u32) * 3,
    208			  (__u8 *)(daddr + 3));
    209}
    210
    211static __always_inline void tcp_estats_conn_id_init(struct tcp_estats_conn_id *conn_id,
    212						    struct sock *sk)
    213{
    214	conn_id->localport = _(inet_sk(sk)->inet_sport);
    215	conn_id->remport = _(inet_sk(sk)->inet_dport);
    216
    217	if (_(sk->sk_family) == AF_INET6)
    218		conn_id_ipv6_init(conn_id,
    219				  sk->sk_v6_rcv_saddr.s6_addr32,
    220				  sk->sk_v6_daddr.s6_addr32);
    221	else
    222		conn_id_ipv4_init(conn_id,
    223				  &inet_sk(sk)->inet_saddr,
    224				  &inet_sk(sk)->inet_daddr);
    225}
    226
    227static __always_inline void tcp_estats_init(struct sock *sk,
    228					    struct tcp_estats_event *event,
    229					    struct tcp_estats_conn_id *conn_id,
    230					    enum tcp_estats_event_type type)
    231{
    232	tcp_estats_ev_init(event, type);
    233	tcp_estats_conn_id_init(conn_id, sk);
    234}
    235
    236static __always_inline void send_basic_event(struct sock *sk,
    237					     enum tcp_estats_event_type type)
    238{
    239	struct tcp_estats_basic_event ev;
    240	__u32 key = bpf_get_prandom_u32();
    241
    242	memset(&ev, 0, sizeof(ev));
    243	tcp_estats_init(sk, &ev.event, &ev.conn_id, type);
    244	bpf_map_update_elem(&ev_record_map, &key, &ev, BPF_ANY);
    245}
    246
    247SEC("tp/dummy/tracepoint")
    248int _dummy_tracepoint(struct dummy_tracepoint_args *arg)
    249{
    250	if (!arg->sock)
    251		return 0;
    252
    253	send_basic_event(arg->sock, TCP_ESTATS_TX_RESET);
    254	return 0;
    255}
    256
    257char _license[] SEC("license") = "GPL";