DragonFlyBSD Kernel Audit
DF-0749 / fix.diff
← back to finding ↓ download raw
diff --git a/sys/net/ipfw3_layer2/ip_fw3_layer2.c b/sys/net/ipfw3_layer2/ip_fw3_layer2.c
index 0000000..1111111 100644
--- a/sys/net/ipfw3_layer2/ip_fw3_layer2.c
+++ b/sys/net/ipfw3_layer2/ip_fw3_layer2.c
@@ -115,12 +115,21 @@
         struct radix_node_head *rnh;
         struct table_mac_entry *ent = NULL;
 
+        *cmd_ctl = IP_FW_CTL_NO;
+        *cmd_val = IP_FW_NOT_MATCH;
+        /* DF-0749: cmd->arg1 comes from userland (mac-from table N parser,
+           lib/libipfw3/layer2/ipfw3_layer2.c:153) with no validation.  The
+           table_ctx array has only IPFW_TABLES_MAX (32) entries; an out-of-
+           range id drives an OOB read of table_ctx->node here. */
+        if (cmd->arg1 >= IPFW_TABLES_MAX)
+                return;
+
         table_ctx = ctx->table_ctx;
         table_ctx += cmd->arg1;
         rnh = table_ctx->node;
 
-        *cmd_ctl = IP_FW_CTL_NO;
-        *cmd_val = IP_FW_NOT_MATCH;
+        if (table_ctx->type == 0 || rnh == NULL)
+                return;
         if ((*args)->eh != NULL) {
                 struct sockaddr sa;
                 sa.sa_len = 8;
@@ -158,12 +167,18 @@
         struct radix_node_head *rnh;
         struct table_mac_entry *ent = NULL;
 
+        *cmd_ctl = IP_FW_CTL_NO;
+        *cmd_val = IP_FW_NOT_MATCH;
+        /* DF-0749: same bounds check as check_mac_from_lookup. */
+        if (cmd->arg1 >= IPFW_TABLES_MAX)
+                return;
+
         table_ctx = ctx->table_ctx;
         table_ctx += cmd->arg1;
         rnh = table_ctx->node;
 
-        *cmd_ctl = IP_FW_CTL_NO;
-        *cmd_val = IP_FW_NOT_MATCH;
+        if (table_ctx->type == 0 || rnh == NULL)
+                return;
         if ((*args)->eh != NULL) {
                 struct sockaddr sa;
                 sa.sa_len = 8;