// SPDX-License-Identifier: GPL-2.0 /* Copyright (c) 2020 Facebook */ #include <linux/bpf.h> #include <stdint.h> #include <bpf/bpf_helpers.h> #include <bpf/bpf_core_read.h> char _license[] SEC("license") = "GPL"; /* fields of exactly the same size */ struct test_struct___samesize { void *ptr; unsigned long long val1; unsigned int val2; unsigned short val3; unsigned char val4; } __attribute((preserve_access_index)); /* unsigned fields that have to be downsized by libbpf */ struct test_struct___downsize { void *ptr; unsigned long val1; unsigned long val2; unsigned long val3; unsigned long val4; /* total sz: 40 */ } __attribute__((preserve_access_index)); /* fields with signed integers of wrong size, should be rejected */ struct test_struct___signed { void *ptr; long val1; long val2; long val3; long val4; } __attribute((preserve_access_index)); /* real layout and sizes according to test's (32-bit) BTF */ struct test_struct___real { unsigned int ptr; /* can't use `void *`, it is always 8 byte in BPF target */ unsigned int val2; unsigned long long val1; unsigned short val3; unsigned char val4; unsigned char _pad; /* total sz: 20 */ }; struct test_struct___real input = { .ptr = 0x01020304, .val1 = 0x1020304050607080, .val2 = 0x0a0b0c0d, .val3 = 0xfeed, .val4 = 0xb9, ._pad = 0xff, /* make sure no accidental zeros are present */ }; unsigned long long ptr_samesized = 0; unsigned long long val1_samesized = 0; unsigned long long val2_samesized = 0; unsigned long long val3_samesized = 0; unsigned long long val4_samesized = 0; struct test_struct___real output_samesized = {}; unsigned long long ptr_downsized = 0; unsigned long long val1_downsized = 0; unsigned long long val2_downsized = 0; unsigned long long val3_downsized = 0; unsigned long long val4_downsized = 0; struct test_struct___real output_downsized = {}; unsigned long long ptr_probed = 0; unsigned long long val1_probed = 0; unsigned long long val2_probed = 0; unsigned long long val3_probed = 0; unsigned long long val4_probed = 0; unsigned long long ptr_signed = 0; unsigned long long val1_signed = 0; unsigned long long val2_signed = 0; unsigned long long val3_signed = 0; unsigned long long val4_signed = 0; struct test_struct___real output_signed = {}; SEC("raw_tp/sys_exit") int handle_samesize(void *ctx) { struct test_struct___samesize *in = (void *)&input; struct test_struct___samesize *out = (void *)&output_samesized; ptr_samesized = (unsigned long long)in->ptr; val1_samesized = in->val1; val2_samesized = in->val2; val3_samesized = in->val3; val4_samesized = in->val4; out->ptr = in->ptr; out->val1 = in->val1; out->val2 = in->val2; out->val3 = in->val3; out->val4 = in->val4; return 0; } SEC("raw_tp/sys_exit") int handle_downsize(void *ctx) { struct test_struct___downsize *in = (void *)&input; struct test_struct___downsize *out = (void *)&output_downsized; ptr_downsized = (unsigned long long)in->ptr; val1_downsized = in->val1; val2_downsized = in->val2; val3_downsized = in->val3; val4_downsized = in->val4; out->ptr = in->ptr; out->val1 = in->val1; out->val2 = in->val2; out->val3 = in->val3; out->val4 = in->val4; return 0; } #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ #define bpf_core_read_int bpf_core_read #else #define bpf_core_read_int(dst, sz, src) ({ \ /* Prevent "subtraction from stack pointer prohibited" */ \ volatile long __off = sizeof(*dst) - (sz); \ bpf_core_read((char *)(dst) + __off, sz, src); \ }) #endif SEC("raw_tp/sys_enter") int handle_probed(void *ctx) { struct test_struct___downsize *in = (void *)&input; __u64 tmp; tmp = 0; bpf_core_read_int(&tmp, bpf_core_field_size(in->ptr), &in->ptr); ptr_probed = tmp; tmp = 0; bpf_core_read_int(&tmp, bpf_core_field_size(in->val1), &in->val1); val1_probed = tmp; tmp = 0; bpf_core_read_int(&tmp, bpf_core_field_size(in->val2), &in->val2); val2_probed = tmp; tmp = 0; bpf_core_read_int(&tmp, bpf_core_field_size(in->val3), &in->val3); val3_probed = tmp; tmp = 0; bpf_core_read_int(&tmp, bpf_core_field_size(in->val4), &in->val4); val4_probed = tmp; return 0; } SEC("raw_tp/sys_enter") int handle_signed(void *ctx) { struct test_struct___signed *in = (void *)&input; struct test_struct___signed *out = (void *)&output_signed; val2_signed = in->val2; val3_signed = in->val3; val4_signed = in->val4; out->val2= in->val2; out->val3= in->val3; out->val4= in->val4; return 0; }