Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

new: extend SEND_X and SENDTO_X #2221

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion driver/SCHEMA_VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
3.6.0
3.7.0
210 changes: 144 additions & 66 deletions driver/bpf/fillers.h
Original file line number Diff line number Diff line change
Expand Up @@ -1529,101 +1529,179 @@ 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
*/
int fd = bpf_syscall_get_argument(data, 0);
return f_sys_send_e_common(data, fd);
}
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);

FILLER(sys_sendto_e, true) {
struct sockaddr __user *usrsockaddr;
unsigned long val;
long size = 0;
int err = 0;
int res;
int fd;
/* 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);

/*
* Push the common params to the ring
/* 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.
*/
fd = bpf_syscall_get_argument(data, 0);
res = 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);

/*
* Get the address
*/
val = bpf_syscall_get_argument(data, 4);
usrsockaddr = (struct sockaddr __user *)val;
/* Parameter 3: fd (type: PT_FD) */
res = bpf_push_s64_to_ring(data, fd);
CHECK_RES(res);

/*
* Get the address len
*/
val = bpf_syscall_get_argument(data, 5);
/* Parameter 4: size (type: PT_UINT32) */
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));
}
if(retval < 0) {
/* Parameter 5: tuple (type: PT_SOCKTUPLE) */
return bpf_push_empty_param(data);
}

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

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

return res;
FILLER(sys_sendto_e, true) {
/* Parameter 1: fd (type: PT_FD) */
int64_t fd = (int64_t)(int32_t)bpf_syscall_get_argument(data, 0);
int res = bpf_push_s64_to_ring(data, fd);
CHECK_RES(res);

/* 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);

/* 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);

/* Evaluate socktuple, leveraging the user-provided sockaddr if possible */
char *tmp_area = data->tmp_scratch + sizeof(struct sockaddr_storage);
uint32_t tuple_size = 0;
bool tuple_extracted = false;
if(usrsockaddr != NULL && usrsockaddr_len != 0) {
/* Copy the address into kernel memory */
struct sockaddr *ksockaddr = (struct sockaddr *)data->tmp_scratch;
res = bpf_addr_to_kernel(usrsockaddr, usrsockaddr_len, ksockaddr);
if(likely(res >= 0)) {
/* Convert the fd into socket endpoint information */
tuple_size = bpf_fd_to_socktuple(data,
fd,
ksockaddr,
usrsockaddr_len,
true,
false,
tmp_area);
tuple_extracted = true;
}
}

if(!tuple_extracted) {
/* Try to extract socktuple from kernel */
tuple_size = bpf_fd_to_socktuple(data, fd, NULL, 0, false, false, tmp_area);
}

/* 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);
}

/* 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);

/* Evaluate socktuple, leveraging the user-provided sockaddr if possible */
char *tmp_area = data->tmp_scratch + sizeof(struct sockaddr_storage);
uint32_t tuple_size = 0;
bool tuple_extracted = false;
if(usrsockaddr != NULL && usrsockaddr_len != 0) {
/* Copy the address into kernel memory */
struct sockaddr *ksockaddr = (struct sockaddr *)data->tmp_scratch;
res = bpf_addr_to_kernel(usrsockaddr, usrsockaddr_len, ksockaddr);
if(likely(res >= 0)) {
/* Convert the fd into socket endpoint information */
tuple_size = bpf_fd_to_socktuple(data,
fd,
ksockaddr,
usrsockaddr_len,
true,
false,
tmp_area);
tuple_extracted = true;
}
}

if(!tuple_extracted) {
/* Try to extract socktuple from kernel */
tuple_size = bpf_fd_to_socktuple(data, fd, NULL, 0, false, false, tmp_area);
}

/* 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 @@ -219,26 +219,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 @@ -29,8 +29,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 @@ -62,16 +62,23 @@ 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);

dynamic_snaplen_args snaplen_args = {
.only_port_range = false,
.evt_type = PPME_SOCKET_SEND_X,
};
int64_t bytes_to_read = ret > 0 ? ret : args[2];
uint16_t snaplen = maps__get_snaplen();
apply_dynamic_snaplen(regs, &snaplen, &snaplen_args);

/* Extract size syscall parameter */
uint32_t size = (uint32_t)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;

if((int64_t)snaplen > bytes_to_read) {
snaplen = bytes_to_read;
}
Expand All @@ -80,6 +87,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
Loading