From bda9ae794e1254463864681eaa71901d3b1d9695 Mon Sep 17 00:00:00 2001 From: Sharad Boni Date: Sun, 26 Apr 2026 17:55:06 -0700 Subject: [PATCH 1/3] net-test: packetdrill: validate IP string before building iptables command config->live_local_ip_string is formatted directly into a shell command passed to system() in wire_server_netdev_drop_test_traffic() and wire_server_netdev_permit_test_traffic() without any sanitization. A crafted IP string containing shell metacharacters would allow command injection. Add is_safe_ip_string() which rejects any character that is not alphanumeric, '.', ':', or '%', and call it before building the iptables command in both functions. Signed-off-by: Sharad Boni --- gtests/net/packetdrill/wire_server_netdev.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/gtests/net/packetdrill/wire_server_netdev.c b/gtests/net/packetdrill/wire_server_netdev.c index d7f7c6db..f5350207 100644 --- a/gtests/net/packetdrill/wire_server_netdev.c +++ b/gtests/net/packetdrill/wire_server_netdev.c @@ -25,6 +25,7 @@ #include "wire_server_netdev.h" +#include #include #include #include @@ -109,6 +110,17 @@ static void wire_server_netdev_dump_firewall_rules(const struct config *config) #endif } +/* Validate that a string looks like an IP address (no shell metacharacters). */ +static bool is_safe_ip_string(const char *s) +{ + if (!s) return false; + for (; *s; ++s) { + if (!isalnum((unsigned char)*s) && *s != '.' && *s != ':' && *s != '%') + return false; + } + return true; +} + /* Drop incoming test traffic packets from the kernel under test, before they * are seen by the TCP/UDP/etc layers of the wire server machine. In some cases * (e.g., if a network does not allow spoofing) the packetdrill test traffic @@ -123,6 +135,9 @@ static void wire_server_netdev_drop_test_traffic(const struct config *config) #ifdef linux char *command = NULL; + if (!is_safe_ip_string(config->live_local_ip_string)) + die("wire_server_netdev: unsafe IP address string\n"); + asprintf(&command, "(" /* drop TCP to connect port: */ @@ -156,6 +171,9 @@ static void wire_server_netdev_permit_test_traffic(const struct config *config) #ifdef linux char *command = NULL; + if (!is_safe_ip_string(config->live_local_ip_string)) + die("wire_server_netdev: unsafe IP address string\n"); + asprintf(&command, "(" /* TCP to connect port: */ From e074e790882b101957cb0f6c84902ea6eb3a993d Mon Sep 17 00:00:00 2001 From: Sharad Boni Date: Sun, 26 Apr 2026 17:55:21 -0700 Subject: [PATCH 2/3] net-test: packetdrill: add bounds check in nla_expr_list_to_nla dst_len is accepted as a parameter but never enforced in the loop body. A caller supplying a list longer than the destination buffer would cause writes past the end of dst. Add a pre-write check that returns STATUS_ERR with an explanatory error message if the next NLA write would exceed dst_len. Signed-off-by: Sharad Boni --- gtests/net/packetdrill/run_system_call.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/gtests/net/packetdrill/run_system_call.c b/gtests/net/packetdrill/run_system_call.c index ebfff192..e3365864 100644 --- a/gtests/net/packetdrill/run_system_call.c +++ b/gtests/net/packetdrill/run_system_call.c @@ -506,6 +506,10 @@ static int nla_expr_list_to_nla(struct expression_list *list, die("out of bound u32 value specified\n"); get_nla_value(value, &val, num_bytes); + if ((char *)dst + NLA_ALIGN(NLA_HDRLEN + num_bytes) - (char *)start > dst_len) { + asprintf(error, "NLA buffer overflow: dst_len=%d exceeded", dst_len); + return STATUS_ERR; + } dst += add_nla(dst, key_num, nla_info[key_num].length, &val); } From 8a60e34bf5e8df2cf51c8d2530b2c298fc23a9c1 Mon Sep 17 00:00:00 2001 From: Sharad Boni Date: Sun, 26 Apr 2026 17:55:36 -0700 Subject: [PATCH 3/3] net-test: packetdrill: reject negative optlen in syscall_getsockopt script_optlen is an s32 (signed 32-bit). Assigning a negative value to live_optlen (type socklen_t, unsigned 32-bit) silently wraps to ~4 GB, causing calloc() to request a huge allocation. Add an explicit non-negative check and return STATUS_ERR before the cast. Signed-off-by: Sharad Boni --- gtests/net/packetdrill/run_system_call.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/gtests/net/packetdrill/run_system_call.c b/gtests/net/packetdrill/run_system_call.c index e3365864..4ff9883e 100644 --- a/gtests/net/packetdrill/run_system_call.c +++ b/gtests/net/packetdrill/run_system_call.c @@ -2587,6 +2587,10 @@ static int syscall_getsockopt(struct state *state, struct syscall_spec *syscall, return STATUS_ERR; /* Allocate space for getsockopt output. */ + if (script_optlen < 0) { + asprintf(error, "getsockopt: negative optlen %d", script_optlen); + return STATUS_ERR; + } live_optlen = script_optlen; live_optval = calloc(1, live_optlen + 1); assert(live_optval != NULL);