Skip to content

Commit

Permalink
feat(kmod): add arguments to recvmmsg and sendmmsg
Browse files Browse the repository at this point in the history
The current implementation is not complete, only the first message is
processed. In order to allow for multiple messages to be processed the
kmod needs to allow for multiple headers to be added to the ringbuffer
from the filler.

Signed-off-by: Mauro Ezequiel Moltrasio <mmoltras@redhat.com>
  • Loading branch information
Molter73 committed Aug 28, 2024
1 parent 269f16a commit 9860c46
Show file tree
Hide file tree
Showing 2 changed files with 363 additions and 12 deletions.
362 changes: 362 additions & 0 deletions driver/ppm_fillers.c
Original file line number Diff line number Diff line change
Expand Up @@ -2798,6 +2798,198 @@ int f_sys_sendmsg_x(struct event_filler_arguments *args)
return add_sentinel(args);
}

int f_sys_sendmmsg_e(struct event_filler_arguments *args)
{
int res;
unsigned long val;
struct mmsghdr mmh;
char *targetbuf = args->str_storage;
const struct iovec __user *iov;
#ifdef CONFIG_COMPAT
const struct compat_iovec __user *compat_iov;
struct compat_mmsghdr compat_mmh;
#endif
unsigned long iovcnt;
int fd;
uint16_t size = 0;
int addrlen;
int err = 0;
struct sockaddr __user *usrsockaddr;
struct sockaddr_storage address;

/*
* fd
*/
syscall_get_arguments_deprecated(args, 0, 1, &val);

fd = val;
res = val_to_ring(args, val, 0, false, 0);
CHECK_RES(res);

/*
* Retrieve the message header
*/
syscall_get_arguments_deprecated(args, 1, 1, &val);

#ifdef CONFIG_COMPAT
if (!args->compat) {
#endif
if (unlikely(ppm_copy_from_user(&mmh, (const void __user *)val, sizeof(mmh))))
return PPM_FAILURE_INVALID_USER_MEMORY;

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

res = parse_readv_writev_bufs(args, iov, iovcnt, args->consumer->snaplen, PRB_FLAG_PUSH_SIZE | PRB_FLAG_IS_WRITE);


CHECK_RES(res);

/*
* tuple
*/
usrsockaddr = (struct sockaddr __user *)mmh.msg_hdr.msg_name;
addrlen = mmh.msg_hdr.msg_namelen;
#ifdef CONFIG_COMPAT
} else {
if (unlikely(ppm_copy_from_user(&compat_mmh, (const void __user *)compat_ptr(val), sizeof(compat_mmh))))
return PPM_FAILURE_INVALID_USER_MEMORY;

/*
* size
*/
compat_iov = (const struct compat_iovec __user *)compat_ptr(compat_mmh.msg_hdr.msg_iov);
iovcnt = compat_mmh.msg_hdr.msg_iovlen;

res = compat_parse_readv_writev_bufs(args, compat_iov, iovcnt, args->consumer->snaplen, PRB_FLAG_PUSH_SIZE | PRB_FLAG_IS_WRITE);


CHECK_RES(res);

/*
* tuple
*/
usrsockaddr = (struct sockaddr __user *)compat_ptr(compat_mmh.msg_hdr.msg_name);
addrlen = compat_mmh.msg_hdr.msg_namelen;
}
#endif

if (usrsockaddr != NULL && addrlen != 0) {
/*
* Copy the address
*/
err = addr_to_kernel(usrsockaddr, addrlen, (struct sockaddr *)&address);
if (likely(err >= 0)) {
/*
* Convert the fd into socket endpoint information
*/
size = fd_to_socktuple(fd,
(struct sockaddr *)&address,
addrlen,
true,
false,
targetbuf,
STR_STORAGE_SIZE);
}
}

/* Copy the endpoint info into the ring */
res = val_to_ring(args,
(uint64_t)(unsigned long)targetbuf,
size,
false,
0);
CHECK_RES(res);

return add_sentinel(args);
}

