Skip to content

Commit

Permalink
new: extend SEND_X and SENDTO_X
Browse files Browse the repository at this point in the history
Signed-off-by: Leonardo Di Giovanna <[email protected]>
  • Loading branch information
ekoops committed Jan 3, 2025
1 parent d1881b4 commit d11578f
Show file tree
Hide file tree
Showing 25 changed files with 1,126 additions and 286 deletions.
2 changes: 1 addition & 1 deletion driver/SCHEMA_VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
3.4.1
3.5.0
215 changes: 151 additions & 64 deletions driver/bpf/fillers.h
Original file line number Diff line number Diff line change
Expand Up @@ -1520,101 +1520,188 @@ FILLER(sys_getsockopt_x, true) {
return bpf_push_u32_to_ring(data, optlen);
}

static __always_inline int f_sys_send_e_common(struct filler_data *data, int fd) {
unsigned long val;
FILLER(sys_send_e, true) {
int res;

/*
* fd
*/
res = bpf_push_s64_to_ring(data, (int64_t)fd);
/* Parameter 1: fd (type: PT_FD) */
int64_t fd = (int64_t)(int32_t)bpf_syscall_get_argument(data, 0);
res = bpf_push_s64_to_ring(data, fd);
CHECK_RES(res);

/*
* size
*/
val = bpf_syscall_get_argument(data, 2);
res = bpf_push_u32_to_ring(data, val);

return res;
/* Parameter 2: size (type: PT_UINT32) */
uint32_t size = (uint32_t)bpf_syscall_get_argument(data, 2);
return bpf_push_u32_to_ring(data, size);
}

FILLER(sys_send_e, true) {
/*
* Push the common params to the ring
FILLER(sys_send_x, true) {
/* Parameter 1: res (type: PT_ERRNO) */
long retval = bpf_syscall_get_retval(data->ctx);
int res = bpf_push_s64_to_ring(data, retval);
CHECK_RES(res);

/* Extract fd and size syscall parameters */
int64_t fd = (int64_t)(int32_t)bpf_syscall_get_argument(data, 0);
uint32_t size = (uint32_t)bpf_syscall_get_argument(data, 2);

/* Parameter 2: data (type: PT_BYTEBUF) */
/* If the syscall doesn't fail we use the return value as `size`
* otherwise we need to rely on the syscall parameter provided by the user.
*/
int fd = bpf_syscall_get_argument(data, 0);
return f_sys_send_e_common(data, fd);
unsigned long sent_data_pointer = bpf_syscall_get_argument(data, 1);
unsigned long bytes_to_read = retval > 0 ? retval : size;
data->fd = fd;
res = __bpf_val_to_ring(data, sent_data_pointer, bytes_to_read, PT_BYTEBUF, -1, true, USER);
CHECK_RES(res);

/* Parameter 3: fd (type: PT_FD) */
res = bpf_push_s64_to_ring(data, fd);
CHECK_RES(res);

/* Parameter 4: size (type: PT_UINT32) */
res = bpf_push_u32_to_ring(data, size);
CHECK_RES(res);

if(retval < 0) {
/* Parameter 5: tuple (type: PT_SOCKTUPLE) */
return bpf_push_empty_param(data);
}

/* Convert the fd into socket endpoint information */
uint16_t tuple_size = bpf_fd_to_socktuple(data,
fd,
NULL,
0,
false,
false,
data->tmp_scratch + sizeof(struct sockaddr_storage));

/* Parameter 5: tuple (type: PT_SOCKTUPLE) */
data->curarg_already_on_frame = true;
return bpf_val_to_ring_len(data, 0, tuple_size);
}

FILLER(sys_sendto_e, true) {
struct sockaddr __user *usrsockaddr;
unsigned long val;
long size = 0;
int err = 0;
int res;
int fd;

/*
* Push the common params to the ring
*/
fd = bpf_syscall_get_argument(data, 0);
res = f_sys_send_e_common(data, fd);
/* Parameter 1: fd (type: PT_FD) */
int64_t fd = (int64_t)(int32_t)bpf_syscall_get_argument(data, 0);
res = bpf_push_s64_to_ring(data, fd);
CHECK_RES(res);

/*
* Get the address
*/
val = bpf_syscall_get_argument(data, 4);
usrsockaddr = (struct sockaddr __user *)val;

/*
* Get the address len
*/
val = bpf_syscall_get_argument(data, 5);
/* Parameter 2: size (type: PT_UINT32) */
uint32_t size = (uint32_t)bpf_syscall_get_argument(data, 2);
res = bpf_push_u32_to_ring(data, size);
CHECK_RES(res);

if(usrsockaddr && val != 0) {
/*
* Copy the address
*/
err = bpf_addr_to_kernel(usrsockaddr, val, (struct sockaddr *)data->tmp_scratch);
if(err >= 0) {
/*
* Convert the fd into socket endpoint information
*/
size = bpf_fd_to_socktuple(data,
fd,
(struct sockaddr *)data->tmp_scratch,
val,
true,
false,
data->tmp_scratch + sizeof(struct sockaddr_storage));
/* The following parameters are populated if we are able to retrieve address information from
* syscall parameters */
struct sockaddr *ksockaddr = NULL;
unsigned long sockaddr_len = 0;
bool use_sockaddr = false;

/* Get the address */
struct sockaddr __user *usrsockaddr =
(struct sockaddr __user *)bpf_syscall_get_argument(data, 4);

/* Get the address len */
unsigned long usrsockaddr_len = bpf_syscall_get_argument(data, 5);

if(usrsockaddr != NULL && usrsockaddr_len != 0) {
/* Copy the address into kernel memory */
res = bpf_addr_to_kernel(usrsockaddr,
usrsockaddr_len,
(struct sockaddr *)data->tmp_scratch);
if(likely(res >= 0)) {
ksockaddr = (struct sockaddr *)data->tmp_scratch;
sockaddr_len = usrsockaddr_len;
use_sockaddr = true;
}
}

/*
* Copy the endpoint info into the ring
*/
data->curarg_already_on_frame = true;
res = bpf_val_to_ring_len(data, 0, size);
/* Convert the fd into socket endpoint information */
uint32_t tuple_size = bpf_fd_to_socktuple(data,
fd,
ksockaddr,
sockaddr_len,
use_sockaddr,
false,
data->tmp_scratch + sizeof(struct sockaddr_storage));

return res;
/* Parameter 3: tuple (type: PT_SOCKTUPLE) */
data->curarg_already_on_frame = true;
return bpf_val_to_ring_len(data, 0, tuple_size);
}

FILLER(sys_send_x, true) {
FILLER(sys_sendto_x, true) {
/* Parameter 1: res (type: PT_ERRNO) */
long retval = bpf_syscall_get_retval(data->ctx);
int res = bpf_push_s64_to_ring(data, retval);
CHECK_RES(res);

/* Extract fd and size syscall parameters */
int64_t fd = (int64_t)(int32_t)bpf_syscall_get_argument(data, 0);
uint32_t size = (uint32_t)bpf_syscall_get_argument(data, 2);

/* Parameter 2: data (type: PT_BYTEBUF) */
/* If the syscall doesn't fail we use the return value as `size`
* otherwise we need to rely on the syscall parameter provided by the user.
*/
unsigned long bytes_to_read = retval > 0 ? retval : bpf_syscall_get_argument(data, 2);
unsigned long sent_data_pointer = bpf_syscall_get_argument(data, 1);
data->fd = bpf_syscall_get_argument(data, 0);
return __bpf_val_to_ring(data, sent_data_pointer, bytes_to_read, PT_BYTEBUF, -1, true, USER);
unsigned long bytes_to_read = retval > 0 ? retval : size;
data->fd = fd;
res = __bpf_val_to_ring(data, sent_data_pointer, bytes_to_read, PT_BYTEBUF, -1, true, USER);
CHECK_RES(res);

/* Parameter 3: fd (type: PT_FD) */
res = bpf_push_s64_to_ring(data, fd);
CHECK_RES(res);

/* Parameter 4: size (type: PT_UINT32) */
res = bpf_push_u32_to_ring(data, size);
CHECK_RES(res);

if(retval < 0) {
/* Parameter 5: tuple (type: PT_SOCKTUPLE) */
return bpf_push_empty_param(data);
}

/* The following parameters are populated if we are able to retrieve address information from
* syscall parameters */
struct sockaddr *ksockaddr = NULL;
unsigned long sockaddr_len = 0;
bool use_sockaddr = false;

/* Get the address */
struct sockaddr __user *usrsockaddr =
(struct sockaddr __user *)bpf_syscall_get_argument(data, 4);

/* Get the address len */
unsigned long usrsockaddr_len = bpf_syscall_get_argument(data, 5);

if(usrsockaddr != NULL && usrsockaddr_len != 0) {
/* Copy the address into kernel memory */
res = bpf_addr_to_kernel(usrsockaddr,
usrsockaddr_len,
(struct sockaddr *)data->tmp_scratch);
if(likely(res >= 0)) {
ksockaddr = (struct sockaddr *)data->tmp_scratch;
sockaddr_len = usrsockaddr_len;
use_sockaddr = true;
}
}

/* Convert the fd into socket endpoint information */
uint32_t tuple_size = bpf_fd_to_socktuple(data,
fd,
ksockaddr,
sockaddr_len,
use_sockaddr,
false,
data->tmp_scratch + sizeof(struct sockaddr_storage));

/* Parameter 5: tuple (type: PT_SOCKTUPLE) */
data->curarg_already_on_frame = true;
return bpf_val_to_ring_len(data, 0, tuple_size);
}

FILLER(sys_execve_e, true) {
Expand Down
26 changes: 18 additions & 8 deletions driver/event_table.c
Original file line number Diff line number Diff line change
Expand Up @@ -216,26 +216,36 @@ const struct ppm_event_info g_event_info[] = {
{"queuepct", PT_UINT8, PF_DEC}}},
[PPME_SOCKET_SEND_E] = {"send",
EC_IO_WRITE | EC_SYSCALL,
EF_USES_FD | EF_WRITES_TO_FD,
EF_USES_FD | EF_WRITES_TO_FD | EF_TMP_CONVERTER_MANAGED,
2,
{{"fd", PT_FD, PF_DEC}, {"size", PT_UINT32, PF_DEC}}},
[PPME_SOCKET_SEND_X] = {"send",
EC_IO_WRITE | EC_SYSCALL,
EF_USES_FD | EF_WRITES_TO_FD,
2,
{{"res", PT_ERRNO, PF_DEC}, {"data", PT_BYTEBUF, PF_NA}}},
EF_USES_FD | EF_WRITES_TO_FD | EF_TMP_CONVERTER_MANAGED,
5,
{{"res", PT_ERRNO, PF_DEC},
{"data", PT_BYTEBUF, PF_NA},
{"fd", PT_FD, PF_DEC},
{"size", PT_UINT32, PF_DEC},
{"tuple", PT_SOCKTUPLE, PF_NA}}},
[PPME_SOCKET_SENDTO_E] = {"sendto",
EC_IO_WRITE | EC_SYSCALL,
EF_USES_FD | EF_WRITES_TO_FD | EF_MODIFIES_STATE,
EF_USES_FD | EF_WRITES_TO_FD | EF_MODIFIES_STATE |
EF_TMP_CONVERTER_MANAGED,
3,
{{"fd", PT_FD, PF_DEC},
{"size", PT_UINT32, PF_DEC},
{"tuple", PT_SOCKTUPLE, PF_NA}}},
[PPME_SOCKET_SENDTO_X] = {"sendto",
EC_IO_WRITE | EC_SYSCALL,
EF_USES_FD | EF_WRITES_TO_FD | EF_MODIFIES_STATE,
2,
{{"res", PT_ERRNO, PF_DEC}, {"data", PT_BYTEBUF, PF_NA}}},
EF_USES_FD | EF_WRITES_TO_FD | EF_MODIFIES_STATE |
EF_TMP_CONVERTER_MANAGED,
5,
{{"res", PT_ERRNO, PF_DEC},
{"data", PT_BYTEBUF, PF_NA},
{"fd", PT_FD, PF_DEC},
{"size", PT_UINT32, PF_DEC},
{"tuple", PT_SOCKTUPLE, PF_NA}}},
[PPME_SOCKET_RECV_E] = {"recv",
EC_IO_READ | EC_SYSCALL,
EF_USES_FD | EF_READS_FROM_FD,
Expand Down
2 changes: 1 addition & 1 deletion driver/fillers_table.c
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ const struct ppm_event_entry g_ppm_events[PPM_EVENT_MAX] = {
[PPME_SOCKET_SEND_E] = {FILLER_REF(sys_send_e)},
[PPME_SOCKET_SEND_X] = {FILLER_REF(sys_send_x)},
[PPME_SOCKET_SENDTO_E] = {FILLER_REF(sys_sendto_e)},
[PPME_SOCKET_SENDTO_X] = {FILLER_REF(sys_send_x)},
[PPME_SOCKET_SENDTO_X] = {FILLER_REF(sys_sendto_x)},
[PPME_SOCKET_RECV_E] = {FILLER_REF(sys_autofill), 2, APT_SOCK, {{0}, {2}}},
[PPME_SOCKET_RECV_X] = {FILLER_REF(sys_recv_x)},
[PPME_SOCKET_RECVFROM_E] = {FILLER_REF(sys_recvfrom_e)},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ int BPF_PROG(send_e, struct pt_regs *regs, long id) {
/*=============================== COLLECT PARAMETERS ===========================*/

/* Parameter 1: fd (type: PT_FD) */
int32_t fd = (int32_t)args[0];
ringbuf__store_s64(&ringbuf, (int64_t)fd);
int64_t fd = (int32_t)args[0];
ringbuf__store_s64(&ringbuf, fd);

/* Parameter 2: size (type: PT_UINT32) */
uint32_t size = (uint32_t)args[2];
Expand Down Expand Up @@ -60,10 +60,15 @@ int BPF_PROG(send_x, struct pt_regs *regs, long ret) {
auxmap__store_s64_param(auxmap, ret);

/* Collect parameters at the beginning to manage socketcalls */
unsigned long args[3] = {0};
extract__network_args(args, 3, regs);
unsigned long args[5] = {0};
extract__network_args(args, 5, regs);

/* Extract size syscall parameter */
uint32_t size = (uint32_t)args[2];

int64_t bytes_to_read = ret > 0 ? ret : args[2];
/* If the syscall doesn't fail we use the return value as `size`
* otherwise we need to rely on the syscall parameter provided by the user */
int64_t bytes_to_read = ret > 0 ? ret : (int64_t)size;
uint16_t snaplen = maps__get_snaplen();
apply_dynamic_snaplen(regs, &snaplen, false, PPME_SOCKET_SEND_X);
if((int64_t)snaplen > bytes_to_read) {
Expand All @@ -74,6 +79,23 @@ int BPF_PROG(send_x, struct pt_regs *regs, long ret) {
unsigned long sent_data_pointer = args[1];
auxmap__store_bytebuf_param(auxmap, sent_data_pointer, snaplen, USER);

/* Parameter 3: fd (type: PT_FD) */
int64_t fd = (int32_t)args[0];
auxmap__store_s64_param(auxmap, fd);

/* Parameter 4: size (type: PT_UINT32) */
auxmap__store_u32_param(auxmap, size);

/* Parameter 5: tuple (type: PT_SOCKTUPLE) */
if(ret >= 0) {
struct sockaddr *usrsockaddr = (struct sockaddr *)args[4];
/* Notice: the following will push an empty parameter if
* something goes wrong (e.g.: fd not valid) */
auxmap__store_socktuple_param(auxmap, fd, OUTBOUND, NULL);
} else {
auxmap__store_empty_param(auxmap);
}

/*=============================== COLLECT PARAMETERS ===========================*/

auxmap__finalize_event_header(auxmap);
Expand Down
Loading

0 comments on commit d11578f

Please sign in to comment.