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)