From patchwork Wed Jul 17 00:30:40 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Matthew Ruffell X-Patchwork-Id: 1133021 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=lists.ubuntu.com (client-ip=91.189.94.19; helo=huckleberry.canonical.com; envelope-from=kernel-team-bounces@lists.ubuntu.com; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=canonical.com Received: from huckleberry.canonical.com (huckleberry.canonical.com [91.189.94.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 45pJ8k0ytGz9sNs; Wed, 17 Jul 2019 10:31:01 +1000 (AEST) Received: from localhost ([127.0.0.1] helo=huckleberry.canonical.com) by huckleberry.canonical.com with esmtp (Exim 4.86_2) (envelope-from ) id 1hnXqS-0003OS-40; Wed, 17 Jul 2019 00:30:56 +0000 Received: from youngberry.canonical.com ([91.189.89.112]) by huckleberry.canonical.com with esmtps (TLS1.0:DHE_RSA_AES_128_CBC_SHA1:128) (Exim 4.86_2) (envelope-from ) id 1hnXqP-0003NO-0A for kernel-team@lists.ubuntu.com; Wed, 17 Jul 2019 00:30:53 +0000 Received: from mail-pl1-f199.google.com ([209.85.214.199]) by youngberry.canonical.com with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.76) (envelope-from ) id 1hnXqO-0005uz-Gx for kernel-team@lists.ubuntu.com; Wed, 17 Jul 2019 00:30:52 +0000 Received: by mail-pl1-f199.google.com with SMTP id a5so11064340pla.3 for ; Tue, 16 Jul 2019 17:30:52 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=NJxGxjd5qDyStyGOnSqfrmsXHpVAQQODyZOvC1qR04c=; b=Fbrk8f0PhRh2Ue9RSUCVZzW0fojDzR7uThm+pSUW8b1M8RmKxZQksIv6LCUqyXAi1A NgkoJN7vfLFEB/a9sYB4xm8wYWiaU4BTaJJ4HImsBk4BsLER0WJKeP/FgYlwp4YUacZ5 hYMmnHY8tF2rjiMnGDNC84cfaXFUzxaDIlVulF9i6e1TPb+vh+VjNNipPvoSm65SUOfa z1DfZzKIx7mQY5BPyF02i1zLE3u9z62KUF1vKtIKZagxUgkY5685LNRAlvJ95qh/t1c9 nIC3/tNhbR7bqEJwbTUtRxLffjHrhxUf2yvtBz6a1Hj3zWyKxYgzWkxwcVx/2O8Jf7j8 AxVQ== X-Gm-Message-State: APjAAAVzfbsONgozbQOPR1ZPPsqvYXvgm8k/qxIYGquCAKSi5gq0U/M1 A4NRQRreIfwdRvvvjZvfeB+qVWcQUwKEXJd88bTMxLcbvE7pSso/vJWEKBHkw+JCSVbAXPLvH+w 6jrFGcXJuN4r9z6uv8BnEUC25O7T3v/3Titi4mX2evw== X-Received: by 2002:a17:902:704a:: with SMTP id h10mr38353652plt.337.1563323451037; Tue, 16 Jul 2019 17:30:51 -0700 (PDT) X-Google-Smtp-Source: APXvYqxxjftBmdYBxoeENgHQL8HhnW2YkXOrZLclQTunHe6/ddlTv0Lfhi/djJ+AWxhpoovlQXXxNg== X-Received: by 2002:a17:902:704a:: with SMTP id h10mr38353638plt.337.1563323450872; Tue, 16 Jul 2019 17:30:50 -0700 (PDT) Received: from localhost.localdomain (125-238-115-161-fibre.sparkbb.co.nz. [125.238.115.161]) by smtp.gmail.com with ESMTPSA id i74sm23814103pje.16.2019.07.16.17.30.49 for (version=TLS1_3 cipher=AEAD-AES256-GCM-SHA384 bits=256/256); Tue, 16 Jul 2019 17:30:50 -0700 (PDT) From: Matthew Ruffell To: kernel-team@lists.ubuntu.com Subject: [SRU][Bionic][PATCH 1/2] netfilter: nf_conntrack: resolve clash for matching conntracks Date: Wed, 17 Jul 2019 12:30:40 +1200 Message-Id: <20190717003041.9775-2-matthew.ruffell@canonical.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20190717003041.9775-1-matthew.ruffell@canonical.com> References: <20190717003041.9775-1-matthew.ruffell@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: Martynas Pumputis BugLink: https://bugs.launchpad.net/bugs/1836816 This patch enables the clash resolution for NAT (disabled in "590b52e10d41") if clashing conntracks match (i.e. both tuples are equal) and a protocol allows it. The clash might happen for a connections-less protocol (e.g. UDP) when two threads in parallel writes to the same socket and consequent calls to "get_unique_tuple" return the same tuples (incl. reply tuples). In this case it is safe to perform the resolution, as the losing CT describes the same mangling as the winning CT, so no modifications to the packet are needed, and the result of rules traversal for the loser's packet stays valid. Signed-off-by: Martynas Pumputis Signed-off-by: Pablo Neira Ayuso (cherry picked from commit ed07d9a021df6da53456663a76999189badc432a) Signed-off-by: Matthew Ruffell --- net/netfilter/nf_conntrack_core.c | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c index 85f643c1e227..dd7c06c1c1e5 100644 --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c @@ -508,6 +508,18 @@ nf_ct_key_equal(struct nf_conntrack_tuple_hash *h, net_eq(net, nf_ct_net(ct)); } +static inline bool +nf_ct_match(const struct nf_conn *ct1, const struct nf_conn *ct2) +{ + return nf_ct_tuple_equal(&ct1->tuplehash[IP_CT_DIR_ORIGINAL].tuple, + &ct2->tuplehash[IP_CT_DIR_ORIGINAL].tuple) && + nf_ct_tuple_equal(&ct1->tuplehash[IP_CT_DIR_REPLY].tuple, + &ct2->tuplehash[IP_CT_DIR_REPLY].tuple) && + nf_ct_zone_equal(ct1, nf_ct_zone(ct2), IP_CT_DIR_ORIGINAL) && + nf_ct_zone_equal(ct1, nf_ct_zone(ct2), IP_CT_DIR_REPLY) && + net_eq(nf_ct_net(ct1), nf_ct_net(ct2)); +} + /* caller must hold rcu readlock and none of the nf_conntrack_locks */ static void nf_ct_gc_expired(struct nf_conn *ct) { @@ -701,19 +713,21 @@ static int nf_ct_resolve_clash(struct net *net, struct sk_buff *skb, /* This is the conntrack entry already in hashes that won race. */ struct nf_conn *ct = nf_ct_tuplehash_to_ctrack(h); const struct nf_conntrack_l4proto *l4proto; + enum ip_conntrack_info oldinfo; + struct nf_conn *loser_ct = nf_ct_get(skb, &oldinfo); l4proto = __nf_ct_l4proto_find(nf_ct_l3num(ct), nf_ct_protonum(ct)); if (l4proto->allow_clash && - ((ct->status & IPS_NAT_DONE_MASK) == 0) && !nf_ct_is_dying(ct) && atomic_inc_not_zero(&ct->ct_general.use)) { - enum ip_conntrack_info oldinfo; - struct nf_conn *loser_ct = nf_ct_get(skb, &oldinfo); - - nf_ct_acct_merge(ct, ctinfo, loser_ct); - nf_conntrack_put(&loser_ct->ct_general); - nf_ct_set(skb, ct, oldinfo); - return NF_ACCEPT; + if (((ct->status & IPS_NAT_DONE_MASK) == 0) || + nf_ct_match(ct, loser_ct)) { + nf_ct_acct_merge(ct, ctinfo, loser_ct); + nf_conntrack_put(&loser_ct->ct_general); + nf_ct_set(skb, ct, oldinfo); + return NF_ACCEPT; + } + nf_ct_put(ct); } NF_CT_STAT_INC(net, drop); return NF_DROP;