BPF kprobe套接字相关的系统调用,读取套接字详细信息失败

Modified gobpf perf.go, change from monitor fchown syscall to socket related syscall, try to read the socket detail like PORT or Addr. For example 'connect' syscall. As I understand the pt_regs* ctx have syscall parameter, I can either use PT_REGS_PARM2 or directly list out, they get samething in my test.

in net/socket.c defined

int __sys_connect(int fd, struct sockaddr __user *uservaddr, int addrlen)

so I expect 1st parameter as socket_fd and second as sockaddr defined in include/linux/socket.h

struct sockaddr {
    sa_family_t     sa_family;      /* address family, AF_xxx       */
    char            sa_data[14];    /* 14 bytes of protocol address */
};

The sa_data is what I wish to read out from kernel and send to userspace.

Below is the kernel part.

#include <uapi/linux/ptrace.h>
#include <bcc/proto.h>
#include <linux/net.h>

typedef struct {
    u32 pid;
    int fd;
    char comm[64];
    int ret;
} syscall_event_t;
BPF_PERF_OUTPUT(syscall_events);
BPF_HASH(syscall, u64, syscall_event_t);

int kprobe__sys_fsyscallat(struct pt_regs *ctx, int socket_fd, struct sockaddr *socketadd, int len)
{
    u64 pid = bpf_get_current_pid_tgid();
    syscall_event_t event = {
        .pid = pid >> 32,
        .fd = socket_fd,
    };
    bpf_probe_read(&event.comm,14,(void *)(&(socketadd->sa_data)));
    syscall.update(&pid, &event);
    return 0;
}

int kretprobe__sys_fsyscallat(struct pt_regs *ctx)
{
    int ret = PT_REGS_RC(ctx);
    u64 pid = bpf_get_current_pid_tgid();
    syscall_event_t *eventp = syscall.lookup(&pid);
    if (eventp == 0) {
        return 0;
    }
    syscall_event_t event = *eventp;
    event.ret = ret;
    syscall_events.perf_submit(ctx, &event, sizeof(event));
    syscall.delete(&pid);
    return 0;
};

In user space part is just what perf.go do

type syscallEvent struct {
    Pid         uint32
    Socket_fd   int32
    Filename    [64]byte
    ReturnValue int32
}
..........................
..........................
go func() {
    var event syscallEvent
    for {
        data := <-channel
        err := binary.Read(bytes.NewBuffer(data), binary.LittleEndian, &event)
        if err != nil {
            fmt.Printf("failed to decode received data: %s
", err)
            continue
        }
        filename := (*C.char)(unsafe.Pointer(&event.Filename))
        fmt.Printf("pid %d fd %d sock  %s  listen (return value: %d)
",
            event.Pid, event.Socket_fd, C.GoString(filename),event.ReturnValue)
    }
}()

After issue some connect syscall, I didn't get anything related to socket info

$ sudo ./syscall 
pid 2024 fd 15859544 sock    listen (return value: 0)

I also tried in kenerl part another way to read parameter, with same result.

void * socketin;    
int socket_fd = PT_REGS_PARM1(ctx);
socketin = (void *)PT_REGS_PARM2(ctx);

Both fd and sock info not read right. Where my understanding or cod is wrong?

Also tried listen syscall as it defined easier

int __sys_listen(int fd, int backlog)

so just read these two integer by

int socket_fd = PT_REGS_PARM1(ctx);
int pa2 = PT_REGS_PARM2(ctx);

the ouptut indicate they are same , what is it, an address ?

$ sudo ./syscall_socket
pid 3644 fd 15597400 parameter2 15597400 sock listen (return value: 0)