Skip to content

Commit b53deef

Browse files
Florian Westphalummakynes
authored andcommitted
netfilter: log: work around missing softdep backend module
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: cefa31a ("netfilter: nft_log: perform module load from nf_tables") Fixes: a38b5b5 ("netfilter: nf_log: add module softdeps") Reported-and-tested-by: Eric Dumazet <[email protected]> Signed-off-by: Florian Westphal <[email protected]> Signed-off-by: Pablo Neira Ayuso <[email protected]>
1 parent cc80721 commit b53deef

File tree

3 files changed

+34
-3
lines changed

3 files changed

+34
-3
lines changed

net/netfilter/nft_compat.c

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include <linux/netfilter_bridge/ebtables.h>
2020
#include <linux/netfilter_arp/arp_tables.h>
2121
#include <net/netfilter/nf_tables.h>
22+
#include <net/netfilter/nf_log.h>
2223

2324
/* Used for matches where *info is larger than X byte */
2425
#define NFT_MATCH_LARGE_THRESH 192
@@ -257,8 +258,22 @@ nft_target_init(const struct nft_ctx *ctx, const struct nft_expr *expr,
257258
nft_compat_wait_for_destructors();
258259

259260
ret = xt_check_target(&par, size, proto, inv);
260-
if (ret < 0)
261+
if (ret < 0) {
262+
if (ret == -ENOENT) {
263+
const char *modname = NULL;
264+
265+
if (strcmp(target->name, "LOG") == 0)
266+
modname = "nf_log_syslog";
267+
else if (strcmp(target->name, "NFLOG") == 0)
268+
modname = "nfnetlink_log";
269+
270+
if (modname &&
271+
nft_request_module(ctx->net, "%s", modname) == -EAGAIN)
272+
return -EAGAIN;
273+
}
274+
261275
return ret;
276+
}
262277

263278
/* The standard target cannot be used */
264279
if (!target->target)

net/netfilter/xt_LOG.c

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ log_tg(struct sk_buff *skb, const struct xt_action_param *par)
4444
static int log_tg_check(const struct xt_tgchk_param *par)
4545
{
4646
const struct xt_log_info *loginfo = par->targinfo;
47+
int ret;
4748

4849
if (par->family != NFPROTO_IPV4 && par->family != NFPROTO_IPV6)
4950
return -EINVAL;
@@ -58,7 +59,14 @@ static int log_tg_check(const struct xt_tgchk_param *par)
5859
return -EINVAL;
5960
}
6061

61-
return nf_logger_find_get(par->family, NF_LOG_TYPE_LOG);
62+
ret = nf_logger_find_get(par->family, NF_LOG_TYPE_LOG);
63+
if (ret != 0 && !par->nft_compat) {
64+
request_module("%s", "nf_log_syslog");
65+
66+
ret = nf_logger_find_get(par->family, NF_LOG_TYPE_LOG);
67+
}
68+
69+
return ret;
6270
}
6371

6472
static void log_tg_destroy(const struct xt_tgdtor_param *par)

net/netfilter/xt_NFLOG.c

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,13 +42,21 @@ nflog_tg(struct sk_buff *skb, const struct xt_action_param *par)
4242
static int nflog_tg_check(const struct xt_tgchk_param *par)
4343
{
4444
const struct xt_nflog_info *info = par->targinfo;
45+
int ret;
4546

4647
if (info->flags & ~XT_NFLOG_MASK)
4748
return -EINVAL;
4849
if (info->prefix[sizeof(info->prefix) - 1] != '\0')
4950
return -EINVAL;
5051

51-
return nf_logger_find_get(par->family, NF_LOG_TYPE_ULOG);
52+
ret = nf_logger_find_get(par->family, NF_LOG_TYPE_ULOG);
53+
if (ret != 0 && !par->nft_compat) {
54+
request_module("%s", "nfnetlink_log");
55+
56+
ret = nf_logger_find_get(par->family, NF_LOG_TYPE_ULOG);
57+
}
58+
59+
return ret;
5260
}
5361

5462
static void nflog_tg_destroy(const struct xt_tgdtor_param *par)

0 commit comments

Comments
 (0)