]> git.baikalelectronics.ru Git - kernel.git/commitdiff
netfilter: log: work around missing softdep backend module
authorFlorian Westphal <fw@strlen.de>
Fri, 17 Sep 2021 16:50:17 +0000 (18:50 +0200)
committerPablo Neira Ayuso <pablo@netfilter.org>
Tue, 21 Sep 2021 01:46:56 +0000 (03:46 +0200)
iptables/nftables has two types of log modules:

1. backend, e.g. nf_log_syslog, which implement the functionality
2. frontend, e.g. xt_LOG or nft_log, which call the functionality
   provided by backend based on nf_tables or xtables rule set.

Problem is that the request_module() call to load the backed in
nf_logger_find_get() might happen with nftables transaction mutex held
in case the call path is via nf_tables/nft_compat.

This can cause deadlocks (see 'Fixes' tags for details).

The chosen solution as to let modprobe deal with this by adding 'pre: '
soft dep tag to xt_LOG (to load the syslog backend) and xt_NFLOG (to
load nflog backend).

Eric reports that this breaks on systems with older modprobe that
doesn't support softdeps.

Another, similar issue occurs when someone either insmods xt_(NF)LOG
directly or unloads the backend module (possible if no log frontend
is in use): because the frontend module is already loaded, modprobe is
not invoked again so the softdep isn't evaluated.

Add a workaround: If nf_logger_find_get() returns -ENOENT and call
is not via nft_compat, load the backend explicitly and try again.

Else, let nft_compat ask for deferred request_module via nf_tables
infra.

Softdeps are kept in-place, so with newer modprobe the dependencies
are resolved from userspace.

Fixes: cefa31a9d461 ("netfilter: nft_log: perform module load from nf_tables")
Fixes: a38b5b56d6f4 ("netfilter: nf_log: add module softdeps")
Reported-and-tested-by: Eric Dumazet <edumazet@google.com>
Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
net/netfilter/nft_compat.c
net/netfilter/xt_LOG.c
net/netfilter/xt_NFLOG.c

index 272bcdb1392dfc830e9bdd3b0a6f54d7b19ca954..f69cc73c581305dfb59963ce15d8716ea7bb52fb 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/netfilter_bridge/ebtables.h>
 #include <linux/netfilter_arp/arp_tables.h>
 #include <net/netfilter/nf_tables.h>
+#include <net/netfilter/nf_log.h>
 
 /* Used for matches where *info is larger than X byte */
 #define NFT_MATCH_LARGE_THRESH 192
@@ -257,8 +258,22 @@ nft_target_init(const struct nft_ctx *ctx, const struct nft_expr *expr,
        nft_compat_wait_for_destructors();
 
        ret = xt_check_target(&par, size, proto, inv);
-       if (ret < 0)
+       if (ret < 0) {
+               if (ret == -ENOENT) {
+                       const char *modname = NULL;
+
+                       if (strcmp(target->name, "LOG") == 0)
+                               modname = "nf_log_syslog";
+                       else if (strcmp(target->name, "NFLOG") == 0)
+                               modname = "nfnetlink_log";
+
+                       if (modname &&
+                           nft_request_module(ctx->net, "%s", modname) == -EAGAIN)
+                               return -EAGAIN;
+               }
+
                return ret;
+       }
 
        /* The standard target cannot be used */
        if (!target->target)
index 2ff75f7637b09dddf0e9b91ccd22b9b41dc6d05d..f39244f9c0ed94348b1d16ff468c1f78da1a0766 100644 (file)
@@ -44,6 +44,7 @@ log_tg(struct sk_buff *skb, const struct xt_action_param *par)
 static int log_tg_check(const struct xt_tgchk_param *par)
 {
        const struct xt_log_info *loginfo = par->targinfo;
+       int ret;
 
        if (par->family != NFPROTO_IPV4 && par->family != NFPROTO_IPV6)
                return -EINVAL;
@@ -58,7 +59,14 @@ static int log_tg_check(const struct xt_tgchk_param *par)
                return -EINVAL;
        }
 
-       return nf_logger_find_get(par->family, NF_LOG_TYPE_LOG);
+       ret = nf_logger_find_get(par->family, NF_LOG_TYPE_LOG);
+       if (ret != 0 && !par->nft_compat) {
+               request_module("%s", "nf_log_syslog");
+
+               ret = nf_logger_find_get(par->family, NF_LOG_TYPE_LOG);
+       }
+
+       return ret;
 }
 
 static void log_tg_destroy(const struct xt_tgdtor_param *par)
index fb579320805984d6c51d2d24bbcfd71f737bea33..e660c3710a10968909b98b5236536996cbb8462b 100644 (file)
@@ -42,13 +42,21 @@ nflog_tg(struct sk_buff *skb, const struct xt_action_param *par)
 static int nflog_tg_check(const struct xt_tgchk_param *par)
 {
        const struct xt_nflog_info *info = par->targinfo;
+       int ret;
 
        if (info->flags & ~XT_NFLOG_MASK)
                return -EINVAL;
        if (info->prefix[sizeof(info->prefix) - 1] != '\0')
                return -EINVAL;
 
-       return nf_logger_find_get(par->family, NF_LOG_TYPE_ULOG);
+       ret = nf_logger_find_get(par->family, NF_LOG_TYPE_ULOG);
+       if (ret != 0 && !par->nft_compat) {
+               request_module("%s", "nfnetlink_log");
+
+               ret = nf_logger_find_get(par->family, NF_LOG_TYPE_ULOG);
+       }
+
+       return ret;
 }
 
 static void nflog_tg_destroy(const struct xt_tgdtor_param *par)