int f_sys_sendmmsg_x(struct event_filler_arguments *args)
{
int res;
unsigned long val;
long retval;
const struct iovec __user *iov;
#ifdef CONFIG_COMPAT
const struct compat_iovec __user *compat_iov;
struct compat_mmsghdr compat_mmh;
#endif
unsigned long iovcnt;

struct mmsghdr mmh;

retval = syscall_get_return_value(current, args->regs);

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

/* Parameter 2: data (type: PT_BYTEBUF) */
res = push_empty_param(args);
CHECK_RES(res);

return add_sentinel(args);
}

/*
* Retrieve the message header
*/
syscall_get_arguments_deprecated(args, 1, 1, &val);

#ifdef CONFIG_COMPAT
if (!args->compat) {
#endif
if (unlikely(ppm_copy_from_user(&mmh, (const void __user *)val, sizeof(mmh))))
{
res = val_to_ring(args, retval, 0, false, 0);
CHECK_RES(res);

res = val_to_ring(args, 0, 0, false, 0);
CHECK_RES(res);
return add_sentinel(args);
}

/* Parameter 1: res (type: PT_ERRNO) */
res = val_to_ring(args, mmh.msg_len, 0, false, 0);
CHECK_RES(res);

iov = (const struct iovec __user *)mmh.msg_hdr.msg_iov;
iovcnt = mmh.msg_hdr.msg_iovlen;

/* Parameter 2: data (type: PT_BYTEBUF) */
res = parse_readv_writev_bufs(args, iov, iovcnt, args->consumer->snaplen, PRB_FLAG_PUSH_DATA | PRB_FLAG_IS_WRITE);
CHECK_RES(res);
#ifdef CONFIG_COMPAT
} else {
if (unlikely(ppm_copy_from_user(&compat_mmh, (const void __user *)compat_ptr(val), sizeof(compat_mmh))))
{
res = val_to_ring(args, retval, 0, false, 0);
CHECK_RES(res);

res = val_to_ring(args, 0, 0, false, 0);
CHECK_RES(res);
return add_sentinel(args);
}

compat_iov = (const struct compat_iovec __user *)compat_ptr(compat_mmh.msg_hdr.msg_iov);
iovcnt = compat_mmh.msg_hdr.msg_iovlen;

/* Parameter 2: data (type: PT_BYTEBUF) */
res = compat_parse_readv_writev_bufs(args, compat_iov, iovcnt, args->consumer->snaplen, PRB_FLAG_PUSH_DATA | PRB_FLAG_IS_WRITE);
CHECK_RES(res);
}
#endif

return add_sentinel(args);
}

int f_sys_listen_e(struct event_filler_arguments *args)
{
unsigned long val = 0;
Expand Down Expand Up @@ -2985,6 +3177,176 @@ int f_sys_recvmsg_x(struct event_filler_arguments *args)
return add_sentinel(args);
}

int f_sys_recvmmsg_e(struct event_filler_arguments *args)
{
unsigned long val = 0;
int res = 0;
int32_t fd = 0;

/* Parameter 1: fd (type: PT_FD)*/
syscall_get_arguments_deprecated(args, 0, 1, &val);
fd = (int32_t)val;
res = val_to_ring(args, (int64_t)fd, 0, false, 0);
CHECK_RES(res);

return add_sentinel(args);
}

int f_sys_recvmmsg_x(struct event_filler_arguments *args)
{
int res;
unsigned long val;
int64_t retval;
const struct iovec __user *iov;
#ifdef CONFIG_COMPAT
const struct compat_iovec __user *compat_iov;
struct compat_mmsghdr compat_mmh;
#endif
unsigned long iovcnt;
struct mmsghdr mmh;
char *targetbuf = args->str_storage;
int fd;
struct sockaddr __user *usrsockaddr;
struct sockaddr_storage address;
uint16_t size = 0;
int addrlen;
int err = 0;

retval = (int64_t)syscall_get_return_value(current, args->regs);

/* If the syscall fails we are not able to collect reliable params
* so we return empty ones.
*/
if(retval < 0)
{
/* Parameter 1: res (type: PT_ERRNO) */
res = val_to_ring(args, retval, 0, false, 0);
CHECK_RES(res);

/* Parameter 2: size (type: PT_UINT32) */
res = val_to_ring(args, 0, 0, false, 0);
CHECK_RES(res);

/* Parameter 3: data (type: PT_BYTEBUF) */
res = push_empty_param(args);
CHECK_RES(res);

/* Parameter 4: tuple (type: PT_SOCKTUPLE) */
res = push_empty_param(args);
CHECK_RES(res);

/* Parameter 5: msg_control (type: PT_BYTEBUF) */
res = push_empty_param(args);
CHECK_RES(res);

return add_sentinel(args);
}

/*
* Retrieve the message header
*/
syscall_get_arguments_deprecated(args, 1, 1, &val);

#ifdef CONFIG_COMPAT
if (!args->compat) {
#endif
if (unlikely(ppm_copy_from_user(&mmh, (const void __user *)val, sizeof(mmh))))
return PPM_FAILURE_INVALID_USER_MEMORY;

/* Parameter 1: res (type: PT_ERRNO) */
res = val_to_ring(args, mmh.msg_len, 0, false, 0);
CHECK_RES(res);

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

res = parse_readv_writev_bufs(args, iov, iovcnt, mmh.msg_len, PRB_FLAG_PUSH_ALL);
#ifdef CONFIG_COMPAT
} else {
if (unlikely(ppm_copy_from_user(&compat_mmh, (const void __user *)compat_ptr(val), sizeof(compat_mmh))))
return PPM_FAILURE_INVALID_USER_MEMORY;

/* Parameter 1: res (type: PT_ERRNO) */
res = val_to_ring(args, compat_mmh.msg_len, 0, false, 0);
CHECK_RES(res);

/*
* data and size
*/
compat_iov = (const struct compat_iovec __user *)compat_ptr(compat_mmh.msg_hdr.msg_iov);
iovcnt = compat_mmh.msg_hdr.msg_iovlen;

res = compat_parse_readv_writev_bufs(args, compat_iov, iovcnt, compat_mmh.msg_len, PRB_FLAG_PUSH_ALL);
}
#endif

CHECK_RES(res);

/*
* tuple
*/
if (retval >= 0) {
/*
* Get the fd
*/
syscall_get_arguments_deprecated(args, 0, 1, &val);
fd = (int)val;

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

if (usrsockaddr != NULL && addrlen != 0) {
/*
* Copy the address
*/
err = addr_to_kernel(usrsockaddr, addrlen, (struct sockaddr *)&address);
if (likely(err >= 0)) {
/*
* Convert the fd into socket endpoint information
*/
size = fd_to_socktuple(fd,
(struct sockaddr *)&address,
addrlen,
true,
true,
targetbuf,
STR_STORAGE_SIZE);
}
}
}

/* Copy the endpoint info into the ring */
res = val_to_ring(args,
(uint64_t)(unsigned long)targetbuf,
size,
false,
0);
CHECK_RES(res);

/*
msg_control: ancillary data.
*/
if (mmh.msg_hdr.msg_control != NULL && mmh.msg_hdr.msg_controllen > 0)
{
res = val_to_ring(args, (uint64_t)mmh.msg_hdr.msg_control, (uint32_t)mmh.msg_hdr.msg_controllen, true, 0);
CHECK_RES(res);
}
else
{
/* pushing empty data */
res = push_empty_param(args);
CHECK_RES(res);
}

return add_sentinel(args);
}

int f_sys_creat_e(struct event_filler_arguments *args)
{
unsigned long val;
Expand Down
13 changes: 1 addition & 12 deletions test/drivers/test_suites/syscall_exit_suite/sendmmsg_x.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -223,18 +223,7 @@ TEST(SyscallExit, sendmmsgXNullIovec)

evt_test->disable_capture();

if(evt_test->is_modern_bpf_engine() || evt_test->is_bpf_engine())
{
evt_test->assert_event_presence();
}
else
{
/* we need to rewrite the logic in old drivers to support this partial collection
* right now we drop the entire event.
*/
evt_test->assert_event_absence();
GTEST_SKIP() << "[SENDMSG_X]: what we receive is correct but we need to reimplement it, see the code" << std::endl;
}
evt_test->assert_event_presence();

if(HasFatalFailure())
{
Expand Down

0 comments on commit 9860c46

Please sign in to comment.