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

Add arguments for sendmmsg and recvmmsg #2027

Open
wants to merge 7 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 @@
2.23.0
2.24.0
233 changes: 233 additions & 0 deletions driver/bpf/fillers.h
Original file line number Diff line number Diff line change
Expand Up @@ -4253,6 +4253,147 @@ FILLER(sys_recvmsg_x_2, true) {
return res;
}

FILLER(sys_recvmmsg_x, true) {
const struct iovec *iov;
struct mmsghdr mmh;
unsigned long iovcnt;
unsigned long val;
int res;
int fd = bpf_syscall_get_argument(data, 0);

/* Parameter 1: res (type: PT_ERRNO) */
long retval = bpf_syscall_get_retval(data->ctx);

/* If the syscall fails we are not able to collect reliable params
* so we return empty ones.
*/
if(retval < 0) {
res = bpf_push_s64_to_ring(data, retval);
CHECK_RES(res);

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

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

/* Parameter 4: data (type: PT_BYTEBUF) */
res = bpf_push_empty_param(data);
CHECK_RES(res);

/* Parameter 5: tuple (type: PT_SOCKTUPLE) */
res = bpf_push_empty_param(data);
CHECK_RES(res);

/* Parameter 6: msg_control (type: PT_BYTEBUF) */
return bpf_push_empty_param(data);
}

/*
* Retrieve the message header
*/
val = bpf_syscall_get_argument(data, 1);
if(bpf_probe_read_user(&mmh, sizeof(mmh), (void *)val))
return PPM_FAILURE_INVALID_USER_MEMORY;

Molter73 marked this conversation as resolved.
Show resolved Hide resolved
/* Parameter 1: res (type: PT_ERRNO) */
res = bpf_push_s64_to_ring(data, mmh.msg_len);
CHECK_RES(res);

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

/*
* data and size
*/
iov = (const struct iovec *)mmh.msg_hdr.msg_iov;
iovcnt = mmh.msg_hdr.msg_iovlen;

/* Parameter 3: size (type: PT_UINT32) */
/* Parameter 4: data (type: PT_BYTEBUF) */
res = bpf_parse_readv_writev_bufs(data, iov, iovcnt, mmh.msg_len, PRB_FLAG_PUSH_ALL);
CHECK_RES(res);

bpf_tail_call(data->ctx, &tail_map, PPM_FILLER_sys_recvmmsg_x_2);
bpf_printk("Can't tail call f_sys_recvmsg_x_2 filler\n");
return PPM_FAILURE_BUG;
}

FILLER(sys_recvmmsg_x_2, true) {
struct sockaddr *usrsockaddr;
struct mmsghdr mmh;
unsigned long val;
uint16_t size = 0;
long retval;
int addrlen;
int res;
int fd;

retval = bpf_syscall_get_retval(data->ctx);

/*
* tuple and msg_control
*/

/*
* Retrieve the message header
*/
val = bpf_syscall_get_argument(data, 1);
if(bpf_probe_read_user(&mmh, sizeof(mmh), (void *)val))
return PPM_FAILURE_INVALID_USER_MEMORY;

/*
* Get the address
*/
usrsockaddr = (struct sockaddr *)mmh.msg_hdr.msg_name;
addrlen = mmh.msg_hdr.msg_namelen;

if(usrsockaddr && addrlen != 0) {
/*
* Copy the address
*/
res = bpf_addr_to_kernel(usrsockaddr, addrlen, (struct sockaddr *)data->tmp_scratch);

if(res >= 0) {
fd = bpf_syscall_get_argument(data, 0);

/*
* Convert the fd into socket endpoint information
*/
size = bpf_fd_to_socktuple(data,
fd,
(struct sockaddr *)data->tmp_scratch,
addrlen,
true,
true,
data->tmp_scratch + sizeof(struct sockaddr_storage));
}
}

/* Parameter 5: tuple (type: PT_SOCKTUPLE) */
data->curarg_already_on_frame = true;
res = __bpf_val_to_ring(data, 0, size, PT_SOCKTUPLE, -1, false, KERNEL);
CHECK_RES(res);

/* Parameter 6: msg_control (type: PT_BYTEBUF) */
if(mmh.msg_hdr.msg_control != NULL) {
res = __bpf_val_to_ring(data,
(unsigned long)mmh.msg_hdr.msg_control,
mmh.msg_hdr.msg_controllen,
PT_BYTEBUF,
-1,
false,
USER);
} else {
res = bpf_push_empty_param(data);
}

return res;
}

