2005-08-10 10:30:24 +08:00
|
|
|
/* Netfilter messages via netlink socket. Allows for user space
|
|
|
|
* protocol helpers and general trouble making from userspace.
|
|
|
|
*
|
|
|
|
* (C) 2001 by Jay Schulist <jschlst@samba.org>,
|
|
|
|
* (C) 2002-2005 by Harald Welte <laforge@gnumonks.org>
|
2017-02-10 19:08:17 +08:00
|
|
|
* (C) 2005-2017 by Pablo Neira Ayuso <pablo@netfilter.org>
|
2005-08-10 10:30:24 +08:00
|
|
|
*
|
|
|
|
* Initial netfilter messages via netlink development funded and
|
|
|
|
* generally made possible by Network Robots, Inc. (www.networkrobots.com)
|
|
|
|
*
|
|
|
|
* Further development of this code funded by Astaro AG (http://www.astaro.com)
|
|
|
|
*
|
|
|
|
* This software may be used and distributed according to the terms
|
|
|
|
* of the GNU General Public License, incorporated herein by reference.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <linux/module.h>
|
|
|
|
#include <linux/types.h>
|
|
|
|
#include <linux/socket.h>
|
|
|
|
#include <linux/kernel.h>
|
|
|
|
#include <linux/string.h>
|
|
|
|
#include <linux/sockios.h>
|
|
|
|
#include <linux/net.h>
|
|
|
|
#include <linux/skbuff.h>
|
2016-12-25 03:46:01 +08:00
|
|
|
#include <linux/uaccess.h>
|
2005-08-10 10:30:24 +08:00
|
|
|
#include <net/sock.h>
|
|
|
|
#include <linux/init.h>
|
2018-05-27 17:24:34 +08:00
|
|
|
#include <linux/sched/signal.h>
|
2005-08-10 10:30:24 +08:00
|
|
|
|
2013-03-27 14:47:04 +08:00
|
|
|
#include <net/netlink.h>
|
2005-08-10 10:30:24 +08:00
|
|
|
#include <linux/netfilter/nfnetlink.h>
|
|
|
|
|
|
|
|
MODULE_LICENSE("GPL");
|
2005-08-10 10:40:55 +08:00
|
|
|
MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
|
|
|
|
MODULE_ALIAS_NET_PF_PROTO(PF_NETLINK, NETLINK_NETFILTER);
|
2005-08-10 10:30:24 +08:00
|
|
|
|
2015-12-03 17:49:42 +08:00
|
|
|
#define nfnl_dereference_protected(id) \
|
|
|
|
rcu_dereference_protected(table[(id)].subsys, \
|
|
|
|
lockdep_nfnl_is_held((id)))
|
|
|
|
|
2018-05-31 03:17:56 +08:00
|
|
|
#define NFNL_MAX_ATTR_COUNT 32
|
|
|
|
|
2013-02-05 08:50:26 +08:00
|
|
|
static struct {
|
|
|
|
struct mutex mutex;
|
|
|
|
const struct nfnetlink_subsystem __rcu *subsys;
|
|
|
|
} table[NFNL_SUBSYS_COUNT];
|
2005-08-10 10:30:24 +08:00
|
|
|
|
2012-06-29 14:15:22 +08:00
|
|
|
static const int nfnl_group2type[NFNLGRP_MAX+1] = {
|
|
|
|
[NFNLGRP_CONNTRACK_NEW] = NFNL_SUBSYS_CTNETLINK,
|
|
|
|
[NFNLGRP_CONNTRACK_UPDATE] = NFNL_SUBSYS_CTNETLINK,
|
|
|
|
[NFNLGRP_CONNTRACK_DESTROY] = NFNL_SUBSYS_CTNETLINK,
|
|
|
|
[NFNLGRP_CONNTRACK_EXP_NEW] = NFNL_SUBSYS_CTNETLINK_EXP,
|
|
|
|
[NFNLGRP_CONNTRACK_EXP_UPDATE] = NFNL_SUBSYS_CTNETLINK_EXP,
|
|
|
|
[NFNLGRP_CONNTRACK_EXP_DESTROY] = NFNL_SUBSYS_CTNETLINK_EXP,
|
2014-11-15 01:14:33 +08:00
|
|
|
[NFNLGRP_NFTABLES] = NFNL_SUBSYS_NFTABLES,
|
|
|
|
[NFNLGRP_ACCT_QUOTA] = NFNL_SUBSYS_ACCT,
|
2015-11-29 04:53:04 +08:00
|
|
|
[NFNLGRP_NFTRACE] = NFNL_SUBSYS_NFTABLES,
|
2012-06-29 14:15:22 +08:00
|
|
|
};
|
|
|
|
|
2013-02-05 08:50:26 +08:00
|
|
|
void nfnl_lock(__u8 subsys_id)
|
2005-08-10 10:30:24 +08:00
|
|
|
{
|
2013-02-05 08:50:26 +08:00
|
|
|
mutex_lock(&table[subsys_id].mutex);
|
2005-08-10 10:30:24 +08:00
|
|
|
}
|
2008-10-15 02:58:31 +08:00
|
|
|
EXPORT_SYMBOL_GPL(nfnl_lock);
|
2005-08-10 10:30:24 +08:00
|
|
|
|
2013-02-05 08:50:26 +08:00
|
|
|
void nfnl_unlock(__u8 subsys_id)
|
2007-03-15 07:39:25 +08:00
|
|
|
{
|
2013-02-05 08:50:26 +08:00
|
|
|
mutex_unlock(&table[subsys_id].mutex);
|
2005-08-10 10:30:24 +08:00
|
|
|
}
|
2008-10-15 02:58:31 +08:00
|
|
|
EXPORT_SYMBOL_GPL(nfnl_unlock);
|
2005-08-10 10:30:24 +08:00
|
|
|
|
2014-02-19 02:06:48 +08:00
|
|
|
#ifdef CONFIG_PROVE_LOCKING
|
2015-10-08 21:28:56 +08:00
|
|
|
bool lockdep_nfnl_is_held(u8 subsys_id)
|
2014-02-19 02:06:48 +08:00
|
|
|
{
|
|
|
|
return lockdep_is_held(&table[subsys_id].mutex);
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(lockdep_nfnl_is_held);
|
|
|
|
#endif
|
|
|
|
|
2007-09-29 05:15:45 +08:00
|
|
|
int nfnetlink_subsys_register(const struct nfnetlink_subsystem *n)
|
2005-08-10 10:30:24 +08:00
|
|
|
{
|
2018-05-31 03:17:56 +08:00
|
|
|
u8 cb_id;
|
|
|
|
|
|
|
|
/* Sanity-check attr_count size to avoid stack buffer overflow. */
|
|
|
|
for (cb_id = 0; cb_id < n->cb_count; cb_id++)
|
|
|
|
if (WARN_ON(n->cb[cb_id].attr_count > NFNL_MAX_ATTR_COUNT))
|
|
|
|
return -EINVAL;
|
|
|
|
|
2013-02-05 08:50:26 +08:00
|
|
|
nfnl_lock(n->subsys_id);
|
|
|
|
if (table[n->subsys_id].subsys) {
|
|
|
|
nfnl_unlock(n->subsys_id);
|
2005-08-10 10:43:44 +08:00
|
|
|
return -EBUSY;
|
|
|
|
}
|
2013-02-05 08:50:26 +08:00
|
|
|
rcu_assign_pointer(table[n->subsys_id].subsys, n);
|
|
|
|
nfnl_unlock(n->subsys_id);
|
2005-08-10 10:30:24 +08:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
2007-03-15 07:42:11 +08:00
|
|
|
EXPORT_SYMBOL_GPL(nfnetlink_subsys_register);
|
2005-08-10 10:30:24 +08:00
|
|
|
|
2007-09-29 05:15:45 +08:00
|
|
|
int nfnetlink_subsys_unregister(const struct nfnetlink_subsystem *n)
|
2005-08-10 10:30:24 +08:00
|
|
|
{
|
2013-02-05 08:50:26 +08:00
|
|
|
nfnl_lock(n->subsys_id);
|
|
|
|
table[n->subsys_id].subsys = NULL;
|
|
|
|
nfnl_unlock(n->subsys_id);
|
2011-07-18 22:08:07 +08:00
|
|
|
synchronize_rcu();
|
2005-08-10 10:30:24 +08:00
|
|
|
return 0;
|
|
|
|
}
|
2007-03-15 07:42:11 +08:00
|
|
|
EXPORT_SYMBOL_GPL(nfnetlink_subsys_unregister);
|
2005-08-10 10:30:24 +08:00
|
|
|
|
2017-02-10 19:08:08 +08:00
|
|
|
static inline const struct nfnetlink_subsystem *nfnetlink_get_subsys(u16 type)
|
2005-08-10 10:30:24 +08:00
|
|
|
{
|
2017-02-10 19:08:08 +08:00
|
|
|
u8 subsys_id = NFNL_SUBSYS_ID(type);
|
2005-08-10 10:30:24 +08:00
|
|
|
|
2007-03-15 07:41:28 +08:00
|
|
|
if (subsys_id >= NFNL_SUBSYS_COUNT)
|
2005-08-10 10:30:24 +08:00
|
|
|
return NULL;
|
|
|
|
|
2013-02-05 08:50:26 +08:00
|
|
|
return rcu_dereference(table[subsys_id].subsys);
|
2005-08-10 10:30:24 +08:00
|
|
|
}
|
|
|
|
|
2007-09-29 05:15:45 +08:00
|
|
|
static inline const struct nfnl_callback *
|
2017-02-10 19:08:08 +08:00
|
|
|
nfnetlink_find_client(u16 type, const struct nfnetlink_subsystem *ss)
|
2005-08-10 10:30:24 +08:00
|
|
|
{
|
2017-02-10 19:08:08 +08:00
|
|
|
u8 cb_id = NFNL_MSG_TYPE(type);
|
2007-02-13 03:15:49 +08:00
|
|
|
|
2007-03-15 07:40:38 +08:00
|
|
|
if (cb_id >= ss->cb_count)
|
2005-08-10 10:30:24 +08:00
|
|
|
return NULL;
|
|
|
|
|
|
|
|
return &ss->cb[cb_id];
|
|
|
|
}
|
|
|
|
|
2010-01-13 23:02:14 +08:00
|
|
|
int nfnetlink_has_listeners(struct net *net, unsigned int group)
|
2006-03-21 10:03:59 +08:00
|
|
|
{
|
2010-01-13 23:02:14 +08:00
|
|
|
return netlink_has_listeners(net->nfnl, group);
|
2006-03-21 10:03:59 +08:00
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(nfnetlink_has_listeners);
|
|
|
|
|
2013-04-17 14:47:08 +08:00
|
|
|
int nfnetlink_send(struct sk_buff *skb, struct net *net, u32 portid,
|
2012-04-15 13:58:06 +08:00
|
|
|
unsigned int group, int echo, gfp_t flags)
|
2005-08-10 10:30:24 +08:00
|
|
|
{
|
2013-04-17 14:47:08 +08:00
|
|
|
return nlmsg_notify(net->nfnl, skb, portid, group, echo, flags);
|
2005-08-10 10:30:24 +08:00
|
|
|
}
|
2007-03-15 07:42:11 +08:00
|
|
|
EXPORT_SYMBOL_GPL(nfnetlink_send);
|
2005-08-10 10:30:24 +08:00
|
|
|
|
2013-04-17 14:47:08 +08:00
|
|
|
int nfnetlink_set_err(struct net *net, u32 portid, u32 group, int error)
|
2009-03-23 20:21:06 +08:00
|
|
|
{
|
2013-04-17 14:47:08 +08:00
|
|
|
return netlink_set_err(net->nfnl, portid, group, error);
|
2009-03-23 20:21:06 +08:00
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(nfnetlink_set_err);
|
|
|
|
|
2013-04-17 14:47:08 +08:00
|
|
|
int nfnetlink_unicast(struct sk_buff *skb, struct net *net, u32 portid,
|
|
|
|
int flags)
|
2005-08-10 10:30:24 +08:00
|
|
|
{
|
2013-04-17 14:47:08 +08:00
|
|
|
return netlink_unicast(net->nfnl, skb, portid, flags);
|
2005-08-10 10:30:24 +08:00
|
|
|
}
|
2007-03-15 07:42:11 +08:00
|
|
|
EXPORT_SYMBOL_GPL(nfnetlink_unicast);
|
2005-08-10 10:30:24 +08:00
|
|
|
|
|
|
|
/* Process one complete nfnetlink message. */
|
2017-04-12 20:34:04 +08:00
|
|
|
static int nfnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh,
|
|
|
|
struct netlink_ext_ack *extack)
|
2005-08-10 10:30:24 +08:00
|
|
|
{
|
2010-01-13 23:02:14 +08:00
|
|
|
struct net *net = sock_net(skb->sk);
|
2007-09-29 05:15:45 +08:00
|
|
|
const struct nfnl_callback *nc;
|
|
|
|
const struct nfnetlink_subsystem *ss;
|
2007-03-23 14:30:12 +08:00
|
|
|
int type, err;
|
2005-08-10 10:30:24 +08:00
|
|
|
|
|
|
|
/* All the messages must at least contain nfgenmsg */
|
2013-03-27 14:47:04 +08:00
|
|
|
if (nlmsg_len(nlh) < sizeof(struct nfgenmsg))
|
2005-08-10 10:30:24 +08:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
type = nlh->nlmsg_type;
|
2008-10-15 02:58:31 +08:00
|
|
|
replay:
|
2011-07-18 22:08:07 +08:00
|
|
|
rcu_read_lock();
|
2005-08-10 10:30:24 +08:00
|
|
|
ss = nfnetlink_get_subsys(type);
|
2005-08-10 10:43:44 +08:00
|
|
|
if (!ss) {
|
2008-10-17 06:24:51 +08:00
|
|
|
#ifdef CONFIG_MODULES
|
2011-07-18 22:08:07 +08:00
|
|
|
rcu_read_unlock();
|
2005-11-15 07:24:59 +08:00
|
|
|
request_module("nfnetlink-subsys-%d", NFNL_SUBSYS_ID(type));
|
2011-07-18 22:08:07 +08:00
|
|
|
rcu_read_lock();
|
2005-11-15 07:24:59 +08:00
|
|
|
ss = nfnetlink_get_subsys(type);
|
2005-08-10 10:43:44 +08:00
|
|
|
if (!ss)
|
|
|
|
#endif
|
2011-07-18 22:08:07 +08:00
|
|
|
{
|
|
|
|
rcu_read_unlock();
|
2007-03-23 14:30:12 +08:00
|
|
|
return -EINVAL;
|
2011-07-18 22:08:07 +08:00
|
|
|
}
|
2005-08-10 10:43:44 +08:00
|
|
|
}
|
2005-08-10 10:30:24 +08:00
|
|
|
|
|
|
|
nc = nfnetlink_find_client(type, ss);
|
2011-07-18 22:08:07 +08:00
|
|
|
if (!nc) {
|
|
|
|
rcu_read_unlock();
|
2007-03-23 14:30:12 +08:00
|
|
|
return -EINVAL;
|
2011-07-18 22:08:07 +08:00
|
|
|
}
|
2005-08-10 10:30:24 +08:00
|
|
|
|
|
|
|
{
|
2013-03-27 14:47:04 +08:00
|
|
|
int min_len = nlmsg_total_size(sizeof(struct nfgenmsg));
|
2017-02-10 19:08:08 +08:00
|
|
|
u8 cb_id = NFNL_MSG_TYPE(nlh->nlmsg_type);
|
2018-05-31 03:17:56 +08:00
|
|
|
struct nlattr *cda[NFNL_MAX_ATTR_COUNT + 1];
|
2009-06-03 02:03:33 +08:00
|
|
|
struct nlattr *attr = (void *)nlh + min_len;
|
|
|
|
int attrlen = nlh->nlmsg_len - min_len;
|
2013-02-05 08:50:26 +08:00
|
|
|
__u8 subsys_id = NFNL_SUBSYS_ID(type);
|
2009-06-03 02:03:33 +08:00
|
|
|
|
2018-05-31 03:17:56 +08:00
|
|
|
/* Sanity-check NFNL_MAX_ATTR_COUNT */
|
|
|
|
if (ss->cb[cb_id].attr_count > NFNL_MAX_ATTR_COUNT) {
|
|
|
|
rcu_read_unlock();
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
|
netlink: make validation more configurable for future strictness
We currently have two levels of strict validation:
1) liberal (default)
- undefined (type >= max) & NLA_UNSPEC attributes accepted
- attribute length >= expected accepted
- garbage at end of message accepted
2) strict (opt-in)
- NLA_UNSPEC attributes accepted
- attribute length >= expected accepted
Split out parsing strictness into four different options:
* TRAILING - check that there's no trailing data after parsing
attributes (in message or nested)
* MAXTYPE - reject attrs > max known type
* UNSPEC - reject attributes with NLA_UNSPEC policy entries
* STRICT_ATTRS - strictly validate attribute size
The default for future things should be *everything*.
The current *_strict() is a combination of TRAILING and MAXTYPE,
and is renamed to _deprecated_strict().
The current regular parsing has none of this, and is renamed to
*_parse_deprecated().
Additionally it allows us to selectively set one of the new flags
even on old policies. Notably, the UNSPEC flag could be useful in
this case, since it can be arranged (by filling in the policy) to
not be an incompatible userspace ABI change, but would then going
forward prevent forgetting attribute entries. Similar can apply
to the POLICY flag.
We end up with the following renames:
* nla_parse -> nla_parse_deprecated
* nla_parse_strict -> nla_parse_deprecated_strict
* nlmsg_parse -> nlmsg_parse_deprecated
* nlmsg_parse_strict -> nlmsg_parse_deprecated_strict
* nla_parse_nested -> nla_parse_nested_deprecated
* nla_validate_nested -> nla_validate_nested_deprecated
Using spatch, of course:
@@
expression TB, MAX, HEAD, LEN, POL, EXT;
@@
-nla_parse(TB, MAX, HEAD, LEN, POL, EXT)
+nla_parse_deprecated(TB, MAX, HEAD, LEN, POL, EXT)
@@
expression NLH, HDRLEN, TB, MAX, POL, EXT;
@@
-nlmsg_parse(NLH, HDRLEN, TB, MAX, POL, EXT)
+nlmsg_parse_deprecated(NLH, HDRLEN, TB, MAX, POL, EXT)
@@
expression NLH, HDRLEN, TB, MAX, POL, EXT;
@@
-nlmsg_parse_strict(NLH, HDRLEN, TB, MAX, POL, EXT)
+nlmsg_parse_deprecated_strict(NLH, HDRLEN, TB, MAX, POL, EXT)
@@
expression TB, MAX, NLA, POL, EXT;
@@
-nla_parse_nested(TB, MAX, NLA, POL, EXT)
+nla_parse_nested_deprecated(TB, MAX, NLA, POL, EXT)
@@
expression START, MAX, POL, EXT;
@@
-nla_validate_nested(START, MAX, POL, EXT)
+nla_validate_nested_deprecated(START, MAX, POL, EXT)
@@
expression NLH, HDRLEN, MAX, POL, EXT;
@@
-nlmsg_validate(NLH, HDRLEN, MAX, POL, EXT)
+nlmsg_validate_deprecated(NLH, HDRLEN, MAX, POL, EXT)
For this patch, don't actually add the strict, non-renamed versions
yet so that it breaks compile if I get it wrong.
Also, while at it, make nla_validate and nla_parse go down to a
common __nla_validate_parse() function to avoid code duplication.
Ultimately, this allows us to have very strict validation for every
new caller of nla_parse()/nlmsg_parse() etc as re-introduced in the
next patch, while existing things will continue to work as is.
In effect then, this adds fully strict validation for any new command.
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2019-04-26 20:07:28 +08:00
|
|
|
err = nla_parse_deprecated(cda, ss->cb[cb_id].attr_count,
|
|
|
|
attr, attrlen,
|
|
|
|
ss->cb[cb_id].policy, extack);
|
2012-06-28 10:57:49 +08:00
|
|
|
if (err < 0) {
|
|
|
|
rcu_read_unlock();
|
2009-06-03 02:03:33 +08:00
|
|
|
return err;
|
2012-06-28 10:57:49 +08:00
|
|
|
}
|
2007-02-13 03:15:49 +08:00
|
|
|
|
2011-07-18 22:08:07 +08:00
|
|
|
if (nc->call_rcu) {
|
2015-12-16 01:41:56 +08:00
|
|
|
err = nc->call_rcu(net, net->nfnl, skb, nlh,
|
2017-06-20 01:35:46 +08:00
|
|
|
(const struct nlattr **)cda,
|
|
|
|
extack);
|
2011-07-18 22:08:07 +08:00
|
|
|
rcu_read_unlock();
|
|
|
|
} else {
|
|
|
|
rcu_read_unlock();
|
2013-02-05 08:50:26 +08:00
|
|
|
nfnl_lock(subsys_id);
|
2015-12-03 17:49:42 +08:00
|
|
|
if (nfnl_dereference_protected(subsys_id) != ss ||
|
2011-07-18 22:08:07 +08:00
|
|
|
nfnetlink_find_client(type, ss) != nc)
|
|
|
|
err = -EAGAIN;
|
2012-06-28 10:57:47 +08:00
|
|
|
else if (nc->call)
|
2015-12-16 01:41:56 +08:00
|
|
|
err = nc->call(net, net->nfnl, skb, nlh,
|
2017-06-20 01:35:46 +08:00
|
|
|
(const struct nlattr **)cda,
|
|
|
|
extack);
|
2012-06-28 10:57:47 +08:00
|
|
|
else
|
|
|
|
err = -EINVAL;
|
2013-02-05 08:50:26 +08:00
|
|
|
nfnl_unlock(subsys_id);
|
2011-07-18 22:08:07 +08:00
|
|
|
}
|
2008-10-15 02:58:31 +08:00
|
|
|
if (err == -EAGAIN)
|
|
|
|
goto replay;
|
|
|
|
return err;
|
2005-08-10 10:30:24 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-09-03 00:04:53 +08:00
|
|
|
struct nfnl_err {
|
|
|
|
struct list_head head;
|
|
|
|
struct nlmsghdr *nlh;
|
|
|
|
int err;
|
2017-06-20 01:35:46 +08:00
|
|
|
struct netlink_ext_ack extack;
|
2014-09-03 00:04:53 +08:00
|
|
|
};
|
|
|
|
|
2017-06-20 01:35:46 +08:00
|
|
|
static int nfnl_err_add(struct list_head *list, struct nlmsghdr *nlh, int err,
|
|
|
|
const struct netlink_ext_ack *extack)
|
2014-09-03 00:04:53 +08:00
|
|
|
{
|
|
|
|
struct nfnl_err *nfnl_err;
|
|
|
|
|
|
|
|
nfnl_err = kmalloc(sizeof(struct nfnl_err), GFP_KERNEL);
|
|
|
|
if (nfnl_err == NULL)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
nfnl_err->nlh = nlh;
|
|
|
|
nfnl_err->err = err;
|
2017-06-20 01:35:46 +08:00
|
|
|
nfnl_err->extack = *extack;
|
2014-09-03 00:04:53 +08:00
|
|
|
list_add_tail(&nfnl_err->head, list);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void nfnl_err_del(struct nfnl_err *nfnl_err)
|
|
|
|
{
|
|
|
|
list_del(&nfnl_err->head);
|
|
|
|
kfree(nfnl_err);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void nfnl_err_reset(struct list_head *err_list)
|
|
|
|
{
|
|
|
|
struct nfnl_err *nfnl_err, *next;
|
|
|
|
|
|
|
|
list_for_each_entry_safe(nfnl_err, next, err_list, head)
|
|
|
|
nfnl_err_del(nfnl_err);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void nfnl_err_deliver(struct list_head *err_list, struct sk_buff *skb)
|
|
|
|
{
|
|
|
|
struct nfnl_err *nfnl_err, *next;
|
|
|
|
|
|
|
|
list_for_each_entry_safe(nfnl_err, next, err_list, head) {
|
2017-06-20 01:35:46 +08:00
|
|
|
netlink_ack(skb, nfnl_err->nlh, nfnl_err->err,
|
|
|
|
&nfnl_err->extack);
|
2014-09-03 00:04:53 +08:00
|
|
|
nfnl_err_del(nfnl_err);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-07-01 22:14:25 +08:00
|
|
|
enum {
|
|
|
|
NFNL_BATCH_FAILURE = (1 << 0),
|
|
|
|
NFNL_BATCH_DONE = (1 << 1),
|
|
|
|
NFNL_BATCH_REPLAY = (1 << 2),
|
|
|
|
};
|
|
|
|
|
netfilter: nfnetlink: add batch support and use it from nf_tables
This patch adds a batch support to nfnetlink. Basically, it adds
two new control messages:
* NFNL_MSG_BATCH_BEGIN, that indicates the beginning of a batch,
the nfgenmsg->res_id indicates the nfnetlink subsystem ID.
* NFNL_MSG_BATCH_END, that results in the invocation of the
ss->commit callback function. If not specified or an error
ocurred in the batch, the ss->abort function is invoked
instead.
The end message represents the commit operation in nftables, the
lack of end message results in an abort. This patch also adds the
.call_batch function that is only called from the batch receival
path.
This patch adds atomic rule updates and dumps based on
bitmask generations. This allows to atomically commit a set of
rule-set updates incrementally without altering the internal
state of existing nf_tables expressions/matches/targets.
The idea consists of using a generation cursor of 1 bit and
a bitmask of 2 bits per rule. Assuming the gencursor is 0,
then the genmask (expressed as a bitmask) can be interpreted
as:
00 active in the present, will be active in the next generation.
01 inactive in the present, will be active in the next generation.
10 active in the present, will be deleted in the next generation.
^
gencursor
Once you invoke the transition to the next generation, the global
gencursor is updated:
00 active in the present, will be active in the next generation.
01 active in the present, needs to zero its future, it becomes 00.
10 inactive in the present, delete now.
^
gencursor
If a dump is in progress and nf_tables enters a new generation,
the dump will stop and return -EBUSY to let userspace know that
it has to retry again. In order to invalidate dumps, a global
genctr counter is increased everytime nf_tables enters a new
generation.
This new operation can be used from the user-space utility
that controls the firewall, eg.
nft -f restore
The rule updates contained in `file' will be applied atomically.
cat file
-----
add filter INPUT ip saddr 1.1.1.1 counter accept #1
del filter INPUT ip daddr 2.2.2.2 counter drop #2
-EOF-
Note that the rule 1 will be inactive until the transition to the
next generation, the rule 2 will be evicted in the next generation.
There is a penalty during the rule update due to the branch
misprediction in the packet matching framework. But that should be
quickly resolved once the iteration over the commit list that
contain rules that require updates is finished.
Event notification happens once the rule-set update has been
committed. So we skip notifications is case the rule-set update
is aborted, which can happen in case that the rule-set is tested
to apply correctly.
This patch squashed the following patches from Pablo:
* nf_tables: atomic rule updates and dumps
* nf_tables: get rid of per rule list_head for commits
* nf_tables: use per netns commit list
* nfnetlink: add batch support and use it from nf_tables
* nf_tables: all rule updates are transactional
* nf_tables: attach replacement rule after stale one
* nf_tables: do not allow deletion/replacement of stale rules
* nf_tables: remove unused NFTA_RULE_FLAGS
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
2013-10-14 17:05:33 +08:00
|
|
|
static void nfnetlink_rcv_batch(struct sk_buff *skb, struct nlmsghdr *nlh,
|
2017-02-10 19:08:17 +08:00
|
|
|
u16 subsys_id, u32 genid)
|
netfilter: nfnetlink: add batch support and use it from nf_tables
This patch adds a batch support to nfnetlink. Basically, it adds
two new control messages:
* NFNL_MSG_BATCH_BEGIN, that indicates the beginning of a batch,
the nfgenmsg->res_id indicates the nfnetlink subsystem ID.
* NFNL_MSG_BATCH_END, that results in the invocation of the
ss->commit callback function. If not specified or an error
ocurred in the batch, the ss->abort function is invoked
instead.
The end message represents the commit operation in nftables, the
lack of end message results in an abort. This patch also adds the
.call_batch function that is only called from the batch receival
path.
This patch adds atomic rule updates and dumps based on
bitmask generations. This allows to atomically commit a set of
rule-set updates incrementally without altering the internal
state of existing nf_tables expressions/matches/targets.
The idea consists of using a generation cursor of 1 bit and
a bitmask of 2 bits per rule. Assuming the gencursor is 0,
then the genmask (expressed as a bitmask) can be interpreted
as:
00 active in the present, will be active in the next generation.
01 inactive in the present, will be active in the next generation.
10 active in the present, will be deleted in the next generation.
^
gencursor
Once you invoke the transition to the next generation, the global
gencursor is updated:
00 active in the present, will be active in the next generation.
01 active in the present, needs to zero its future, it becomes 00.
10 inactive in the present, delete now.
^
gencursor
If a dump is in progress and nf_tables enters a new generation,
the dump will stop and return -EBUSY to let userspace know that
it has to retry again. In order to invalidate dumps, a global
genctr counter is increased everytime nf_tables enters a new
generation.
This new operation can be used from the user-space utility
that controls the firewall, eg.
nft -f restore
The rule updates contained in `file' will be applied atomically.
cat file
-----
add filter INPUT ip saddr 1.1.1.1 counter accept #1
del filter INPUT ip daddr 2.2.2.2 counter drop #2
-EOF-
Note that the rule 1 will be inactive until the transition to the
next generation, the rule 2 will be evicted in the next generation.
There is a penalty during the rule update due to the branch
misprediction in the packet matching framework. But that should be
quickly resolved once the iteration over the commit list that
contain rules that require updates is finished.
Event notification happens once the rule-set update has been
committed. So we skip notifications is case the rule-set update
is aborted, which can happen in case that the rule-set is tested
to apply correctly.
This patch squashed the following patches from Pablo:
* nf_tables: atomic rule updates and dumps
* nf_tables: get rid of per rule list_head for commits
* nf_tables: use per netns commit list
* nfnetlink: add batch support and use it from nf_tables
* nf_tables: all rule updates are transactional
* nf_tables: attach replacement rule after stale one
* nf_tables: do not allow deletion/replacement of stale rules
* nf_tables: remove unused NFTA_RULE_FLAGS
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
2013-10-14 17:05:33 +08:00
|
|
|
{
|
2014-12-10 17:21:59 +08:00
|
|
|
struct sk_buff *oskb = skb;
|
netfilter: nfnetlink: add batch support and use it from nf_tables
This patch adds a batch support to nfnetlink. Basically, it adds
two new control messages:
* NFNL_MSG_BATCH_BEGIN, that indicates the beginning of a batch,
the nfgenmsg->res_id indicates the nfnetlink subsystem ID.
* NFNL_MSG_BATCH_END, that results in the invocation of the
ss->commit callback function. If not specified or an error
ocurred in the batch, the ss->abort function is invoked
instead.
The end message represents the commit operation in nftables, the
lack of end message results in an abort. This patch also adds the
.call_batch function that is only called from the batch receival
path.
This patch adds atomic rule updates and dumps based on
bitmask generations. This allows to atomically commit a set of
rule-set updates incrementally without altering the internal
state of existing nf_tables expressions/matches/targets.
The idea consists of using a generation cursor of 1 bit and
a bitmask of 2 bits per rule. Assuming the gencursor is 0,
then the genmask (expressed as a bitmask) can be interpreted
as:
00 active in the present, will be active in the next generation.
01 inactive in the present, will be active in the next generation.
10 active in the present, will be deleted in the next generation.
^
gencursor
Once you invoke the transition to the next generation, the global
gencursor is updated:
00 active in the present, will be active in the next generation.
01 active in the present, needs to zero its future, it becomes 00.
10 inactive in the present, delete now.
^
gencursor
If a dump is in progress and nf_tables enters a new generation,
the dump will stop and return -EBUSY to let userspace know that
it has to retry again. In order to invalidate dumps, a global
genctr counter is increased everytime nf_tables enters a new
generation.
This new operation can be used from the user-space utility
that controls the firewall, eg.
nft -f restore
The rule updates contained in `file' will be applied atomically.
cat file
-----
add filter INPUT ip saddr 1.1.1.1 counter accept #1
del filter INPUT ip daddr 2.2.2.2 counter drop #2
-EOF-
Note that the rule 1 will be inactive until the transition to the
next generation, the rule 2 will be evicted in the next generation.
There is a penalty during the rule update due to the branch
misprediction in the packet matching framework. But that should be
quickly resolved once the iteration over the commit list that
contain rules that require updates is finished.
Event notification happens once the rule-set update has been
committed. So we skip notifications is case the rule-set update
is aborted, which can happen in case that the rule-set is tested
to apply correctly.
This patch squashed the following patches from Pablo:
* nf_tables: atomic rule updates and dumps
* nf_tables: get rid of per rule list_head for commits
* nf_tables: use per netns commit list
* nfnetlink: add batch support and use it from nf_tables
* nf_tables: all rule updates are transactional
* nf_tables: attach replacement rule after stale one
* nf_tables: do not allow deletion/replacement of stale rules
* nf_tables: remove unused NFTA_RULE_FLAGS
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
2013-10-14 17:05:33 +08:00
|
|
|
struct net *net = sock_net(skb->sk);
|
|
|
|
const struct nfnetlink_subsystem *ss;
|
|
|
|
const struct nfnl_callback *nc;
|
2017-06-20 01:35:46 +08:00
|
|
|
struct netlink_ext_ack extack;
|
2017-02-18 10:35:47 +08:00
|
|
|
LIST_HEAD(err_list);
|
2015-07-01 22:14:25 +08:00
|
|
|
u32 status;
|
netfilter: nfnetlink: add batch support and use it from nf_tables
This patch adds a batch support to nfnetlink. Basically, it adds
two new control messages:
* NFNL_MSG_BATCH_BEGIN, that indicates the beginning of a batch,
the nfgenmsg->res_id indicates the nfnetlink subsystem ID.
* NFNL_MSG_BATCH_END, that results in the invocation of the
ss->commit callback function. If not specified or an error
ocurred in the batch, the ss->abort function is invoked
instead.
The end message represents the commit operation in nftables, the
lack of end message results in an abort. This patch also adds the
.call_batch function that is only called from the batch receival
path.
This patch adds atomic rule updates and dumps based on
bitmask generations. This allows to atomically commit a set of
rule-set updates incrementally without altering the internal
state of existing nf_tables expressions/matches/targets.
The idea consists of using a generation cursor of 1 bit and
a bitmask of 2 bits per rule. Assuming the gencursor is 0,
then the genmask (expressed as a bitmask) can be interpreted
as:
00 active in the present, will be active in the next generation.
01 inactive in the present, will be active in the next generation.
10 active in the present, will be deleted in the next generation.
^
gencursor
Once you invoke the transition to the next generation, the global
gencursor is updated:
00 active in the present, will be active in the next generation.
01 active in the present, needs to zero its future, it becomes 00.
10 inactive in the present, delete now.
^
gencursor
If a dump is in progress and nf_tables enters a new generation,
the dump will stop and return -EBUSY to let userspace know that
it has to retry again. In order to invalidate dumps, a global
genctr counter is increased everytime nf_tables enters a new
generation.
This new operation can be used from the user-space utility
that controls the firewall, eg.
nft -f restore
The rule updates contained in `file' will be applied atomically.
cat file
-----
add filter INPUT ip saddr 1.1.1.1 counter accept #1
del filter INPUT ip daddr 2.2.2.2 counter drop #2
-EOF-
Note that the rule 1 will be inactive until the transition to the
next generation, the rule 2 will be evicted in the next generation.
There is a penalty during the rule update due to the branch
misprediction in the packet matching framework. But that should be
quickly resolved once the iteration over the commit list that
contain rules that require updates is finished.
Event notification happens once the rule-set update has been
committed. So we skip notifications is case the rule-set update
is aborted, which can happen in case that the rule-set is tested
to apply correctly.
This patch squashed the following patches from Pablo:
* nf_tables: atomic rule updates and dumps
* nf_tables: get rid of per rule list_head for commits
* nf_tables: use per netns commit list
* nfnetlink: add batch support and use it from nf_tables
* nf_tables: all rule updates are transactional
* nf_tables: attach replacement rule after stale one
* nf_tables: do not allow deletion/replacement of stale rules
* nf_tables: remove unused NFTA_RULE_FLAGS
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
2013-10-14 17:05:33 +08:00
|
|
|
int err;
|
|
|
|
|
|
|
|
if (subsys_id >= NFNL_SUBSYS_COUNT)
|
2017-04-12 20:34:04 +08:00
|
|
|
return netlink_ack(skb, nlh, -EINVAL, NULL);
|
netfilter: nfnetlink: add batch support and use it from nf_tables
This patch adds a batch support to nfnetlink. Basically, it adds
two new control messages:
* NFNL_MSG_BATCH_BEGIN, that indicates the beginning of a batch,
the nfgenmsg->res_id indicates the nfnetlink subsystem ID.
* NFNL_MSG_BATCH_END, that results in the invocation of the
ss->commit callback function. If not specified or an error
ocurred in the batch, the ss->abort function is invoked
instead.
The end message represents the commit operation in nftables, the
lack of end message results in an abort. This patch also adds the
.call_batch function that is only called from the batch receival
path.
This patch adds atomic rule updates and dumps based on
bitmask generations. This allows to atomically commit a set of
rule-set updates incrementally without altering the internal
state of existing nf_tables expressions/matches/targets.
The idea consists of using a generation cursor of 1 bit and
a bitmask of 2 bits per rule. Assuming the gencursor is 0,
then the genmask (expressed as a bitmask) can be interpreted
as:
00 active in the present, will be active in the next generation.
01 inactive in the present, will be active in the next generation.
10 active in the present, will be deleted in the next generation.
^
gencursor
Once you invoke the transition to the next generation, the global
gencursor is updated:
00 active in the present, will be active in the next generation.
01 active in the present, needs to zero its future, it becomes 00.
10 inactive in the present, delete now.
^
gencursor
If a dump is in progress and nf_tables enters a new generation,
the dump will stop and return -EBUSY to let userspace know that
it has to retry again. In order to invalidate dumps, a global
genctr counter is increased everytime nf_tables enters a new
generation.
This new operation can be used from the user-space utility
that controls the firewall, eg.
nft -f restore
The rule updates contained in `file' will be applied atomically.
cat file
-----
add filter INPUT ip saddr 1.1.1.1 counter accept #1
del filter INPUT ip daddr 2.2.2.2 counter drop #2
-EOF-
Note that the rule 1 will be inactive until the transition to the
next generation, the rule 2 will be evicted in the next generation.
There is a penalty during the rule update due to the branch
misprediction in the packet matching framework. But that should be
quickly resolved once the iteration over the commit list that
contain rules that require updates is finished.
Event notification happens once the rule-set update has been
committed. So we skip notifications is case the rule-set update
is aborted, which can happen in case that the rule-set is tested
to apply correctly.
This patch squashed the following patches from Pablo:
* nf_tables: atomic rule updates and dumps
* nf_tables: get rid of per rule list_head for commits
* nf_tables: use per netns commit list
* nfnetlink: add batch support and use it from nf_tables
* nf_tables: all rule updates are transactional
* nf_tables: attach replacement rule after stale one
* nf_tables: do not allow deletion/replacement of stale rules
* nf_tables: remove unused NFTA_RULE_FLAGS
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
2013-10-14 17:05:33 +08:00
|
|
|
replay:
|
2015-07-01 22:14:25 +08:00
|
|
|
status = 0;
|
|
|
|
|
2014-12-10 17:21:59 +08:00
|
|
|
skb = netlink_skb_clone(oskb, GFP_KERNEL);
|
|
|
|
if (!skb)
|
2017-04-12 20:34:04 +08:00
|
|
|
return netlink_ack(oskb, nlh, -ENOMEM, NULL);
|
netfilter: nfnetlink: add batch support and use it from nf_tables
This patch adds a batch support to nfnetlink. Basically, it adds
two new control messages:
* NFNL_MSG_BATCH_BEGIN, that indicates the beginning of a batch,
the nfgenmsg->res_id indicates the nfnetlink subsystem ID.
* NFNL_MSG_BATCH_END, that results in the invocation of the
ss->commit callback function. If not specified or an error
ocurred in the batch, the ss->abort function is invoked
instead.
The end message represents the commit operation in nftables, the
lack of end message results in an abort. This patch also adds the
.call_batch function that is only called from the batch receival
path.
This patch adds atomic rule updates and dumps based on
bitmask generations. This allows to atomically commit a set of
rule-set updates incrementally without altering the internal
state of existing nf_tables expressions/matches/targets.
The idea consists of using a generation cursor of 1 bit and
a bitmask of 2 bits per rule. Assuming the gencursor is 0,
then the genmask (expressed as a bitmask) can be interpreted
as:
00 active in the present, will be active in the next generation.
01 inactive in the present, will be active in the next generation.
10 active in the present, will be deleted in the next generation.
^
gencursor
Once you invoke the transition to the next generation, the global
gencursor is updated:
00 active in the present, will be active in the next generation.
01 active in the present, needs to zero its future, it becomes 00.
10 inactive in the present, delete now.
^
gencursor
If a dump is in progress and nf_tables enters a new generation,
the dump will stop and return -EBUSY to let userspace know that
it has to retry again. In order to invalidate dumps, a global
genctr counter is increased everytime nf_tables enters a new
generation.
This new operation can be used from the user-space utility
that controls the firewall, eg.
nft -f restore
The rule updates contained in `file' will be applied atomically.
cat file
-----
add filter INPUT ip saddr 1.1.1.1 counter accept #1
del filter INPUT ip daddr 2.2.2.2 counter drop #2
-EOF-
Note that the rule 1 will be inactive until the transition to the
next generation, the rule 2 will be evicted in the next generation.
There is a penalty during the rule update due to the branch
misprediction in the packet matching framework. But that should be
quickly resolved once the iteration over the commit list that
contain rules that require updates is finished.
Event notification happens once the rule-set update has been
committed. So we skip notifications is case the rule-set update
is aborted, which can happen in case that the rule-set is tested
to apply correctly.
This patch squashed the following patches from Pablo:
* nf_tables: atomic rule updates and dumps
* nf_tables: get rid of per rule list_head for commits
* nf_tables: use per netns commit list
* nfnetlink: add batch support and use it from nf_tables
* nf_tables: all rule updates are transactional
* nf_tables: attach replacement rule after stale one
* nf_tables: do not allow deletion/replacement of stale rules
* nf_tables: remove unused NFTA_RULE_FLAGS
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
2013-10-14 17:05:33 +08:00
|
|
|
|
|
|
|
nfnl_lock(subsys_id);
|
2015-12-03 17:49:42 +08:00
|
|
|
ss = nfnl_dereference_protected(subsys_id);
|
netfilter: nfnetlink: add batch support and use it from nf_tables
This patch adds a batch support to nfnetlink. Basically, it adds
two new control messages:
* NFNL_MSG_BATCH_BEGIN, that indicates the beginning of a batch,
the nfgenmsg->res_id indicates the nfnetlink subsystem ID.
* NFNL_MSG_BATCH_END, that results in the invocation of the
ss->commit callback function. If not specified or an error
ocurred in the batch, the ss->abort function is invoked
instead.
The end message represents the commit operation in nftables, the
lack of end message results in an abort. This patch also adds the
.call_batch function that is only called from the batch receival
path.
This patch adds atomic rule updates and dumps based on
bitmask generations. This allows to atomically commit a set of
rule-set updates incrementally without altering the internal
state of existing nf_tables expressions/matches/targets.
The idea consists of using a generation cursor of 1 bit and
a bitmask of 2 bits per rule. Assuming the gencursor is 0,
then the genmask (expressed as a bitmask) can be interpreted
as:
00 active in the present, will be active in the next generation.
01 inactive in the present, will be active in the next generation.
10 active in the present, will be deleted in the next generation.
^
gencursor
Once you invoke the transition to the next generation, the global
gencursor is updated:
00 active in the present, will be active in the next generation.
01 active in the present, needs to zero its future, it becomes 00.
10 inactive in the present, delete now.
^
gencursor
If a dump is in progress and nf_tables enters a new generation,
the dump will stop and return -EBUSY to let userspace know that
it has to retry again. In order to invalidate dumps, a global
genctr counter is increased everytime nf_tables enters a new
generation.
This new operation can be used from the user-space utility
that controls the firewall, eg.
nft -f restore
The rule updates contained in `file' will be applied atomically.
cat file
-----
add filter INPUT ip saddr 1.1.1.1 counter accept #1
del filter INPUT ip daddr 2.2.2.2 counter drop #2
-EOF-
Note that the rule 1 will be inactive until the transition to the
next generation, the rule 2 will be evicted in the next generation.
There is a penalty during the rule update due to the branch
misprediction in the packet matching framework. But that should be
quickly resolved once the iteration over the commit list that
contain rules that require updates is finished.
Event notification happens once the rule-set update has been
committed. So we skip notifications is case the rule-set update
is aborted, which can happen in case that the rule-set is tested
to apply correctly.
This patch squashed the following patches from Pablo:
* nf_tables: atomic rule updates and dumps
* nf_tables: get rid of per rule list_head for commits
* nf_tables: use per netns commit list
* nfnetlink: add batch support and use it from nf_tables
* nf_tables: all rule updates are transactional
* nf_tables: attach replacement rule after stale one
* nf_tables: do not allow deletion/replacement of stale rules
* nf_tables: remove unused NFTA_RULE_FLAGS
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
2013-10-14 17:05:33 +08:00
|
|
|
if (!ss) {
|
|
|
|
#ifdef CONFIG_MODULES
|
|
|
|
nfnl_unlock(subsys_id);
|
|
|
|
request_module("nfnetlink-subsys-%d", subsys_id);
|
|
|
|
nfnl_lock(subsys_id);
|
2015-12-03 17:49:42 +08:00
|
|
|
ss = nfnl_dereference_protected(subsys_id);
|
netfilter: nfnetlink: add batch support and use it from nf_tables
This patch adds a batch support to nfnetlink. Basically, it adds
two new control messages:
* NFNL_MSG_BATCH_BEGIN, that indicates the beginning of a batch,
the nfgenmsg->res_id indicates the nfnetlink subsystem ID.
* NFNL_MSG_BATCH_END, that results in the invocation of the
ss->commit callback function. If not specified or an error
ocurred in the batch, the ss->abort function is invoked
instead.
The end message represents the commit operation in nftables, the
lack of end message results in an abort. This patch also adds the
.call_batch function that is only called from the batch receival
path.
This patch adds atomic rule updates and dumps based on
bitmask generations. This allows to atomically commit a set of
rule-set updates incrementally without altering the internal
state of existing nf_tables expressions/matches/targets.
The idea consists of using a generation cursor of 1 bit and
a bitmask of 2 bits per rule. Assuming the gencursor is 0,
then the genmask (expressed as a bitmask) can be interpreted
as:
00 active in the present, will be active in the next generation.
01 inactive in the present, will be active in the next generation.
10 active in the present, will be deleted in the next generation.
^
gencursor
Once you invoke the transition to the next generation, the global
gencursor is updated:
00 active in the present, will be active in the next generation.
01 active in the present, needs to zero its future, it becomes 00.
10 inactive in the present, delete now.
^
gencursor
If a dump is in progress and nf_tables enters a new generation,
the dump will stop and return -EBUSY to let userspace know that
it has to retry again. In order to invalidate dumps, a global
genctr counter is increased everytime nf_tables enters a new
generation.
This new operation can be used from the user-space utility
that controls the firewall, eg.
nft -f restore
The rule updates contained in `file' will be applied atomically.
cat file
-----
add filter INPUT ip saddr 1.1.1.1 counter accept #1
del filter INPUT ip daddr 2.2.2.2 counter drop #2
-EOF-
Note that the rule 1 will be inactive until the transition to the
next generation, the rule 2 will be evicted in the next generation.
There is a penalty during the rule update due to the branch
misprediction in the packet matching framework. But that should be
quickly resolved once the iteration over the commit list that
contain rules that require updates is finished.
Event notification happens once the rule-set update has been
committed. So we skip notifications is case the rule-set update
is aborted, which can happen in case that the rule-set is tested
to apply correctly.
This patch squashed the following patches from Pablo:
* nf_tables: atomic rule updates and dumps
* nf_tables: get rid of per rule list_head for commits
* nf_tables: use per netns commit list
* nfnetlink: add batch support and use it from nf_tables
* nf_tables: all rule updates are transactional
* nf_tables: attach replacement rule after stale one
* nf_tables: do not allow deletion/replacement of stale rules
* nf_tables: remove unused NFTA_RULE_FLAGS
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
2013-10-14 17:05:33 +08:00
|
|
|
if (!ss)
|
|
|
|
#endif
|
|
|
|
{
|
|
|
|
nfnl_unlock(subsys_id);
|
2017-04-12 20:34:04 +08:00
|
|
|
netlink_ack(oskb, nlh, -EOPNOTSUPP, NULL);
|
2014-12-10 17:21:59 +08:00
|
|
|
return kfree_skb(skb);
|
netfilter: nfnetlink: add batch support and use it from nf_tables
This patch adds a batch support to nfnetlink. Basically, it adds
two new control messages:
* NFNL_MSG_BATCH_BEGIN, that indicates the beginning of a batch,
the nfgenmsg->res_id indicates the nfnetlink subsystem ID.
* NFNL_MSG_BATCH_END, that results in the invocation of the
ss->commit callback function. If not specified or an error
ocurred in the batch, the ss->abort function is invoked
instead.
The end message represents the commit operation in nftables, the
lack of end message results in an abort. This patch also adds the
.call_batch function that is only called from the batch receival
path.
This patch adds atomic rule updates and dumps based on
bitmask generations. This allows to atomically commit a set of
rule-set updates incrementally without altering the internal
state of existing nf_tables expressions/matches/targets.
The idea consists of using a generation cursor of 1 bit and
a bitmask of 2 bits per rule. Assuming the gencursor is 0,
then the genmask (expressed as a bitmask) can be interpreted
as:
00 active in the present, will be active in the next generation.
01 inactive in the present, will be active in the next generation.
10 active in the present, will be deleted in the next generation.
^
gencursor
Once you invoke the transition to the next generation, the global
gencursor is updated:
00 active in the present, will be active in the next generation.
01 active in the present, needs to zero its future, it becomes 00.
10 inactive in the present, delete now.
^
gencursor
If a dump is in progress and nf_tables enters a new generation,
the dump will stop and return -EBUSY to let userspace know that
it has to retry again. In order to invalidate dumps, a global
genctr counter is increased everytime nf_tables enters a new
generation.
This new operation can be used from the user-space utility
that controls the firewall, eg.
nft -f restore
The rule updates contained in `file' will be applied atomically.
cat file
-----
add filter INPUT ip saddr 1.1.1.1 counter accept #1
del filter INPUT ip daddr 2.2.2.2 counter drop #2
-EOF-
Note that the rule 1 will be inactive until the transition to the
next generation, the rule 2 will be evicted in the next generation.
There is a penalty during the rule update due to the branch
misprediction in the packet matching framework. But that should be
quickly resolved once the iteration over the commit list that
contain rules that require updates is finished.
Event notification happens once the rule-set update has been
committed. So we skip notifications is case the rule-set update
is aborted, which can happen in case that the rule-set is tested
to apply correctly.
This patch squashed the following patches from Pablo:
* nf_tables: atomic rule updates and dumps
* nf_tables: get rid of per rule list_head for commits
* nf_tables: use per netns commit list
* nfnetlink: add batch support and use it from nf_tables
* nf_tables: all rule updates are transactional
* nf_tables: attach replacement rule after stale one
* nf_tables: do not allow deletion/replacement of stale rules
* nf_tables: remove unused NFTA_RULE_FLAGS
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
2013-10-14 17:05:33 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-11 19:45:11 +08:00
|
|
|
if (!ss->valid_genid || !ss->commit || !ss->abort) {
|
netfilter: nfnetlink: add batch support and use it from nf_tables
This patch adds a batch support to nfnetlink. Basically, it adds
two new control messages:
* NFNL_MSG_BATCH_BEGIN, that indicates the beginning of a batch,
the nfgenmsg->res_id indicates the nfnetlink subsystem ID.
* NFNL_MSG_BATCH_END, that results in the invocation of the
ss->commit callback function. If not specified or an error
ocurred in the batch, the ss->abort function is invoked
instead.
The end message represents the commit operation in nftables, the
lack of end message results in an abort. This patch also adds the
.call_batch function that is only called from the batch receival
path.
This patch adds atomic rule updates and dumps based on
bitmask generations. This allows to atomically commit a set of
rule-set updates incrementally without altering the internal
state of existing nf_tables expressions/matches/targets.
The idea consists of using a generation cursor of 1 bit and
a bitmask of 2 bits per rule. Assuming the gencursor is 0,
then the genmask (expressed as a bitmask) can be interpreted
as:
00 active in the present, will be active in the next generation.
01 inactive in the present, will be active in the next generation.
10 active in the present, will be deleted in the next generation.
^
gencursor
Once you invoke the transition to the next generation, the global
gencursor is updated:
00 active in the present, will be active in the next generation.
01 active in the present, needs to zero its future, it becomes 00.
10 inactive in the present, delete now.
^
gencursor
If a dump is in progress and nf_tables enters a new generation,
the dump will stop and return -EBUSY to let userspace know that
it has to retry again. In order to invalidate dumps, a global
genctr counter is increased everytime nf_tables enters a new
generation.
This new operation can be used from the user-space utility
that controls the firewall, eg.
nft -f restore
The rule updates contained in `file' will be applied atomically.
cat file
-----
add filter INPUT ip saddr 1.1.1.1 counter accept #1
del filter INPUT ip daddr 2.2.2.2 counter drop #2
-EOF-
Note that the rule 1 will be inactive until the transition to the
next generation, the rule 2 will be evicted in the next generation.
There is a penalty during the rule update due to the branch
misprediction in the packet matching framework. But that should be
quickly resolved once the iteration over the commit list that
contain rules that require updates is finished.
Event notification happens once the rule-set update has been
committed. So we skip notifications is case the rule-set update
is aborted, which can happen in case that the rule-set is tested
to apply correctly.
This patch squashed the following patches from Pablo:
* nf_tables: atomic rule updates and dumps
* nf_tables: get rid of per rule list_head for commits
* nf_tables: use per netns commit list
* nfnetlink: add batch support and use it from nf_tables
* nf_tables: all rule updates are transactional
* nf_tables: attach replacement rule after stale one
* nf_tables: do not allow deletion/replacement of stale rules
* nf_tables: remove unused NFTA_RULE_FLAGS
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
2013-10-14 17:05:33 +08:00
|
|
|
nfnl_unlock(subsys_id);
|
2017-04-12 20:34:04 +08:00
|
|
|
netlink_ack(oskb, nlh, -EOPNOTSUPP, NULL);
|
2014-05-04 19:35:37 +08:00
|
|
|
return kfree_skb(skb);
|
netfilter: nfnetlink: add batch support and use it from nf_tables
This patch adds a batch support to nfnetlink. Basically, it adds
two new control messages:
* NFNL_MSG_BATCH_BEGIN, that indicates the beginning of a batch,
the nfgenmsg->res_id indicates the nfnetlink subsystem ID.
* NFNL_MSG_BATCH_END, that results in the invocation of the
ss->commit callback function. If not specified or an error
ocurred in the batch, the ss->abort function is invoked
instead.
The end message represents the commit operation in nftables, the
lack of end message results in an abort. This patch also adds the
.call_batch function that is only called from the batch receival
path.
This patch adds atomic rule updates and dumps based on
bitmask generations. This allows to atomically commit a set of
rule-set updates incrementally without altering the internal
state of existing nf_tables expressions/matches/targets.
The idea consists of using a generation cursor of 1 bit and
a bitmask of 2 bits per rule. Assuming the gencursor is 0,
then the genmask (expressed as a bitmask) can be interpreted
as:
00 active in the present, will be active in the next generation.
01 inactive in the present, will be active in the next generation.
10 active in the present, will be deleted in the next generation.
^
gencursor
Once you invoke the transition to the next generation, the global
gencursor is updated:
00 active in the present, will be active in the next generation.
01 active in the present, needs to zero its future, it becomes 00.
10 inactive in the present, delete now.
^
gencursor
If a dump is in progress and nf_tables enters a new generation,
the dump will stop and return -EBUSY to let userspace know that
it has to retry again. In order to invalidate dumps, a global
genctr counter is increased everytime nf_tables enters a new
generation.
This new operation can be used from the user-space utility
that controls the firewall, eg.
nft -f restore
The rule updates contained in `file' will be applied atomically.
cat file
-----
add filter INPUT ip saddr 1.1.1.1 counter accept #1
del filter INPUT ip daddr 2.2.2.2 counter drop #2
-EOF-
Note that the rule 1 will be inactive until the transition to the
next generation, the rule 2 will be evicted in the next generation.
There is a penalty during the rule update due to the branch
misprediction in the packet matching framework. But that should be
quickly resolved once the iteration over the commit list that
contain rules that require updates is finished.
Event notification happens once the rule-set update has been
committed. So we skip notifications is case the rule-set update
is aborted, which can happen in case that the rule-set is tested
to apply correctly.
This patch squashed the following patches from Pablo:
* nf_tables: atomic rule updates and dumps
* nf_tables: get rid of per rule list_head for commits
* nf_tables: use per netns commit list
* nfnetlink: add batch support and use it from nf_tables
* nf_tables: all rule updates are transactional
* nf_tables: attach replacement rule after stale one
* nf_tables: do not allow deletion/replacement of stale rules
* nf_tables: remove unused NFTA_RULE_FLAGS
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
2013-10-14 17:05:33 +08:00
|
|
|
}
|
|
|
|
|
2018-07-11 19:45:12 +08:00
|
|
|
if (!try_module_get(ss->owner)) {
|
|
|
|
nfnl_unlock(subsys_id);
|
|
|
|
netlink_ack(oskb, nlh, -EOPNOTSUPP, NULL);
|
|
|
|
return kfree_skb(skb);
|
|
|
|
}
|
|
|
|
|
2018-07-11 19:45:11 +08:00
|
|
|
if (!ss->valid_genid(net, genid)) {
|
2018-07-11 19:45:12 +08:00
|
|
|
module_put(ss->owner);
|
2017-02-10 19:08:17 +08:00
|
|
|
nfnl_unlock(subsys_id);
|
2017-04-12 20:34:04 +08:00
|
|
|
netlink_ack(oskb, nlh, -ERESTART, NULL);
|
2017-02-10 19:08:17 +08:00
|
|
|
return kfree_skb(skb);
|
|
|
|
}
|
|
|
|
|
2018-07-11 19:45:14 +08:00
|
|
|
nfnl_unlock(subsys_id);
|
|
|
|
|
netfilter: nfnetlink: add batch support and use it from nf_tables
This patch adds a batch support to nfnetlink. Basically, it adds
two new control messages:
* NFNL_MSG_BATCH_BEGIN, that indicates the beginning of a batch,
the nfgenmsg->res_id indicates the nfnetlink subsystem ID.
* NFNL_MSG_BATCH_END, that results in the invocation of the
ss->commit callback function. If not specified or an error
ocurred in the batch, the ss->abort function is invoked
instead.
The end message represents the commit operation in nftables, the
lack of end message results in an abort. This patch also adds the
.call_batch function that is only called from the batch receival
path.
This patch adds atomic rule updates and dumps based on
bitmask generations. This allows to atomically commit a set of
rule-set updates incrementally without altering the internal
state of existing nf_tables expressions/matches/targets.
The idea consists of using a generation cursor of 1 bit and
a bitmask of 2 bits per rule. Assuming the gencursor is 0,
then the genmask (expressed as a bitmask) can be interpreted
as:
00 active in the present, will be active in the next generation.
01 inactive in the present, will be active in the next generation.
10 active in the present, will be deleted in the next generation.
^
gencursor
Once you invoke the transition to the next generation, the global
gencursor is updated:
00 active in the present, will be active in the next generation.
01 active in the present, needs to zero its future, it becomes 00.
10 inactive in the present, delete now.
^
gencursor
If a dump is in progress and nf_tables enters a new generation,
the dump will stop and return -EBUSY to let userspace know that
it has to retry again. In order to invalidate dumps, a global
genctr counter is increased everytime nf_tables enters a new
generation.
This new operation can be used from the user-space utility
that controls the firewall, eg.
nft -f restore
The rule updates contained in `file' will be applied atomically.
cat file
-----
add filter INPUT ip saddr 1.1.1.1 counter accept #1
del filter INPUT ip daddr 2.2.2.2 counter drop #2
-EOF-
Note that the rule 1 will be inactive until the transition to the
next generation, the rule 2 will be evicted in the next generation.
There is a penalty during the rule update due to the branch
misprediction in the packet matching framework. But that should be
quickly resolved once the iteration over the commit list that
contain rules that require updates is finished.
Event notification happens once the rule-set update has been
committed. So we skip notifications is case the rule-set update
is aborted, which can happen in case that the rule-set is tested
to apply correctly.
This patch squashed the following patches from Pablo:
* nf_tables: atomic rule updates and dumps
* nf_tables: get rid of per rule list_head for commits
* nf_tables: use per netns commit list
* nfnetlink: add batch support and use it from nf_tables
* nf_tables: all rule updates are transactional
* nf_tables: attach replacement rule after stale one
* nf_tables: do not allow deletion/replacement of stale rules
* nf_tables: remove unused NFTA_RULE_FLAGS
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
2013-10-14 17:05:33 +08:00
|
|
|
while (skb->len >= nlmsg_total_size(0)) {
|
|
|
|
int msglen, type;
|
|
|
|
|
2018-05-27 17:24:34 +08:00
|
|
|
if (fatal_signal_pending(current)) {
|
|
|
|
nfnl_err_reset(&err_list);
|
|
|
|
err = -EINTR;
|
|
|
|
status = NFNL_BATCH_FAILURE;
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
2017-06-20 01:35:46 +08:00
|
|
|
memset(&extack, 0, sizeof(extack));
|
netfilter: nfnetlink: add batch support and use it from nf_tables
This patch adds a batch support to nfnetlink. Basically, it adds
two new control messages:
* NFNL_MSG_BATCH_BEGIN, that indicates the beginning of a batch,
the nfgenmsg->res_id indicates the nfnetlink subsystem ID.
* NFNL_MSG_BATCH_END, that results in the invocation of the
ss->commit callback function. If not specified or an error
ocurred in the batch, the ss->abort function is invoked
instead.
The end message represents the commit operation in nftables, the
lack of end message results in an abort. This patch also adds the
.call_batch function that is only called from the batch receival
path.
This patch adds atomic rule updates and dumps based on
bitmask generations. This allows to atomically commit a set of
rule-set updates incrementally without altering the internal
state of existing nf_tables expressions/matches/targets.
The idea consists of using a generation cursor of 1 bit and
a bitmask of 2 bits per rule. Assuming the gencursor is 0,
then the genmask (expressed as a bitmask) can be interpreted
as:
00 active in the present, will be active in the next generation.
01 inactive in the present, will be active in the next generation.
10 active in the present, will be deleted in the next generation.
^
gencursor
Once you invoke the transition to the next generation, the global
gencursor is updated:
00 active in the present, will be active in the next generation.
01 active in the present, needs to zero its future, it becomes 00.
10 inactive in the present, delete now.
^
gencursor
If a dump is in progress and nf_tables enters a new generation,
the dump will stop and return -EBUSY to let userspace know that
it has to retry again. In order to invalidate dumps, a global
genctr counter is increased everytime nf_tables enters a new
generation.
This new operation can be used from the user-space utility
that controls the firewall, eg.
nft -f restore
The rule updates contained in `file' will be applied atomically.
cat file
-----
add filter INPUT ip saddr 1.1.1.1 counter accept #1
del filter INPUT ip daddr 2.2.2.2 counter drop #2
-EOF-
Note that the rule 1 will be inactive until the transition to the
next generation, the rule 2 will be evicted in the next generation.
There is a penalty during the rule update due to the branch
misprediction in the packet matching framework. But that should be
quickly resolved once the iteration over the commit list that
contain rules that require updates is finished.
Event notification happens once the rule-set update has been
committed. So we skip notifications is case the rule-set update
is aborted, which can happen in case that the rule-set is tested
to apply correctly.
This patch squashed the following patches from Pablo:
* nf_tables: atomic rule updates and dumps
* nf_tables: get rid of per rule list_head for commits
* nf_tables: use per netns commit list
* nfnetlink: add batch support and use it from nf_tables
* nf_tables: all rule updates are transactional
* nf_tables: attach replacement rule after stale one
* nf_tables: do not allow deletion/replacement of stale rules
* nf_tables: remove unused NFTA_RULE_FLAGS
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
2013-10-14 17:05:33 +08:00
|
|
|
nlh = nlmsg_hdr(skb);
|
|
|
|
err = 0;
|
|
|
|
|
2016-02-03 02:36:45 +08:00
|
|
|
if (nlh->nlmsg_len < NLMSG_HDRLEN ||
|
|
|
|
skb->len < nlh->nlmsg_len ||
|
|
|
|
nlmsg_len(nlh) < sizeof(struct nfgenmsg)) {
|
|
|
|
nfnl_err_reset(&err_list);
|
|
|
|
status |= NFNL_BATCH_FAILURE;
|
|
|
|
goto done;
|
netfilter: nfnetlink: add batch support and use it from nf_tables
This patch adds a batch support to nfnetlink. Basically, it adds
two new control messages:
* NFNL_MSG_BATCH_BEGIN, that indicates the beginning of a batch,
the nfgenmsg->res_id indicates the nfnetlink subsystem ID.
* NFNL_MSG_BATCH_END, that results in the invocation of the
ss->commit callback function. If not specified or an error
ocurred in the batch, the ss->abort function is invoked
instead.
The end message represents the commit operation in nftables, the
lack of end message results in an abort. This patch also adds the
.call_batch function that is only called from the batch receival
path.
This patch adds atomic rule updates and dumps based on
bitmask generations. This allows to atomically commit a set of
rule-set updates incrementally without altering the internal
state of existing nf_tables expressions/matches/targets.
The idea consists of using a generation cursor of 1 bit and
a bitmask of 2 bits per rule. Assuming the gencursor is 0,
then the genmask (expressed as a bitmask) can be interpreted
as:
00 active in the present, will be active in the next generation.
01 inactive in the present, will be active in the next generation.
10 active in the present, will be deleted in the next generation.
^
gencursor
Once you invoke the transition to the next generation, the global
gencursor is updated:
00 active in the present, will be active in the next generation.
01 active in the present, needs to zero its future, it becomes 00.
10 inactive in the present, delete now.
^
gencursor
If a dump is in progress and nf_tables enters a new generation,
the dump will stop and return -EBUSY to let userspace know that
it has to retry again. In order to invalidate dumps, a global
genctr counter is increased everytime nf_tables enters a new
generation.
This new operation can be used from the user-space utility
that controls the firewall, eg.
nft -f restore
The rule updates contained in `file' will be applied atomically.
cat file
-----
add filter INPUT ip saddr 1.1.1.1 counter accept #1
del filter INPUT ip daddr 2.2.2.2 counter drop #2
-EOF-
Note that the rule 1 will be inactive until the transition to the
next generation, the rule 2 will be evicted in the next generation.
There is a penalty during the rule update due to the branch
misprediction in the packet matching framework. But that should be
quickly resolved once the iteration over the commit list that
contain rules that require updates is finished.
Event notification happens once the rule-set update has been
committed. So we skip notifications is case the rule-set update
is aborted, which can happen in case that the rule-set is tested
to apply correctly.
This patch squashed the following patches from Pablo:
* nf_tables: atomic rule updates and dumps
* nf_tables: get rid of per rule list_head for commits
* nf_tables: use per netns commit list
* nfnetlink: add batch support and use it from nf_tables
* nf_tables: all rule updates are transactional
* nf_tables: attach replacement rule after stale one
* nf_tables: do not allow deletion/replacement of stale rules
* nf_tables: remove unused NFTA_RULE_FLAGS
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
2013-10-14 17:05:33 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Only requests are handled by the kernel */
|
|
|
|
if (!(nlh->nlmsg_flags & NLM_F_REQUEST)) {
|
|
|
|
err = -EINVAL;
|
|
|
|
goto ack;
|
|
|
|
}
|
|
|
|
|
|
|
|
type = nlh->nlmsg_type;
|
|
|
|
if (type == NFNL_MSG_BATCH_BEGIN) {
|
|
|
|
/* Malformed: Batch begin twice */
|
2014-09-03 00:04:53 +08:00
|
|
|
nfnl_err_reset(&err_list);
|
2015-07-01 22:14:25 +08:00
|
|
|
status |= NFNL_BATCH_FAILURE;
|
netfilter: nfnetlink: add batch support and use it from nf_tables
This patch adds a batch support to nfnetlink. Basically, it adds
two new control messages:
* NFNL_MSG_BATCH_BEGIN, that indicates the beginning of a batch,
the nfgenmsg->res_id indicates the nfnetlink subsystem ID.
* NFNL_MSG_BATCH_END, that results in the invocation of the
ss->commit callback function. If not specified or an error
ocurred in the batch, the ss->abort function is invoked
instead.
The end message represents the commit operation in nftables, the
lack of end message results in an abort. This patch also adds the
.call_batch function that is only called from the batch receival
path.
This patch adds atomic rule updates and dumps based on
bitmask generations. This allows to atomically commit a set of
rule-set updates incrementally without altering the internal
state of existing nf_tables expressions/matches/targets.
The idea consists of using a generation cursor of 1 bit and
a bitmask of 2 bits per rule. Assuming the gencursor is 0,
then the genmask (expressed as a bitmask) can be interpreted
as:
00 active in the present, will be active in the next generation.
01 inactive in the present, will be active in the next generation.
10 active in the present, will be deleted in the next generation.
^
gencursor
Once you invoke the transition to the next generation, the global
gencursor is updated:
00 active in the present, will be active in the next generation.
01 active in the present, needs to zero its future, it becomes 00.
10 inactive in the present, delete now.
^
gencursor
If a dump is in progress and nf_tables enters a new generation,
the dump will stop and return -EBUSY to let userspace know that
it has to retry again. In order to invalidate dumps, a global
genctr counter is increased everytime nf_tables enters a new
generation.
This new operation can be used from the user-space utility
that controls the firewall, eg.
nft -f restore
The rule updates contained in `file' will be applied atomically.
cat file
-----
add filter INPUT ip saddr 1.1.1.1 counter accept #1
del filter INPUT ip daddr 2.2.2.2 counter drop #2
-EOF-
Note that the rule 1 will be inactive until the transition to the
next generation, the rule 2 will be evicted in the next generation.
There is a penalty during the rule update due to the branch
misprediction in the packet matching framework. But that should be
quickly resolved once the iteration over the commit list that
contain rules that require updates is finished.
Event notification happens once the rule-set update has been
committed. So we skip notifications is case the rule-set update
is aborted, which can happen in case that the rule-set is tested
to apply correctly.
This patch squashed the following patches from Pablo:
* nf_tables: atomic rule updates and dumps
* nf_tables: get rid of per rule list_head for commits
* nf_tables: use per netns commit list
* nfnetlink: add batch support and use it from nf_tables
* nf_tables: all rule updates are transactional
* nf_tables: attach replacement rule after stale one
* nf_tables: do not allow deletion/replacement of stale rules
* nf_tables: remove unused NFTA_RULE_FLAGS
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
2013-10-14 17:05:33 +08:00
|
|
|
goto done;
|
|
|
|
} else if (type == NFNL_MSG_BATCH_END) {
|
2015-07-01 22:14:25 +08:00
|
|
|
status |= NFNL_BATCH_DONE;
|
netfilter: nfnetlink: add batch support and use it from nf_tables
This patch adds a batch support to nfnetlink. Basically, it adds
two new control messages:
* NFNL_MSG_BATCH_BEGIN, that indicates the beginning of a batch,
the nfgenmsg->res_id indicates the nfnetlink subsystem ID.
* NFNL_MSG_BATCH_END, that results in the invocation of the
ss->commit callback function. If not specified or an error
ocurred in the batch, the ss->abort function is invoked
instead.
The end message represents the commit operation in nftables, the
lack of end message results in an abort. This patch also adds the
.call_batch function that is only called from the batch receival
path.
This patch adds atomic rule updates and dumps based on
bitmask generations. This allows to atomically commit a set of
rule-set updates incrementally without altering the internal
state of existing nf_tables expressions/matches/targets.
The idea consists of using a generation cursor of 1 bit and
a bitmask of 2 bits per rule. Assuming the gencursor is 0,
then the genmask (expressed as a bitmask) can be interpreted
as:
00 active in the present, will be active in the next generation.
01 inactive in the present, will be active in the next generation.
10 active in the present, will be deleted in the next generation.
^
gencursor
Once you invoke the transition to the next generation, the global
gencursor is updated:
00 active in the present, will be active in the next generation.
01 active in the present, needs to zero its future, it becomes 00.
10 inactive in the present, delete now.
^
gencursor
If a dump is in progress and nf_tables enters a new generation,
the dump will stop and return -EBUSY to let userspace know that
it has to retry again. In order to invalidate dumps, a global
genctr counter is increased everytime nf_tables enters a new
generation.
This new operation can be used from the user-space utility
that controls the firewall, eg.
nft -f restore
The rule updates contained in `file' will be applied atomically.
cat file
-----
add filter INPUT ip saddr 1.1.1.1 counter accept #1
del filter INPUT ip daddr 2.2.2.2 counter drop #2
-EOF-
Note that the rule 1 will be inactive until the transition to the
next generation, the rule 2 will be evicted in the next generation.
There is a penalty during the rule update due to the branch
misprediction in the packet matching framework. But that should be
quickly resolved once the iteration over the commit list that
contain rules that require updates is finished.
Event notification happens once the rule-set update has been
committed. So we skip notifications is case the rule-set update
is aborted, which can happen in case that the rule-set is tested
to apply correctly.
This patch squashed the following patches from Pablo:
* nf_tables: atomic rule updates and dumps
* nf_tables: get rid of per rule list_head for commits
* nf_tables: use per netns commit list
* nfnetlink: add batch support and use it from nf_tables
* nf_tables: all rule updates are transactional
* nf_tables: attach replacement rule after stale one
* nf_tables: do not allow deletion/replacement of stale rules
* nf_tables: remove unused NFTA_RULE_FLAGS
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
2013-10-14 17:05:33 +08:00
|
|
|
goto done;
|
|
|
|
} else if (type < NLMSG_MIN_TYPE) {
|
|
|
|
err = -EINVAL;
|
|
|
|
goto ack;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* We only accept a batch with messages for the same
|
|
|
|
* subsystem.
|
|
|
|
*/
|
|
|
|
if (NFNL_SUBSYS_ID(type) != subsys_id) {
|
|
|
|
err = -EINVAL;
|
|
|
|
goto ack;
|
|
|
|
}
|
|
|
|
|
|
|
|
nc = nfnetlink_find_client(type, ss);
|
|
|
|
if (!nc) {
|
|
|
|
err = -EINVAL;
|
|
|
|
goto ack;
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
int min_len = nlmsg_total_size(sizeof(struct nfgenmsg));
|
2017-02-10 19:08:08 +08:00
|
|
|
u8 cb_id = NFNL_MSG_TYPE(nlh->nlmsg_type);
|
2018-05-31 03:17:56 +08:00
|
|
|
struct nlattr *cda[NFNL_MAX_ATTR_COUNT + 1];
|
netfilter: nfnetlink: add batch support and use it from nf_tables
This patch adds a batch support to nfnetlink. Basically, it adds
two new control messages:
* NFNL_MSG_BATCH_BEGIN, that indicates the beginning of a batch,
the nfgenmsg->res_id indicates the nfnetlink subsystem ID.
* NFNL_MSG_BATCH_END, that results in the invocation of the
ss->commit callback function. If not specified or an error
ocurred in the batch, the ss->abort function is invoked
instead.
The end message represents the commit operation in nftables, the
lack of end message results in an abort. This patch also adds the
.call_batch function that is only called from the batch receival
path.
This patch adds atomic rule updates and dumps based on
bitmask generations. This allows to atomically commit a set of
rule-set updates incrementally without altering the internal
state of existing nf_tables expressions/matches/targets.
The idea consists of using a generation cursor of 1 bit and
a bitmask of 2 bits per rule. Assuming the gencursor is 0,
then the genmask (expressed as a bitmask) can be interpreted
as:
00 active in the present, will be active in the next generation.
01 inactive in the present, will be active in the next generation.
10 active in the present, will be deleted in the next generation.
^
gencursor
Once you invoke the transition to the next generation, the global
gencursor is updated:
00 active in the present, will be active in the next generation.
01 active in the present, needs to zero its future, it becomes 00.
10 inactive in the present, delete now.
^
gencursor
If a dump is in progress and nf_tables enters a new generation,
the dump will stop and return -EBUSY to let userspace know that
it has to retry again. In order to invalidate dumps, a global
genctr counter is increased everytime nf_tables enters a new
generation.
This new operation can be used from the user-space utility
that controls the firewall, eg.
nft -f restore
The rule updates contained in `file' will be applied atomically.
cat file
-----
add filter INPUT ip saddr 1.1.1.1 counter accept #1
del filter INPUT ip daddr 2.2.2.2 counter drop #2
-EOF-
Note that the rule 1 will be inactive until the transition to the
next generation, the rule 2 will be evicted in the next generation.
There is a penalty during the rule update due to the branch
misprediction in the packet matching framework. But that should be
quickly resolved once the iteration over the commit list that
contain rules that require updates is finished.
Event notification happens once the rule-set update has been
committed. So we skip notifications is case the rule-set update
is aborted, which can happen in case that the rule-set is tested
to apply correctly.
This patch squashed the following patches from Pablo:
* nf_tables: atomic rule updates and dumps
* nf_tables: get rid of per rule list_head for commits
* nf_tables: use per netns commit list
* nfnetlink: add batch support and use it from nf_tables
* nf_tables: all rule updates are transactional
* nf_tables: attach replacement rule after stale one
* nf_tables: do not allow deletion/replacement of stale rules
* nf_tables: remove unused NFTA_RULE_FLAGS
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
2013-10-14 17:05:33 +08:00
|
|
|
struct nlattr *attr = (void *)nlh + min_len;
|
|
|
|
int attrlen = nlh->nlmsg_len - min_len;
|
|
|
|
|
2018-05-31 03:17:56 +08:00
|
|
|
/* Sanity-check NFTA_MAX_ATTR */
|
|
|
|
if (ss->cb[cb_id].attr_count > NFNL_MAX_ATTR_COUNT) {
|
|
|
|
err = -ENOMEM;
|
|
|
|
goto ack;
|
|
|
|
}
|
|
|
|
|
netlink: make validation more configurable for future strictness
We currently have two levels of strict validation:
1) liberal (default)
- undefined (type >= max) & NLA_UNSPEC attributes accepted
- attribute length >= expected accepted
- garbage at end of message accepted
2) strict (opt-in)
- NLA_UNSPEC attributes accepted
- attribute length >= expected accepted
Split out parsing strictness into four different options:
* TRAILING - check that there's no trailing data after parsing
attributes (in message or nested)
* MAXTYPE - reject attrs > max known type
* UNSPEC - reject attributes with NLA_UNSPEC policy entries
* STRICT_ATTRS - strictly validate attribute size
The default for future things should be *everything*.
The current *_strict() is a combination of TRAILING and MAXTYPE,
and is renamed to _deprecated_strict().
The current regular parsing has none of this, and is renamed to
*_parse_deprecated().
Additionally it allows us to selectively set one of the new flags
even on old policies. Notably, the UNSPEC flag could be useful in
this case, since it can be arranged (by filling in the policy) to
not be an incompatible userspace ABI change, but would then going
forward prevent forgetting attribute entries. Similar can apply
to the POLICY flag.
We end up with the following renames:
* nla_parse -> nla_parse_deprecated
* nla_parse_strict -> nla_parse_deprecated_strict
* nlmsg_parse -> nlmsg_parse_deprecated
* nlmsg_parse_strict -> nlmsg_parse_deprecated_strict
* nla_parse_nested -> nla_parse_nested_deprecated
* nla_validate_nested -> nla_validate_nested_deprecated
Using spatch, of course:
@@
expression TB, MAX, HEAD, LEN, POL, EXT;
@@
-nla_parse(TB, MAX, HEAD, LEN, POL, EXT)
+nla_parse_deprecated(TB, MAX, HEAD, LEN, POL, EXT)
@@
expression NLH, HDRLEN, TB, MAX, POL, EXT;
@@
-nlmsg_parse(NLH, HDRLEN, TB, MAX, POL, EXT)
+nlmsg_parse_deprecated(NLH, HDRLEN, TB, MAX, POL, EXT)
@@
expression NLH, HDRLEN, TB, MAX, POL, EXT;
@@
-nlmsg_parse_strict(NLH, HDRLEN, TB, MAX, POL, EXT)
+nlmsg_parse_deprecated_strict(NLH, HDRLEN, TB, MAX, POL, EXT)
@@
expression TB, MAX, NLA, POL, EXT;
@@
-nla_parse_nested(TB, MAX, NLA, POL, EXT)
+nla_parse_nested_deprecated(TB, MAX, NLA, POL, EXT)
@@
expression START, MAX, POL, EXT;
@@
-nla_validate_nested(START, MAX, POL, EXT)
+nla_validate_nested_deprecated(START, MAX, POL, EXT)
@@
expression NLH, HDRLEN, MAX, POL, EXT;
@@
-nlmsg_validate(NLH, HDRLEN, MAX, POL, EXT)
+nlmsg_validate_deprecated(NLH, HDRLEN, MAX, POL, EXT)
For this patch, don't actually add the strict, non-renamed versions
yet so that it breaks compile if I get it wrong.
Also, while at it, make nla_validate and nla_parse go down to a
common __nla_validate_parse() function to avoid code duplication.
Ultimately, this allows us to have very strict validation for every
new caller of nla_parse()/nlmsg_parse() etc as re-introduced in the
next patch, while existing things will continue to work as is.
In effect then, this adds fully strict validation for any new command.
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2019-04-26 20:07:28 +08:00
|
|
|
err = nla_parse_deprecated(cda,
|
|
|
|
ss->cb[cb_id].attr_count,
|
|
|
|
attr, attrlen,
|
|
|
|
ss->cb[cb_id].policy, NULL);
|
netfilter: nfnetlink: add batch support and use it from nf_tables
This patch adds a batch support to nfnetlink. Basically, it adds
two new control messages:
* NFNL_MSG_BATCH_BEGIN, that indicates the beginning of a batch,
the nfgenmsg->res_id indicates the nfnetlink subsystem ID.
* NFNL_MSG_BATCH_END, that results in the invocation of the
ss->commit callback function. If not specified or an error
ocurred in the batch, the ss->abort function is invoked
instead.
The end message represents the commit operation in nftables, the
lack of end message results in an abort. This patch also adds the
.call_batch function that is only called from the batch receival
path.
This patch adds atomic rule updates and dumps based on
bitmask generations. This allows to atomically commit a set of
rule-set updates incrementally without altering the internal
state of existing nf_tables expressions/matches/targets.
The idea consists of using a generation cursor of 1 bit and
a bitmask of 2 bits per rule. Assuming the gencursor is 0,
then the genmask (expressed as a bitmask) can be interpreted
as:
00 active in the present, will be active in the next generation.
01 inactive in the present, will be active in the next generation.
10 active in the present, will be deleted in the next generation.
^
gencursor
Once you invoke the transition to the next generation, the global
gencursor is updated:
00 active in the present, will be active in the next generation.
01 active in the present, needs to zero its future, it becomes 00.
10 inactive in the present, delete now.
^
gencursor
If a dump is in progress and nf_tables enters a new generation,
the dump will stop and return -EBUSY to let userspace know that
it has to retry again. In order to invalidate dumps, a global
genctr counter is increased everytime nf_tables enters a new
generation.
This new operation can be used from the user-space utility
that controls the firewall, eg.
nft -f restore
The rule updates contained in `file' will be applied atomically.
cat file
-----
add filter INPUT ip saddr 1.1.1.1 counter accept #1
del filter INPUT ip daddr 2.2.2.2 counter drop #2
-EOF-
Note that the rule 1 will be inactive until the transition to the
next generation, the rule 2 will be evicted in the next generation.
There is a penalty during the rule update due to the branch
misprediction in the packet matching framework. But that should be
quickly resolved once the iteration over the commit list that
contain rules that require updates is finished.
Event notification happens once the rule-set update has been
committed. So we skip notifications is case the rule-set update
is aborted, which can happen in case that the rule-set is tested
to apply correctly.
This patch squashed the following patches from Pablo:
* nf_tables: atomic rule updates and dumps
* nf_tables: get rid of per rule list_head for commits
* nf_tables: use per netns commit list
* nfnetlink: add batch support and use it from nf_tables
* nf_tables: all rule updates are transactional
* nf_tables: attach replacement rule after stale one
* nf_tables: do not allow deletion/replacement of stale rules
* nf_tables: remove unused NFTA_RULE_FLAGS
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
2013-10-14 17:05:33 +08:00
|
|
|
if (err < 0)
|
|
|
|
goto ack;
|
|
|
|
|
|
|
|
if (nc->call_batch) {
|
2015-12-09 19:08:26 +08:00
|
|
|
err = nc->call_batch(net, net->nfnl, skb, nlh,
|
2017-06-20 01:35:46 +08:00
|
|
|
(const struct nlattr **)cda,
|
|
|
|
&extack);
|
netfilter: nfnetlink: add batch support and use it from nf_tables
This patch adds a batch support to nfnetlink. Basically, it adds
two new control messages:
* NFNL_MSG_BATCH_BEGIN, that indicates the beginning of a batch,
the nfgenmsg->res_id indicates the nfnetlink subsystem ID.
* NFNL_MSG_BATCH_END, that results in the invocation of the
ss->commit callback function. If not specified or an error
ocurred in the batch, the ss->abort function is invoked
instead.
The end message represents the commit operation in nftables, the
lack of end message results in an abort. This patch also adds the
.call_batch function that is only called from the batch receival
path.
This patch adds atomic rule updates and dumps based on
bitmask generations. This allows to atomically commit a set of
rule-set updates incrementally without altering the internal
state of existing nf_tables expressions/matches/targets.
The idea consists of using a generation cursor of 1 bit and
a bitmask of 2 bits per rule. Assuming the gencursor is 0,
then the genmask (expressed as a bitmask) can be interpreted
as:
00 active in the present, will be active in the next generation.
01 inactive in the present, will be active in the next generation.
10 active in the present, will be deleted in the next generation.
^
gencursor
Once you invoke the transition to the next generation, the global
gencursor is updated:
00 active in the present, will be active in the next generation.
01 active in the present, needs to zero its future, it becomes 00.
10 inactive in the present, delete now.
^
gencursor
If a dump is in progress and nf_tables enters a new generation,
the dump will stop and return -EBUSY to let userspace know that
it has to retry again. In order to invalidate dumps, a global
genctr counter is increased everytime nf_tables enters a new
generation.
This new operation can be used from the user-space utility
that controls the firewall, eg.
nft -f restore
The rule updates contained in `file' will be applied atomically.
cat file
-----
add filter INPUT ip saddr 1.1.1.1 counter accept #1
del filter INPUT ip daddr 2.2.2.2 counter drop #2
-EOF-
Note that the rule 1 will be inactive until the transition to the
next generation, the rule 2 will be evicted in the next generation.
There is a penalty during the rule update due to the branch
misprediction in the packet matching framework. But that should be
quickly resolved once the iteration over the commit list that
contain rules that require updates is finished.
Event notification happens once the rule-set update has been
committed. So we skip notifications is case the rule-set update
is aborted, which can happen in case that the rule-set is tested
to apply correctly.
This patch squashed the following patches from Pablo:
* nf_tables: atomic rule updates and dumps
* nf_tables: get rid of per rule list_head for commits
* nf_tables: use per netns commit list
* nfnetlink: add batch support and use it from nf_tables
* nf_tables: all rule updates are transactional
* nf_tables: attach replacement rule after stale one
* nf_tables: do not allow deletion/replacement of stale rules
* nf_tables: remove unused NFTA_RULE_FLAGS
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
2013-10-14 17:05:33 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/* The lock was released to autoload some module, we
|
|
|
|
* have to abort and start from scratch using the
|
|
|
|
* original skb.
|
|
|
|
*/
|
|
|
|
if (err == -EAGAIN) {
|
2015-07-01 22:14:25 +08:00
|
|
|
status |= NFNL_BATCH_REPLAY;
|
2018-06-11 19:20:35 +08:00
|
|
|
goto done;
|
netfilter: nfnetlink: add batch support and use it from nf_tables
This patch adds a batch support to nfnetlink. Basically, it adds
two new control messages:
* NFNL_MSG_BATCH_BEGIN, that indicates the beginning of a batch,
the nfgenmsg->res_id indicates the nfnetlink subsystem ID.
* NFNL_MSG_BATCH_END, that results in the invocation of the
ss->commit callback function. If not specified or an error
ocurred in the batch, the ss->abort function is invoked
instead.
The end message represents the commit operation in nftables, the
lack of end message results in an abort. This patch also adds the
.call_batch function that is only called from the batch receival
path.
This patch adds atomic rule updates and dumps based on
bitmask generations. This allows to atomically commit a set of
rule-set updates incrementally without altering the internal
state of existing nf_tables expressions/matches/targets.
The idea consists of using a generation cursor of 1 bit and
a bitmask of 2 bits per rule. Assuming the gencursor is 0,
then the genmask (expressed as a bitmask) can be interpreted
as:
00 active in the present, will be active in the next generation.
01 inactive in the present, will be active in the next generation.
10 active in the present, will be deleted in the next generation.
^
gencursor
Once you invoke the transition to the next generation, the global
gencursor is updated:
00 active in the present, will be active in the next generation.
01 active in the present, needs to zero its future, it becomes 00.
10 inactive in the present, delete now.
^
gencursor
If a dump is in progress and nf_tables enters a new generation,
the dump will stop and return -EBUSY to let userspace know that
it has to retry again. In order to invalidate dumps, a global
genctr counter is increased everytime nf_tables enters a new
generation.
This new operation can be used from the user-space utility
that controls the firewall, eg.
nft -f restore
The rule updates contained in `file' will be applied atomically.
cat file
-----
add filter INPUT ip saddr 1.1.1.1 counter accept #1
del filter INPUT ip daddr 2.2.2.2 counter drop #2
-EOF-
Note that the rule 1 will be inactive until the transition to the
next generation, the rule 2 will be evicted in the next generation.
There is a penalty during the rule update due to the branch
misprediction in the packet matching framework. But that should be
quickly resolved once the iteration over the commit list that
contain rules that require updates is finished.
Event notification happens once the rule-set update has been
committed. So we skip notifications is case the rule-set update
is aborted, which can happen in case that the rule-set is tested
to apply correctly.
This patch squashed the following patches from Pablo:
* nf_tables: atomic rule updates and dumps
* nf_tables: get rid of per rule list_head for commits
* nf_tables: use per netns commit list
* nfnetlink: add batch support and use it from nf_tables
* nf_tables: all rule updates are transactional
* nf_tables: attach replacement rule after stale one
* nf_tables: do not allow deletion/replacement of stale rules
* nf_tables: remove unused NFTA_RULE_FLAGS
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
2013-10-14 17:05:33 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
ack:
|
|
|
|
if (nlh->nlmsg_flags & NLM_F_ACK || err) {
|
2014-09-03 00:04:53 +08:00
|
|
|
/* Errors are delivered once the full batch has been
|
|
|
|
* processed, this avoids that the same error is
|
|
|
|
* reported several times when replaying the batch.
|
|
|
|
*/
|
2017-06-20 01:35:46 +08:00
|
|
|
if (nfnl_err_add(&err_list, nlh, err, &extack) < 0) {
|
2014-09-03 00:04:53 +08:00
|
|
|
/* We failed to enqueue an error, reset the
|
|
|
|
* list of errors and send OOM to userspace
|
|
|
|
* pointing to the batch header.
|
|
|
|
*/
|
|
|
|
nfnl_err_reset(&err_list);
|
2017-04-12 20:34:04 +08:00
|
|
|
netlink_ack(oskb, nlmsg_hdr(oskb), -ENOMEM,
|
|
|
|
NULL);
|
2015-07-01 22:14:25 +08:00
|
|
|
status |= NFNL_BATCH_FAILURE;
|
2014-09-03 00:04:53 +08:00
|
|
|
goto done;
|
|
|
|
}
|
netfilter: nfnetlink: add batch support and use it from nf_tables
This patch adds a batch support to nfnetlink. Basically, it adds
two new control messages:
* NFNL_MSG_BATCH_BEGIN, that indicates the beginning of a batch,
the nfgenmsg->res_id indicates the nfnetlink subsystem ID.
* NFNL_MSG_BATCH_END, that results in the invocation of the
ss->commit callback function. If not specified or an error
ocurred in the batch, the ss->abort function is invoked
instead.
The end message represents the commit operation in nftables, the
lack of end message results in an abort. This patch also adds the
.call_batch function that is only called from the batch receival
path.
This patch adds atomic rule updates and dumps based on
bitmask generations. This allows to atomically commit a set of
rule-set updates incrementally without altering the internal
state of existing nf_tables expressions/matches/targets.
The idea consists of using a generation cursor of 1 bit and
a bitmask of 2 bits per rule. Assuming the gencursor is 0,
then the genmask (expressed as a bitmask) can be interpreted
as:
00 active in the present, will be active in the next generation.
01 inactive in the present, will be active in the next generation.
10 active in the present, will be deleted in the next generation.
^
gencursor
Once you invoke the transition to the next generation, the global
gencursor is updated:
00 active in the present, will be active in the next generation.
01 active in the present, needs to zero its future, it becomes 00.
10 inactive in the present, delete now.
^
gencursor
If a dump is in progress and nf_tables enters a new generation,
the dump will stop and return -EBUSY to let userspace know that
it has to retry again. In order to invalidate dumps, a global
genctr counter is increased everytime nf_tables enters a new
generation.
This new operation can be used from the user-space utility
that controls the firewall, eg.
nft -f restore
The rule updates contained in `file' will be applied atomically.
cat file
-----
add filter INPUT ip saddr 1.1.1.1 counter accept #1
del filter INPUT ip daddr 2.2.2.2 counter drop #2
-EOF-
Note that the rule 1 will be inactive until the transition to the
next generation, the rule 2 will be evicted in the next generation.
There is a penalty during the rule update due to the branch
misprediction in the packet matching framework. But that should be
quickly resolved once the iteration over the commit list that
contain rules that require updates is finished.
Event notification happens once the rule-set update has been
committed. So we skip notifications is case the rule-set update
is aborted, which can happen in case that the rule-set is tested
to apply correctly.
This patch squashed the following patches from Pablo:
* nf_tables: atomic rule updates and dumps
* nf_tables: get rid of per rule list_head for commits
* nf_tables: use per netns commit list
* nfnetlink: add batch support and use it from nf_tables
* nf_tables: all rule updates are transactional
* nf_tables: attach replacement rule after stale one
* nf_tables: do not allow deletion/replacement of stale rules
* nf_tables: remove unused NFTA_RULE_FLAGS
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
2013-10-14 17:05:33 +08:00
|
|
|
/* We don't stop processing the batch on errors, thus,
|
|
|
|
* userspace gets all the errors that the batch
|
|
|
|
* triggers.
|
|
|
|
*/
|
|
|
|
if (err)
|
2015-07-01 22:14:25 +08:00
|
|
|
status |= NFNL_BATCH_FAILURE;
|
netfilter: nfnetlink: add batch support and use it from nf_tables
This patch adds a batch support to nfnetlink. Basically, it adds
two new control messages:
* NFNL_MSG_BATCH_BEGIN, that indicates the beginning of a batch,
the nfgenmsg->res_id indicates the nfnetlink subsystem ID.
* NFNL_MSG_BATCH_END, that results in the invocation of the
ss->commit callback function. If not specified or an error
ocurred in the batch, the ss->abort function is invoked
instead.
The end message represents the commit operation in nftables, the
lack of end message results in an abort. This patch also adds the
.call_batch function that is only called from the batch receival
path.
This patch adds atomic rule updates and dumps based on
bitmask generations. This allows to atomically commit a set of
rule-set updates incrementally without altering the internal
state of existing nf_tables expressions/matches/targets.
The idea consists of using a generation cursor of 1 bit and
a bitmask of 2 bits per rule. Assuming the gencursor is 0,
then the genmask (expressed as a bitmask) can be interpreted
as:
00 active in the present, will be active in the next generation.
01 inactive in the present, will be active in the next generation.
10 active in the present, will be deleted in the next generation.
^
gencursor
Once you invoke the transition to the next generation, the global
gencursor is updated:
00 active in the present, will be active in the next generation.
01 active in the present, needs to zero its future, it becomes 00.
10 inactive in the present, delete now.
^
gencursor
If a dump is in progress and nf_tables enters a new generation,
the dump will stop and return -EBUSY to let userspace know that
it has to retry again. In order to invalidate dumps, a global
genctr counter is increased everytime nf_tables enters a new
generation.
This new operation can be used from the user-space utility
that controls the firewall, eg.
nft -f restore
The rule updates contained in `file' will be applied atomically.
cat file
-----
add filter INPUT ip saddr 1.1.1.1 counter accept #1
del filter INPUT ip daddr 2.2.2.2 counter drop #2
-EOF-
Note that the rule 1 will be inactive until the transition to the
next generation, the rule 2 will be evicted in the next generation.
There is a penalty during the rule update due to the branch
misprediction in the packet matching framework. But that should be
quickly resolved once the iteration over the commit list that
contain rules that require updates is finished.
Event notification happens once the rule-set update has been
committed. So we skip notifications is case the rule-set update
is aborted, which can happen in case that the rule-set is tested
to apply correctly.
This patch squashed the following patches from Pablo:
* nf_tables: atomic rule updates and dumps
* nf_tables: get rid of per rule list_head for commits
* nf_tables: use per netns commit list
* nfnetlink: add batch support and use it from nf_tables
* nf_tables: all rule updates are transactional
* nf_tables: attach replacement rule after stale one
* nf_tables: do not allow deletion/replacement of stale rules
* nf_tables: remove unused NFTA_RULE_FLAGS
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
2013-10-14 17:05:33 +08:00
|
|
|
}
|
2018-06-11 19:20:35 +08:00
|
|
|
|
netfilter: nfnetlink: add batch support and use it from nf_tables
This patch adds a batch support to nfnetlink. Basically, it adds
two new control messages:
* NFNL_MSG_BATCH_BEGIN, that indicates the beginning of a batch,
the nfgenmsg->res_id indicates the nfnetlink subsystem ID.
* NFNL_MSG_BATCH_END, that results in the invocation of the
ss->commit callback function. If not specified or an error
ocurred in the batch, the ss->abort function is invoked
instead.
The end message represents the commit operation in nftables, the
lack of end message results in an abort. This patch also adds the
.call_batch function that is only called from the batch receival
path.
This patch adds atomic rule updates and dumps based on
bitmask generations. This allows to atomically commit a set of
rule-set updates incrementally without altering the internal
state of existing nf_tables expressions/matches/targets.
The idea consists of using a generation cursor of 1 bit and
a bitmask of 2 bits per rule. Assuming the gencursor is 0,
then the genmask (expressed as a bitmask) can be interpreted
as:
00 active in the present, will be active in the next generation.
01 inactive in the present, will be active in the next generation.
10 active in the present, will be deleted in the next generation.
^
gencursor
Once you invoke the transition to the next generation, the global
gencursor is updated:
00 active in the present, will be active in the next generation.
01 active in the present, needs to zero its future, it becomes 00.
10 inactive in the present, delete now.
^
gencursor
If a dump is in progress and nf_tables enters a new generation,
the dump will stop and return -EBUSY to let userspace know that
it has to retry again. In order to invalidate dumps, a global
genctr counter is increased everytime nf_tables enters a new
generation.
This new operation can be used from the user-space utility
that controls the firewall, eg.
nft -f restore
The rule updates contained in `file' will be applied atomically.
cat file
-----
add filter INPUT ip saddr 1.1.1.1 counter accept #1
del filter INPUT ip daddr 2.2.2.2 counter drop #2
-EOF-
Note that the rule 1 will be inactive until the transition to the
next generation, the rule 2 will be evicted in the next generation.
There is a penalty during the rule update due to the branch
misprediction in the packet matching framework. But that should be
quickly resolved once the iteration over the commit list that
contain rules that require updates is finished.
Event notification happens once the rule-set update has been
committed. So we skip notifications is case the rule-set update
is aborted, which can happen in case that the rule-set is tested
to apply correctly.
This patch squashed the following patches from Pablo:
* nf_tables: atomic rule updates and dumps
* nf_tables: get rid of per rule list_head for commits
* nf_tables: use per netns commit list
* nfnetlink: add batch support and use it from nf_tables
* nf_tables: all rule updates are transactional
* nf_tables: attach replacement rule after stale one
* nf_tables: do not allow deletion/replacement of stale rules
* nf_tables: remove unused NFTA_RULE_FLAGS
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
2013-10-14 17:05:33 +08:00
|
|
|
msglen = NLMSG_ALIGN(nlh->nlmsg_len);
|
|
|
|
if (msglen > skb->len)
|
|
|
|
msglen = skb->len;
|
|
|
|
skb_pull(skb, msglen);
|
|
|
|
}
|
|
|
|
done:
|
2015-07-01 22:14:25 +08:00
|
|
|
if (status & NFNL_BATCH_REPLAY) {
|
netfilter: nf_tables: autoload modules from the abort path
This patch introduces a list of pending module requests. This new module
list is composed of nft_module_request objects that contain the module
name and one status field that tells if the module has been already
loaded (the 'done' field).
In the first pass, from the preparation phase, the netlink command finds
that a module is missing on this list. Then, a module request is
allocated and added to this list and nft_request_module() returns
-EAGAIN. This triggers the abort path with the autoload parameter set on
from nfnetlink, request_module() is called and the module request enters
the 'done' state. Since the mutex is released when loading modules from
the abort phase, the module list is zapped so this is iteration occurs
over a local list. Therefore, the request_module() calls happen when
object lists are in consistent state (after fulling aborting the
transaction) and the commit list is empty.
On the second pass, the netlink command will find that it already tried
to load the module, so it does not request it again and
nft_request_module() returns 0. Then, there is a look up to find the
object that the command was missing. If the module was successfully
loaded, the command proceeds normally since it finds the missing object
in place, otherwise -ENOENT is reported to userspace.
This patch also updates nfnetlink to include the reason to enter the
abort phase, which is required for this new autoload module rationale.
Fixes: ec7470b834fe ("netfilter: nf_tables: store transaction list locally while requesting module")
Reported-by: syzbot+29125d208b3dae9a7019@syzkaller.appspotmail.com
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
2020-01-21 23:48:03 +08:00
|
|
|
ss->abort(net, oskb, true);
|
2015-07-01 22:14:25 +08:00
|
|
|
nfnl_err_reset(&err_list);
|
|
|
|
kfree_skb(skb);
|
2018-07-11 19:45:12 +08:00
|
|
|
module_put(ss->owner);
|
2015-07-01 22:14:25 +08:00
|
|
|
goto replay;
|
|
|
|
} else if (status == NFNL_BATCH_DONE) {
|
2018-05-25 06:25:47 +08:00
|
|
|
err = ss->commit(net, oskb);
|
|
|
|
if (err == -EAGAIN) {
|
|
|
|
status |= NFNL_BATCH_REPLAY;
|
|
|
|
goto done;
|
|
|
|
} else if (err) {
|
netfilter: nf_tables: autoload modules from the abort path
This patch introduces a list of pending module requests. This new module
list is composed of nft_module_request objects that contain the module
name and one status field that tells if the module has been already
loaded (the 'done' field).
In the first pass, from the preparation phase, the netlink command finds
that a module is missing on this list. Then, a module request is
allocated and added to this list and nft_request_module() returns
-EAGAIN. This triggers the abort path with the autoload parameter set on
from nfnetlink, request_module() is called and the module request enters
the 'done' state. Since the mutex is released when loading modules from
the abort phase, the module list is zapped so this is iteration occurs
over a local list. Therefore, the request_module() calls happen when
object lists are in consistent state (after fulling aborting the
transaction) and the commit list is empty.
On the second pass, the netlink command will find that it already tried
to load the module, so it does not request it again and
nft_request_module() returns 0. Then, there is a look up to find the
object that the command was missing. If the module was successfully
loaded, the command proceeds normally since it finds the missing object
in place, otherwise -ENOENT is reported to userspace.
This patch also updates nfnetlink to include the reason to enter the
abort phase, which is required for this new autoload module rationale.
Fixes: ec7470b834fe ("netfilter: nf_tables: store transaction list locally while requesting module")
Reported-by: syzbot+29125d208b3dae9a7019@syzkaller.appspotmail.com
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
2020-01-21 23:48:03 +08:00
|
|
|
ss->abort(net, oskb, false);
|
2018-05-25 06:25:47 +08:00
|
|
|
netlink_ack(oskb, nlmsg_hdr(oskb), err, NULL);
|
|
|
|
}
|
2015-07-01 22:14:25 +08:00
|
|
|
} else {
|
netfilter: nf_tables: autoload modules from the abort path
This patch introduces a list of pending module requests. This new module
list is composed of nft_module_request objects that contain the module
name and one status field that tells if the module has been already
loaded (the 'done' field).
In the first pass, from the preparation phase, the netlink command finds
that a module is missing on this list. Then, a module request is
allocated and added to this list and nft_request_module() returns
-EAGAIN. This triggers the abort path with the autoload parameter set on
from nfnetlink, request_module() is called and the module request enters
the 'done' state. Since the mutex is released when loading modules from
the abort phase, the module list is zapped so this is iteration occurs
over a local list. Therefore, the request_module() calls happen when
object lists are in consistent state (after fulling aborting the
transaction) and the commit list is empty.
On the second pass, the netlink command will find that it already tried
to load the module, so it does not request it again and
nft_request_module() returns 0. Then, there is a look up to find the
object that the command was missing. If the module was successfully
loaded, the command proceeds normally since it finds the missing object
in place, otherwise -ENOENT is reported to userspace.
This patch also updates nfnetlink to include the reason to enter the
abort phase, which is required for this new autoload module rationale.
Fixes: ec7470b834fe ("netfilter: nf_tables: store transaction list locally while requesting module")
Reported-by: syzbot+29125d208b3dae9a7019@syzkaller.appspotmail.com
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
2020-01-21 23:48:03 +08:00
|
|
|
ss->abort(net, oskb, false);
|
2015-07-01 22:14:25 +08:00
|
|
|
}
|
2018-05-31 02:18:57 +08:00
|
|
|
if (ss->cleanup)
|
|
|
|
ss->cleanup(net);
|
netfilter: nfnetlink: add batch support and use it from nf_tables
This patch adds a batch support to nfnetlink. Basically, it adds
two new control messages:
* NFNL_MSG_BATCH_BEGIN, that indicates the beginning of a batch,
the nfgenmsg->res_id indicates the nfnetlink subsystem ID.
* NFNL_MSG_BATCH_END, that results in the invocation of the
ss->commit callback function. If not specified or an error
ocurred in the batch, the ss->abort function is invoked
instead.
The end message represents the commit operation in nftables, the
lack of end message results in an abort. This patch also adds the
.call_batch function that is only called from the batch receival
path.
This patch adds atomic rule updates and dumps based on
bitmask generations. This allows to atomically commit a set of
rule-set updates incrementally without altering the internal
state of existing nf_tables expressions/matches/targets.
The idea consists of using a generation cursor of 1 bit and
a bitmask of 2 bits per rule. Assuming the gencursor is 0,
then the genmask (expressed as a bitmask) can be interpreted
as:
00 active in the present, will be active in the next generation.
01 inactive in the present, will be active in the next generation.
10 active in the present, will be deleted in the next generation.
^
gencursor
Once you invoke the transition to the next generation, the global
gencursor is updated:
00 active in the present, will be active in the next generation.
01 active in the present, needs to zero its future, it becomes 00.
10 inactive in the present, delete now.
^
gencursor
If a dump is in progress and nf_tables enters a new generation,
the dump will stop and return -EBUSY to let userspace know that
it has to retry again. In order to invalidate dumps, a global
genctr counter is increased everytime nf_tables enters a new
generation.
This new operation can be used from the user-space utility
that controls the firewall, eg.
nft -f restore
The rule updates contained in `file' will be applied atomically.
cat file
-----
add filter INPUT ip saddr 1.1.1.1 counter accept #1
del filter INPUT ip daddr 2.2.2.2 counter drop #2
-EOF-
Note that the rule 1 will be inactive until the transition to the
next generation, the rule 2 will be evicted in the next generation.
There is a penalty during the rule update due to the branch
misprediction in the packet matching framework. But that should be
quickly resolved once the iteration over the commit list that
contain rules that require updates is finished.
Event notification happens once the rule-set update has been
committed. So we skip notifications is case the rule-set update
is aborted, which can happen in case that the rule-set is tested
to apply correctly.
This patch squashed the following patches from Pablo:
* nf_tables: atomic rule updates and dumps
* nf_tables: get rid of per rule list_head for commits
* nf_tables: use per netns commit list
* nfnetlink: add batch support and use it from nf_tables
* nf_tables: all rule updates are transactional
* nf_tables: attach replacement rule after stale one
* nf_tables: do not allow deletion/replacement of stale rules
* nf_tables: remove unused NFTA_RULE_FLAGS
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
2013-10-14 17:05:33 +08:00
|
|
|
|
2014-09-03 00:04:53 +08:00
|
|
|
nfnl_err_deliver(&err_list, oskb);
|
2014-12-10 17:21:59 +08:00
|
|
|
kfree_skb(skb);
|
2018-07-11 19:45:12 +08:00
|
|
|
module_put(ss->owner);
|
netfilter: nfnetlink: add batch support and use it from nf_tables
This patch adds a batch support to nfnetlink. Basically, it adds
two new control messages:
* NFNL_MSG_BATCH_BEGIN, that indicates the beginning of a batch,
the nfgenmsg->res_id indicates the nfnetlink subsystem ID.
* NFNL_MSG_BATCH_END, that results in the invocation of the
ss->commit callback function. If not specified or an error
ocurred in the batch, the ss->abort function is invoked
instead.
The end message represents the commit operation in nftables, the
lack of end message results in an abort. This patch also adds the
.call_batch function that is only called from the batch receival
path.
This patch adds atomic rule updates and dumps based on
bitmask generations. This allows to atomically commit a set of
rule-set updates incrementally without altering the internal
state of existing nf_tables expressions/matches/targets.
The idea consists of using a generation cursor of 1 bit and
a bitmask of 2 bits per rule. Assuming the gencursor is 0,
then the genmask (expressed as a bitmask) can be interpreted
as:
00 active in the present, will be active in the next generation.
01 inactive in the present, will be active in the next generation.
10 active in the present, will be deleted in the next generation.
^
gencursor
Once you invoke the transition to the next generation, the global
gencursor is updated:
00 active in the present, will be active in the next generation.
01 active in the present, needs to zero its future, it becomes 00.
10 inactive in the present, delete now.
^
gencursor
If a dump is in progress and nf_tables enters a new generation,
the dump will stop and return -EBUSY to let userspace know that
it has to retry again. In order to invalidate dumps, a global
genctr counter is increased everytime nf_tables enters a new
generation.
This new operation can be used from the user-space utility
that controls the firewall, eg.
nft -f restore
The rule updates contained in `file' will be applied atomically.
cat file
-----
add filter INPUT ip saddr 1.1.1.1 counter accept #1
del filter INPUT ip daddr 2.2.2.2 counter drop #2
-EOF-
Note that the rule 1 will be inactive until the transition to the
next generation, the rule 2 will be evicted in the next generation.
There is a penalty during the rule update due to the branch
misprediction in the packet matching framework. But that should be
quickly resolved once the iteration over the commit list that
contain rules that require updates is finished.
Event notification happens once the rule-set update has been
committed. So we skip notifications is case the rule-set update
is aborted, which can happen in case that the rule-set is tested
to apply correctly.
This patch squashed the following patches from Pablo:
* nf_tables: atomic rule updates and dumps
* nf_tables: get rid of per rule list_head for commits
* nf_tables: use per netns commit list
* nfnetlink: add batch support and use it from nf_tables
* nf_tables: all rule updates are transactional
* nf_tables: attach replacement rule after stale one
* nf_tables: do not allow deletion/replacement of stale rules
* nf_tables: remove unused NFTA_RULE_FLAGS
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
2013-10-14 17:05:33 +08:00
|
|
|
}
|
|
|
|
|
2017-02-10 19:08:17 +08:00
|
|
|
static const struct nla_policy nfnl_batch_policy[NFNL_BATCH_MAX + 1] = {
|
|
|
|
[NFNL_BATCH_GENID] = { .type = NLA_U32 },
|
|
|
|
};
|
|
|
|
|
2017-02-10 19:08:14 +08:00
|
|
|
static void nfnetlink_rcv_skb_batch(struct sk_buff *skb, struct nlmsghdr *nlh)
|
2005-08-10 10:30:24 +08:00
|
|
|
{
|
2017-02-10 19:08:17 +08:00
|
|
|
int min_len = nlmsg_total_size(sizeof(struct nfgenmsg));
|
|
|
|
struct nlattr *attr = (void *)nlh + min_len;
|
|
|
|
struct nlattr *cda[NFNL_BATCH_MAX + 1];
|
|
|
|
int attrlen = nlh->nlmsg_len - min_len;
|
2017-02-10 19:08:14 +08:00
|
|
|
struct nfgenmsg *nfgenmsg;
|
2017-02-10 19:08:17 +08:00
|
|
|
int msglen, err;
|
|
|
|
u32 gen_id = 0;
|
2017-02-10 19:08:08 +08:00
|
|
|
u16 res_id;
|
netfilter: nfnetlink: add batch support and use it from nf_tables
This patch adds a batch support to nfnetlink. Basically, it adds
two new control messages:
* NFNL_MSG_BATCH_BEGIN, that indicates the beginning of a batch,
the nfgenmsg->res_id indicates the nfnetlink subsystem ID.
* NFNL_MSG_BATCH_END, that results in the invocation of the
ss->commit callback function. If not specified or an error
ocurred in the batch, the ss->abort function is invoked
instead.
The end message represents the commit operation in nftables, the
lack of end message results in an abort. This patch also adds the
.call_batch function that is only called from the batch receival
path.
This patch adds atomic rule updates and dumps based on
bitmask generations. This allows to atomically commit a set of
rule-set updates incrementally without altering the internal
state of existing nf_tables expressions/matches/targets.
The idea consists of using a generation cursor of 1 bit and
a bitmask of 2 bits per rule. Assuming the gencursor is 0,
then the genmask (expressed as a bitmask) can be interpreted
as:
00 active in the present, will be active in the next generation.
01 inactive in the present, will be active in the next generation.
10 active in the present, will be deleted in the next generation.
^
gencursor
Once you invoke the transition to the next generation, the global
gencursor is updated:
00 active in the present, will be active in the next generation.
01 active in the present, needs to zero its future, it becomes 00.
10 inactive in the present, delete now.
^
gencursor
If a dump is in progress and nf_tables enters a new generation,
the dump will stop and return -EBUSY to let userspace know that
it has to retry again. In order to invalidate dumps, a global
genctr counter is increased everytime nf_tables enters a new
generation.
This new operation can be used from the user-space utility
that controls the firewall, eg.
nft -f restore
The rule updates contained in `file' will be applied atomically.
cat file
-----
add filter INPUT ip saddr 1.1.1.1 counter accept #1
del filter INPUT ip daddr 2.2.2.2 counter drop #2
-EOF-
Note that the rule 1 will be inactive until the transition to the
next generation, the rule 2 will be evicted in the next generation.
There is a penalty during the rule update due to the branch
misprediction in the packet matching framework. But that should be
quickly resolved once the iteration over the commit list that
contain rules that require updates is finished.
Event notification happens once the rule-set update has been
committed. So we skip notifications is case the rule-set update
is aborted, which can happen in case that the rule-set is tested
to apply correctly.
This patch squashed the following patches from Pablo:
* nf_tables: atomic rule updates and dumps
* nf_tables: get rid of per rule list_head for commits
* nf_tables: use per netns commit list
* nfnetlink: add batch support and use it from nf_tables
* nf_tables: all rule updates are transactional
* nf_tables: attach replacement rule after stale one
* nf_tables: do not allow deletion/replacement of stale rules
* nf_tables: remove unused NFTA_RULE_FLAGS
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
2013-10-14 17:05:33 +08:00
|
|
|
|
2017-02-10 19:08:14 +08:00
|
|
|
msglen = NLMSG_ALIGN(nlh->nlmsg_len);
|
|
|
|
if (msglen > skb->len)
|
|
|
|
msglen = skb->len;
|
|
|
|
|
2017-06-07 21:50:38 +08:00
|
|
|
if (skb->len < NLMSG_HDRLEN + sizeof(struct nfgenmsg))
|
2017-02-10 19:08:14 +08:00
|
|
|
return;
|
|
|
|
|
netlink: make validation more configurable for future strictness
We currently have two levels of strict validation:
1) liberal (default)
- undefined (type >= max) & NLA_UNSPEC attributes accepted
- attribute length >= expected accepted
- garbage at end of message accepted
2) strict (opt-in)
- NLA_UNSPEC attributes accepted
- attribute length >= expected accepted
Split out parsing strictness into four different options:
* TRAILING - check that there's no trailing data after parsing
attributes (in message or nested)
* MAXTYPE - reject attrs > max known type
* UNSPEC - reject attributes with NLA_UNSPEC policy entries
* STRICT_ATTRS - strictly validate attribute size
The default for future things should be *everything*.
The current *_strict() is a combination of TRAILING and MAXTYPE,
and is renamed to _deprecated_strict().
The current regular parsing has none of this, and is renamed to
*_parse_deprecated().
Additionally it allows us to selectively set one of the new flags
even on old policies. Notably, the UNSPEC flag could be useful in
this case, since it can be arranged (by filling in the policy) to
not be an incompatible userspace ABI change, but would then going
forward prevent forgetting attribute entries. Similar can apply
to the POLICY flag.
We end up with the following renames:
* nla_parse -> nla_parse_deprecated
* nla_parse_strict -> nla_parse_deprecated_strict
* nlmsg_parse -> nlmsg_parse_deprecated
* nlmsg_parse_strict -> nlmsg_parse_deprecated_strict
* nla_parse_nested -> nla_parse_nested_deprecated
* nla_validate_nested -> nla_validate_nested_deprecated
Using spatch, of course:
@@
expression TB, MAX, HEAD, LEN, POL, EXT;
@@
-nla_parse(TB, MAX, HEAD, LEN, POL, EXT)
+nla_parse_deprecated(TB, MAX, HEAD, LEN, POL, EXT)
@@
expression NLH, HDRLEN, TB, MAX, POL, EXT;
@@
-nlmsg_parse(NLH, HDRLEN, TB, MAX, POL, EXT)
+nlmsg_parse_deprecated(NLH, HDRLEN, TB, MAX, POL, EXT)
@@
expression NLH, HDRLEN, TB, MAX, POL, EXT;
@@
-nlmsg_parse_strict(NLH, HDRLEN, TB, MAX, POL, EXT)
+nlmsg_parse_deprecated_strict(NLH, HDRLEN, TB, MAX, POL, EXT)
@@
expression TB, MAX, NLA, POL, EXT;
@@
-nla_parse_nested(TB, MAX, NLA, POL, EXT)
+nla_parse_nested_deprecated(TB, MAX, NLA, POL, EXT)
@@
expression START, MAX, POL, EXT;
@@
-nla_validate_nested(START, MAX, POL, EXT)
+nla_validate_nested_deprecated(START, MAX, POL, EXT)
@@
expression NLH, HDRLEN, MAX, POL, EXT;
@@
-nlmsg_validate(NLH, HDRLEN, MAX, POL, EXT)
+nlmsg_validate_deprecated(NLH, HDRLEN, MAX, POL, EXT)
For this patch, don't actually add the strict, non-renamed versions
yet so that it breaks compile if I get it wrong.
Also, while at it, make nla_validate and nla_parse go down to a
common __nla_validate_parse() function to avoid code duplication.
Ultimately, this allows us to have very strict validation for every
new caller of nla_parse()/nlmsg_parse() etc as re-introduced in the
next patch, while existing things will continue to work as is.
In effect then, this adds fully strict validation for any new command.
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2019-04-26 20:07:28 +08:00
|
|
|
err = nla_parse_deprecated(cda, NFNL_BATCH_MAX, attr, attrlen,
|
|
|
|
nfnl_batch_policy, NULL);
|
2017-02-10 19:08:17 +08:00
|
|
|
if (err < 0) {
|
2017-04-12 20:34:04 +08:00
|
|
|
netlink_ack(skb, nlh, err, NULL);
|
2017-02-10 19:08:17 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (cda[NFNL_BATCH_GENID])
|
|
|
|
gen_id = ntohl(nla_get_be32(cda[NFNL_BATCH_GENID]));
|
|
|
|
|
2017-02-10 19:08:14 +08:00
|
|
|
nfgenmsg = nlmsg_data(nlh);
|
|
|
|
skb_pull(skb, msglen);
|
|
|
|
/* Work around old nft using host byte order */
|
|
|
|
if (nfgenmsg->res_id == NFNL_SUBSYS_NFTABLES)
|
|
|
|
res_id = NFNL_SUBSYS_NFTABLES;
|
|
|
|
else
|
|
|
|
res_id = ntohs(nfgenmsg->res_id);
|
|
|
|
|
2017-02-10 19:08:17 +08:00
|
|
|
nfnetlink_rcv_batch(skb, nlh, res_id, gen_id);
|
2017-02-10 19:08:14 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static void nfnetlink_rcv(struct sk_buff *skb)
|
|
|
|
{
|
|
|
|
struct nlmsghdr *nlh = nlmsg_hdr(skb);
|
|
|
|
|
2017-06-07 21:50:38 +08:00
|
|
|
if (skb->len < NLMSG_HDRLEN ||
|
|
|
|
nlh->nlmsg_len < NLMSG_HDRLEN ||
|
netfilter: nfnetlink: add batch support and use it from nf_tables
This patch adds a batch support to nfnetlink. Basically, it adds
two new control messages:
* NFNL_MSG_BATCH_BEGIN, that indicates the beginning of a batch,
the nfgenmsg->res_id indicates the nfnetlink subsystem ID.
* NFNL_MSG_BATCH_END, that results in the invocation of the
ss->commit callback function. If not specified or an error
ocurred in the batch, the ss->abort function is invoked
instead.
The end message represents the commit operation in nftables, the
lack of end message results in an abort. This patch also adds the
.call_batch function that is only called from the batch receival
path.
This patch adds atomic rule updates and dumps based on
bitmask generations. This allows to atomically commit a set of
rule-set updates incrementally without altering the internal
state of existing nf_tables expressions/matches/targets.
The idea consists of using a generation cursor of 1 bit and
a bitmask of 2 bits per rule. Assuming the gencursor is 0,
then the genmask (expressed as a bitmask) can be interpreted
as:
00 active in the present, will be active in the next generation.
01 inactive in the present, will be active in the next generation.
10 active in the present, will be deleted in the next generation.
^
gencursor
Once you invoke the transition to the next generation, the global
gencursor is updated:
00 active in the present, will be active in the next generation.
01 active in the present, needs to zero its future, it becomes 00.
10 inactive in the present, delete now.
^
gencursor
If a dump is in progress and nf_tables enters a new generation,
the dump will stop and return -EBUSY to let userspace know that
it has to retry again. In order to invalidate dumps, a global
genctr counter is increased everytime nf_tables enters a new
generation.
This new operation can be used from the user-space utility
that controls the firewall, eg.
nft -f restore
The rule updates contained in `file' will be applied atomically.
cat file
-----
add filter INPUT ip saddr 1.1.1.1 counter accept #1
del filter INPUT ip daddr 2.2.2.2 counter drop #2
-EOF-
Note that the rule 1 will be inactive until the transition to the
next generation, the rule 2 will be evicted in the next generation.
There is a penalty during the rule update due to the branch
misprediction in the packet matching framework. But that should be
quickly resolved once the iteration over the commit list that
contain rules that require updates is finished.
Event notification happens once the rule-set update has been
committed. So we skip notifications is case the rule-set update
is aborted, which can happen in case that the rule-set is tested
to apply correctly.
This patch squashed the following patches from Pablo:
* nf_tables: atomic rule updates and dumps
* nf_tables: get rid of per rule list_head for commits
* nf_tables: use per netns commit list
* nfnetlink: add batch support and use it from nf_tables
* nf_tables: all rule updates are transactional
* nf_tables: attach replacement rule after stale one
* nf_tables: do not allow deletion/replacement of stale rules
* nf_tables: remove unused NFTA_RULE_FLAGS
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
2013-10-14 17:05:33 +08:00
|
|
|
skb->len < nlh->nlmsg_len)
|
|
|
|
return;
|
|
|
|
|
2014-04-24 05:29:27 +08:00
|
|
|
if (!netlink_net_capable(skb, CAP_NET_ADMIN)) {
|
2017-04-12 20:34:04 +08:00
|
|
|
netlink_ack(skb, nlh, -EPERM, NULL);
|
2013-11-08 02:59:19 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-02-10 19:08:14 +08:00
|
|
|
if (nlh->nlmsg_type == NFNL_MSG_BATCH_BEGIN)
|
|
|
|
nfnetlink_rcv_skb_batch(skb, nlh);
|
|
|
|
else
|
2017-04-02 17:22:12 +08:00
|
|
|
netlink_rcv_skb(skb, nfnetlink_rcv_msg);
|
2005-08-10 10:30:24 +08:00
|
|
|
}
|
|
|
|
|
2012-06-29 14:15:22 +08:00
|
|
|
#ifdef CONFIG_MODULES
|
2014-12-24 04:00:06 +08:00
|
|
|
static int nfnetlink_bind(struct net *net, int group)
|
2012-06-29 14:15:22 +08:00
|
|
|
{
|
|
|
|
const struct nfnetlink_subsystem *ss;
|
2014-11-15 01:14:33 +08:00
|
|
|
int type;
|
|
|
|
|
|
|
|
if (group <= NFNLGRP_NONE || group > NFNLGRP_MAX)
|
2015-01-04 22:20:41 +08:00
|
|
|
return 0;
|
2014-11-15 01:14:33 +08:00
|
|
|
|
|
|
|
type = nfnl_group2type[group];
|
2012-06-29 14:15:22 +08:00
|
|
|
|
|
|
|
rcu_read_lock();
|
2015-10-27 20:20:25 +08:00
|
|
|
ss = nfnetlink_get_subsys(type << 8);
|
2012-06-29 14:15:22 +08:00
|
|
|
rcu_read_unlock();
|
2014-04-23 09:31:53 +08:00
|
|
|
if (!ss)
|
2019-07-03 03:41:40 +08:00
|
|
|
request_module_nowait("nfnetlink-subsys-%d", type);
|
2014-04-23 09:31:54 +08:00
|
|
|
return 0;
|
2012-06-29 14:15:22 +08:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2010-01-13 23:02:14 +08:00
|
|
|
static int __net_init nfnetlink_net_init(struct net *net)
|
2005-08-10 10:30:24 +08:00
|
|
|
{
|
2010-01-13 23:02:14 +08:00
|
|
|
struct sock *nfnl;
|
2012-06-29 14:15:21 +08:00
|
|
|
struct netlink_kernel_cfg cfg = {
|
|
|
|
.groups = NFNLGRP_MAX,
|
|
|
|
.input = nfnetlink_rcv,
|
2012-06-29 14:15:22 +08:00
|
|
|
#ifdef CONFIG_MODULES
|
|
|
|
.bind = nfnetlink_bind,
|
|
|
|
#endif
|
2012-06-29 14:15:21 +08:00
|
|
|
};
|
2010-01-13 23:02:14 +08:00
|
|
|
|
2012-09-08 10:53:54 +08:00
|
|
|
nfnl = netlink_kernel_create(net, NETLINK_NETFILTER, &cfg);
|
2010-01-13 23:02:14 +08:00
|
|
|
if (!nfnl)
|
|
|
|
return -ENOMEM;
|
|
|
|
net->nfnl_stash = nfnl;
|
2012-01-12 12:41:32 +08:00
|
|
|
rcu_assign_pointer(net->nfnl, nfnl);
|
2010-01-13 23:02:14 +08:00
|
|
|
return 0;
|
2005-08-10 10:30:24 +08:00
|
|
|
}
|
|
|
|
|
2010-01-13 23:02:14 +08:00
|
|
|
static void __net_exit nfnetlink_net_exit_batch(struct list_head *net_exit_list)
|
2005-08-10 10:30:24 +08:00
|
|
|
{
|
2010-01-13 23:02:14 +08:00
|
|
|
struct net *net;
|
2005-08-10 10:30:24 +08:00
|
|
|
|
2010-01-13 23:02:14 +08:00
|
|
|
list_for_each_entry(net, net_exit_list, exit_list)
|
2011-08-02 00:19:00 +08:00
|
|
|
RCU_INIT_POINTER(net->nfnl, NULL);
|
2010-01-13 23:02:14 +08:00
|
|
|
synchronize_net();
|
|
|
|
list_for_each_entry(net, net_exit_list, exit_list)
|
|
|
|
netlink_kernel_release(net->nfnl_stash);
|
|
|
|
}
|
2005-08-10 10:30:24 +08:00
|
|
|
|
2010-01-13 23:02:14 +08:00
|
|
|
static struct pernet_operations nfnetlink_net_ops = {
|
|
|
|
.init = nfnetlink_net_init,
|
|
|
|
.exit_batch = nfnetlink_net_exit_batch,
|
|
|
|
};
|
|
|
|
|
|
|
|
static int __init nfnetlink_init(void)
|
|
|
|
{
|
2013-02-05 08:50:26 +08:00
|
|
|
int i;
|
|
|
|
|
2014-11-15 01:14:33 +08:00
|
|
|
for (i = NFNLGRP_NONE + 1; i <= NFNLGRP_MAX; i++)
|
|
|
|
BUG_ON(nfnl_group2type[i] == NFNL_SUBSYS_NONE);
|
|
|
|
|
2013-02-05 08:50:26 +08:00
|
|
|
for (i=0; i<NFNL_SUBSYS_COUNT; i++)
|
|
|
|
mutex_init(&table[i].mutex);
|
|
|
|
|
2010-01-13 23:02:14 +08:00
|
|
|
return register_pernet_subsys(&nfnetlink_net_ops);
|
2005-08-10 10:30:24 +08:00
|
|
|
}
|
|
|
|
|
2010-01-13 23:02:14 +08:00
|
|
|
static void __exit nfnetlink_exit(void)
|
|
|
|
{
|
|
|
|
unregister_pernet_subsys(&nfnetlink_net_ops);
|
|
|
|
}
|
2005-08-10 10:30:24 +08:00
|
|
|
module_init(nfnetlink_init);
|
|
|
|
module_exit(nfnetlink_exit);
|