From patchwork Sat Sep 16 00:48:20 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Cengiz Can X-Patchwork-Id: 1835314 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.ubuntu.com (client-ip=185.125.189.65; helo=lists.ubuntu.com; envelope-from=kernel-team-bounces@lists.ubuntu.com; receiver=patchwork.ozlabs.org) Received: from lists.ubuntu.com (lists.ubuntu.com [185.125.189.65]) (using TLSv1.2 with cipher ECDHE-ECDSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4RnXYq4WhYz1yhP for ; Sat, 16 Sep 2023 10:51:27 +1000 (AEST) Received: from localhost ([127.0.0.1] helo=lists.ubuntu.com) by lists.ubuntu.com with esmtp (Exim 4.86_2) (envelope-from ) id 1qhJWj-0007vk-63; Sat, 16 Sep 2023 00:51:13 +0000 Received: from smtp-relay-internal-0.internal ([10.131.114.225] helo=smtp-relay-internal-0.canonical.com) by lists.ubuntu.com with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.86_2) (envelope-from ) id 1qhJVX-0006vt-L2 for kernel-team@lists.ubuntu.com; Sat, 16 Sep 2023 00:50:06 +0000 Received: from mail-pf1-f200.google.com (mail-pf1-f200.google.com [209.85.210.200]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by smtp-relay-internal-0.canonical.com (Postfix) with ESMTPS id 6F5323F665 for ; Sat, 16 Sep 2023 00:49:59 +0000 (UTC) Received: by mail-pf1-f200.google.com with SMTP id d2e1a72fcca58-68fcbbdf9c3so3012931b3a.1 for ; Fri, 15 Sep 2023 17:49:59 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1694825398; x=1695430198; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=Qa1nyArrFY8+qNFRV31SdUSS/GS5UwUN+5n9UH2QHzU=; b=kUzrDmuER0bAAZkv53KezWlWKfOwIU/wLHmiG7xOFn6HJaJ1I034JFdFY4FQLaj/Hv rfuufAKVO/ABILNj5weleTXoKR/G0pVJHN3g2XSK4G6d67l0d1Bwv/Hh/YvrTkeyUR5M 2mqIeFpYB6GLymvJvRv8kvMkykIrMnS2aVu+4/5zGPiG7wR/3SDq+G5wV/VTwlrSZrxl AaY6IzUXoG5LZKhXmndQHeJaWVmsAdEbV6chyAY1TpQQFbhMYCS4P7lgEIdOUkEqOQsD n6V1nvdaOmTPKfQ20Uf5+7TGGRg4CrCDtLAaqvydvQrU4yr3RGfMrvpVLyDnlW2GYWiP bdoA== X-Gm-Message-State: AOJu0YwqjCSnDO8dBAAWFVfdMLKMdnFThY9+rW7aHRwwhaiprVwReL/y X7LQlPtxZkXGEid1vSraLuSXJ/DAEBz7+O+eNtOJWkVuSaHQupg3PLwDsR5GN4n0AJI+L5XO6W6 wCgTx3a0jQ/5QhNj2lqmOlmHbJ4lYiXejQXb1FfcKK2kI6XMvKeZQ X-Received: by 2002:a05:6a20:9147:b0:134:73f6:5832 with SMTP id x7-20020a056a20914700b0013473f65832mr4440510pzc.16.1694825397688; Fri, 15 Sep 2023 17:49:57 -0700 (PDT) X-Google-Smtp-Source: AGHT+IFhDtCqqirkEBe1FGMx+lCBmvksc/mK9pVu6IBZcA011Mth+26Fz9OoH28MmGEuVchIl52vPQ== X-Received: by 2002:a05:6a20:9147:b0:134:73f6:5832 with SMTP id x7-20020a056a20914700b0013473f65832mr4440500pzc.16.1694825397398; Fri, 15 Sep 2023 17:49:57 -0700 (PDT) Received: from localhost (uk.sesame.canonical.com. [185.125.190.60]) by smtp.gmail.com with ESMTPSA id e23-20020aa78c57000000b0068ffd56f705sm3489527pfd.118.2023.09.15.17.49.55 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 15 Sep 2023 17:49:57 -0700 (PDT) From: Cengiz Can To: kernel-team@lists.ubuntu.com Subject: [SRU OEM-6.0] netfilter: nf_tables: validate catch-all set elements Date: Sat, 16 Sep 2023 03:48:20 +0300 Message-Id: <20230916004839.706452-11-cengiz.can@canonical.com> X-Mailer: git-send-email 2.39.2 In-Reply-To: <20230916004839.706452-1-cengiz.can@canonical.com> References: <20230916004839.706452-1-cengiz.can@canonical.com> MIME-Version: 1.0 X-BeenThere: kernel-team@lists.ubuntu.com X-Mailman-Version: 2.1.20 Precedence: list List-Id: Kernel team discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: kernel-team-bounces@lists.ubuntu.com Sender: "kernel-team" From: Pablo Neira Ayuso catch-all set element might jump/goto to chain that uses expressions that require validation. Fixes: aaa31047a6d2 ("netfilter: nftables: add catch-all set element support") Signed-off-by: Pablo Neira Ayuso (backported from commit d46fc894147cf98dd6e8210aa99ed46854191840) CVE-2023-4244 [cengizcan: prerequisite commit] [cengizcan: adjust line order in nf_tables.h to be exactly like upstream] Signed-off-by: Cengiz Can --- include/net/netfilter/nf_tables.h | 4 ++ net/netfilter/nf_tables_api.c | 64 ++++++++++++++++++++++++++++--- net/netfilter/nft_lookup.c | 36 ++--------------- 3 files changed, 66 insertions(+), 38 deletions(-) diff --git a/include/net/netfilter/nf_tables.h b/include/net/netfilter/nf_tables.h index c77a3eefe39c..984f7d308773 100644 --- a/include/net/netfilter/nf_tables.h +++ b/include/net/netfilter/nf_tables.h @@ -1085,6 +1085,10 @@ struct nft_chain { }; int nft_chain_validate(const struct nft_ctx *ctx, const struct nft_chain *chain); +int nft_setelem_validate(const struct nft_ctx *ctx, struct nft_set *set, + const struct nft_set_iter *iter, + struct nft_set_elem *elem); +int nft_set_catchall_validate(const struct nft_ctx *ctx, struct nft_set *set); int nf_tables_bind_chain(const struct nft_ctx *ctx, struct nft_chain *chain); void nf_tables_unbind_chain(const struct nft_ctx *ctx, struct nft_chain *chain); diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c index 37ad10abe819..418e1168d78c 100644 --- a/net/netfilter/nf_tables_api.c +++ b/net/netfilter/nf_tables_api.c @@ -3455,6 +3455,64 @@ static int nft_table_validate(struct net *net, const struct nft_table *table) return 0; } +int nft_setelem_validate(const struct nft_ctx *ctx, struct nft_set *set, + const struct nft_set_iter *iter, + struct nft_set_elem *elem) +{ + const struct nft_set_ext *ext = nft_set_elem_ext(set, elem->priv); + struct nft_ctx *pctx = (struct nft_ctx *)ctx; + const struct nft_data *data; + int err; + + if (nft_set_ext_exists(ext, NFT_SET_EXT_FLAGS) && + *nft_set_ext_flags(ext) & NFT_SET_ELEM_INTERVAL_END) + return 0; + + data = nft_set_ext_data(ext); + switch (data->verdict.code) { + case NFT_JUMP: + case NFT_GOTO: + pctx->level++; + err = nft_chain_validate(ctx, data->verdict.chain); + if (err < 0) + return err; + pctx->level--; + break; + default: + break; + } + + return 0; +} + +struct nft_set_elem_catchall { + struct list_head list; + struct rcu_head rcu; + void *elem; +}; + +int nft_set_catchall_validate(const struct nft_ctx *ctx, struct nft_set *set) +{ + u8 genmask = nft_genmask_next(ctx->net); + struct nft_set_elem_catchall *catchall; + struct nft_set_elem elem; + struct nft_set_ext *ext; + int ret = 0; + + list_for_each_entry_rcu(catchall, &set->catchall_list, list) { + ext = nft_set_elem_ext(set, catchall->elem); + if (!nft_set_elem_active(ext, genmask)) + continue; + + elem.priv = catchall->elem; + ret = nft_setelem_validate(ctx, set, NULL, &elem); + if (ret < 0) + return ret; + } + + return ret; +} + static struct nft_rule *nft_rule_lookup_byid(const struct net *net, const struct nft_chain *chain, const struct nlattr *nla); @@ -4765,12 +4823,6 @@ static int nf_tables_newset(struct sk_buff *skb, const struct nfnl_info *info, return err; } -struct nft_set_elem_catchall { - struct list_head list; - struct rcu_head rcu; - void *elem; -}; - static void nft_set_catchall_destroy(const struct nft_ctx *ctx, struct nft_set *set) { diff --git a/net/netfilter/nft_lookup.c b/net/netfilter/nft_lookup.c index 650c939208ce..68a5dea80548 100644 --- a/net/netfilter/nft_lookup.c +++ b/net/netfilter/nft_lookup.c @@ -198,37 +198,6 @@ static int nft_lookup_dump(struct sk_buff *skb, const struct nft_expr *expr) return -1; } -static int nft_lookup_validate_setelem(const struct nft_ctx *ctx, - struct nft_set *set, - const struct nft_set_iter *iter, - struct nft_set_elem *elem) -{ - const struct nft_set_ext *ext = nft_set_elem_ext(set, elem->priv); - struct nft_ctx *pctx = (struct nft_ctx *)ctx; - const struct nft_data *data; - int err; - - if (nft_set_ext_exists(ext, NFT_SET_EXT_FLAGS) && - *nft_set_ext_flags(ext) & NFT_SET_ELEM_INTERVAL_END) - return 0; - - data = nft_set_ext_data(ext); - switch (data->verdict.code) { - case NFT_JUMP: - case NFT_GOTO: - pctx->level++; - err = nft_chain_validate(ctx, data->verdict.chain); - if (err < 0) - return err; - pctx->level--; - break; - default: - break; - } - - return 0; -} - static int nft_lookup_validate(const struct nft_ctx *ctx, const struct nft_expr *expr, const struct nft_data **d) @@ -244,9 +213,12 @@ static int nft_lookup_validate(const struct nft_ctx *ctx, iter.skip = 0; iter.count = 0; iter.err = 0; - iter.fn = nft_lookup_validate_setelem; + iter.fn = nft_setelem_validate; priv->set->ops->walk(ctx, priv->set, &iter); + if (!iter.err) + iter.err = nft_set_catchall_validate(ctx, priv->set); + if (iter.err < 0) return iter.err;