Commit 4de75d3e authored by Jakub Kicinski's avatar Jakub Kicinski

Merge tag 'nf-23-12-06' of git://git.kernel.org/pub/scm/linux/kernel/git/netfilter/nf

Pablo Neira Ayuso says:

====================
Netfilter fixes for net

The following patchset contains Netfilter fixes for net:

1) Incorrect nf_defrag registration for bpf link infra, from D. Wythe.

2) Skip inactive elements in pipapo set backend walk to avoid double
   deactivation, from Florian Westphal.

3) Fix NFT_*_F_PRESENT check with big endian arch, also from Florian.

4) Bail out if number of expressions in NFTA_DYNSET_EXPRESSIONS mismatch
   stateful expressions in set declaration.

5) Honor family in table lookup by handle. Broken since 4.16.

6) Use sk_callback_lock to protect access to sk->sk_socket in xt_owner.
   sock_orphan() might zap this pointer, from Phil Sutter.

All of these fixes address broken stuff for several releases.

* tag 'nf-23-12-06' of git://git.kernel.org/pub/scm/linux/kernel/git/netfilter/nf:
  netfilter: xt_owner: Fix for unsafe access of sk->sk_socket
  netfilter: nf_tables: validate family when identifying table via handle
  netfilter: nf_tables: bail out on mismatching dynset and set expressions
  netfilter: nf_tables: fix 'exist' matching on bigendian arches
  netfilter: nft_set_pipapo: skip inactive elements during set walk
  netfilter: bpf: fix bad registration on nf_defrag
====================

