Skip to content

Commit bf66bc2

Browse files
committed
fix(drivers): align and improve connect kernel drivers fillers
The current bpf and kmod's `connect` fillers implementations extract socket tuple information only if the socket file descriptor is greater than or equal to zero: this does not ensure that the file descriptor is valid and that the kernel has the correct amount of information needed to build the socket tuple. On the other side, the modern probe implementation correctly checks the system call return value on the exit program, but doesn't try hard enough to build the socket tuple, as it does not leverage the sockaddr provided by the user. Align all three implementations, checking the system call return value and leveraging the user-provided sockaddr information to build the socket tuple. Signed-off-by: Leonardo Di Giovanna <[email protected]>
1 parent b917815 commit bf66bc2

File tree

6 files changed

+154
-246
lines changed

6 files changed

+154
-246
lines changed

driver/bpf/fillers.h

Lines changed: 64 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -1404,101 +1404,89 @@ FILLER(sys_setrlimit_x, true) {
14041404
}
14051405

14061406
FILLER(sys_connect_e, true) {
1407-
struct sockaddr *usrsockaddr;
1408-
unsigned long val;
1409-
long size = 0;
1410-
long retval;
1411-
int err;
1412-
int res;
1413-
int fd;
1414-
1415-
fd = bpf_syscall_get_argument(data, 0);
1416-
res = bpf_push_s64_to_ring(data, fd);
1407+
/* Parameter 1: fd (type: PT_FD) */
1408+
int64_t fd = (int64_t)(int32_t)bpf_syscall_get_argument(data, 0);
1409+
int res = bpf_push_s64_to_ring(data, fd);
14171410
CHECK_RES(res);
14181411

1419-
if(fd >= 0) {
1420-
usrsockaddr = (struct sockaddr *)bpf_syscall_get_argument(data, 1);
1421-
val = bpf_syscall_get_argument(data, 2);
1412+
/* Get the sockaddr pointer and its length. */
1413+
struct sockaddr __user *usrsockaddr =
1414+
(struct sockaddr __user *)bpf_syscall_get_argument(data, 1);
1415+
unsigned long usrsockaddr_len = bpf_syscall_get_argument(data, 2);
14221416

1423-
if(usrsockaddr && val != 0) {
1424-
/*
1425-
* Copy the address
1426-
*/
1427-
err = bpf_addr_to_kernel(usrsockaddr, val, (struct sockaddr *)data->tmp_scratch);
1428-
if(err >= 0) {
1429-
/*
1430-
* Convert the fd into socket endpoint information
1431-
*/
1432-
size = bpf_pack_addr(data, (struct sockaddr *)data->tmp_scratch, val);
1433-
}
1417+
long addr_size = 0;
1418+
if(usrsockaddr != NULL && usrsockaddr_len != 0) {
1419+
struct sockaddr *ksockaddr = (struct sockaddr *)data->tmp_scratch;
1420+
/* Copy the address into kernel memory. */
1421+
res = bpf_addr_to_kernel(usrsockaddr, usrsockaddr_len, ksockaddr);
1422+
if(likely(res >= 0)) {
1423+
/* Convert the fd into socket endpoint information. */
1424+
addr_size = bpf_pack_addr(data, ksockaddr, usrsockaddr_len);
14341425
}
14351426
}
14361427

1437-
/*
1438-
* Copy the endpoint info into the ring
1439-
*/
1428+
/* Parameter 2: addr (type: PT_SOCKADDR) */
14401429
data->curarg_already_on_frame = true;
1441-
res = bpf_val_to_ring_len(data, 0, size);
1442-
1443-
return res;
1430+
return bpf_val_to_ring_len(data, 0, addr_size);
14441431
}
14451432

14461433
FILLER(sys_connect_x, true) {
1447-
struct sockaddr *usrsockaddr;
1448-
unsigned long val;
1449-
long size = 0;
1450-
long retval;
1451-
int err;
1452-
int res;
1453-
int fd;
1454-
1455-
/*
1456-
* Push the result
1457-
*/
1458-
retval = bpf_syscall_get_retval(data->ctx);
1459-
res = bpf_push_s64_to_ring(data, retval);
1434+
/* Parameter 1: res (type: PT_ERRNO) */
1435+
long retval = bpf_syscall_get_retval(data->ctx);
1436+
int res = bpf_push_s64_to_ring(data, retval);
14601437
CHECK_RES(res);
14611438

1462-
/*
1463-
* Retrieve the fd and push it to the ring.
1464-
* Note that, even if we are in the exit callback, the arguments are still
1465-
* in the stack, and therefore we can consume them.
1466-
*/
1467-
fd = bpf_syscall_get_argument(data, 0);
1468-
if(fd >= 0) {
1469-
usrsockaddr = (struct sockaddr *)bpf_syscall_get_argument(data, 1);
1470-
val = bpf_syscall_get_argument(data, 2);
1439+
int64_t fd = (int64_t)(int32_t)bpf_syscall_get_argument(data, 0);
14711440

1472-
if(usrsockaddr && val != 0) {
1473-
/*
1474-
* Copy the address
1475-
*/
1476-
err = bpf_addr_to_kernel(usrsockaddr, val, (struct sockaddr *)data->tmp_scratch);
1477-
if(err >= 0) {
1478-
/*
1479-
* Convert the fd into socket endpoint information
1480-
*/
1481-
size = bpf_fd_to_socktuple(data,
1482-
fd,
1483-
(struct sockaddr *)data->tmp_scratch,
1484-
val,
1485-
true,
1486-
false,
1487-
data->tmp_scratch + sizeof(struct sockaddr_storage));
1488-
}
1441+
if(retval != 0 && retval != -EINPROGRESS) {
1442+
/* Parameter 2: tuple (type: PT_SOCKTUPLE) */
1443+
res = bpf_push_empty_param(data);
1444+
CHECK_RES(res);
1445+
1446+
/* Parameter 3: fd (type: PT_FD) */
1447+
return bpf_push_s64_to_ring(data, fd);
1448+
}
1449+
1450+
/* Get the sockaddr pointer and length. */
1451+
struct sockaddr __user *usrsockaddr =
1452+
(struct sockaddr __user *)bpf_syscall_get_argument(data, 1);
1453+
unsigned long usrsockaddr_len = bpf_syscall_get_argument(data, 2);
1454+
1455+
/* Evaluate socktuple, leveraging the user-provided sockaddr if possible */
1456+
struct sockaddr *ksockaddr = (struct sockaddr *)data->tmp_scratch;
1457+
bool use_sockaddr_user_data = false;
1458+
bool push_socktuple = true;
1459+
if(usrsockaddr != NULL && usrsockaddr_len != 0) {
1460+
/* Copy the address into kernel memory. */
1461+
res = bpf_addr_to_kernel(usrsockaddr, usrsockaddr_len, ksockaddr);
1462+
if(likely(res >= 0)) {
1463+
/* Convert the fd into socket endpoint information. */
1464+
use_sockaddr_user_data = true;
1465+
} else {
1466+
/* Do not send any socket endpoint information. */
1467+
push_socktuple = false;
14891468
}
14901469
}
14911470

1492-
/*
1493-
* Copy the endpoint info into the ring
1494-
*/
1471+
uint32_t tuple_size = 0;
1472+
if(push_socktuple) {
1473+
/* Convert the fd into socket endpoint information */
1474+
tuple_size = bpf_fd_to_socktuple(data,
1475+
fd,
1476+
ksockaddr,
1477+
usrsockaddr_len,
1478+
use_sockaddr_user_data,
1479+
false,
1480+
data->tmp_scratch + sizeof(struct sockaddr_storage));
1481+
}
1482+
1483+
/* Parameter 2: tuple (type: PT_SOCKTUPLE) */
14951484
data->curarg_already_on_frame = true;
1496-
res = bpf_val_to_ring_len(data, 0, size);
1485+
res = bpf_val_to_ring_len(data, 0, tuple_size);
14971486
CHECK_RES(res);
14981487

1499-
/* Parameter 3: fd (type: PT_FD)*/
1500-
res = bpf_push_s64_to_ring(data, fd);
1501-
return res;
1488+
/* Parameter 3: fd (type: PT_FD) */
1489+
return bpf_push_s64_to_ring(data, fd);
15021490
}
15031491

15041492
FILLER(sys_socketpair_x, true) {
@@ -1905,7 +1893,6 @@ FILLER(sys_sendto_e, true) {
19051893
/* Get the address len */
19061894
unsigned long usrsockaddr_len = bpf_syscall_get_argument(data, 5);
19071895

1908-
/* Evaluate socktuple, leveraging the user-provided sockaddr if possible */
19091896
struct sockaddr *ksockaddr = (struct sockaddr *)data->tmp_scratch;
19101897
bool use_sockaddr_user_data = false;
19111898
bool push_socktuple = true;

driver/modern_bpf/programs/tail_called/events/syscall_dispatched_events/connect.bpf.c

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,11 @@ int BPF_PROG(connect_e, struct pt_regs *regs, long id) {
2424
unsigned long args[3] = {0};
2525
extract__network_args(args, 3, regs);
2626

27-
/* Parameter 1: fd (type: PT_FD)*/
28-
int32_t socket_fd = (int32_t)args[0];
29-
auxmap__store_s64_param(auxmap, (int64_t)socket_fd);
27+
/* Parameter 1: fd (type: PT_FD) */
28+
int64_t socket_fd = (int64_t)(int32_t)args[0];
29+
auxmap__store_s64_param(auxmap, socket_fd);
3030

31-
/* Parameter 2: addr (type: PT_SOCKADDR)*/
31+
/* Parameter 2: addr (type: PT_SOCKADDR) */
3232
unsigned long sockaddr_ptr = args[1];
3333
uint16_t addrlen = (uint16_t)args[2];
3434
auxmap__store_sockaddr_param(auxmap, sockaddr_ptr, addrlen);
@@ -57,25 +57,25 @@ int BPF_PROG(connect_x, struct pt_regs *regs, long ret) {
5757

5858
/*=============================== COLLECT PARAMETERS ===========================*/
5959

60-
unsigned long socket_fd = 0;
61-
extract__network_args(&socket_fd, 1, regs);
60+
unsigned long args[2] = {0};
61+
extract__network_args(args, 2, regs);
62+
int64_t socket_fd = (int64_t)(int32_t)args[0];
6263

6364
/* Parameter 1: res (type: PT_ERRNO) */
6465
auxmap__store_s64_param(auxmap, ret);
6566

6667
/* Parameter 2: tuple (type: PT_SOCKTUPLE) */
67-
/* We need a valid sockfd to extract source data.*/
6868
if(ret == 0 || ret == -EINPROGRESS) {
69-
auxmap__store_socktuple_param(auxmap, (int32_t)socket_fd, OUTBOUND, NULL);
69+
struct sockaddr *usrsockaddr = (struct sockaddr *)args[1];
70+
/* Notice: the following will push an empty parameter if
71+
* something goes wrong (e.g.: fd not valid). */
72+
auxmap__store_socktuple_param(auxmap, (int32_t)socket_fd, OUTBOUND, usrsockaddr);
7073
} else {
7174
auxmap__store_empty_param(auxmap);
7275
}
7376

74-
/* Parameter 3: fd (type: PT_FD)*/
75-
/* We need the double cast to extract the first 4 bytes and then
76-
* convert them to a signed integer on 64-bit
77-
*/
78-
auxmap__store_s64_param(auxmap, (int64_t)(int32_t)socket_fd);
77+
/* Parameter 3: fd (type: PT_FD) */
78+
auxmap__store_s64_param(auxmap, socket_fd);
7979

8080
/*=============================== COLLECT PARAMETERS ===========================*/
8181

0 commit comments

Comments
 (0)