]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
netfilter: ebtables: terminate table name before find_table_lock()
authorXiang Mei <xmei5@asu.edu>
Sun, 5 Jul 2026 21:58:00 +0000 (14:58 -0700)
committerFlorian Westphal <fw@strlen.de>
Wed, 8 Jul 2026 13:22:03 +0000 (15:22 +0200)
update_counters() and compat_update_counters() forward a user-supplied
32-byte table name to find_table_lock() without NUL-terminating it. On a
lookup miss, find_inlist_lock() calls try_then_request_module(..., "%s%s",
"ebtable_", name), and vsnprintf() reads past the name field and the
stack object until it hits a zero byte.

  BUG: KASAN: stack-out-of-bounds in string (lib/vsprintf.c:648 lib/vsprintf.c:730)
  Read of size 1 at addr ffff8880119dfb20 by task exploit/147
  Call Trace:
  ...
   string (lib/vsprintf.c:648 lib/vsprintf.c:730)
   vsnprintf (lib/vsprintf.c:2945)
   __request_module (kernel/module/kmod.c:150)
   do_update_counters.isra.0 (net/bridge/netfilter/ebtables.c:371 net/bridge/netfilter/ebtables.c:380)
   update_counters (net/bridge/netfilter/ebtables.c:1440)
   do_ebt_set_ctl (net/bridge/netfilter/ebtables.c:2573)
   nf_setsockopt (net/netfilter/nf_sockopt.c:101)
   ip_setsockopt (net/ipv4/ip_sockglue.c:1424)
   raw_setsockopt (net/ipv4/raw.c:847)
   __sys_setsockopt (net/socket.c:2393)
  ...

compat_do_replace() shares the same unterminated name via
compat_copy_ebt_replace_from_user(); terminate it there too so all
find_table_lock() callers behave alike. The other callers already
terminate the name after the copy.

Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Fixes: 81e675c227ec ("netfilter: ebtables: add CONFIG_COMPAT support")
Cc: stable@vger.kernel.org
Reported-by: Weiming Shi <bestswngs@gmail.com>
Assisted-by: Claude:claude-opus-4-8
Signed-off-by: Xiang Mei <xmei5@asu.edu>
Signed-off-by: Florian Westphal <fw@strlen.de>
net/bridge/netfilter/ebtables.c

index f20c039e44c8d719c6e6b77ee7c72508a6fbde30..5b74ff827493fad4533b1b66caddbe5f35de355f 100644 (file)
@@ -1434,6 +1434,8 @@ static int update_counters(struct net *net, sockptr_t arg, unsigned int len)
        if (copy_from_sockptr(&hlp, arg, sizeof(hlp)))
                return -EFAULT;
 
+       hlp.name[sizeof(hlp.name) - 1] = '\0';
+
        if (len != sizeof(hlp) + hlp.num_counters * sizeof(struct ebt_counter))
                return -EINVAL;
 
@@ -2273,6 +2275,8 @@ static int compat_copy_ebt_replace_from_user(struct ebt_replace *repl,
 
        memcpy(repl, &tmp, offsetof(struct ebt_replace, hook_entry));
 
+       repl->name[sizeof(repl->name) - 1] = '\0';
+
        /* starting with hook_entry, 32 vs. 64 bit structures are different */
        for (i = 0; i < NF_BR_NUMHOOKS; i++)
                repl->hook_entry[i] = compat_ptr(tmp.hook_entry[i]);
@@ -2395,6 +2399,8 @@ static int compat_update_counters(struct net *net, sockptr_t arg,
        if (copy_from_sockptr(&hlp, arg, sizeof(hlp)))
                return -EFAULT;
 
+       hlp.name[sizeof(hlp.name) - 1] = '\0';
+
        /* try real handler in case userland supplied needed padding */
        if (len != sizeof(hlp) + hlp.num_counters * sizeof(struct ebt_counter))
                return update_counters(net, arg, len);