]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
netfilter: nfnetlink_cthelper: use {READ,WRITE}_ONCE for accessing helper flags
authorPablo Neira Ayuso <pablo@netfilter.org>
Tue, 26 May 2026 16:40:44 +0000 (18:40 +0200)
committerPablo Neira Ayuso <pablo@netfilter.org>
Fri, 5 Jun 2026 11:11:54 +0000 (13:11 +0200)
Conntrack helper flags are accessed from packet and netlink dump path.
Concurrent update of userspace helper flags is not possible, because the
nfnl_mutex in held on updates. These flags are only used by userspace
helpers. Use {READ,WRITE}_ONCE() to access this flags from lockless
paths.

Fixes: 12f7a505331e ("netfilter: add user-space connection tracking helper infrastructure")
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
net/netfilter/nf_conntrack_core.c
net/netfilter/nfnetlink_cthelper.c

index b521b5ebd66449cac2981b5b52b74c6756169426..c072a14a306afeb0832c822b0a077e60203b35b7 100644 (file)
@@ -2213,6 +2213,7 @@ static int nf_confirm_cthelper(struct sk_buff *skb, struct nf_conn *ct,
 {
        const struct nf_conntrack_helper *helper;
        const struct nf_conn_help *help;
+       unsigned int helper_flags;
        int protoff;
 
        help = nfct_help(ct);
@@ -2223,7 +2224,8 @@ static int nf_confirm_cthelper(struct sk_buff *skb, struct nf_conn *ct,
        if (!helper)
                return NF_ACCEPT;
 
-       if (!(helper->flags & NF_CT_HELPER_F_USERSPACE))
+       helper_flags = READ_ONCE(helper->flags);
+       if (!(helper_flags & NF_CT_HELPER_F_USERSPACE))
                return NF_ACCEPT;
 
        switch (nf_ct_l3num(ct)) {
index 34af6840803e2b830751f4f07ba4f36d0b4c4920..267eac1167f3b3f1614d5dc43aef6fcf6f195684 100644 (file)
@@ -41,8 +41,9 @@ static int
 nfnl_userspace_cthelper(struct sk_buff *skb, unsigned int protoff,
                        struct nf_conn *ct, enum ip_conntrack_info ctinfo)
 {
-       const struct nf_conn_help *help;
        struct nf_conntrack_helper *helper;
+       const struct nf_conn_help *help;
+       unsigned int helper_flags;
 
        help = nfct_help(ct);
        if (help == NULL)
@@ -53,8 +54,10 @@ nfnl_userspace_cthelper(struct sk_buff *skb, unsigned int protoff,
        if (helper == NULL)
                return NF_DROP;
 
+       helper_flags = READ_ONCE(helper->flags);
+
        /* This is a user-space helper not yet configured, skip. */
-       if ((helper->flags &
+       if ((helper_flags &
            (NF_CT_HELPER_F_USERSPACE | NF_CT_HELPER_F_CONFIGURED)) ==
             NF_CT_HELPER_F_USERSPACE)
                return NF_ACCEPT;
@@ -404,10 +407,10 @@ nfnl_cthelper_update(const struct nlattr * const tb[],
 
                switch(status) {
                case NFCT_HELPER_STATUS_ENABLED:
-                       helper->flags |= NF_CT_HELPER_F_CONFIGURED;
+                       WRITE_ONCE(helper->flags, helper->flags | NF_CT_HELPER_F_CONFIGURED);
                        break;
                case NFCT_HELPER_STATUS_DISABLED:
-                       helper->flags &= ~NF_CT_HELPER_F_CONFIGURED;
+                       WRITE_ONCE(helper->flags, helper->flags & ~NF_CT_HELPER_F_CONFIGURED);
                        break;
                }
        }
@@ -529,8 +532,8 @@ static int
 nfnl_cthelper_fill_info(struct sk_buff *skb, u32 portid, u32 seq, u32 type,
                        int event, struct nf_conntrack_helper *helper)
 {
-       struct nlmsghdr *nlh;
        unsigned int flags = portid ? NLM_F_MULTI : 0;
+       struct nlmsghdr *nlh;
        int status;
 
        event = nfnl_msg_type(NFNL_SUBSYS_CTHELPER, event);
@@ -554,7 +557,7 @@ nfnl_cthelper_fill_info(struct sk_buff *skb, u32 portid, u32 seq, u32 type,
        if (nla_put_be32(skb, NFCTH_PRIV_DATA_LEN, htonl(helper->data_len)))
                goto nla_put_failure;
 
-       if (helper->flags & NF_CT_HELPER_F_CONFIGURED)
+       if (READ_ONCE(helper->flags) & NF_CT_HELPER_F_CONFIGURED)
                status = NFCT_HELPER_STATUS_ENABLED;
        else
                status = NFCT_HELPER_STATUS_DISABLED;
@@ -575,6 +578,7 @@ static int
 nfnl_cthelper_dump_table(struct sk_buff *skb, struct netlink_callback *cb)
 {
        struct nf_conntrack_helper *cur, *last;
+       unsigned int helper_flags;
 
        rcu_read_lock();
        last = (struct nf_conntrack_helper *)cb->args[1];
@@ -583,8 +587,10 @@ restart:
                hlist_for_each_entry_rcu(cur,
                                &nf_ct_helper_hash[cb->args[0]], hnode) {
 
+                       helper_flags = READ_ONCE(cur->flags);
+
                        /* skip non-userspace conntrack helpers. */
-                       if (!(cur->flags & NF_CT_HELPER_F_USERSPACE))
+                       if (!(helper_flags & NF_CT_HELPER_F_USERSPACE))
                                continue;
 
                        if (cb->args[1]) {