mirror of
https://github.com/edk2-porting/linux-next.git
synced 2024-12-23 04:34:11 +08:00
netfilter: nf_tables: add and use helper for module autoload
module autoload is problematic, it requires dropping the mutex that protects the transaction. Once the mutex has been dropped, another client can start a new transaction before we had a chance to abort current transaction log. This helper makes sure we first zap the transaction log, then drop mutex for module autoload. In case autload is successful, the caller has to reply entire message anyway. Signed-off-by: Florian Westphal <fw@strlen.de> Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
This commit is contained in:
parent
440534d3c5
commit
452238e8d5
@ -455,8 +455,40 @@ __nf_tables_chain_type_lookup(const struct nlattr *nla, u8 family)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Loading a module requires dropping mutex that guards the
|
||||
* transaction.
|
||||
* We first need to abort any pending transactions as once
|
||||
* mutex is unlocked a different client could start a new
|
||||
* transaction. It must not see any 'future generation'
|
||||
* changes * as these changes will never happen.
|
||||
*/
|
||||
#ifdef CONFIG_MODULES
|
||||
static int __nf_tables_abort(struct net *net);
|
||||
|
||||
static void nft_request_module(struct net *net, const char *fmt, ...)
|
||||
{
|
||||
char module_name[MODULE_NAME_LEN];
|
||||
va_list args;
|
||||
int ret;
|
||||
|
||||
__nf_tables_abort(net);
|
||||
|
||||
va_start(args, fmt);
|
||||
ret = vsnprintf(module_name, MODULE_NAME_LEN, fmt, args);
|
||||
va_end(args);
|
||||
if (WARN(ret >= MODULE_NAME_LEN, "truncated: '%s' (len %d)", module_name, ret))
|
||||
return;
|
||||
|
||||
nfnl_unlock(NFNL_SUBSYS_NFTABLES);
|
||||
request_module("%s", module_name);
|
||||
nfnl_lock(NFNL_SUBSYS_NFTABLES);
|
||||
}
|
||||
#endif
|
||||
|
||||
static const struct nft_chain_type *
|
||||
nf_tables_chain_type_lookup(const struct nlattr *nla, u8 family, bool autoload)
|
||||
nf_tables_chain_type_lookup(struct net *net, const struct nlattr *nla,
|
||||
u8 family, bool autoload)
|
||||
{
|
||||
const struct nft_chain_type *type;
|
||||
|
||||
@ -465,10 +497,8 @@ nf_tables_chain_type_lookup(const struct nlattr *nla, u8 family, bool autoload)
|
||||
return type;
|
||||
#ifdef CONFIG_MODULES
|
||||
if (autoload) {
|
||||
nfnl_unlock(NFNL_SUBSYS_NFTABLES);
|
||||
request_module("nft-chain-%u-%.*s", family,
|
||||
nla_len(nla), (const char *)nla_data(nla));
|
||||
nfnl_lock(NFNL_SUBSYS_NFTABLES);
|
||||
nft_request_module(net, "nft-chain-%u-%.*s", family,
|
||||
nla_len(nla), (const char *)nla_data(nla));
|
||||
type = __nf_tables_chain_type_lookup(nla, family);
|
||||
if (type != NULL)
|
||||
return ERR_PTR(-EAGAIN);
|
||||
@ -1412,7 +1442,7 @@ static int nft_chain_parse_hook(struct net *net,
|
||||
|
||||
type = chain_type[family][NFT_CHAIN_T_DEFAULT];
|
||||
if (nla[NFTA_CHAIN_TYPE]) {
|
||||
type = nf_tables_chain_type_lookup(nla[NFTA_CHAIN_TYPE],
|
||||
type = nf_tables_chain_type_lookup(net, nla[NFTA_CHAIN_TYPE],
|
||||
family, create);
|
||||
if (IS_ERR(type))
|
||||
return PTR_ERR(type);
|
||||
@ -1875,7 +1905,8 @@ static const struct nft_expr_type *__nft_expr_type_get(u8 family,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const struct nft_expr_type *nft_expr_type_get(u8 family,
|
||||
static const struct nft_expr_type *nft_expr_type_get(struct net *net,
|
||||
u8 family,
|
||||
struct nlattr *nla)
|
||||
{
|
||||
const struct nft_expr_type *type;
|
||||
@ -1889,17 +1920,13 @@ static const struct nft_expr_type *nft_expr_type_get(u8 family,
|
||||
|
||||
#ifdef CONFIG_MODULES
|
||||
if (type == NULL) {
|
||||
nfnl_unlock(NFNL_SUBSYS_NFTABLES);
|
||||
request_module("nft-expr-%u-%.*s", family,
|
||||
nla_len(nla), (char *)nla_data(nla));
|
||||
nfnl_lock(NFNL_SUBSYS_NFTABLES);
|
||||
nft_request_module(net, "nft-expr-%u-%.*s", family,
|
||||
nla_len(nla), (char *)nla_data(nla));
|
||||
if (__nft_expr_type_get(family, nla))
|
||||
return ERR_PTR(-EAGAIN);
|
||||
|
||||
nfnl_unlock(NFNL_SUBSYS_NFTABLES);
|
||||
request_module("nft-expr-%.*s",
|
||||
nla_len(nla), (char *)nla_data(nla));
|
||||
nfnl_lock(NFNL_SUBSYS_NFTABLES);
|
||||
nft_request_module(net, "nft-expr-%.*s",
|
||||
nla_len(nla), (char *)nla_data(nla));
|
||||
if (__nft_expr_type_get(family, nla))
|
||||
return ERR_PTR(-EAGAIN);
|
||||
}
|
||||
@ -1968,7 +1995,7 @@ static int nf_tables_expr_parse(const struct nft_ctx *ctx,
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
type = nft_expr_type_get(ctx->family, tb[NFTA_EXPR_NAME]);
|
||||
type = nft_expr_type_get(ctx->net, ctx->family, tb[NFTA_EXPR_NAME]);
|
||||
if (IS_ERR(type))
|
||||
return PTR_ERR(type);
|
||||
|
||||
@ -2744,9 +2771,7 @@ nft_select_set_ops(const struct nft_ctx *ctx,
|
||||
|
||||
#ifdef CONFIG_MODULES
|
||||
if (list_empty(&nf_tables_set_types)) {
|
||||
nfnl_unlock(NFNL_SUBSYS_NFTABLES);
|
||||
request_module("nft-set");
|
||||
nfnl_lock(NFNL_SUBSYS_NFTABLES);
|
||||
nft_request_module(ctx->net, "nft-set");
|
||||
if (!list_empty(&nf_tables_set_types))
|
||||
return ERR_PTR(-EAGAIN);
|
||||
}
|
||||
@ -4779,7 +4804,8 @@ static const struct nft_object_type *__nft_obj_type_get(u32 objtype)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const struct nft_object_type *nft_obj_type_get(u32 objtype)
|
||||
static const struct nft_object_type *
|
||||
nft_obj_type_get(struct net *net, u32 objtype)
|
||||
{
|
||||
const struct nft_object_type *type;
|
||||
|
||||
@ -4789,9 +4815,7 @@ static const struct nft_object_type *nft_obj_type_get(u32 objtype)
|
||||
|
||||
#ifdef CONFIG_MODULES
|
||||
if (type == NULL) {
|
||||
nfnl_unlock(NFNL_SUBSYS_NFTABLES);
|
||||
request_module("nft-obj-%u", objtype);
|
||||
nfnl_lock(NFNL_SUBSYS_NFTABLES);
|
||||
nft_request_module(net, "nft-obj-%u", objtype);
|
||||
if (__nft_obj_type_get(objtype))
|
||||
return ERR_PTR(-EAGAIN);
|
||||
}
|
||||
@ -4843,7 +4867,7 @@ static int nf_tables_newobj(struct net *net, struct sock *nlsk,
|
||||
|
||||
nft_ctx_init(&ctx, net, skb, nlh, family, table, NULL, nla);
|
||||
|
||||
type = nft_obj_type_get(objtype);
|
||||
type = nft_obj_type_get(net, objtype);
|
||||
if (IS_ERR(type))
|
||||
return PTR_ERR(type);
|
||||
|
||||
@ -5339,7 +5363,8 @@ static const struct nf_flowtable_type *__nft_flowtable_type_get(u8 family)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const struct nf_flowtable_type *nft_flowtable_type_get(u8 family)
|
||||
static const struct nf_flowtable_type *
|
||||
nft_flowtable_type_get(struct net *net, u8 family)
|
||||
{
|
||||
const struct nf_flowtable_type *type;
|
||||
|
||||
@ -5349,9 +5374,7 @@ static const struct nf_flowtable_type *nft_flowtable_type_get(u8 family)
|
||||
|
||||
#ifdef CONFIG_MODULES
|
||||
if (type == NULL) {
|
||||
nfnl_unlock(NFNL_SUBSYS_NFTABLES);
|
||||
request_module("nf-flowtable-%u", family);
|
||||
nfnl_lock(NFNL_SUBSYS_NFTABLES);
|
||||
nft_request_module(net, "nf-flowtable-%u", family);
|
||||
if (__nft_flowtable_type_get(family))
|
||||
return ERR_PTR(-EAGAIN);
|
||||
}
|
||||
@ -5431,7 +5454,7 @@ static int nf_tables_newflowtable(struct net *net, struct sock *nlsk,
|
||||
goto err1;
|
||||
}
|
||||
|
||||
type = nft_flowtable_type_get(family);
|
||||
type = nft_flowtable_type_get(net, family);
|
||||
if (IS_ERR(type)) {
|
||||
err = PTR_ERR(type);
|
||||
goto err2;
|
||||
|
Loading…
Reference in New Issue
Block a user