Commit 2650be2c authored by David S. Miller's avatar David S. Miller

Merge git://git.kernel.org/pub/scm/linux/kernel/git/pablo/nf

Pablo Neira Ayuso says:

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

The following patchset contains Netfilter fixes for net:

1) Allow conntrack entries with l3num == NFPROTO_IPV4 or == NFPROTO_IPV6
   only via ctnetlink, from Will McVicker.

2) Batch notifications to userspace to improve netlink socket receive
   utilization.

3) Restore mark based dump filtering via ctnetlink, from Martin Willi.

4) nf_conncount_init() fails with -EPROTO with CONFIG_IPV6, from
   Eelco Chaudron.

5) Containers fail to match on meta skuid and skgid, use socket user_ns
   to retrieve meta skuid and skgid.
===================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 843d926b 0c92411b
...@@ -8,6 +8,7 @@ struct netns_nftables { ...@@ -8,6 +8,7 @@ struct netns_nftables {
struct list_head tables; struct list_head tables;
struct list_head commit_list; struct list_head commit_list;
struct list_head module_list; struct list_head module_list;
struct list_head notify_list;
struct mutex commit_mutex; struct mutex commit_mutex;
unsigned int base_seq; unsigned int base_seq;
u8 gencursor; u8 gencursor;
......
...@@ -851,7 +851,6 @@ static int ctnetlink_done(struct netlink_callback *cb) ...@@ -851,7 +851,6 @@ static int ctnetlink_done(struct netlink_callback *cb)
} }
struct ctnetlink_filter { struct ctnetlink_filter {
u_int32_t cta_flags;
u8 family; u8 family;
u_int32_t orig_flags; u_int32_t orig_flags;
...@@ -906,10 +905,6 @@ static int ctnetlink_parse_tuple_filter(const struct nlattr * const cda[], ...@@ -906,10 +905,6 @@ static int ctnetlink_parse_tuple_filter(const struct nlattr * const cda[],
struct nf_conntrack_zone *zone, struct nf_conntrack_zone *zone,
u_int32_t flags); u_int32_t flags);
/* applied on filters */
#define CTA_FILTER_F_CTA_MARK (1 << 0)
#define CTA_FILTER_F_CTA_MARK_MASK (1 << 1)
static struct ctnetlink_filter * static struct ctnetlink_filter *
ctnetlink_alloc_filter(const struct nlattr * const cda[], u8 family) ctnetlink_alloc_filter(const struct nlattr * const cda[], u8 family)
{ {
...@@ -930,14 +925,10 @@ ctnetlink_alloc_filter(const struct nlattr * const cda[], u8 family) ...@@ -930,14 +925,10 @@ ctnetlink_alloc_filter(const struct nlattr * const cda[], u8 family)
#ifdef CONFIG_NF_CONNTRACK_MARK #ifdef CONFIG_NF_CONNTRACK_MARK
if (cda[CTA_MARK]) { if (cda[CTA_MARK]) {
filter->mark.val = ntohl(nla_get_be32(cda[CTA_MARK])); filter->mark.val = ntohl(nla_get_be32(cda[CTA_MARK]));
filter->cta_flags |= CTA_FILTER_FLAG(CTA_MARK); if (cda[CTA_MARK_MASK])
if (cda[CTA_MARK_MASK]) {
filter->mark.mask = ntohl(nla_get_be32(cda[CTA_MARK_MASK])); filter->mark.mask = ntohl(nla_get_be32(cda[CTA_MARK_MASK]));
filter->cta_flags |= CTA_FILTER_FLAG(CTA_MARK_MASK); else
} else {
filter->mark.mask = 0xffffffff; filter->mark.mask = 0xffffffff;
}
} else if (cda[CTA_MARK_MASK]) { } else if (cda[CTA_MARK_MASK]) {
err = -EINVAL; err = -EINVAL;
goto err_filter; goto err_filter;
...@@ -1117,11 +1108,7 @@ static int ctnetlink_filter_match(struct nf_conn *ct, void *data) ...@@ -1117,11 +1108,7 @@ static int ctnetlink_filter_match(struct nf_conn *ct, void *data)
} }
#ifdef CONFIG_NF_CONNTRACK_MARK #ifdef CONFIG_NF_CONNTRACK_MARK
if ((filter->cta_flags & CTA_FILTER_FLAG(CTA_MARK_MASK)) && if ((ct->mark & filter->mark.mask) != filter->mark.val)
(ct->mark & filter->mark.mask) != filter->mark.val)
goto ignore_entry;
else if ((filter->cta_flags & CTA_FILTER_FLAG(CTA_MARK)) &&
ct->mark != filter->mark.val)
goto ignore_entry; goto ignore_entry;
#endif #endif
...@@ -1404,7 +1391,8 @@ ctnetlink_parse_tuple_filter(const struct nlattr * const cda[], ...@@ -1404,7 +1391,8 @@ ctnetlink_parse_tuple_filter(const struct nlattr * const cda[],
if (err < 0) if (err < 0)
return err; return err;
if (l3num != NFPROTO_IPV4 && l3num != NFPROTO_IPV6)
return -EOPNOTSUPP;
tuple->src.l3num = l3num; tuple->src.l3num = l3num;
if (flags & CTA_FILTER_FLAG(CTA_IP_DST) || if (flags & CTA_FILTER_FLAG(CTA_IP_DST) ||
......
...@@ -565,6 +565,7 @@ static int nf_ct_netns_inet_get(struct net *net) ...@@ -565,6 +565,7 @@ static int nf_ct_netns_inet_get(struct net *net)
int err; int err;
err = nf_ct_netns_do_get(net, NFPROTO_IPV4); err = nf_ct_netns_do_get(net, NFPROTO_IPV4);
#if IS_ENABLED(CONFIG_IPV6)
if (err < 0) if (err < 0)
goto err1; goto err1;
err = nf_ct_netns_do_get(net, NFPROTO_IPV6); err = nf_ct_netns_do_get(net, NFPROTO_IPV6);
...@@ -575,6 +576,7 @@ static int nf_ct_netns_inet_get(struct net *net) ...@@ -575,6 +576,7 @@ static int nf_ct_netns_inet_get(struct net *net)
err2: err2:
nf_ct_netns_put(net, NFPROTO_IPV4); nf_ct_netns_put(net, NFPROTO_IPV4);
err1: err1:
#endif
return err; return err;
} }
......
...@@ -684,6 +684,18 @@ static int nf_tables_fill_table_info(struct sk_buff *skb, struct net *net, ...@@ -684,6 +684,18 @@ static int nf_tables_fill_table_info(struct sk_buff *skb, struct net *net,
return -1; return -1;
} }
struct nftnl_skb_parms {
bool report;
};
#define NFT_CB(skb) (*(struct nftnl_skb_parms*)&((skb)->cb))
static void nft_notify_enqueue(struct sk_buff *skb, bool report,
struct list_head *notify_list)
{
NFT_CB(skb).report = report;
list_add_tail(&skb->list, notify_list);
}
static void nf_tables_table_notify(const struct nft_ctx *ctx, int event) static void nf_tables_table_notify(const struct nft_ctx *ctx, int event)
{ {
struct sk_buff *skb; struct sk_buff *skb;
...@@ -715,8 +727,7 @@ static void nf_tables_table_notify(const struct nft_ctx *ctx, int event) ...@@ -715,8 +727,7 @@ static void nf_tables_table_notify(const struct nft_ctx *ctx, int event)
goto err; goto err;
} }
nfnetlink_send(skb, ctx->net, ctx->portid, NFNLGRP_NFTABLES, nft_notify_enqueue(skb, ctx->report, &ctx->net->nft.notify_list);
ctx->report, GFP_KERNEL);
return; return;
err: err:
nfnetlink_set_err(ctx->net, ctx->portid, NFNLGRP_NFTABLES, -ENOBUFS); nfnetlink_set_err(ctx->net, ctx->portid, NFNLGRP_NFTABLES, -ENOBUFS);
...@@ -1468,8 +1479,7 @@ static void nf_tables_chain_notify(const struct nft_ctx *ctx, int event) ...@@ -1468,8 +1479,7 @@ static void nf_tables_chain_notify(const struct nft_ctx *ctx, int event)
goto err; goto err;
} }
nfnetlink_send(skb, ctx->net, ctx->portid, NFNLGRP_NFTABLES, nft_notify_enqueue(skb, ctx->report, &ctx->net->nft.notify_list);
ctx->report, GFP_KERNEL);
return; return;
err: err:
nfnetlink_set_err(ctx->net, ctx->portid, NFNLGRP_NFTABLES, -ENOBUFS); nfnetlink_set_err(ctx->net, ctx->portid, NFNLGRP_NFTABLES, -ENOBUFS);
...@@ -2807,8 +2817,7 @@ static void nf_tables_rule_notify(const struct nft_ctx *ctx, ...@@ -2807,8 +2817,7 @@ static void nf_tables_rule_notify(const struct nft_ctx *ctx,
goto err; goto err;
} }
nfnetlink_send(skb, ctx->net, ctx->portid, NFNLGRP_NFTABLES, nft_notify_enqueue(skb, ctx->report, &ctx->net->nft.notify_list);
ctx->report, GFP_KERNEL);
return; return;
err: err:
nfnetlink_set_err(ctx->net, ctx->portid, NFNLGRP_NFTABLES, -ENOBUFS); nfnetlink_set_err(ctx->net, ctx->portid, NFNLGRP_NFTABLES, -ENOBUFS);
...@@ -3837,8 +3846,7 @@ static void nf_tables_set_notify(const struct nft_ctx *ctx, ...@@ -3837,8 +3846,7 @@ static void nf_tables_set_notify(const struct nft_ctx *ctx,
goto err; goto err;
} }
nfnetlink_send(skb, ctx->net, portid, NFNLGRP_NFTABLES, ctx->report, nft_notify_enqueue(skb, ctx->report, &ctx->net->nft.notify_list);
gfp_flags);
return; return;
err: err:
nfnetlink_set_err(ctx->net, portid, NFNLGRP_NFTABLES, -ENOBUFS); nfnetlink_set_err(ctx->net, portid, NFNLGRP_NFTABLES, -ENOBUFS);
...@@ -4959,8 +4967,7 @@ static void nf_tables_setelem_notify(const struct nft_ctx *ctx, ...@@ -4959,8 +4967,7 @@ static void nf_tables_setelem_notify(const struct nft_ctx *ctx,
goto err; goto err;
} }
nfnetlink_send(skb, net, portid, NFNLGRP_NFTABLES, ctx->report, nft_notify_enqueue(skb, ctx->report, &ctx->net->nft.notify_list);
GFP_KERNEL);
return; return;
err: err:
nfnetlink_set_err(net, portid, NFNLGRP_NFTABLES, -ENOBUFS); nfnetlink_set_err(net, portid, NFNLGRP_NFTABLES, -ENOBUFS);
...@@ -6275,7 +6282,7 @@ void nft_obj_notify(struct net *net, const struct nft_table *table, ...@@ -6275,7 +6282,7 @@ void nft_obj_notify(struct net *net, const struct nft_table *table,
goto err; goto err;
} }
nfnetlink_send(skb, net, portid, NFNLGRP_NFTABLES, report, gfp); nft_notify_enqueue(skb, report, &net->nft.notify_list);
return; return;
err: err:
nfnetlink_set_err(net, portid, NFNLGRP_NFTABLES, -ENOBUFS); nfnetlink_set_err(net, portid, NFNLGRP_NFTABLES, -ENOBUFS);
...@@ -7085,8 +7092,7 @@ static void nf_tables_flowtable_notify(struct nft_ctx *ctx, ...@@ -7085,8 +7092,7 @@ static void nf_tables_flowtable_notify(struct nft_ctx *ctx,
goto err; goto err;
} }
nfnetlink_send(skb, ctx->net, ctx->portid, NFNLGRP_NFTABLES, nft_notify_enqueue(skb, ctx->report, &ctx->net->nft.notify_list);
ctx->report, GFP_KERNEL);
return; return;
err: err:
nfnetlink_set_err(ctx->net, ctx->portid, NFNLGRP_NFTABLES, -ENOBUFS); nfnetlink_set_err(ctx->net, ctx->portid, NFNLGRP_NFTABLES, -ENOBUFS);
...@@ -7695,6 +7701,41 @@ static void nf_tables_commit_release(struct net *net) ...@@ -7695,6 +7701,41 @@ static void nf_tables_commit_release(struct net *net)
mutex_unlock(&net->nft.commit_mutex); mutex_unlock(&net->nft.commit_mutex);
} }
static void nft_commit_notify(struct net *net, u32 portid)
{
struct sk_buff *batch_skb = NULL, *nskb, *skb;
unsigned char *data;
int len;
list_for_each_entry_safe(skb, nskb, &net->nft.notify_list, list) {
if (!batch_skb) {
new_batch:
batch_skb = skb;
len = NLMSG_GOODSIZE - skb->len;
list_del(&skb->list);
continue;
}
len -= skb->len;
if (len > 0 && NFT_CB(skb).report == NFT_CB(batch_skb).report) {
data = skb_put(batch_skb, skb->len);
memcpy(data, skb->data, skb->len);
list_del(&skb->list);
kfree_skb(skb);
continue;
}
nfnetlink_send(batch_skb, net, portid, NFNLGRP_NFTABLES,
NFT_CB(batch_skb).report, GFP_KERNEL);
goto new_batch;
}
if (batch_skb) {
nfnetlink_send(batch_skb, net, portid, NFNLGRP_NFTABLES,
NFT_CB(batch_skb).report, GFP_KERNEL);
}
WARN_ON_ONCE(!list_empty(&net->nft.notify_list));
}
static int nf_tables_commit(struct net *net, struct sk_buff *skb) static int nf_tables_commit(struct net *net, struct sk_buff *skb)
{ {
struct nft_trans *trans, *next; struct nft_trans *trans, *next;
...@@ -7897,6 +7938,7 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb) ...@@ -7897,6 +7938,7 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb)
} }
} }
nft_commit_notify(net, NETLINK_CB(skb).portid);
nf_tables_gen_notify(net, skb, NFT_MSG_NEWGEN); nf_tables_gen_notify(net, skb, NFT_MSG_NEWGEN);
nf_tables_commit_release(net); nf_tables_commit_release(net);
...@@ -8721,6 +8763,7 @@ static int __net_init nf_tables_init_net(struct net *net) ...@@ -8721,6 +8763,7 @@ static int __net_init nf_tables_init_net(struct net *net)
INIT_LIST_HEAD(&net->nft.tables); INIT_LIST_HEAD(&net->nft.tables);
INIT_LIST_HEAD(&net->nft.commit_list); INIT_LIST_HEAD(&net->nft.commit_list);
INIT_LIST_HEAD(&net->nft.module_list); INIT_LIST_HEAD(&net->nft.module_list);
INIT_LIST_HEAD(&net->nft.notify_list);
mutex_init(&net->nft.commit_mutex); mutex_init(&net->nft.commit_mutex);
net->nft.base_seq = 1; net->nft.base_seq = 1;
net->nft.validate_state = NFT_VALIDATE_SKIP; net->nft.validate_state = NFT_VALIDATE_SKIP;
...@@ -8737,6 +8780,7 @@ static void __net_exit nf_tables_exit_net(struct net *net) ...@@ -8737,6 +8780,7 @@ static void __net_exit nf_tables_exit_net(struct net *net)
mutex_unlock(&net->nft.commit_mutex); mutex_unlock(&net->nft.commit_mutex);
WARN_ON_ONCE(!list_empty(&net->nft.tables)); WARN_ON_ONCE(!list_empty(&net->nft.tables));
WARN_ON_ONCE(!list_empty(&net->nft.module_list)); WARN_ON_ONCE(!list_empty(&net->nft.module_list));
WARN_ON_ONCE(!list_empty(&net->nft.notify_list));
} }
static struct pernet_operations nf_tables_net_ops = { static struct pernet_operations nf_tables_net_ops = {
......
...@@ -147,11 +147,11 @@ nft_meta_get_eval_skugid(enum nft_meta_keys key, ...@@ -147,11 +147,11 @@ nft_meta_get_eval_skugid(enum nft_meta_keys key,
switch (key) { switch (key) {
case NFT_META_SKUID: case NFT_META_SKUID:
*dest = from_kuid_munged(&init_user_ns, *dest = from_kuid_munged(sock_net(sk)->user_ns,
sock->file->f_cred->fsuid); sock->file->f_cred->fsuid);
break; break;
case NFT_META_SKGID: case NFT_META_SKGID:
*dest = from_kgid_munged(&init_user_ns, *dest = from_kgid_munged(sock_net(sk)->user_ns,
sock->file->f_cred->fsgid); sock->file->f_cred->fsgid);
break; break;
default: default:
......
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