BPF Системный вызов, связанный с сокетом kprobe, ошибка чтения данных сокета

Измените gobpf perf.go, измените системный вызов fchown на системный вызов, связанный с сокетом, попробуйте прочитать сведения о сокете, такие как PORT или Addr. Например, системный вызов 'connect'. Как я понимаю, у pt_regs * ctx есть параметр syscall, я могу либо использовать PT_REGS_PARM2, либо напрямую перечислить, они получают одно и то же в моем тесте.

в net/socket.c определены

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

поэтому я ожидаю, что 1-й параметр в виде socket_fd и второй в качестве sockaddr, определенного в include/linux/socket.h

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

Sa_data - это то, что я хочу прочитать из ядра и отправить в пространство пользователя.

Ниже часть ядра.

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

В пользовательском пространстве часть - это то, что делает perf.go

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\n", err)
            continue
        }
        filename := (*C.char)(unsafe.Pointer(&event.Filename))
        fmt.Printf("pid %d fd %d sock  %s  listen (return value: %d)\n",
            event.Pid, event.Socket_fd, C.GoString(filename),event.ReturnValue)
    }
}()

После некоторой проблемы с подключением, я не получил ничего, связанного с информацией о сокете

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

Я также попробовал в части kenerl другой способ чтения параметров, с тем же результатом.

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

Информация о fd и sock не читается правильно. Где мое понимание или треска не так?

Также попробовал прослушать syscall, как он определил проще

int __sys_listen(int fd, int backlog)

так что просто прочитайте эти два целых числа

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

выход указывает, что они одинаковы, что это, адрес?

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

0 ответов

Другие вопросы по тегам