Received: by 2002:a25:8b91:0:0:0:0:0 with SMTP id j17csp17922268ybl; Thu, 2 Jan 2020 14:52:34 -0800 (PST) X-Google-Smtp-Source: APXvYqy/WIEoHqPQue7crCD3Wy8DYnYqpHCaQm7nELZEy0+L2KAd9JX5R1SWXGroRDeajhVqncGI X-Received: by 2002:a9d:5c02:: with SMTP id o2mr87433533otk.176.1578005554518; Thu, 02 Jan 2020 14:52:34 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1578005554; cv=none; d=google.com; s=arc-20160816; b=i+x83yUnNu9Y8bllad+TvoGVOH7WZDCq4esN56tdjV93SC9Qcbz4r4yDOfpwm+Z43y T0LFrzCbLkfta7vMeqgTh46MGnI1SqpKyU+7gXtepJVZ96nXpC83gwXrFsCh7b5DzrRA X4zgXFWqIwKg731YutBx1NT5hceQTQ4rmzzx0SD0rq8C+qWGXiD8vAZgQzx2dQB0bl/C Oq3vq3SGmdMSFO99LZaBFX0fVA/xLtlvofsy0SQ5KHmG3GuB2Cn12MkvSZxP29ghrYB2 0IoWsLv+i3G1wvuGJmBS5ACxwfU1op2DtWmywnU3UTwoW6VP4d3yhxbHJbZHOoIacAmq 3oJQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:content-transfer-encoding:mime-version :user-agent:references:in-reply-to:message-id:date:subject:cc:to :from:dkim-signature; bh=TNkrx+XjyLq6NnlpobAbuKhaok56k9uDn9XZmmhcm1Y=; b=UsJWpIwnuqlr0RqYMl8CzpaYo8/123S5ISV1xA+GbijfnryMk0uk6nNsRC0sZCRGwU 0VNgVUiLGLXeAsLKsQ4epxqeg/kht/UFVkt/+QpdmxG/og45LRd4bVzT5WizDZxOFbiO 8/cNoeh1kkOlQbLm8AosRF3krhG50izorB+zbhN6ozAdrQ7c4b5IQu0P5VY43UJ5JeWB RQl7mGK5wUo7HsWRK1PeR8YDrF/o1KFd4AEQ+k5TVWs/CZez/nAdEmWsnlvV1ywtNGuU sQwwi6EfwY8oYxZVYmgzpyjLc2+soYQS0XjOyJnX6NnTnfXgtpy03MBN/M9d6H85/Gtw 6dSQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@kernel.org header.s=default header.b=z+TW9DeN; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id p21si20400835otk.162.2020.01.02.14.52.23; Thu, 02 Jan 2020 14:52:34 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@kernel.org header.s=default header.b=z+TW9DeN; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728797AbgABWZn (ORCPT + 99 others); Thu, 2 Jan 2020 17:25:43 -0500 Received: from mail.kernel.org ([198.145.29.99]:51606 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1729023AbgABWZm (ORCPT ); Thu, 2 Jan 2020 17:25:42 -0500 Received: from localhost (83-86-89-107.cable.dynamic.v4.ziggo.nl [83.86.89.107]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPSA id 7A2A62253D; Thu, 2 Jan 2020 22:25:41 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=default; t=1578003941; bh=cAXW1ArC2h5cxAmqua/9/NNnDaRZDLuYbmOudVCJqjQ=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=z+TW9DeN+GD2JJlE4pJ1kT3K/FCch4tpqPWHVxcIfN4kdkBVnw7VRuRL026errXiy ipUFDwbbEzlOytw+sqhW76zKOs/jaa2mOgbZCEahCAB0lLy6TpopeuX0m4w9GO5M51 2TUp0FePd40dIVkMYtuLKw5E4l1zLr3JCfgpc2BY= From: Greg Kroah-Hartman To: linux-kernel@vger.kernel.org Cc: Greg Kroah-Hartman , stable@vger.kernel.org, syzbot+f68108fed972453a0ad4@syzkaller.appspotmail.com, Florian Westphal , Pablo Neira Ayuso Subject: [PATCH 4.14 64/91] netfilter: ebtables: compat: reject all padding in matches/watchers Date: Thu, 2 Jan 2020 23:07:46 +0100 Message-Id: <20200102220442.509364885@linuxfoundation.org> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200102220356.856162165@linuxfoundation.org> References: <20200102220356.856162165@linuxfoundation.org> User-Agent: quilt/0.66 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Florian Westphal commit e608f631f0ba5f1fc5ee2e260a3a35d13107cbfe upstream. syzbot reported following splat: BUG: KASAN: vmalloc-out-of-bounds in size_entry_mwt net/bridge/netfilter/ebtables.c:2063 [inline] BUG: KASAN: vmalloc-out-of-bounds in compat_copy_entries+0x128b/0x1380 net/bridge/netfilter/ebtables.c:2155 Read of size 4 at addr ffffc900004461f4 by task syz-executor267/7937 CPU: 1 PID: 7937 Comm: syz-executor267 Not tainted 5.5.0-rc1-syzkaller #0 size_entry_mwt net/bridge/netfilter/ebtables.c:2063 [inline] compat_copy_entries+0x128b/0x1380 net/bridge/netfilter/ebtables.c:2155 compat_do_replace+0x344/0x720 net/bridge/netfilter/ebtables.c:2249 compat_do_ebt_set_ctl+0x22f/0x27e net/bridge/netfilter/ebtables.c:2333 [..] Because padding isn't considered during computation of ->buf_user_offset, "total" is decremented by fewer bytes than it should. Therefore, the first part of if (*total < sizeof(*entry) || entry->next_offset < sizeof(*entry)) will pass, -- it should not have. This causes oob access: entry->next_offset is past the vmalloced size. Reject padding and check that computed user offset (sum of ebt_entry structure plus all individual matches/watchers/targets) is same value that userspace gave us as the offset of the next entry. Reported-by: syzbot+f68108fed972453a0ad4@syzkaller.appspotmail.com Fixes: 81e675c227ec ("netfilter: ebtables: add CONFIG_COMPAT support") Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso Signed-off-by: Greg Kroah-Hartman --- net/bridge/netfilter/ebtables.c | 33 ++++++++++++++++----------------- 1 file changed, 16 insertions(+), 17 deletions(-) --- a/net/bridge/netfilter/ebtables.c +++ b/net/bridge/netfilter/ebtables.c @@ -1876,7 +1876,7 @@ static int ebt_buf_count(struct ebt_entr } static int ebt_buf_add(struct ebt_entries_buf_state *state, - void *data, unsigned int sz) + const void *data, unsigned int sz) { if (state->buf_kern_start == NULL) goto count_only; @@ -1910,7 +1910,7 @@ enum compat_mwt { EBT_COMPAT_TARGET, }; -static int compat_mtw_from_user(struct compat_ebt_entry_mwt *mwt, +static int compat_mtw_from_user(const struct compat_ebt_entry_mwt *mwt, enum compat_mwt compat_mwt, struct ebt_entries_buf_state *state, const unsigned char *base) @@ -1986,22 +1986,23 @@ static int compat_mtw_from_user(struct c /* return size of all matches, watchers or target, including necessary * alignment and padding. */ -static int ebt_size_mwt(struct compat_ebt_entry_mwt *match32, +static int ebt_size_mwt(const struct compat_ebt_entry_mwt *match32, unsigned int size_left, enum compat_mwt type, struct ebt_entries_buf_state *state, const void *base) { + const char *buf = (const char *)match32; int growth = 0; - char *buf; if (size_left == 0) return 0; - buf = (char *) match32; - - while (size_left >= sizeof(*match32)) { + do { struct ebt_entry_match *match_kern; int ret; + if (size_left < sizeof(*match32)) + return -EINVAL; + match_kern = (struct ebt_entry_match *) state->buf_kern_start; if (match_kern) { char *tmp; @@ -2038,22 +2039,18 @@ static int ebt_size_mwt(struct compat_eb if (match_kern) match_kern->match_size = ret; - /* rule should have no remaining data after target */ - if (type == EBT_COMPAT_TARGET && size_left) - return -EINVAL; - match32 = (struct compat_ebt_entry_mwt *) buf; - } + } while (size_left); return growth; } /* called for all ebt_entry structures. */ -static int size_entry_mwt(struct ebt_entry *entry, const unsigned char *base, +static int size_entry_mwt(const struct ebt_entry *entry, const unsigned char *base, unsigned int *total, struct ebt_entries_buf_state *state) { - unsigned int i, j, startoff, new_offset = 0; + unsigned int i, j, startoff, next_expected_off, new_offset = 0; /* stores match/watchers/targets & offset of next struct ebt_entry: */ unsigned int offsets[4]; unsigned int *offsets_update = NULL; @@ -2140,11 +2137,13 @@ static int size_entry_mwt(struct ebt_ent return ret; } - startoff = state->buf_user_offset - startoff; + next_expected_off = state->buf_user_offset - startoff; + if (next_expected_off != entry->next_offset) + return -EINVAL; - if (WARN_ON(*total < startoff)) + if (*total < entry->next_offset) return -EINVAL; - *total -= startoff; + *total -= entry->next_offset; return 0; }