Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion bpf/process/bpf_generic_tracepoint.c
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,7 @@ generic_tracepoint_event(struct generic_tracepoint_event_arg *ctx)
get_ctx_ul((char *)ctx + ctx_off, ty);
});

generic_process_init(msg, MSG_OP_GENERIC_TRACEPOINT, config);
generic_process_init(msg, MSG_OP_GENERIC_TRACEPOINT);

msg->common.op = MSG_OP_GENERIC_TRACEPOINT;
msg->sel.curr = 0;
Expand Down
26 changes: 20 additions & 6 deletions bpf/process/generic_calls.h
Original file line number Diff line number Diff line change
Expand Up @@ -449,6 +449,17 @@ FUNC_INLINE int arg_idx(int index)
return config->idx[index];
}

FUNC_INLINE long get_pt_regs_arg(struct pt_regs *ctx, struct config_reg_arg *reg)
{
__u8 shift = 64 - reg->size*8;
unsigned long *val;

val = (unsigned long *) ctx + (reg->offset / sizeof(unsigned long));
*val <<= shift;
*val >>= shift;
return *val;
}

FUNC_INLINE long generic_read_arg(void *ctx, int index, long off, struct bpf_map_def *tailcals)
{
struct msg_generic_kprobe *e;
Expand Down Expand Up @@ -483,9 +494,12 @@ FUNC_INLINE long generic_read_arg(void *ctx, int index, long off, struct bpf_map
/* Getting argument data based on the source attribute, which is encoded
* in argument meta data, so far it's either:
*
* - pt_regs register
* - current task object
* - real argument value
*/
if (am & ARGM_PT_REGS)
a = get_pt_regs_arg(ctx, &config->reg_arg[arg_index]);
if (am & ARGM_CURRENT_TASK)
a = get_current_task();
else
Expand Down Expand Up @@ -543,7 +557,7 @@ generic_process_event(void *ctx, struct bpf_map_def *tailcals)
}

FUNC_INLINE void
generic_process_init(struct msg_generic_kprobe *e, u8 op, struct event_config *config)
generic_process_init(struct msg_generic_kprobe *e, u8 op)
{
e->common.op = op;

Expand Down Expand Up @@ -693,7 +707,7 @@ generic_process_event_and_setup(struct pt_regs *ctx, struct bpf_map_def *tailcal
e->a4 = PT_REGS_PARM5_CORE(ctx);
}

generic_process_init(e, MSG_OP_GENERIC_KPROBE, config);
generic_process_init(e, MSG_OP_GENERIC_KPROBE);

e->retprobe_id = retprobe_map_get_key(ctx);

Expand All @@ -711,7 +725,7 @@ generic_process_event_and_setup(struct pt_regs *ctx, struct bpf_map_def *tailcal
e->a2 = BPF_CORE_READ(raw_args, args[2]);
e->a3 = BPF_CORE_READ(raw_args, args[3]);
e->a4 = BPF_CORE_READ(raw_args, args[4]);
generic_process_init(e, MSG_OP_GENERIC_LSM, config);
generic_process_init(e, MSG_OP_GENERIC_LSM);
#endif

#ifdef GENERIC_UPROBE
Expand All @@ -720,7 +734,7 @@ generic_process_event_and_setup(struct pt_regs *ctx, struct bpf_map_def *tailcal
e->a2 = PT_REGS_PARM3_CORE(ctx);
e->a3 = PT_REGS_PARM4_CORE(ctx);
e->a4 = PT_REGS_PARM5_CORE(ctx);
generic_process_init(e, MSG_OP_GENERIC_UPROBE, config);
generic_process_init(e, MSG_OP_GENERIC_UPROBE);

e->retprobe_id = retprobe_map_get_key(ctx);

Expand All @@ -731,7 +745,7 @@ generic_process_event_and_setup(struct pt_regs *ctx, struct bpf_map_def *tailcal
#endif

#ifdef GENERIC_USDT
generic_process_init(e, MSG_OP_GENERIC_USDT, config);
generic_process_init(e, MSG_OP_GENERIC_USDT);
#endif

#ifdef GENERIC_RAWTP
Expand All @@ -742,7 +756,7 @@ generic_process_event_and_setup(struct pt_regs *ctx, struct bpf_map_def *tailcal
e->a2 = BPF_CORE_READ(raw_args, args[2]);
e->a3 = BPF_CORE_READ(raw_args, args[3]);
e->a4 = BPF_CORE_READ(raw_args, args[4]);
generic_process_init(e, MSG_OP_GENERIC_TRACEPOINT, config);
generic_process_init(e, MSG_OP_GENERIC_TRACEPOINT);
#endif

#ifdef GENERIC_USDT
Expand Down
9 changes: 9 additions & 0 deletions bpf/process/types/basic.h
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,12 @@ struct config_usdt_arg {
__u32 pad1;
} __attribute__((packed));

struct config_reg_arg {
__u16 offset;
__u8 size;
__u8 pad;
} __attribute__((packed));

struct extract_arg_data {
struct config_btf_arg *btf_config;
unsigned long *arg;
Expand All @@ -189,6 +195,7 @@ struct extract_arg_data {
#define MAX_BTF_ARG_DEPTH 10
#define EVENT_CONFIG_MAX_ARG 5
#define EVENT_CONFIG_MAX_USDT_ARG 8
#define EVENT_CONFIG_MAX_REG_ARG 8

struct event_config {
__u32 func_id;
Expand All @@ -212,6 +219,7 @@ struct event_config {
__u32 pad;
struct config_btf_arg btf_arg[EVENT_CONFIG_MAX_ARG][MAX_BTF_ARG_DEPTH];
struct config_usdt_arg usdt_arg[EVENT_CONFIG_MAX_USDT_ARG];
struct config_reg_arg reg_arg[EVENT_CONFIG_MAX_REG_ARG];
} __attribute__((packed));

#define MAX_ARGS_SIZE 80
Expand Down Expand Up @@ -574,6 +582,7 @@ FUNC_INLINE long copy_kernel_module(char *args, unsigned long arg)
#define ARGM_RETURN_COPY BIT(4)
#define ARGM_MAX_DATA BIT(5)
#define ARGM_CURRENT_TASK BIT(6)
#define ARGM_PT_REGS BIT(7)

FUNC_INLINE bool has_return_copy(unsigned long argm)
{
Expand Down
105 changes: 72 additions & 33 deletions bpf/process/uprobe_offload.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ struct reg_assignment {
__u8 pad1;
__u16 src;
__u16 dst;
__u16 pad2;
__u8 src_size;
__u8 dst_size;
__u64 off;
};

Expand Down Expand Up @@ -59,8 +60,8 @@ FUNC_INLINE void do_uprobe_override(void *ctx, __u32 idx)
map_update_elem(&sleepable_offload, &id, &idx, BPF_ANY);
}

FUNC_INLINE int
write_reg(struct pt_regs *ctx, __u32 dst, __u64 val)
FUNC_LOCAL int
write_reg(struct pt_regs *ctx, __u32 dst, __u8 size, __u64 val)
{
/*
* Using inlined asm to make sure we access context via 'ctx-reg + offset'.
Expand All @@ -69,43 +70,81 @@ write_reg(struct pt_regs *ctx, __u32 dst, __u64 val)
*
* Using clang-20 seems to work, but we need to upgrade first ;-)
*/
#define WRITE_REG(reg) \
asm volatile("if %[dst] != %[off] goto +1\n" \
"*(u64 *)(%[ctx] + %[off]) = %[val]\n" \
: [ctx] "+r"(ctx), [dst] "+r"(dst), [val] "+r"(val) \
: [off] "i"(offsetof(struct pt_regs, reg)) \
:);

WRITE_REG(r15);
WRITE_REG(r14);
WRITE_REG(r13);
WRITE_REG(r12);
WRITE_REG(r11);
WRITE_REG(r10);
WRITE_REG(r9);
WRITE_REG(r8);
WRITE_REG(ax);
WRITE_REG(cx);
WRITE_REG(dx);
WRITE_REG(si);
WRITE_REG(di);
WRITE_REG(ip);
WRITE_REG(sp);

#define WRITE_REG(reg) ({ \
asm volatile("if %[size] != 8 goto +2\n" \
"*(u64 *)(%[ctx] + %[off]) = %[val]\n" \
"goto +8\n" \
"if %[size] != 4 goto +2\n" \
"*(u32 *)(%[ctx] + %[off]) = %[val]\n" \
"goto +5\n" \
"if %[size] != 2 goto +2\n" \
"*(u16 *)(%[ctx] + %[off]) = %[val]\n" \
"goto +2\n" \
"if %[size] != 1 goto +1\n" \
"*(u8 *)(%[ctx] + %[off]) = %[val]\n" \
: [ctx] "+r"(ctx), [val] "+r"(val), [size] "+r"(size) \
: [off] "i"(offsetof(struct pt_regs, reg)) \
:); \
0; \
})

switch (dst) {
case offsetof(struct pt_regs, r15):
return WRITE_REG(r15);
case offsetof(struct pt_regs, r14):
return WRITE_REG(r14);
case offsetof(struct pt_regs, r13):
return WRITE_REG(r13);
case offsetof(struct pt_regs, r12):
return WRITE_REG(r12);
case offsetof(struct pt_regs, bp):
return WRITE_REG(bp);
case offsetof(struct pt_regs, bx):
return WRITE_REG(bx);
case offsetof(struct pt_regs, r11):
return WRITE_REG(r11);
case offsetof(struct pt_regs, r10):
return WRITE_REG(r10);
case offsetof(struct pt_regs, r9):
return WRITE_REG(r9);
case offsetof(struct pt_regs, r8):
return WRITE_REG(r8);
case offsetof(struct pt_regs, ax):
return WRITE_REG(ax);
case offsetof(struct pt_regs, cx):
return WRITE_REG(cx);
case offsetof(struct pt_regs, dx):
return WRITE_REG(dx);
case offsetof(struct pt_regs, si):
return WRITE_REG(si);
case offsetof(struct pt_regs, di):
return WRITE_REG(di);
case offsetof(struct pt_regs, ip):
return WRITE_REG(ip);
case offsetof(struct pt_regs, sp):
return WRITE_REG(sp);
}

#undef WRITE_REG
return 0;
}

FUNC_INLINE __u64
read_reg(struct pt_regs *ctx, __u32 src)
read_reg(struct pt_regs *ctx, struct reg_assignment *ass)
{
__u32 src = ass->src;
__u8 shift = 64 - ass->src_size*8;

/* Using inlined asm for same reason we use WRITE_REG above. */
#define READ_REG(reg) ({ \
__u64 val; \
asm volatile("%[val] = *(u64 *)(%[ctx] + %[off])\n" \
: [ctx] "+r"(ctx), [val] "+r"(val) \
: [off] "i"(offsetof(struct pt_regs, reg)) \
:); \
val <<= shift; \
val >>= shift; \
val; \
})

Expand Down Expand Up @@ -173,22 +212,22 @@ uprobe_offload_x86(struct pt_regs *ctx)

switch (ass->type) {
case ASM_ASSIGNMENT_TYPE_CONST:
write_reg(ctx, ass->dst, ass->off);
write_reg(ctx, ass->dst, ass->dst_size, ass->off);
break;
case ASM_ASSIGNMENT_TYPE_REG:
val = read_reg(ctx, ass->src);
write_reg(ctx, ass->dst, val);
val = read_reg(ctx, ass);
write_reg(ctx, ass->dst, ass->dst_size, val);
break;
case ASM_ASSIGNMENT_TYPE_REG_OFF:
val = read_reg(ctx, ass->src);
val = read_reg(ctx, ass);
val += ass->off;
write_reg(ctx, ass->dst, val);
write_reg(ctx, ass->dst, ass->dst_size, val);
break;
case ASM_ASSIGNMENT_TYPE_REG_DEREF:
val = read_reg(ctx, ass->src);
val = read_reg(ctx, ass);
err = probe_read_user(&val, sizeof(val), (void *)val + ass->off);
if (!err)
write_reg(ctx, ass->dst, val);
write_reg(ctx, ass->dst, ass->dst_size, val);
break;
case ASM_ASSIGNMENT_TYPE_NONE:
default:
Expand Down
21 changes: 20 additions & 1 deletion contrib/tester-progs/regs-override.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,35 @@ static __naked int test_1()
);
}

static __naked unsigned long test_2()
{
asm(
"push %rbp\n" /* +0 55 */
"mov %rsp,%rbp\n" /* +1 48 89 e5 */
"mov $0xdeadbeefdeadbeef,%rax\n" /* +4 48 b8 00 00 00 00 ef be ad de */
"pop %rbp\n" /* +14 5d */
"ret\n" /* +15 c3 */
);
}

int main(int argc, char **argv)
{
int num;

if (argc != 2)
if (argc < 2)
return -1;

num = atoi(argv[1]);
if (num == 1)
return test_1();
if (num == 2) {
unsigned long val;

if (argc != 3)
return -1;
val = strtoul(argv[2], NULL, 0);
return test_2() == val ? 0 : -1;
}

return -1;
}
13 changes: 7 additions & 6 deletions pkg/api/processapi/processapi.go
Original file line number Diff line number Diff line change
Expand Up @@ -273,10 +273,11 @@ type CgroupRateOptions struct {
}

type RegAssignment struct {
Type uint8
Pad1 uint8
Src uint16
Dst uint16
Pad2 uint16
Off uint64
Type uint8
Pad1 uint8
Src uint16
Dst uint16
SrcSize uint8
DstSize uint8
Off uint64
}
8 changes: 8 additions & 0 deletions pkg/api/tracingapi/client_kprobe.go
Original file line number Diff line number Diff line change
Expand Up @@ -630,9 +630,16 @@ type ConfigUsdtArg struct {
Pad1 uint32 `align:"pad1"`
}

type ConfigRegArg struct {
Offset uint16 `align:"offset"`
Size uint8 `align:"size"`
Pad uint8 `align:"pad"`
}

const (
EventConfigMaxArgs = 5
EventConfigMaxUsdtArgs = 8
EventConfigMaxRegArgs = 8
MaxBTFArgDepth = 10 // Artificial value for compilation, may be extended
)

Expand All @@ -651,4 +658,5 @@ type EventConfig struct {
Pad uint32 `align:"pad"`
BTFArg [EventConfigMaxArgs][MaxBTFArgDepth]ConfigBTFArg `align:"btf_arg"`
UsdtArg [EventConfigMaxUsdtArgs]ConfigUsdtArg `align:"usdt_arg"`
RegArg [EventConfigMaxRegArgs]ConfigRegArg `align:"reg_arg"`
}
Loading
Loading