Commit fc14963f 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 your net tree,
they are:

1) Fix incorrect timestamp in nfnetlink_queue introduced when addressing
   y2038 safe timestamp, from Florian Westphal.

2) Get rid of leftover conntrack definition from the previous merge
   window, oneliner from Florian.

3) Make nf_queue handler pernet to resolve race on dereferencing the
   hook state structure with netns removal, from Eric Biederman.

4) Ensure clean exit on unregistered helper ports, from Taehee Yoo.

5) Restore FLOWI_FLAG_KNOWN_NH in nf_dup_ipv6. This got lost while
   generalizing xt_TEE to add packet duplication support in nf_tables,
   from Paolo Abeni.

6) Insufficient netlink NFTA_SET_TABLE attribute check in
   nf_tables_getset(), from Phil Turnbull.

7) Reject helper registration on duplicated ports via modparams.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 31843af4 893e093c
...@@ -28,8 +28,8 @@ struct nf_queue_handler { ...@@ -28,8 +28,8 @@ struct nf_queue_handler {
struct nf_hook_ops *ops); struct nf_hook_ops *ops);
}; };
void nf_register_queue_handler(const struct nf_queue_handler *qh); void nf_register_queue_handler(struct net *net, const struct nf_queue_handler *qh);
void nf_unregister_queue_handler(void); void nf_unregister_queue_handler(struct net *net);
void nf_reinject(struct nf_queue_entry *entry, unsigned int verdict); void nf_reinject(struct nf_queue_entry *entry, unsigned int verdict);
void nf_queue_entry_get_refs(struct nf_queue_entry *entry); void nf_queue_entry_get_refs(struct nf_queue_entry *entry);
......
...@@ -5,11 +5,13 @@ ...@@ -5,11 +5,13 @@
struct proc_dir_entry; struct proc_dir_entry;
struct nf_logger; struct nf_logger;
struct nf_queue_handler;
struct netns_nf { struct netns_nf {
#if defined CONFIG_PROC_FS #if defined CONFIG_PROC_FS
struct proc_dir_entry *proc_netfilter; struct proc_dir_entry *proc_netfilter;
#endif #endif
const struct nf_queue_handler __rcu *queue_handler;
const struct nf_logger __rcu *nf_loggers[NFPROTO_NUMPROTO]; const struct nf_logger __rcu *nf_loggers[NFPROTO_NUMPROTO];
#ifdef CONFIG_SYSCTL #ifdef CONFIG_SYSCTL
struct ctl_table_header *nf_log_dir_header; struct ctl_table_header *nf_log_dir_header;
......
...@@ -33,6 +33,7 @@ static bool nf_dup_ipv6_route(struct net *net, struct sk_buff *skb, ...@@ -33,6 +33,7 @@ static bool nf_dup_ipv6_route(struct net *net, struct sk_buff *skb,
fl6.daddr = *gw; fl6.daddr = *gw;
fl6.flowlabel = (__force __be32)(((iph->flow_lbl[0] & 0xF) << 16) | fl6.flowlabel = (__force __be32)(((iph->flow_lbl[0] & 0xF) << 16) |
(iph->flow_lbl[1] << 8) | iph->flow_lbl[2]); (iph->flow_lbl[1] << 8) | iph->flow_lbl[2]);
fl6.flowi6_flags = FLOWI_FLAG_KNOWN_NH;
dst = ip6_route_output(net, NULL, &fl6); dst = ip6_route_output(net, NULL, &fl6);
if (dst->error) { if (dst->error) {
dst_release(dst); dst_release(dst);
......
...@@ -632,6 +632,7 @@ static int __init nf_conntrack_ftp_init(void) ...@@ -632,6 +632,7 @@ static int __init nf_conntrack_ftp_init(void)
if (ret) { if (ret) {
pr_err("failed to register helper for pf: %d port: %d\n", pr_err("failed to register helper for pf: %d port: %d\n",
ftp[i][j].tuple.src.l3num, ports[i]); ftp[i][j].tuple.src.l3num, ports[i]);
ports_c = i;
nf_conntrack_ftp_fini(); nf_conntrack_ftp_fini();
return ret; return ret;
} }
......
...@@ -361,9 +361,10 @@ EXPORT_SYMBOL_GPL(nf_ct_helper_log); ...@@ -361,9 +361,10 @@ EXPORT_SYMBOL_GPL(nf_ct_helper_log);
int nf_conntrack_helper_register(struct nf_conntrack_helper *me) int nf_conntrack_helper_register(struct nf_conntrack_helper *me)
{ {
int ret = 0; struct nf_conntrack_tuple_mask mask = { .src.u.all = htons(0xFFFF) };
struct nf_conntrack_helper *cur;
unsigned int h = helper_hash(&me->tuple); unsigned int h = helper_hash(&me->tuple);
struct nf_conntrack_helper *cur;
int ret = 0;
BUG_ON(me->expect_policy == NULL); BUG_ON(me->expect_policy == NULL);
BUG_ON(me->expect_class_max >= NF_CT_MAX_EXPECT_CLASSES); BUG_ON(me->expect_class_max >= NF_CT_MAX_EXPECT_CLASSES);
...@@ -371,9 +372,7 @@ int nf_conntrack_helper_register(struct nf_conntrack_helper *me) ...@@ -371,9 +372,7 @@ int nf_conntrack_helper_register(struct nf_conntrack_helper *me)
mutex_lock(&nf_ct_helper_mutex); mutex_lock(&nf_ct_helper_mutex);
hlist_for_each_entry(cur, &nf_ct_helper_hash[h], hnode) { hlist_for_each_entry(cur, &nf_ct_helper_hash[h], hnode) {
if (strncmp(cur->name, me->name, NF_CT_HELPER_NAME_LEN) == 0 && if (nf_ct_tuple_src_mask_cmp(&cur->tuple, &me->tuple, &mask)) {
cur->tuple.src.l3num == me->tuple.src.l3num &&
cur->tuple.dst.protonum == me->tuple.dst.protonum) {
ret = -EEXIST; ret = -EEXIST;
goto out; goto out;
} }
......
...@@ -271,6 +271,7 @@ static int __init nf_conntrack_irc_init(void) ...@@ -271,6 +271,7 @@ static int __init nf_conntrack_irc_init(void)
if (ret) { if (ret) {
pr_err("failed to register helper for pf: %u port: %u\n", pr_err("failed to register helper for pf: %u port: %u\n",
irc[i].tuple.src.l3num, ports[i]); irc[i].tuple.src.l3num, ports[i]);
ports_c = i;
nf_conntrack_irc_fini(); nf_conntrack_irc_fini();
return ret; return ret;
} }
......
...@@ -223,6 +223,7 @@ static int __init nf_conntrack_sane_init(void) ...@@ -223,6 +223,7 @@ static int __init nf_conntrack_sane_init(void)
if (ret) { if (ret) {
pr_err("failed to register helper for pf: %d port: %d\n", pr_err("failed to register helper for pf: %d port: %d\n",
sane[i][j].tuple.src.l3num, ports[i]); sane[i][j].tuple.src.l3num, ports[i]);
ports_c = i;
nf_conntrack_sane_fini(); nf_conntrack_sane_fini();
return ret; return ret;
} }
......
...@@ -1669,6 +1669,7 @@ static int __init nf_conntrack_sip_init(void) ...@@ -1669,6 +1669,7 @@ static int __init nf_conntrack_sip_init(void)
if (ret) { if (ret) {
pr_err("failed to register helper for pf: %u port: %u\n", pr_err("failed to register helper for pf: %u port: %u\n",
sip[i][j].tuple.src.l3num, ports[i]); sip[i][j].tuple.src.l3num, ports[i]);
ports_c = i;
nf_conntrack_sip_fini(); nf_conntrack_sip_fini();
return ret; return ret;
} }
......
...@@ -487,8 +487,6 @@ static struct ctl_table nf_ct_sysctl_table[] = { ...@@ -487,8 +487,6 @@ static struct ctl_table nf_ct_sysctl_table[] = {
{ } { }
}; };
#define NET_NF_CONNTRACK_MAX 2089
static struct ctl_table nf_ct_netfilter_table[] = { static struct ctl_table nf_ct_netfilter_table[] = {
{ {
.procname = "nf_conntrack_max", .procname = "nf_conntrack_max",
......
...@@ -142,6 +142,7 @@ static int __init nf_conntrack_tftp_init(void) ...@@ -142,6 +142,7 @@ static int __init nf_conntrack_tftp_init(void)
if (ret) { if (ret) {
pr_err("failed to register helper for pf: %u port: %u\n", pr_err("failed to register helper for pf: %u port: %u\n",
tftp[i][j].tuple.src.l3num, ports[i]); tftp[i][j].tuple.src.l3num, ports[i]);
ports_c = i;
nf_conntrack_tftp_fini(); nf_conntrack_tftp_fini();
return ret; return ret;
} }
......
...@@ -26,23 +26,21 @@ ...@@ -26,23 +26,21 @@
* Once the queue is registered it must reinject all packets it * Once the queue is registered it must reinject all packets it
* receives, no matter what. * receives, no matter what.
*/ */
static const struct nf_queue_handler __rcu *queue_handler __read_mostly;
/* return EBUSY when somebody else is registered, return EEXIST if the /* return EBUSY when somebody else is registered, return EEXIST if the
* same handler is registered, return 0 in case of success. */ * same handler is registered, return 0 in case of success. */
void nf_register_queue_handler(const struct nf_queue_handler *qh) void nf_register_queue_handler(struct net *net, const struct nf_queue_handler *qh)
{ {
/* should never happen, we only have one queueing backend in kernel */ /* should never happen, we only have one queueing backend in kernel */
WARN_ON(rcu_access_pointer(queue_handler)); WARN_ON(rcu_access_pointer(net->nf.queue_handler));
rcu_assign_pointer(queue_handler, qh); rcu_assign_pointer(net->nf.queue_handler, qh);
} }
EXPORT_SYMBOL(nf_register_queue_handler); EXPORT_SYMBOL(nf_register_queue_handler);
/* The caller must flush their queue before this */ /* The caller must flush their queue before this */
void nf_unregister_queue_handler(void) void nf_unregister_queue_handler(struct net *net)
{ {
RCU_INIT_POINTER(queue_handler, NULL); RCU_INIT_POINTER(net->nf.queue_handler, NULL);
synchronize_rcu();
} }
EXPORT_SYMBOL(nf_unregister_queue_handler); EXPORT_SYMBOL(nf_unregister_queue_handler);
...@@ -103,7 +101,7 @@ void nf_queue_nf_hook_drop(struct net *net, struct nf_hook_ops *ops) ...@@ -103,7 +101,7 @@ void nf_queue_nf_hook_drop(struct net *net, struct nf_hook_ops *ops)
const struct nf_queue_handler *qh; const struct nf_queue_handler *qh;
rcu_read_lock(); rcu_read_lock();
qh = rcu_dereference(queue_handler); qh = rcu_dereference(net->nf.queue_handler);
if (qh) if (qh)
qh->nf_hook_drop(net, ops); qh->nf_hook_drop(net, ops);
rcu_read_unlock(); rcu_read_unlock();
...@@ -122,9 +120,10 @@ int nf_queue(struct sk_buff *skb, ...@@ -122,9 +120,10 @@ int nf_queue(struct sk_buff *skb,
struct nf_queue_entry *entry = NULL; struct nf_queue_entry *entry = NULL;
const struct nf_afinfo *afinfo; const struct nf_afinfo *afinfo;
const struct nf_queue_handler *qh; const struct nf_queue_handler *qh;
struct net *net = state->net;
/* QUEUE == DROP if no one is waiting, to be safe. */ /* QUEUE == DROP if no one is waiting, to be safe. */
qh = rcu_dereference(queue_handler); qh = rcu_dereference(net->nf.queue_handler);
if (!qh) { if (!qh) {
status = -ESRCH; status = -ESRCH;
goto err; goto err;
......
...@@ -2647,6 +2647,8 @@ static int nf_tables_getset(struct net *net, struct sock *nlsk, ...@@ -2647,6 +2647,8 @@ static int nf_tables_getset(struct net *net, struct sock *nlsk,
/* Only accept unspec with dump */ /* Only accept unspec with dump */
if (nfmsg->nfgen_family == NFPROTO_UNSPEC) if (nfmsg->nfgen_family == NFPROTO_UNSPEC)
return -EAFNOSUPPORT; return -EAFNOSUPPORT;
if (!nla[NFTA_SET_TABLE])
return -EINVAL;
set = nf_tables_set_lookup(ctx.table, nla[NFTA_SET_NAME]); set = nf_tables_set_lookup(ctx.table, nla[NFTA_SET_NAME]);
if (IS_ERR(set)) if (IS_ERR(set))
......
...@@ -557,7 +557,7 @@ nfqnl_build_packet_message(struct net *net, struct nfqnl_instance *queue, ...@@ -557,7 +557,7 @@ nfqnl_build_packet_message(struct net *net, struct nfqnl_instance *queue,
if (entskb->tstamp.tv64) { if (entskb->tstamp.tv64) {
struct nfqnl_msg_packet_timestamp ts; struct nfqnl_msg_packet_timestamp ts;
struct timespec64 kts = ktime_to_timespec64(skb->tstamp); struct timespec64 kts = ktime_to_timespec64(entskb->tstamp);
ts.sec = cpu_to_be64(kts.tv_sec); ts.sec = cpu_to_be64(kts.tv_sec);
ts.usec = cpu_to_be64(kts.tv_nsec / NSEC_PER_USEC); ts.usec = cpu_to_be64(kts.tv_nsec / NSEC_PER_USEC);
...@@ -1482,21 +1482,29 @@ static int __net_init nfnl_queue_net_init(struct net *net) ...@@ -1482,21 +1482,29 @@ static int __net_init nfnl_queue_net_init(struct net *net)
net->nf.proc_netfilter, &nfqnl_file_ops)) net->nf.proc_netfilter, &nfqnl_file_ops))
return -ENOMEM; return -ENOMEM;
#endif #endif
nf_register_queue_handler(net, &nfqh);
return 0; return 0;
} }
static void __net_exit nfnl_queue_net_exit(struct net *net) static void __net_exit nfnl_queue_net_exit(struct net *net)
{ {
nf_unregister_queue_handler(net);
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
remove_proc_entry("nfnetlink_queue", net->nf.proc_netfilter); remove_proc_entry("nfnetlink_queue", net->nf.proc_netfilter);
#endif #endif
} }
static void nfnl_queue_net_exit_batch(struct list_head *net_exit_list)
{
synchronize_rcu();
}
static struct pernet_operations nfnl_queue_net_ops = { static struct pernet_operations nfnl_queue_net_ops = {
.init = nfnl_queue_net_init, .init = nfnl_queue_net_init,
.exit = nfnl_queue_net_exit, .exit = nfnl_queue_net_exit,
.id = &nfnl_queue_net_id, .exit_batch = nfnl_queue_net_exit_batch,
.size = sizeof(struct nfnl_queue_net), .id = &nfnl_queue_net_id,
.size = sizeof(struct nfnl_queue_net),
}; };
static int __init nfnetlink_queue_init(void) static int __init nfnetlink_queue_init(void)
...@@ -1517,7 +1525,6 @@ static int __init nfnetlink_queue_init(void) ...@@ -1517,7 +1525,6 @@ static int __init nfnetlink_queue_init(void)
} }
register_netdevice_notifier(&nfqnl_dev_notifier); register_netdevice_notifier(&nfqnl_dev_notifier);
nf_register_queue_handler(&nfqh);
return status; return status;
cleanup_netlink_notifier: cleanup_netlink_notifier:
...@@ -1529,7 +1536,6 @@ static int __init nfnetlink_queue_init(void) ...@@ -1529,7 +1536,6 @@ static int __init nfnetlink_queue_init(void)
static void __exit nfnetlink_queue_fini(void) static void __exit nfnetlink_queue_fini(void)
{ {
nf_unregister_queue_handler();
unregister_netdevice_notifier(&nfqnl_dev_notifier); unregister_netdevice_notifier(&nfqnl_dev_notifier);
nfnetlink_subsys_unregister(&nfqnl_subsys); nfnetlink_subsys_unregister(&nfqnl_subsys);
netlink_unregister_notifier(&nfqnl_rtnl_notifier); netlink_unregister_notifier(&nfqnl_rtnl_notifier);
......
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