From 9caa409c01cc336cb13f3eb8f4292728bf826b7a Mon Sep 17 00:00:00 2001 From: Leonardo Di Donato Date: Thu, 14 Jan 2021 16:50:27 +0000 Subject: [PATCH 1/2] fix(driver/bpf): bpf_addr_to_kernel takes an unsigned length (less than BPF_MAX_VAR_SIZE) The `bpf_syscall_get_argument` function returns an `unsigned long` that was assigned to an `int` and passed to `bpf_addr_to_kernel` (`ulen` variable). We need to enusre the value is always unsigned (thus removing the inner check for it being greater than 0). We also need to ensure it is not bigger than `1ULL << 29` (ie., `BPF_MAX_VAR_SIZE`). Otherwise the verifier gives un an "unbounded memory access" error. This happens for Linux kernels containing [this patch](https://lore.kernel.org/bpf/20190614072557.196239-10-ast@kernel.org/). Co-authored-by: Lorenzo Fontana Signed-off-by: Leonardo Di Donato --- driver/bpf/filler_helpers.h | 11 +++++++---- driver/bpf/fillers.h | 6 +++--- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/driver/bpf/filler_helpers.h b/driver/bpf/filler_helpers.h index bdcf0652ad..0c7e2a5448 100644 --- a/driver/bpf/filler_helpers.h +++ b/driver/bpf/filler_helpers.h @@ -19,6 +19,9 @@ or GPL2.txt for full copies of the license. #include "../ppm_flag_helpers.h" +// Maximum var size allowed by the verifier +#define BPF_MAX_VAR_SIZE 1ULL << 29 + static __always_inline bool in_port_range(uint16_t port, uint16_t min, uint16_t max) { return port >= min && port <= max; @@ -212,10 +215,10 @@ static __always_inline bool bpf_getsockname(struct socket *sock, return true; } -static __always_inline int bpf_addr_to_kernel(void *uaddr, int ulen, +static __always_inline int bpf_addr_to_kernel(void *uaddr, unsigned long ulen, struct sockaddr *kaddr) { - if (ulen < 0 || ulen > sizeof(struct sockaddr_storage)) + if (ulen > BPF_MAX_VAR_SIZE) return -EINVAL; if (ulen == 0) @@ -289,7 +292,7 @@ static __always_inline u32 bpf_compute_snaplen(struct filler_data *data, if (!bpf_getsockname(sock, peer_address, 1)) return res; } else { - int addrlen = bpf_syscall_get_argument(data, 5); + unsigned long addrlen = bpf_syscall_get_argument(data, 5); if (addrlen != 0) { if (bpf_addr_to_kernel(usrsockaddr, addrlen, (struct sockaddr *)peer_address)) @@ -302,7 +305,7 @@ static __always_inline u32 bpf_compute_snaplen(struct filler_data *data, struct sockaddr *usrsockaddr; struct user_msghdr mh; unsigned long val; - int addrlen; + unsigned long addrlen; val = bpf_syscall_get_argument(data, 1); if (bpf_probe_read(&mh, sizeof(mh), (void *)val)) { diff --git a/driver/bpf/fillers.h b/driver/bpf/fillers.h index 7a483bef76..87e8a9d453 100644 --- a/driver/bpf/fillers.h +++ b/driver/bpf/fillers.h @@ -2640,7 +2640,7 @@ FILLER(sys_recvfrom_x, true) unsigned long val; u16 size = 0; long retval; - int addrlen; + unsigned long addrlen; int err = 0; int res; int fd; @@ -2770,7 +2770,7 @@ FILLER(sys_recvmsg_x_2, true) unsigned long val; u16 size = 0; long retval; - int addrlen; + unsigned long addrlen; int res; int fd; @@ -2832,7 +2832,7 @@ FILLER(sys_sendmsg_e, true) unsigned long iovcnt; unsigned long val; u16 size = 0; - int addrlen; + unsigned long addrlen; int err = 0; int res; int fd; From 4c2353a32d643cbc1d9dd5648951a785b1047ab0 Mon Sep 17 00:00:00 2001 From: Leo Di Donato Date: Fri, 15 Jan 2021 16:35:22 +0100 Subject: [PATCH 2/2] docs(driver/bpf): document the source of BPF_MAX_VAR_SIZE Signed-off-by: Leonardo Di Donato --- driver/bpf/filler_helpers.h | 1 + 1 file changed, 1 insertion(+) diff --git a/driver/bpf/filler_helpers.h b/driver/bpf/filler_helpers.h index 0c7e2a5448..d48404ea27 100644 --- a/driver/bpf/filler_helpers.h +++ b/driver/bpf/filler_helpers.h @@ -20,6 +20,7 @@ or GPL2.txt for full copies of the license. #include "../ppm_flag_helpers.h" // Maximum var size allowed by the verifier +// From BPF_MAX_VAR_SIZ in linux/bpf_verifier.h #define BPF_MAX_VAR_SIZE 1ULL << 29 static __always_inline bool in_port_range(uint16_t port, uint16_t min, uint16_t max)