Link: https://lore.kernel.org/r/20231206180357.959930-1-pablo@netfilter.orgSigned-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents c85e5594 7ae836a3
...@@ -31,7 +31,7 @@ struct bpf_nf_link { ...@@ -31,7 +31,7 @@ struct bpf_nf_link {
#if IS_ENABLED(CONFIG_NF_DEFRAG_IPV4) || IS_ENABLED(CONFIG_NF_DEFRAG_IPV6) #if IS_ENABLED(CONFIG_NF_DEFRAG_IPV4) || IS_ENABLED(CONFIG_NF_DEFRAG_IPV6)
static const struct nf_defrag_hook * static const struct nf_defrag_hook *
get_proto_defrag_hook(struct bpf_nf_link *link, get_proto_defrag_hook(struct bpf_nf_link *link,
const struct nf_defrag_hook __rcu *global_hook, const struct nf_defrag_hook __rcu **ptr_global_hook,
const char *mod) const char *mod)
{ {
const struct nf_defrag_hook *hook; const struct nf_defrag_hook *hook;
...@@ -39,7 +39,7 @@ get_proto_defrag_hook(struct bpf_nf_link *link, ...@@ -39,7 +39,7 @@ get_proto_defrag_hook(struct bpf_nf_link *link,
/* RCU protects us from races against module unloading */ /* RCU protects us from races against module unloading */
rcu_read_lock(); rcu_read_lock();
hook = rcu_dereference(global_hook); hook = rcu_dereference(*ptr_global_hook);
if (!hook) { if (!hook) {
rcu_read_unlock(); rcu_read_unlock();
err = request_module(mod); err = request_module(mod);
...@@ -47,7 +47,7 @@ get_proto_defrag_hook(struct bpf_nf_link *link, ...@@ -47,7 +47,7 @@ get_proto_defrag_hook(struct bpf_nf_link *link,
return ERR_PTR(err < 0 ? err : -EINVAL); return ERR_PTR(err < 0 ? err : -EINVAL);
rcu_read_lock(); rcu_read_lock();
hook = rcu_dereference(global_hook); hook = rcu_dereference(*ptr_global_hook);
} }
if (hook && try_module_get(hook->owner)) { if (hook && try_module_get(hook->owner)) {
...@@ -78,7 +78,7 @@ static int bpf_nf_enable_defrag(struct bpf_nf_link *link) ...@@ -78,7 +78,7 @@ static int bpf_nf_enable_defrag(struct bpf_nf_link *link)
switch (link->hook_ops.pf) { switch (link->hook_ops.pf) {
#if IS_ENABLED(CONFIG_NF_DEFRAG_IPV4) #if IS_ENABLED(CONFIG_NF_DEFRAG_IPV4)
case NFPROTO_IPV4: case NFPROTO_IPV4:
hook = get_proto_defrag_hook(link, nf_defrag_v4_hook, "nf_defrag_ipv4"); hook = get_proto_defrag_hook(link, &nf_defrag_v4_hook, "nf_defrag_ipv4");
if (IS_ERR(hook)) if (IS_ERR(hook))
return PTR_ERR(hook); return PTR_ERR(hook);
...@@ -87,7 +87,7 @@ static int bpf_nf_enable_defrag(struct bpf_nf_link *link) ...@@ -87,7 +87,7 @@ static int bpf_nf_enable_defrag(struct bpf_nf_link *link)
#endif #endif
#if IS_ENABLED(CONFIG_NF_DEFRAG_IPV6) #if IS_ENABLED(CONFIG_NF_DEFRAG_IPV6)
case NFPROTO_IPV6: case NFPROTO_IPV6:
hook = get_proto_defrag_hook(link, nf_defrag_v6_hook, "nf_defrag_ipv6"); hook = get_proto_defrag_hook(link, &nf_defrag_v6_hook, "nf_defrag_ipv6");
if (IS_ERR(hook)) if (IS_ERR(hook))
return PTR_ERR(hook); return PTR_ERR(hook);
......
...@@ -803,7 +803,7 @@ static struct nft_table *nft_table_lookup(const struct net *net, ...@@ -803,7 +803,7 @@ static struct nft_table *nft_table_lookup(const struct net *net,
static struct nft_table *nft_table_lookup_byhandle(const struct net *net, static struct nft_table *nft_table_lookup_byhandle(const struct net *net,
const struct nlattr *nla, const struct nlattr *nla,
u8 genmask, u32 nlpid) int family, u8 genmask, u32 nlpid)
{ {
struct nftables_pernet *nft_net; struct nftables_pernet *nft_net;
struct nft_table *table; struct nft_table *table;
...@@ -811,6 +811,7 @@ static struct nft_table *nft_table_lookup_byhandle(const struct net *net, ...@@ -811,6 +811,7 @@ static struct nft_table *nft_table_lookup_byhandle(const struct net *net,
nft_net = nft_pernet(net); nft_net = nft_pernet(net);
list_for_each_entry(table, &nft_net->tables, list) { list_for_each_entry(table, &nft_net->tables, list) {
if (be64_to_cpu(nla_get_be64(nla)) == table->handle && if (be64_to_cpu(nla_get_be64(nla)) == table->handle &&
table->family == family &&
nft_active_genmask(table, genmask)) { nft_active_genmask(table, genmask)) {
if (nft_table_has_owner(table) && if (nft_table_has_owner(table) &&
nlpid && table->nlpid != nlpid) nlpid && table->nlpid != nlpid)
...@@ -1544,7 +1545,7 @@ static int nf_tables_deltable(struct sk_buff *skb, const struct nfnl_info *info, ...@@ -1544,7 +1545,7 @@ static int nf_tables_deltable(struct sk_buff *skb, const struct nfnl_info *info,
if (nla[NFTA_TABLE_HANDLE]) { if (nla[NFTA_TABLE_HANDLE]) {
attr = nla[NFTA_TABLE_HANDLE]; attr = nla[NFTA_TABLE_HANDLE];
table = nft_table_lookup_byhandle(net, attr, genmask, table = nft_table_lookup_byhandle(net, attr, family, genmask,
NETLINK_CB(skb).portid); NETLINK_CB(skb).portid);
} else { } else {
attr = nla[NFTA_TABLE_NAME]; attr = nla[NFTA_TABLE_NAME];
......
...@@ -280,11 +280,16 @@ static int nft_dynset_init(const struct nft_ctx *ctx, ...@@ -280,11 +280,16 @@ static int nft_dynset_init(const struct nft_ctx *ctx,
priv->expr_array[i] = dynset_expr; priv->expr_array[i] = dynset_expr;
priv->num_exprs++; priv->num_exprs++;
if (set->num_exprs && if (set->num_exprs) {
dynset_expr->ops != set->exprs[i]->ops) { if (i >= set->num_exprs) {
err = -EINVAL;
goto err_expr_free;
}
if (dynset_expr->ops != set->exprs[i]->ops) {
err = -EOPNOTSUPP; err = -EOPNOTSUPP;
goto err_expr_free; goto err_expr_free;
} }
}
i++; i++;
} }
if (set->num_exprs && set->num_exprs != i) { if (set->num_exprs && set->num_exprs != i) {
......
...@@ -214,7 +214,7 @@ static void nft_exthdr_tcp_eval(const struct nft_expr *expr, ...@@ -214,7 +214,7 @@ static void nft_exthdr_tcp_eval(const struct nft_expr *expr,
offset = i + priv->offset; offset = i + priv->offset;
if (priv->flags & NFT_EXTHDR_F_PRESENT) { if (priv->flags & NFT_EXTHDR_F_PRESENT) {
*dest = 1; nft_reg_store8(dest, 1);
} else { } else {
if (priv->len % NFT_REG32_SIZE) if (priv->len % NFT_REG32_SIZE)
dest[priv->len / NFT_REG32_SIZE] = 0; dest[priv->len / NFT_REG32_SIZE] = 0;
...@@ -461,7 +461,7 @@ static void nft_exthdr_dccp_eval(const struct nft_expr *expr, ...@@ -461,7 +461,7 @@ static void nft_exthdr_dccp_eval(const struct nft_expr *expr,
type = bufp[0]; type = bufp[0];
if (type == priv->type) { if (type == priv->type) {
*dest = 1; nft_reg_store8(dest, 1);
return; return;
} }
......
...@@ -145,11 +145,15 @@ void nft_fib_store_result(void *reg, const struct nft_fib *priv, ...@@ -145,11 +145,15 @@ void nft_fib_store_result(void *reg, const struct nft_fib *priv,
switch (priv->result) { switch (priv->result) {
case NFT_FIB_RESULT_OIF: case NFT_FIB_RESULT_OIF:
index = dev ? dev->ifindex : 0; index = dev ? dev->ifindex : 0;
*dreg = (priv->flags & NFTA_FIB_F_PRESENT) ? !!index : index; if (priv->flags & NFTA_FIB_F_PRESENT)
nft_reg_store8(dreg, !!index);
else
*dreg = index;
break; break;
case NFT_FIB_RESULT_OIFNAME: case NFT_FIB_RESULT_OIFNAME:
if (priv->flags & NFTA_FIB_F_PRESENT) if (priv->flags & NFTA_FIB_F_PRESENT)
*dreg = !!dev; nft_reg_store8(dreg, !!dev);
else else
strscpy_pad(reg, dev ? dev->name : "", IFNAMSIZ); strscpy_pad(reg, dev ? dev->name : "", IFNAMSIZ);
break; break;
......
...@@ -2043,6 +2043,9 @@ static void nft_pipapo_walk(const struct nft_ctx *ctx, struct nft_set *set, ...@@ -2043,6 +2043,9 @@ static void nft_pipapo_walk(const struct nft_ctx *ctx, struct nft_set *set,
e = f->mt[r].e; e = f->mt[r].e;
if (!nft_set_elem_active(&e->ext, iter->genmask))
goto cont;
iter->err = iter->fn(ctx, set, iter, &e->priv); iter->err = iter->fn(ctx, set, iter, &e->priv);
if (iter->err < 0) if (iter->err < 0)
goto out; goto out;
......
...@@ -76,19 +76,24 @@ owner_mt(const struct sk_buff *skb, struct xt_action_param *par) ...@@ -76,19 +76,24 @@ owner_mt(const struct sk_buff *skb, struct xt_action_param *par)
*/ */
return false; return false;
filp = sk->sk_socket->file; read_lock_bh(&sk->sk_callback_lock);
if (filp == NULL) filp = sk->sk_socket ? sk->sk_socket->file : NULL;
if (filp == NULL) {
read_unlock_bh(&sk->sk_callback_lock);
return ((info->match ^ info->invert) & return ((info->match ^ info->invert) &
(XT_OWNER_UID | XT_OWNER_GID)) == 0; (XT_OWNER_UID | XT_OWNER_GID)) == 0;
}
if (info->match & XT_OWNER_UID) { if (info->match & XT_OWNER_UID) {
kuid_t uid_min = make_kuid(net->user_ns, info->uid_min); kuid_t uid_min = make_kuid(net->user_ns, info->uid_min);
kuid_t uid_max = make_kuid(net->user_ns, info->uid_max); kuid_t uid_max = make_kuid(net->user_ns, info->uid_max);
if ((uid_gte(filp->f_cred->fsuid, uid_min) && if ((uid_gte(filp->f_cred->fsuid, uid_min) &&
uid_lte(filp->f_cred->fsuid, uid_max)) ^ uid_lte(filp->f_cred->fsuid, uid_max)) ^
!(info->invert & XT_OWNER_UID)) !(info->invert & XT_OWNER_UID)) {
read_unlock_bh(&sk->sk_callback_lock);
return false; return false;
} }
}
if (info->match & XT_OWNER_GID) { if (info->match & XT_OWNER_GID) {
unsigned int i, match = false; unsigned int i, match = false;
...@@ -112,10 +117,13 @@ owner_mt(const struct sk_buff *skb, struct xt_action_param *par) ...@@ -112,10 +117,13 @@ owner_mt(const struct sk_buff *skb, struct xt_action_param *par)
} }
} }
if (match ^ !(info->invert & XT_OWNER_GID)) if (match ^ !(info->invert & XT_OWNER_GID)) {
read_unlock_bh(&sk->sk_callback_lock);
return false; return false;
} }
}
read_unlock_bh(&sk->sk_callback_lock);
return true; return true;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment