diff --git a/driver/bpf/filler_helpers.h b/driver/bpf/filler_helpers.h index b6661e6a96c..a1eabcdfab9 100644 --- a/driver/bpf/filler_helpers.h +++ b/driver/bpf/filler_helpers.h @@ -606,8 +606,7 @@ static __always_inline int unix_socket_path(char *dest, const char *user_ptr, si * specified length of the address structure. */ if(res == 1) { - dest[0] = '@'; - res = bpf_probe_read_kernel_str(dest + 1, + res = bpf_probe_read_kernel_str(dest, size - 1, // account for '@' user_ptr + 1); res++; // account for '@' @@ -882,7 +881,7 @@ static __always_inline long bpf_fd_to_socktuple(struct filler_data *data, */ struct unix_sock *us = (struct unix_sock *)sk; struct sock *speer = _READ(us->peer); - char *us_name; + char *us_name = NULL; data->buf[data->state->tail_ctx.curoff & SCRATCH_SIZE_HALF] = socket_family_to_scap(family); @@ -891,27 +890,17 @@ static __always_inline long bpf_fd_to_socktuple(struct filler_data *data, memcpy(&data->buf[(data->state->tail_ctx.curoff + 1 + 8) & SCRATCH_SIZE_HALF], &speer, 8); + us_name = ((struct sockaddr_un *)sock_address)->sun_path; } else { memcpy(&data->buf[(data->state->tail_ctx.curoff + 1) & SCRATCH_SIZE_HALF], &speer, 8); memcpy(&data->buf[(data->state->tail_ctx.curoff + 1 + 8) & SCRATCH_SIZE_HALF], &us, 8); + bpf_getsockname(sock, peer_address, 1); + us_name = ((struct sockaddr_un *)peer_address)->sun_path; } - /* - * Pack the data into the target buffer - */ - size = 1 + 8 + 8; - - if(!use_userdata) { - if(is_inbound) { - us_name = ((struct sockaddr_un *)sock_address)->sun_path; - } else { - bpf_getsockname(sock, peer_address, 1); - us_name = ((struct sockaddr_un *)peer_address)->sun_path; - } - } else { - /* - * Map the user-provided address to a sockaddr_in - */ + // `us_name` should contain the socket path extracted from the kernel if we cannot retrieve + // it we can fallback to the user-provided address + if(us_name && us_name[0] == '\0') { struct sockaddr_un *usrsockaddr_un = (struct sockaddr_un *)usrsockaddr; /* @@ -929,11 +918,11 @@ static __always_inline long bpf_fd_to_socktuple(struct filler_data *data, us_name = usrsockaddr_un->sun_path; } + size = 1 + 8 + 8; int res = unix_socket_path( &data->buf[(data->state->tail_ctx.curoff + 1 + 8 + 8) & SCRATCH_SIZE_HALF], us_name, UNIX_PATH_MAX); - size += res; break; diff --git a/driver/ppm_events.c b/driver/ppm_events.c index 8d8bde5bdd6..831b4f9557b 100644 --- a/driver/ppm_events.c +++ b/driver/ppm_events.c @@ -858,15 +858,16 @@ static struct socket *ppm_sockfd_lookup_light(int fd, int *err, int *fput_needed static void unix_socket_path(char *dest, const char *path, size_t size) { if(path[0] == '\0') { - /* - * Extract from: https://man7.org/linux/man-pages/man7/unix.7.html - * an abstract socket address is distinguished (from a + /* Please note exceptions in the `sun_path`: + * Taken from: https://man7.org/linux/man-pages/man7/unix.7.html + * + * An `abstract socket address` is distinguished (from a * pathname socket) by the fact that sun_path[0] is a null byte - * ('\0'). The socket's address in this namespace is given by - * the additional bytes in sun_path that are covered by the - * specified length of the address structure. + * ('\0'). + * + * So in this case, we need to skip the initial `\0`. */ - snprintf(dest, size, "@%s", path + 1); + snprintf(dest, size, "%s", path + 1); } else { snprintf(dest, size, @@ -999,7 +1000,7 @@ uint16_t fd_to_socktuple(int fd, struct socket *sock; char *dest; struct unix_sock *us; - char *us_name; + char *us_name = NULL; struct sock *speer; struct sockaddr_un *usrsockaddr_un; @@ -1164,29 +1165,17 @@ uint16_t fd_to_socktuple(int fd, if(is_inbound) { *(uint64_t *)(targetbuf + 1) = (uint64_t)(unsigned long)us; *(uint64_t *)(targetbuf + 1 + 8) = (uint64_t)(unsigned long)speer; + us_name = ((struct sockaddr_un *)&sock_address)->sun_path; } else { *(uint64_t *)(targetbuf + 1) = (uint64_t)(unsigned long)speer; *(uint64_t *)(targetbuf + 1 + 8) = (uint64_t)(unsigned long)us; + sock_getname(sock, (struct sockaddr *)&peer_address, 1); + us_name = ((struct sockaddr_un *)&peer_address)->sun_path; } - /* - * Pack the data into the target buffer - */ - size = 1 + 8 + 8; - - if(!use_userdata) { - if(is_inbound) { - us_name = ((struct sockaddr_un *)&sock_address)->sun_path; - } else { - err = sock_getname(sock, (struct sockaddr *)&peer_address, 1); - ASSERT(err == 0); - - us_name = ((struct sockaddr_un *)&peer_address)->sun_path; - } - } else { - /* - * Map the user-provided address to a sockaddr_in - */ + // `us_name` should contain the socket path extracted from the kernel if we cannot retrieve + // it we can fallback to the user-provided address + if(us_name && us_name[0] == '\0') { usrsockaddr_un = (struct sockaddr_un *)usrsockaddr; /* @@ -1203,12 +1192,9 @@ uint16_t fd_to_socktuple(int fd, else us_name = usrsockaddr_un->sun_path; } - - ASSERT(us_name); - - dest = targetbuf + 1 + 8 + 8; + size = 1 + 8 + 8; + dest = targetbuf + size; unix_socket_path(dest, us_name, UNIX_PATH_MAX); - size += strlen(dest) + 1; break; default: diff --git a/test/drivers/test_suites/syscall_exit_suite/connect_x.cpp b/test/drivers/test_suites/syscall_exit_suite/connect_x.cpp index 1526e16776d..9a2353f995d 100644 --- a/test/drivers/test_suites/syscall_exit_suite/connect_x.cpp +++ b/test/drivers/test_suites/syscall_exit_suite/connect_x.cpp @@ -187,6 +187,14 @@ TEST(SyscallExit, connectX_UNIX) { NOT_EQUAL, -1); + // Create a symlink + const char* server_symlink = "/tmp/xyzxe-server-symlink"; + int ret = symlink(UNIX_SERVER, server_symlink); + if(ret == -1) { + FAIL() << "Failed to create symlink"; + } + strlcpy(server_addr.sun_path, server_symlink, MAX_SUN_PATH); + assert_syscall_state( SYSCALL_SUCCESS, "connect (client)", @@ -198,6 +206,7 @@ TEST(SyscallExit, connectX_UNIX) { syscall(__NR_close, client_socket_fd); syscall(__NR_close, server_socket_fd); syscall(__NR_unlinkat, 0, UNIX_CLIENT, 0); + syscall(__NR_unlinkat, 0, server_symlink, 0); syscall(__NR_unlinkat, 0, UNIX_SERVER, 0); /*=============================== TRIGGER SYSCALL ===========================*/