diff mbox series

[nf] netfilter/ebtables: reject bogus getopt len value

Message ID 20200813074611.281558-1-fw@strlen.de
State Awaiting Upstream
Delegated to: David Miller
Headers show
Series [nf] netfilter/ebtables: reject bogus getopt len value | expand

Commit Message

Florian Westphal Aug. 13, 2020, 7:46 a.m. UTC
syzkaller reports splat:
------------[ cut here ]------------
Buffer overflow detected (80 < 137)!
Call Trace:
 do_ebt_get_ctl+0x2b4/0x790 net/bridge/netfilter/ebtables.c:2317
 nf_getsockopt+0x72/0xd0 net/netfilter/nf_sockopt.c:116
 ip_getsockopt net/ipv4/ip_sockglue.c:1778 [inline]

caused by a copy-to-user with a too-large "*len" value.
This adds a argument check on *len just like in the non-compat version
of the handler.

Before the "Fixes" commit, the reproducer fails with -EINVAL as
expected:
1. core calls the "compat" getsockopt version
2. compat getsockopt version detects the *len value is possibly
   in 64-bit layout (*len != compat_len)
3. compat getsockopt version delegates everything to native getsockopt
   version
4. native getsockopt rejects invalid *len

-> compat handler only sees len == sizeof(compat_struct) for GET_ENTRIES.

After the refactor, event sequence is:
1. getsockopt calls "compat" version (len != native_len)
2. compat version attempts to copy *len bytes, where *len is random
   value from userspace

Fixes: fc66de8e16e ("netfilter/ebtables: clean up compat {get, set}sockopt handling")
Reported-by: syzbot+5accb5c62faa1d346480@syzkaller.appspotmail.com
Signed-off-by: Florian Westphal <fw@strlen.de>
---
 net/bridge/netfilter/ebtables.c | 4 ++++
 1 file changed, 4 insertions(+)

Comments

Christoph Hellwig Aug. 13, 2020, 3:40 p.m. UTC | #1
Looks good, sorry:

Reviewed-by: Christoph Hellwig <hch@lst.de>
Jakub Kicinski Aug. 13, 2020, 4:05 p.m. UTC | #2
On Thu, 13 Aug 2020 09:46:11 +0200 Florian Westphal wrote:
> Fixes: fc66de8e16e ("netfilter/ebtables: clean up compat {get, set}sockopt handling")

Fixes tag: Fixes: fc66de8e16e ("netfilter/ebtables: clean up compat {get, set}sockopt handling")
Has these problem(s):
	- SHA1 should be at least 12 digits long
	  Can be fixed by setting core.abbrev to 12 (or more) or (for git v2.11
	  or later) just making sure it is not set (or set to "auto").
Pablo Neira Ayuso Aug. 14, 2020, 9:59 a.m. UTC | #3
On Thu, Aug 13, 2020 at 09:46:11AM +0200, Florian Westphal wrote:
> syzkaller reports splat:
> ------------[ cut here ]------------
> Buffer overflow detected (80 < 137)!
> Call Trace:
>  do_ebt_get_ctl+0x2b4/0x790 net/bridge/netfilter/ebtables.c:2317
>  nf_getsockopt+0x72/0xd0 net/netfilter/nf_sockopt.c:116
>  ip_getsockopt net/ipv4/ip_sockglue.c:1778 [inline]
> 
> caused by a copy-to-user with a too-large "*len" value.
> This adds a argument check on *len just like in the non-compat version
> of the handler.
> 
> Before the "Fixes" commit, the reproducer fails with -EINVAL as
> expected:
> 1. core calls the "compat" getsockopt version
> 2. compat getsockopt version detects the *len value is possibly
>    in 64-bit layout (*len != compat_len)
> 3. compat getsockopt version delegates everything to native getsockopt
>    version
> 4. native getsockopt rejects invalid *len
> 
> -> compat handler only sees len == sizeof(compat_struct) for GET_ENTRIES.
> 
> After the refactor, event sequence is:
> 1. getsockopt calls "compat" version (len != native_len)
> 2. compat version attempts to copy *len bytes, where *len is random
>    value from userspace

Applied, thanks.
diff mbox series

Patch

diff --git a/net/bridge/netfilter/ebtables.c b/net/bridge/netfilter/ebtables.c
index 1641f414d1ba..ebe33b60efd6 100644
--- a/net/bridge/netfilter/ebtables.c
+++ b/net/bridge/netfilter/ebtables.c
@@ -2238,6 +2238,10 @@  static int compat_do_ebt_get_ctl(struct sock *sk, int cmd,
 	struct ebt_table *t;
 	struct net *net = sock_net(sk);
 
+	if ((cmd == EBT_SO_GET_INFO || cmd == EBT_SO_GET_INIT_INFO) &&
+	    *len != sizeof(struct compat_ebt_replace))
+		return -EINVAL;
+
 	if (copy_from_user(&tmp, user, sizeof(tmp)))
 		return -EFAULT;