FILLER(sys_sendmsg_e, true) {
struct sockaddr *usrsockaddr;
const struct iovec *iov;
Expand Down Expand Up @@ -4346,6 +4487,98 @@ FILLER(sys_sendmsg_x, true) {
return res;
}

FILLER(sys_sendmmsg_x, true) {
struct sockaddr *usrsockaddr;
struct mmsghdr mmh = {0};
struct mmsghdr *mmh_ptr;
unsigned long vlen;
unsigned long val;
uint16_t size = 0;
int addrlen;
int err = 0;
int res;
long retval = bpf_syscall_get_retval(data->ctx);
int fd = bpf_syscall_get_argument(data, 0);

if(retval < 0) {
/* Parameter 1: res (type: PT_ERRNO) */
res = bpf_push_s64_to_ring(data, retval);
CHECK_RES(res);

/* Parameter 2: fd (type: PT_BYTEBUF) */
res = bpf_push_s64_to_ring(data, fd);
CHECK_RES(res);

/* Parameter 3: size (type: PT_UINT32) */
bpf_push_u32_to_ring(data, 0);
CHECK_RES(res);

/* Parameter 4: data (type: PT_BYTEBUF) */
bpf_push_empty_param(data);
CHECK_RES(res);

/* Parameter 5: tuple (type: PT_SOCKTUPLE) */
return bpf_push_empty_param(data);
}

mmh_ptr = (struct mmsghdr *)bpf_syscall_get_argument(data, 1);
vlen = bpf_syscall_get_argument(data, 2);

/* Retrieve the message header */
if(bpf_probe_read_user(&mmh, sizeof(mmh), (void *)(mmh_ptr))) {
Andreagit97 marked this conversation as resolved.
Show resolved Hide resolved
return PPM_FAILURE_INVALID_USER_MEMORY;
}

/* Parameter 1: res (type: PT_ERRNO) */
res = bpf_push_s64_to_ring(data, mmh.msg_len);
CHECK_RES(res);

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

/* Parameter 3: size (type: PT_UINT32) */
/* Parameter 4: data (type: PT_BYTEBUF) */
const struct iovec *iov = (const struct iovec *)mmh.msg_hdr.msg_iov;
unsigned long iovcnt = mmh.msg_hdr.msg_iovlen;

res = bpf_parse_readv_writev_bufs(data,
iov,
iovcnt,
mmh.msg_len,
PRB_FLAG_PUSH_ALL | PRB_FLAG_IS_WRITE);
CHECK_RES(res);

/* Parameter 5: tuple (type: PT_SOCKTUPLE) */
usrsockaddr = (struct sockaddr *)mmh.msg_hdr.msg_name;
addrlen = mmh.msg_hdr.msg_namelen;

if(usrsockaddr && addrlen != 0) {
/*
* Copy the address
*/
err = bpf_addr_to_kernel(usrsockaddr, addrlen, (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,
addrlen,
true,
false,
data->tmp_scratch + sizeof(struct sockaddr_storage));
}

data->curarg_already_on_frame = true;
res = __bpf_val_to_ring(data, 0, size, PT_SOCKTUPLE, -1, false, KERNEL);
}

return res;
}

FILLER(sys_creat_e, true) {
unsigned long val;
unsigned long mode;
Expand Down
21 changes: 19 additions & 2 deletions driver/event_table.c
Original file line number Diff line number Diff line change
Expand Up @@ -311,7 +311,15 @@ const struct ppm_event_info g_event_info[] = {
2,
{{"res", PT_ERRNO, PF_DEC}, {"data", PT_BYTEBUF, PF_NA}}},
[PPME_SOCKET_SENDMMSG_E] = {"sendmmsg", EC_IO_WRITE | EC_SYSCALL, EF_NONE, 0},
[PPME_SOCKET_SENDMMSG_X] = {"sendmmsg", EC_IO_WRITE | EC_SYSCALL, EF_NONE, 0},
[PPME_SOCKET_SENDMMSG_X] = {"sendmmsg",
EC_IO_WRITE | EC_SYSCALL,
EF_USES_FD | EF_WRITES_TO_FD | EF_MODIFIES_STATE,
5,
{{"res", PT_ERRNO, PF_DEC},
{"fd", PT_FD, PF_DEC},
{"size", PT_UINT32, PF_DEC},
{"data", PT_BYTEBUF, PF_NA},
{"tuple", PT_SOCKTUPLE, PF_NA}}},
[PPME_SOCKET_RECVMSG_E] = {"recvmsg",
EC_IO_READ | EC_SYSCALL,
EF_USES_FD | EF_READS_FROM_FD | EF_MODIFIES_STATE,
Expand All @@ -327,7 +335,16 @@ const struct ppm_event_info g_event_info[] = {
{"tuple", PT_SOCKTUPLE, PF_NA},
{"msgcontrol", PT_BYTEBUF, PF_NA}}},
[PPME_SOCKET_RECVMMSG_E] = {"recvmmsg", EC_IO_READ | EC_SYSCALL, EF_NONE, 0},
[PPME_SOCKET_RECVMMSG_X] = {"recvmmsg", EC_IO_READ | EC_SYSCALL, EF_NONE, 0},
[PPME_SOCKET_RECVMMSG_X] = {"recvmmsg",
EC_IO_READ | EC_SYSCALL,
EF_USES_FD | EF_READS_FROM_FD | EF_MODIFIES_STATE,
6,
{{"res", PT_ERRNO, PF_DEC},
{"fd", PT_FD, PF_DEC},
{"size", PT_UINT32, PF_DEC},
{"data", PT_BYTEBUF, PF_NA},
{"tuple", PT_SOCKTUPLE, PF_NA},
{"msgcontrol", PT_BYTEBUF, PF_NA}}},
[PPME_SOCKET_ACCEPT4_E] = {"accept",
EC_NET | EC_SYSCALL,
EF_CREATES_FD | EF_MODIFIES_STATE | EF_OLD_VERSION,
Expand Down
4 changes: 2 additions & 2 deletions driver/fillers_table.c
Original file line number Diff line number Diff line change
Expand Up @@ -67,11 +67,11 @@ const struct ppm_event_entry g_ppm_events[PPM_EVENT_MAX] = {
[PPME_SOCKET_SENDMSG_E] = {FILLER_REF(sys_sendmsg_e)},
[PPME_SOCKET_SENDMSG_X] = {FILLER_REF(sys_sendmsg_x)},
[PPME_SOCKET_SENDMMSG_E] = {FILLER_REF(sys_empty)},
[PPME_SOCKET_SENDMMSG_X] = {FILLER_REF(sys_empty)},
[PPME_SOCKET_SENDMMSG_X] = {FILLER_REF(sys_sendmmsg_x)},
[PPME_SOCKET_RECVMSG_E] = {FILLER_REF(sys_recvmsg_e)},
[PPME_SOCKET_RECVMSG_X] = {FILLER_REF(sys_recvmsg_x)},
[PPME_SOCKET_RECVMMSG_E] = {FILLER_REF(sys_empty)},
[PPME_SOCKET_RECVMMSG_X] = {FILLER_REF(sys_empty)},
[PPME_SOCKET_RECVMMSG_X] = {FILLER_REF(sys_recvmmsg_x)},
[PPME_SYSCALL_CREAT_E] = {FILLER_REF(sys_creat_e)},
[PPME_SYSCALL_CREAT_X] = {FILLER_REF(sys_creat_x)},
[PPME_SYSCALL_PIPE_E] = {FILLER_REF(sys_empty)},
Expand Down
35 changes: 35 additions & 0 deletions driver/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,10 @@ struct event_data_t {
struct {
struct pt_regs *regs;
long id;
struct {
long index;
long count;
} mmsg;
} syscall_data;

struct {
Expand Down Expand Up @@ -1788,6 +1792,10 @@ static int record_event_consumer(struct ppm_consumer_t *consumer,
if(unlikely(preload_params(&args, event_datap->extract_socketcall_params) == -1)) {
return res;
}

if(event_type == PPME_SOCKET_SENDMMSG_X || event_type == PPME_SOCKET_RECVMMSG_X) {
args.mmsg.index = event_datap->event_info.syscall_data.mmsg.index;
}
}

if(event_type != PPME_DROP_E && event_type != PPME_DROP_X) {
Expand Down Expand Up @@ -2006,6 +2014,12 @@ static int record_event_consumer(struct ppm_consumer_t *consumer,
ASSERT(0);
}
}

if(event_datap->category == PPMC_SYSCALL &&
(event_type == PPME_SOCKET_SENDMMSG_X || event_type == PPME_SOCKET_RECVMMSG_X)) {
// Communicate the number of total messages to the caller
event_datap->event_info.syscall_data.mmsg.count = args.mmsg.count;
}
}

if(likely(!drop)) {
Expand Down Expand Up @@ -2317,6 +2331,27 @@ TRACEPOINT_PROBE(syscall_exit_probe, struct pt_regs *regs, long ret) {
return;
#endif

if(event_pair->exit_event_type == PPME_SOCKET_SENDMMSG_X ||
event_pair->exit_event_type == PPME_SOCKET_RECVMMSG_X) {
int i;

// We don't know how many messages the syscall actually handled until
// we call the filler the first time, so we set it to the max for the
// first call.
//
// If the syscall failed, the count value will be negative, so we
// immediately exit after sending a failure event.
event_data.event_info.syscall_data.mmsg.count = 1024;

for(i = 0; i < event_data.event_info.syscall_data.mmsg.count; i++) {
event_data.event_info.syscall_data.mmsg.index = i;
record_event_all_consumers(event_pair->exit_event_type,
event_pair->flags,
&event_data,
KMOD_PROG_SYS_EXIT);
}
}

if(event_pair->flags & UF_USED)
record_event_all_consumers(event_pair->exit_event_type,
event_pair->flags,
Expand Down
Loading
Loading