my environment: ubuntu 20.04 kernel version: 5.15.0-46-generic x86_64
below is my code:
import sys
import signal
from bcc import BPF
import os
# define BPF program
bpf_text = """
#include <linux/bpf.h>
#include <linux/version.h>
#include <linux/sockptr.h>
#include<linux/bpfptr.h>
int fn_kprobe(struct pt_regs *ctx,int cmd, bpfptr_t uattr){
int pid=bpf_get_current_pid_tgid();
char tmp[40];
switch (cmd) {
case BPF_MAP_CREATE:
memcpy(tmp,"BPF_MAP_CREATE",39);
bpf_trace_printk("the cmd is %s",tmp);
break;
case BPF_MAP_LOOKUP_ELEM:
memcpy(tmp,"BPF_MAP_LOOKUP_ELEM",39);
bpf_trace_printk("the cmd is %s",tmp);
break;
default:
break;
}
return 0;
}
it raises this error:
/virtual/main.c:21:30: error: initializing 'bpfptr_t' (aka 'sockptr_t') with an expression of incompatible type 'unsigned long' int cmd = ctx->di; bpfptr_t uattr = ctx->si; ^ ~~~~~~~ 1 error generated.
I think this error may due to bpfptr_t is a struct rather than a pointer, but I am not sure.
I have tried to get the second parameter through PT_REGS_PARM2, but it did not work.
————————————————————————————————————
I opened an issue in github and have partially solved my problem. below is the modified code:
import sys
from bcc import BPF
bpf_text = """
#include <linux/bpf.h>
#include <linux/version.h>
#include <linux/sockptr.h>
#include<linux/bpfptr.h>
int fn_kprobe(struct pt_regs *ctx){
union bpf_attr attr;
bpfptr_t uattr={0};
unsigned int size=0;
int cmd=0;
bpf_probe_read_kernel((void*)(&cmd), sizeof(int), &PT_REGS_PARM1(ctx));
bpf_probe_read_kernel((void*)(&uattr), sizeof(bpfptr_t), &PT_REGS_PARM2(ctx));
bpf_probe_read_kernel((void*)(&size), sizeof(unsigned int), &PT_REGS_PARM3(ctx));
bpf_trace_printk("the first parameter is %d",cmd);
bpf_trace_printk("the uattr.user is %lx",uattr.user);
bpf_trace_printk("the third parameter is %u",size);
return 0;
}
"""
b = BPF(text=bpf_text)
b.attach_kprobe(event="__sys_bpf", fn_name="fn_kprobe")
while True:
try:
b.trace_print()
except KeyboardInterrupt:
sys.exit(0)
I can successfully get the first and the seconde parameter of __sys_bpf
, but it's weird that the third parameter is always 0(the third parameter represents the size of bpf_attr, it should not be 0):
b' <...>-73493 [002] d...1 510983.010254: bpf_trace_printk: the first parameter is 5'
b' <...>-73493 [002] d...1 510983.010268: bpf_trace_printk: the address of uattr.user is 0x7ffcbedebd60'
b' <...>-73493 [002] d...1 510983.010269: bpf_trace_printk: the third parameter is 0'
b' <...>-73493 [002] d...1 510983.010476: bpf_trace_printk: the first parameter is 18'
b' <...>-73493 [002] d...1 510983.010485: bpf_trace_printk: the address of uattr.user is 0x7ffcbedebe90'
b' <...>-73493 [002] d...1 510983.010485: bpf_trace_printk: the third parameter is 0'
another question is: before I meet this problem, I can get parameter like this:
int fn_kprobe(struct pt_regs *ctx,int cmd){
bpf_trace_printk("the cmd is %d",cmd);
return 0;
}
but in __sys_bpf
I have to use bpf_probe_read_kernel
, which really confuses me.