// 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;
}