Received: by 2002:a25:8b91:0:0:0:0:0 with SMTP id j17csp17923659ybl; Thu, 2 Jan 2020 14:54:37 -0800 (PST) X-Google-Smtp-Source: APXvYqzHX8FMJ/AQUaXsQDLwMkzh9PF4w86ue2u2RCGWpseNovujg6zWbhwDtScCfhBP2v5a59Sl X-Received: by 2002:a9d:4805:: with SMTP id c5mr59788360otf.292.1578005677314; Thu, 02 Jan 2020 14:54:37 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1578005677; cv=none; d=google.com; s=arc-20160816; b=xcjGoUIWjXfl4TmTFFgwQ5NV+sbzoagtEFfgD7hxvyLF7gwOgS7Qci+YahWtiOi5N/ DZNDENwX7lL+G1HQsS59xJ+eM+S0Z8VTO5fo+1F9ItO2h1N9FOwhxfTlWqjnz56+hRkg nAyeHLKNYzmhaqPq6Vnh2Zx3ViIyV7MudkMsCEw/RfsASsChbM/ZL78+Y0cnYF34I9To uxb2wt2/dF2fBDgxX5tRqoHp5b9JfE7YGROa7409h1fkpoJpboctm+lskpzYbb7Pxgg4 BbKA4sFw43Uz/PRr4FMx1EVrCXXDg2spXiuCMODB08IrkWDYLmE5tRgeEAOfvCdSMa6E nN4w== 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=q2i/if/V0XN/BspZ5fvuWwQrvDuxCGlUY0UmghroVGU=; b=COPkjzx+V18X2VaGO/fLk2VCv/McgSm9F8I6GqXcqHxASktuy515T5Y7xAxMtfShhJ /f+G0UD270f2k3N47sdwRbH4CgQCfzKK2FGNVf6uGx5Q9nldDphVCaf9uSRh070EogOH p0htA7lo4Cb8JEiqi2hMHFU8i+PuBkxvFcgOtlD16evnPAe/ivYxajd76/Iehnj+Ieeb 5tZtGI5VH4uey3IE/JPrmCFKO29wCF6Oq+jG2+ekXiiuvf3Y83YP2ujqzEPW3wXnMMvk /J0I+RJzsn1b5tqu98UVUZVAUbRFqDkrtGW5oXfZvaY4tSXYEngDmcEZnYl8JjzVfgQb kQxQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@kernel.org header.s=default header.b="kmI/oxtW"; 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 i19si18030180oik.272.2020.01.02.14.54.25; Thu, 02 Jan 2020 14:54:37 -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="kmI/oxtW"; 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 S1728514AbgABWWB (ORCPT + 99 others); Thu, 2 Jan 2020 17:22:01 -0500 Received: from mail.kernel.org ([198.145.29.99]:41630 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728611AbgABWVw (ORCPT ); Thu, 2 Jan 2020 17:21:52 -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 AED1E21D7D; Thu, 2 Jan 2020 22:21:50 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=default; t=1578003711; bh=zZsaeynMCpwoa3ybK+tlz92a77OWMbnxZCQX6T/LXss=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=kmI/oxtWkROBJy0amHfcgNUB8MX1YNIFsUepopUui5q6BPi6kuiEAjx4/JgB8fmKF 0EwzuV/AxpWGsaAHwEgPWAzgWUdnHflHO0AhudQ2JbHvc+YMZjmD3np51MogLTbQ3n vuQHHXIYDwDPibKVLpZIZS7/sZ2VpfJxwwjTRNqQ= 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.19 083/114] netfilter: ebtables: compat: reject all padding in matches/watchers Date: Thu, 2 Jan 2020 23:07:35 +0100 Message-Id: <20200102220037.546181771@linuxfoundation.org> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200102220029.183913184@linuxfoundation.org> References: <20200102220029.183913184@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) @@ -1988,22 +1988,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; @@ -2040,22 +2041,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; @@ -2141,11 +2138,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; }