From patchwork Fri Aug 30 09:05:22 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Massimiliano Pellizzer X-Patchwork-Id: 1978839 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 4WwC382GkNz1ygJ for ; Fri, 30 Aug 2024 19:07:31 +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 1sjxbC-00075b-L3; Fri, 30 Aug 2024 09:07:18 +0000 Received: from smtp-relay-internal-1.internal ([10.131.114.114] helo=smtp-relay-internal-1.canonical.com) by lists.ubuntu.com with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.86_2) (envelope-from ) id 1sjxbA-00075D-EA for kernel-team@lists.ubuntu.com; Fri, 30 Aug 2024 09:07:16 +0000 Received: from mail-ej1-f72.google.com (mail-ej1-f72.google.com [209.85.218.72]) (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-1.canonical.com (Postfix) with ESMTPS id 1E6103F196 for ; Fri, 30 Aug 2024 09:07:16 +0000 (UTC) Received: by mail-ej1-f72.google.com with SMTP id a640c23a62f3a-a868c4d16a6so134567766b.0 for ; Fri, 30 Aug 2024 02:07:16 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1725008835; x=1725613635; 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=2JpoFf/SrNeYe8Yoc+5WcTFmVGGTmlr2dFy+4Ii2u0U=; b=M0M1+LezPQ04k+ICEurgdA5Rt5dGlG3Qwpew/ZTBLqB9GKtu3sx39+u4XWRKqGOhpy 8kQnr0ri9sJgss3kAf0SmhGGVqBDjTwRkIPYBbAmCSThQSZmvOIB8cjI4pDjiRWh512f 6/awx17SezXadSoacSD9qjchj6jnmcN7OSOGOLm+HW+m0EdBgw2/1i4qPKiUlTU/QExS 6OcUk2sdtpP8+rCsovrwnXR741zTD1RAf5nsimYAKp0M3EJAXHHuKBI5/HCv6xS9pjti wIZopQYLULcZ7KDFLo0UQBWOi5OtOKpvvWA00Qp4UXoMWWPEhTaZGgoDRCed4886DYPf lC3w== X-Gm-Message-State: AOJu0YyxUmHihf2zcY0nxgQBYsVaosYm6ugU66yBXHTiESS1Sp4cyWsk GY/bTTm8KxXzEMPlyuDosgel4TELmK/djaTsXAW4HB8VXlTPu2G1/K2RyNXvjBuFHMUyTv0+2Gt 1WfMLUXd+/w661zrbLXEiUeRh6Wqvc0lDnxPc3DfVEzAKPhE7zCbX/HIyZPql+aPleM9SdRVRfG AOG1arkcDBHg== X-Received: by 2002:a17:907:9686:b0:a86:96d1:d1b with SMTP id a640c23a62f3a-a897f83ad1amr416956366b.16.1725008835413; Fri, 30 Aug 2024 02:07:15 -0700 (PDT) X-Google-Smtp-Source: AGHT+IGiBLRvVmkBIpx/y/KkqFHZonf5TORnsHXgk5ivCvGlUbm1yTue00iFV4FWvtkisOH748lwRA== X-Received: by 2002:a17:907:9686:b0:a86:96d1:d1b with SMTP id a640c23a62f3a-a897f83ad1amr416952566b.16.1725008834515; Fri, 30 Aug 2024 02:07:14 -0700 (PDT) Received: from framework-canonical.station (net-93-71-65-44.cust.vodafonedsl.it. [93.71.65.44]) by smtp.gmail.com with ESMTPSA id a640c23a62f3a-a89891d713asm191076766b.152.2024.08.30.02.07.13 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 30 Aug 2024 02:07:14 -0700 (PDT) From: Massimiliano Pellizzer To: kernel-team@lists.ubuntu.com Subject: [SRU][F][PATCH 1/1] netfilter: nf_tables: use timestamp to check for set element timeout Date: Fri, 30 Aug 2024 11:05:22 +0200 Message-ID: <20240830090626.18537-2-massimiliano.pellizzer@canonical.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20240830090626.18537-1-massimiliano.pellizzer@canonical.com> References: <20240830090626.18537-1-massimiliano.pellizzer@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 commit 7395dfacfff65e9938ac0889dafa1ab01e987d15 upstream Add a timestamp field at the beginning of the transaction, store it in the nftables per-netns area. Update set backend .insert, .deactivate and sync gc path to use the timestamp, this avoids that an element expires while control plane transaction is still unfinished. .lookup and .update, which are used from packet path, still use the current time to check if the element has expired. And .get path and dump also since this runs lockless under rcu read size lock. Then, there is async gc which also needs to check the current time since it runs asynchronously from a workqueue. [ NB: rbtree GC updates has been excluded because GC is asynchronous. ] Fixes: c3e1b005ed1c ("netfilter: nf_tables: add set element timeout support") Signed-off-by: Pablo Neira Ayuso Signed-off-by: Greg Kroah-Hartman (backported from commit eaf1a29ea5d7dba8e84e9e9f3b3f47d0cd540bfe linux-5.4.y) [mpellizzer: solved a merge conflict due to a variable declaration which does not affect the patch] CVE--2024-27397 Signed-off-by: Massimiliano Pellizzer --- include/net/netfilter/nf_tables.h | 21 +++++++++++++++++++-- net/netfilter/nf_tables_api.c | 1 + net/netfilter/nft_set_hash.c | 8 +++++++- net/netfilter/nft_set_rbtree.c | 6 ++++-- 4 files changed, 31 insertions(+), 5 deletions(-) diff --git a/include/net/netfilter/nf_tables.h b/include/net/netfilter/nf_tables.h index 74ee59746f6b..a7672b8a909e 100644 --- a/include/net/netfilter/nf_tables.h +++ b/include/net/netfilter/nf_tables.h @@ -13,6 +13,7 @@ #include #include #include +#include struct module; @@ -656,10 +657,16 @@ static inline struct nft_expr *nft_set_ext_expr(const struct nft_set_ext *ext) return nft_set_ext(ext, NFT_SET_EXT_EXPR); } -static inline bool nft_set_elem_expired(const struct nft_set_ext *ext) +static inline bool __nft_set_elem_expired(const struct nft_set_ext *ext, + u64 tstamp) { return nft_set_ext_exists(ext, NFT_SET_EXT_EXPIRATION) && - time_is_before_eq_jiffies64(*nft_set_ext_expiration(ext)); + time_after_eq64(tstamp, *nft_set_ext_expiration(ext)); +} + +static inline bool nft_set_elem_expired(const struct nft_set_ext *ext) +{ + return __nft_set_elem_expired(ext, get_jiffies_64()); } static inline struct nft_set_ext *nft_set_elem_ext(const struct nft_set *set, @@ -1488,9 +1495,19 @@ struct nftables_pernet { struct list_head module_list; struct list_head notify_list; struct mutex commit_mutex; + u64 tstamp; unsigned int base_seq; u8 validate_state; unsigned int gc_seq; }; +extern unsigned int nf_tables_net_id; + +static inline u64 nft_net_tstamp(const struct net *net) +{ + struct nftables_pernet *nft_net = net_generic(net, nf_tables_net_id); + + return nft_net->tstamp; +} + #endif /* _NET_NF_TABLES_H */ diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c index 10e7d8e9df04..14f730a371bd 100644 --- a/net/netfilter/nf_tables_api.c +++ b/net/netfilter/nf_tables_api.c @@ -7810,6 +7810,7 @@ static bool nf_tables_valid_genid(struct net *net, u32 genid) bool genid_ok; mutex_lock(&nft_net->commit_mutex); + nft_net->tstamp = get_jiffies_64(); genid_ok = genid == 0 || nft_net->base_seq == genid; if (!genid_ok) diff --git a/net/netfilter/nft_set_hash.c b/net/netfilter/nft_set_hash.c index 7f49c6c37c94..92ab00d17337 100644 --- a/net/netfilter/nft_set_hash.c +++ b/net/netfilter/nft_set_hash.c @@ -38,6 +38,7 @@ struct nft_rhash_cmp_arg { const struct nft_set *set; const u32 *key; u8 genmask; + u64 tstamp; }; static inline u32 nft_rhash_key(const void *data, u32 len, u32 seed) @@ -64,7 +65,7 @@ static inline int nft_rhash_cmp(struct rhashtable_compare_arg *arg, return 1; if (nft_set_elem_is_dead(&he->ext)) return 1; - if (nft_set_elem_expired(&he->ext)) + if (__nft_set_elem_expired(&he->ext, x->tstamp)) return 1; if (!nft_set_elem_active(&he->ext, x->genmask)) return 1; @@ -88,6 +89,7 @@ static bool nft_rhash_lookup(const struct net *net, const struct nft_set *set, .genmask = nft_genmask_cur(net), .set = set, .key = key, + .tstamp = get_jiffies_64(), }; he = rhashtable_lookup(&priv->ht, &arg, nft_rhash_params); @@ -106,6 +108,7 @@ static void *nft_rhash_get(const struct net *net, const struct nft_set *set, .genmask = nft_genmask_cur(net), .set = set, .key = elem->key.val.data, + .tstamp = get_jiffies_64(), }; he = rhashtable_lookup(&priv->ht, &arg, nft_rhash_params); @@ -129,6 +132,7 @@ static bool nft_rhash_update(struct nft_set *set, const u32 *key, .genmask = NFT_GENMASK_ANY, .set = set, .key = key, + .tstamp = get_jiffies_64(), }; he = rhashtable_lookup(&priv->ht, &arg, nft_rhash_params); @@ -172,6 +176,7 @@ static int nft_rhash_insert(const struct net *net, const struct nft_set *set, .genmask = nft_genmask_next(net), .set = set, .key = elem->key.val.data, + .tstamp = nft_net_tstamp(net), }; struct nft_rhash_elem *prev; @@ -214,6 +219,7 @@ static void *nft_rhash_deactivate(const struct net *net, .genmask = nft_genmask_next(net), .set = set, .key = elem->key.val.data, + .tstamp = nft_net_tstamp(net), }; rcu_read_lock(); diff --git a/net/netfilter/nft_set_rbtree.c b/net/netfilter/nft_set_rbtree.c index ec322d818de0..4594e1d88cf9 100644 --- a/net/netfilter/nft_set_rbtree.c +++ b/net/netfilter/nft_set_rbtree.c @@ -316,6 +316,7 @@ static int __nft_rbtree_insert(const struct net *net, const struct nft_set *set, struct nft_rbtree *priv = nft_set_priv(set); u8 cur_genmask = nft_genmask_cur(net); u8 genmask = nft_genmask_next(net); + u64 tstamp = nft_net_tstamp(net); int d; /* Descend the tree to search for an existing element greater than the @@ -363,7 +364,7 @@ static int __nft_rbtree_insert(const struct net *net, const struct nft_set *set, /* perform garbage collection to avoid bogus overlap reports * but skip new elements in this transaction. */ - if (nft_set_elem_expired(&rbe->ext) && + if (__nft_set_elem_expired(&rbe->ext, tstamp) && nft_set_elem_active(&rbe->ext, cur_genmask)) { const struct nft_rbtree_elem *removed_end; @@ -550,6 +551,7 @@ static void *nft_rbtree_deactivate(const struct net *net, const struct rb_node *parent = priv->root.rb_node; struct nft_rbtree_elem *rbe, *this = elem->priv; u8 genmask = nft_genmask_next(net); + u64 tstamp = nft_net_tstamp(net); int d; while (parent != NULL) { @@ -570,7 +572,7 @@ static void *nft_rbtree_deactivate(const struct net *net, nft_rbtree_interval_end(this)) { parent = parent->rb_right; continue; - } else if (nft_set_elem_expired(&rbe->ext)) { + } else if (__nft_set_elem_expired(&rbe->ext, tstamp)) { break; } else if (!nft_set_elem_active(&rbe->ext, genmask)) { parent = parent->rb_left;