Commit 32511f8e authored by David S. Miller's avatar David S. Miller

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

Pablo Neira Ayuso says:

====================
Netfilter updates for net-next

The following patchset contains Netfilter updates for net-next:

1) Add two helper functions to release one table and hooks from
   the netns and netlink event path.

2) Add table ownership infrastructure, this new infrastructure allows
   users to bind a table (and its content) to a process through the
   netlink socket.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 96313e1d 6001a930
...@@ -1106,11 +1106,17 @@ struct nft_table { ...@@ -1106,11 +1106,17 @@ struct nft_table {
u16 family:6, u16 family:6,
flags:8, flags:8,
genmask:2; genmask:2;
u32 nlpid;
char *name; char *name;
u16 udlen; u16 udlen;
u8 *udata; u8 *udata;
}; };
static inline bool nft_table_has_owner(const struct nft_table *table)
{
return table->flags & NFT_TABLE_F_OWNER;
}
static inline bool nft_base_chain_netdev(int family, u32 hooknum) static inline bool nft_base_chain_netdev(int family, u32 hooknum)
{ {
return family == NFPROTO_NETDEV || return family == NFPROTO_NETDEV ||
......
...@@ -164,7 +164,10 @@ enum nft_hook_attributes { ...@@ -164,7 +164,10 @@ enum nft_hook_attributes {
*/ */
enum nft_table_flags { enum nft_table_flags {
NFT_TABLE_F_DORMANT = 0x1, NFT_TABLE_F_DORMANT = 0x1,
NFT_TABLE_F_OWNER = 0x2,
}; };
#define NFT_TABLE_F_MASK (NFT_TABLE_F_DORMANT | \
NFT_TABLE_F_OWNER)
/** /**
* enum nft_table_attributes - nf_tables table netlink attributes * enum nft_table_attributes - nf_tables table netlink attributes
...@@ -173,6 +176,7 @@ enum nft_table_flags { ...@@ -173,6 +176,7 @@ enum nft_table_flags {
* @NFTA_TABLE_FLAGS: bitmask of enum nft_table_flags (NLA_U32) * @NFTA_TABLE_FLAGS: bitmask of enum nft_table_flags (NLA_U32)
* @NFTA_TABLE_USE: number of chains in this table (NLA_U32) * @NFTA_TABLE_USE: number of chains in this table (NLA_U32)
* @NFTA_TABLE_USERDATA: user data (NLA_BINARY) * @NFTA_TABLE_USERDATA: user data (NLA_BINARY)
* @NFTA_TABLE_OWNER: owner of this table through netlink portID (NLA_U32)
*/ */
enum nft_table_attributes { enum nft_table_attributes {
NFTA_TABLE_UNSPEC, NFTA_TABLE_UNSPEC,
...@@ -182,6 +186,7 @@ enum nft_table_attributes { ...@@ -182,6 +186,7 @@ enum nft_table_attributes {
NFTA_TABLE_HANDLE, NFTA_TABLE_HANDLE,
NFTA_TABLE_PAD, NFTA_TABLE_PAD,
NFTA_TABLE_USERDATA, NFTA_TABLE_USERDATA,
NFTA_TABLE_OWNER,
__NFTA_TABLE_MAX __NFTA_TABLE_MAX
}; };
#define NFTA_TABLE_MAX (__NFTA_TABLE_MAX - 1) #define NFTA_TABLE_MAX (__NFTA_TABLE_MAX - 1)
......
...@@ -508,7 +508,7 @@ static int nft_delflowtable(struct nft_ctx *ctx, ...@@ -508,7 +508,7 @@ static int nft_delflowtable(struct nft_ctx *ctx,
static struct nft_table *nft_table_lookup(const struct net *net, static struct nft_table *nft_table_lookup(const struct net *net,
const struct nlattr *nla, const struct nlattr *nla,
u8 family, u8 genmask) u8 family, u8 genmask, u32 nlpid)
{ {
struct nft_table *table; struct nft_table *table;
...@@ -519,9 +519,14 @@ static struct nft_table *nft_table_lookup(const struct net *net, ...@@ -519,9 +519,14 @@ static struct nft_table *nft_table_lookup(const struct net *net,
lockdep_is_held(&net->nft.commit_mutex)) { lockdep_is_held(&net->nft.commit_mutex)) {
if (!nla_strcmp(nla, table->name) && if (!nla_strcmp(nla, table->name) &&
table->family == family && table->family == family &&
nft_active_genmask(table, genmask)) nft_active_genmask(table, genmask)) {
if (nft_table_has_owner(table) &&
table->nlpid != nlpid)
return ERR_PTR(-EPERM);
return table; return table;
} }
}
return ERR_PTR(-ENOENT); return ERR_PTR(-ENOENT);
} }
...@@ -679,6 +684,9 @@ static int nf_tables_fill_table_info(struct sk_buff *skb, struct net *net, ...@@ -679,6 +684,9 @@ static int nf_tables_fill_table_info(struct sk_buff *skb, struct net *net,
nla_put_be64(skb, NFTA_TABLE_HANDLE, cpu_to_be64(table->handle), nla_put_be64(skb, NFTA_TABLE_HANDLE, cpu_to_be64(table->handle),
NFTA_TABLE_PAD)) NFTA_TABLE_PAD))
goto nla_put_failure; goto nla_put_failure;
if (nft_table_has_owner(table) &&
nla_put_be32(skb, NFTA_TABLE_OWNER, htonl(table->nlpid)))
goto nla_put_failure;
if (table->udata) { if (table->udata) {
if (nla_put(skb, NFTA_TABLE_USERDATA, table->udlen, table->udata)) if (nla_put(skb, NFTA_TABLE_USERDATA, table->udlen, table->udata))
...@@ -821,7 +829,7 @@ static int nf_tables_gettable(struct net *net, struct sock *nlsk, ...@@ -821,7 +829,7 @@ static int nf_tables_gettable(struct net *net, struct sock *nlsk,
return nft_netlink_dump_start_rcu(nlsk, skb, nlh, &c); return nft_netlink_dump_start_rcu(nlsk, skb, nlh, &c);
} }
table = nft_table_lookup(net, nla[NFTA_TABLE_NAME], family, genmask); table = nft_table_lookup(net, nla[NFTA_TABLE_NAME], family, genmask, 0);
if (IS_ERR(table)) { if (IS_ERR(table)) {
NL_SET_BAD_ATTR(extack, nla[NFTA_TABLE_NAME]); NL_SET_BAD_ATTR(extack, nla[NFTA_TABLE_NAME]);
return PTR_ERR(table); return PTR_ERR(table);
...@@ -902,8 +910,8 @@ static int nf_tables_updtable(struct nft_ctx *ctx) ...@@ -902,8 +910,8 @@ static int nf_tables_updtable(struct nft_ctx *ctx)
return 0; return 0;
flags = ntohl(nla_get_be32(ctx->nla[NFTA_TABLE_FLAGS])); flags = ntohl(nla_get_be32(ctx->nla[NFTA_TABLE_FLAGS]));
if (flags & ~NFT_TABLE_F_DORMANT) if (flags & ~NFT_TABLE_F_MASK)
return -EINVAL; return -EOPNOTSUPP;
if (flags == ctx->table->flags) if (flags == ctx->table->flags)
return 0; return 0;
...@@ -1003,7 +1011,8 @@ static int nf_tables_newtable(struct net *net, struct sock *nlsk, ...@@ -1003,7 +1011,8 @@ static int nf_tables_newtable(struct net *net, struct sock *nlsk,
lockdep_assert_held(&net->nft.commit_mutex); lockdep_assert_held(&net->nft.commit_mutex);
attr = nla[NFTA_TABLE_NAME]; attr = nla[NFTA_TABLE_NAME];
table = nft_table_lookup(net, attr, family, genmask); table = nft_table_lookup(net, attr, family, genmask,
NETLINK_CB(skb).portid);
if (IS_ERR(table)) { if (IS_ERR(table)) {
if (PTR_ERR(table) != -ENOENT) if (PTR_ERR(table) != -ENOENT)
return PTR_ERR(table); return PTR_ERR(table);
...@@ -1021,8 +1030,8 @@ static int nf_tables_newtable(struct net *net, struct sock *nlsk, ...@@ -1021,8 +1030,8 @@ static int nf_tables_newtable(struct net *net, struct sock *nlsk,
if (nla[NFTA_TABLE_FLAGS]) { if (nla[NFTA_TABLE_FLAGS]) {
flags = ntohl(nla_get_be32(nla[NFTA_TABLE_FLAGS])); flags = ntohl(nla_get_be32(nla[NFTA_TABLE_FLAGS]));
if (flags & ~NFT_TABLE_F_DORMANT) if (flags & ~NFT_TABLE_F_MASK)
return -EINVAL; return -EOPNOTSUPP;
} }
err = -ENOMEM; err = -ENOMEM;
...@@ -1053,6 +1062,8 @@ static int nf_tables_newtable(struct net *net, struct sock *nlsk, ...@@ -1053,6 +1062,8 @@ static int nf_tables_newtable(struct net *net, struct sock *nlsk,
table->family = family; table->family = family;
table->flags = flags; table->flags = flags;
table->handle = ++table_handle; table->handle = ++table_handle;
if (table->flags & NFT_TABLE_F_OWNER)
table->nlpid = NETLINK_CB(skb).portid;
nft_ctx_init(&ctx, net, skb, nlh, family, table, NULL, nla); nft_ctx_init(&ctx, net, skb, nlh, family, table, NULL, nla);
err = nft_trans_table_add(&ctx, NFT_MSG_NEWTABLE); err = nft_trans_table_add(&ctx, NFT_MSG_NEWTABLE);
...@@ -1160,6 +1171,9 @@ static int nft_flush(struct nft_ctx *ctx, int family) ...@@ -1160,6 +1171,9 @@ static int nft_flush(struct nft_ctx *ctx, int family)
if (!nft_is_active_next(ctx->net, table)) if (!nft_is_active_next(ctx->net, table))
continue; continue;
if (nft_table_has_owner(table) && table->nlpid != ctx->portid)
continue;
if (nla[NFTA_TABLE_NAME] && if (nla[NFTA_TABLE_NAME] &&
nla_strcmp(nla[NFTA_TABLE_NAME], table->name) != 0) nla_strcmp(nla[NFTA_TABLE_NAME], table->name) != 0)
continue; continue;
...@@ -1196,7 +1210,8 @@ static int nf_tables_deltable(struct net *net, struct sock *nlsk, ...@@ -1196,7 +1210,8 @@ static int nf_tables_deltable(struct net *net, struct sock *nlsk,
table = nft_table_lookup_byhandle(net, attr, genmask); table = nft_table_lookup_byhandle(net, attr, genmask);
} else { } else {
attr = nla[NFTA_TABLE_NAME]; attr = nla[NFTA_TABLE_NAME];
table = nft_table_lookup(net, attr, family, genmask); table = nft_table_lookup(net, attr, family, genmask,
NETLINK_CB(skb).portid);
} }
if (IS_ERR(table)) { if (IS_ERR(table)) {
...@@ -1579,7 +1594,7 @@ static int nf_tables_getchain(struct net *net, struct sock *nlsk, ...@@ -1579,7 +1594,7 @@ static int nf_tables_getchain(struct net *net, struct sock *nlsk,
return nft_netlink_dump_start_rcu(nlsk, skb, nlh, &c); return nft_netlink_dump_start_rcu(nlsk, skb, nlh, &c);
} }
table = nft_table_lookup(net, nla[NFTA_CHAIN_TABLE], family, genmask); table = nft_table_lookup(net, nla[NFTA_CHAIN_TABLE], family, genmask, 0);
if (IS_ERR(table)) { if (IS_ERR(table)) {
NL_SET_BAD_ATTR(extack, nla[NFTA_CHAIN_TABLE]); NL_SET_BAD_ATTR(extack, nla[NFTA_CHAIN_TABLE]);
return PTR_ERR(table); return PTR_ERR(table);
...@@ -2299,7 +2314,8 @@ static int nf_tables_newchain(struct net *net, struct sock *nlsk, ...@@ -2299,7 +2314,8 @@ static int nf_tables_newchain(struct net *net, struct sock *nlsk,
lockdep_assert_held(&net->nft.commit_mutex); lockdep_assert_held(&net->nft.commit_mutex);
table = nft_table_lookup(net, nla[NFTA_CHAIN_TABLE], family, genmask); table = nft_table_lookup(net, nla[NFTA_CHAIN_TABLE], family, genmask,
NETLINK_CB(skb).portid);
if (IS_ERR(table)) { if (IS_ERR(table)) {
NL_SET_BAD_ATTR(extack, nla[NFTA_CHAIN_TABLE]); NL_SET_BAD_ATTR(extack, nla[NFTA_CHAIN_TABLE]);
return PTR_ERR(table); return PTR_ERR(table);
...@@ -2395,7 +2411,8 @@ static int nf_tables_delchain(struct net *net, struct sock *nlsk, ...@@ -2395,7 +2411,8 @@ static int nf_tables_delchain(struct net *net, struct sock *nlsk,
u32 use; u32 use;
int err; int err;
table = nft_table_lookup(net, nla[NFTA_CHAIN_TABLE], family, genmask); table = nft_table_lookup(net, nla[NFTA_CHAIN_TABLE], family, genmask,
NETLINK_CB(skb).portid);
if (IS_ERR(table)) { if (IS_ERR(table)) {
NL_SET_BAD_ATTR(extack, nla[NFTA_CHAIN_TABLE]); NL_SET_BAD_ATTR(extack, nla[NFTA_CHAIN_TABLE]);
return PTR_ERR(table); return PTR_ERR(table);
...@@ -3041,7 +3058,7 @@ static int nf_tables_getrule(struct net *net, struct sock *nlsk, ...@@ -3041,7 +3058,7 @@ static int nf_tables_getrule(struct net *net, struct sock *nlsk,
return nft_netlink_dump_start_rcu(nlsk, skb, nlh, &c); return nft_netlink_dump_start_rcu(nlsk, skb, nlh, &c);
} }
table = nft_table_lookup(net, nla[NFTA_RULE_TABLE], family, genmask); table = nft_table_lookup(net, nla[NFTA_RULE_TABLE], family, genmask, 0);
if (IS_ERR(table)) { if (IS_ERR(table)) {
NL_SET_BAD_ATTR(extack, nla[NFTA_RULE_TABLE]); NL_SET_BAD_ATTR(extack, nla[NFTA_RULE_TABLE]);
return PTR_ERR(table); return PTR_ERR(table);
...@@ -3179,7 +3196,8 @@ static int nf_tables_newrule(struct net *net, struct sock *nlsk, ...@@ -3179,7 +3196,8 @@ static int nf_tables_newrule(struct net *net, struct sock *nlsk,
lockdep_assert_held(&net->nft.commit_mutex); lockdep_assert_held(&net->nft.commit_mutex);
table = nft_table_lookup(net, nla[NFTA_RULE_TABLE], family, genmask); table = nft_table_lookup(net, nla[NFTA_RULE_TABLE], family, genmask,
NETLINK_CB(skb).portid);
if (IS_ERR(table)) { if (IS_ERR(table)) {
NL_SET_BAD_ATTR(extack, nla[NFTA_RULE_TABLE]); NL_SET_BAD_ATTR(extack, nla[NFTA_RULE_TABLE]);
return PTR_ERR(table); return PTR_ERR(table);
...@@ -3403,7 +3421,8 @@ static int nf_tables_delrule(struct net *net, struct sock *nlsk, ...@@ -3403,7 +3421,8 @@ static int nf_tables_delrule(struct net *net, struct sock *nlsk,
int family = nfmsg->nfgen_family, err = 0; int family = nfmsg->nfgen_family, err = 0;
struct nft_ctx ctx; struct nft_ctx ctx;
table = nft_table_lookup(net, nla[NFTA_RULE_TABLE], family, genmask); table = nft_table_lookup(net, nla[NFTA_RULE_TABLE], family, genmask,
NETLINK_CB(skb).portid);
if (IS_ERR(table)) { if (IS_ERR(table)) {
NL_SET_BAD_ATTR(extack, nla[NFTA_RULE_TABLE]); NL_SET_BAD_ATTR(extack, nla[NFTA_RULE_TABLE]);
return PTR_ERR(table); return PTR_ERR(table);
...@@ -3584,7 +3603,7 @@ static int nft_ctx_init_from_setattr(struct nft_ctx *ctx, struct net *net, ...@@ -3584,7 +3603,7 @@ static int nft_ctx_init_from_setattr(struct nft_ctx *ctx, struct net *net,
const struct nlmsghdr *nlh, const struct nlmsghdr *nlh,
const struct nlattr * const nla[], const struct nlattr * const nla[],
struct netlink_ext_ack *extack, struct netlink_ext_ack *extack,
u8 genmask) u8 genmask, u32 nlpid)
{ {
const struct nfgenmsg *nfmsg = nlmsg_data(nlh); const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
int family = nfmsg->nfgen_family; int family = nfmsg->nfgen_family;
...@@ -3592,7 +3611,7 @@ static int nft_ctx_init_from_setattr(struct nft_ctx *ctx, struct net *net, ...@@ -3592,7 +3611,7 @@ static int nft_ctx_init_from_setattr(struct nft_ctx *ctx, struct net *net,
if (nla[NFTA_SET_TABLE] != NULL) { if (nla[NFTA_SET_TABLE] != NULL) {
table = nft_table_lookup(net, nla[NFTA_SET_TABLE], family, table = nft_table_lookup(net, nla[NFTA_SET_TABLE], family,
genmask); genmask, nlpid);
if (IS_ERR(table)) { if (IS_ERR(table)) {
NL_SET_BAD_ATTR(extack, nla[NFTA_SET_TABLE]); NL_SET_BAD_ATTR(extack, nla[NFTA_SET_TABLE]);
return PTR_ERR(table); return PTR_ERR(table);
...@@ -4007,7 +4026,7 @@ static int nf_tables_getset(struct net *net, struct sock *nlsk, ...@@ -4007,7 +4026,7 @@ static int nf_tables_getset(struct net *net, struct sock *nlsk,
/* Verify existence before starting dump */ /* Verify existence before starting dump */
err = nft_ctx_init_from_setattr(&ctx, net, skb, nlh, nla, extack, err = nft_ctx_init_from_setattr(&ctx, net, skb, nlh, nla, extack,
genmask); genmask, 0);
if (err < 0) if (err < 0)
return err; return err;
...@@ -4236,7 +4255,8 @@ static int nf_tables_newset(struct net *net, struct sock *nlsk, ...@@ -4236,7 +4255,8 @@ static int nf_tables_newset(struct net *net, struct sock *nlsk,
if (nla[NFTA_SET_EXPR] || nla[NFTA_SET_EXPRESSIONS]) if (nla[NFTA_SET_EXPR] || nla[NFTA_SET_EXPRESSIONS])
desc.expr = true; desc.expr = true;
table = nft_table_lookup(net, nla[NFTA_SET_TABLE], family, genmask); table = nft_table_lookup(net, nla[NFTA_SET_TABLE], family, genmask,
NETLINK_CB(skb).portid);
if (IS_ERR(table)) { if (IS_ERR(table)) {
NL_SET_BAD_ATTR(extack, nla[NFTA_SET_TABLE]); NL_SET_BAD_ATTR(extack, nla[NFTA_SET_TABLE]);
return PTR_ERR(table); return PTR_ERR(table);
...@@ -4413,7 +4433,7 @@ static int nf_tables_delset(struct net *net, struct sock *nlsk, ...@@ -4413,7 +4433,7 @@ static int nf_tables_delset(struct net *net, struct sock *nlsk,
return -EINVAL; return -EINVAL;
err = nft_ctx_init_from_setattr(&ctx, net, skb, nlh, nla, extack, err = nft_ctx_init_from_setattr(&ctx, net, skb, nlh, nla, extack,
genmask); genmask, NETLINK_CB(skb).portid);
if (err < 0) if (err < 0)
return err; return err;
...@@ -4608,14 +4628,14 @@ static int nft_ctx_init_from_elemattr(struct nft_ctx *ctx, struct net *net, ...@@ -4608,14 +4628,14 @@ static int nft_ctx_init_from_elemattr(struct nft_ctx *ctx, struct net *net,
const struct nlmsghdr *nlh, const struct nlmsghdr *nlh,
const struct nlattr * const nla[], const struct nlattr * const nla[],
struct netlink_ext_ack *extack, struct netlink_ext_ack *extack,
u8 genmask) u8 genmask, u32 nlpid)
{ {
const struct nfgenmsg *nfmsg = nlmsg_data(nlh); const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
int family = nfmsg->nfgen_family; int family = nfmsg->nfgen_family;
struct nft_table *table; struct nft_table *table;
table = nft_table_lookup(net, nla[NFTA_SET_ELEM_LIST_TABLE], family, table = nft_table_lookup(net, nla[NFTA_SET_ELEM_LIST_TABLE], family,
genmask); genmask, nlpid);
if (IS_ERR(table)) { if (IS_ERR(table)) {
NL_SET_BAD_ATTR(extack, nla[NFTA_SET_ELEM_LIST_TABLE]); NL_SET_BAD_ATTR(extack, nla[NFTA_SET_ELEM_LIST_TABLE]);
return PTR_ERR(table); return PTR_ERR(table);
...@@ -5032,7 +5052,7 @@ static int nf_tables_getsetelem(struct net *net, struct sock *nlsk, ...@@ -5032,7 +5052,7 @@ static int nf_tables_getsetelem(struct net *net, struct sock *nlsk,
int rem, err = 0; int rem, err = 0;
err = nft_ctx_init_from_elemattr(&ctx, net, skb, nlh, nla, extack, err = nft_ctx_init_from_elemattr(&ctx, net, skb, nlh, nla, extack,
genmask); genmask, NETLINK_CB(skb).portid);
if (err < 0) if (err < 0)
return err; return err;
...@@ -5613,7 +5633,7 @@ static int nf_tables_newsetelem(struct net *net, struct sock *nlsk, ...@@ -5613,7 +5633,7 @@ static int nf_tables_newsetelem(struct net *net, struct sock *nlsk,
return -EINVAL; return -EINVAL;
err = nft_ctx_init_from_elemattr(&ctx, net, skb, nlh, nla, extack, err = nft_ctx_init_from_elemattr(&ctx, net, skb, nlh, nla, extack,
genmask); genmask, NETLINK_CB(skb).portid);
if (err < 0) if (err < 0)
return err; return err;
...@@ -5821,7 +5841,7 @@ static int nf_tables_delsetelem(struct net *net, struct sock *nlsk, ...@@ -5821,7 +5841,7 @@ static int nf_tables_delsetelem(struct net *net, struct sock *nlsk,
int rem, err = 0; int rem, err = 0;
err = nft_ctx_init_from_elemattr(&ctx, net, skb, nlh, nla, extack, err = nft_ctx_init_from_elemattr(&ctx, net, skb, nlh, nla, extack,
genmask); genmask, NETLINK_CB(skb).portid);
if (err < 0) if (err < 0)
return err; return err;
...@@ -6124,7 +6144,8 @@ static int nf_tables_newobj(struct net *net, struct sock *nlsk, ...@@ -6124,7 +6144,8 @@ static int nf_tables_newobj(struct net *net, struct sock *nlsk,
!nla[NFTA_OBJ_DATA]) !nla[NFTA_OBJ_DATA])
return -EINVAL; return -EINVAL;
table = nft_table_lookup(net, nla[NFTA_OBJ_TABLE], family, genmask); table = nft_table_lookup(net, nla[NFTA_OBJ_TABLE], family, genmask,
NETLINK_CB(skb).portid);
if (IS_ERR(table)) { if (IS_ERR(table)) {
NL_SET_BAD_ATTR(extack, nla[NFTA_OBJ_TABLE]); NL_SET_BAD_ATTR(extack, nla[NFTA_OBJ_TABLE]);
return PTR_ERR(table); return PTR_ERR(table);
...@@ -6394,7 +6415,7 @@ static int nf_tables_getobj(struct net *net, struct sock *nlsk, ...@@ -6394,7 +6415,7 @@ static int nf_tables_getobj(struct net *net, struct sock *nlsk,
!nla[NFTA_OBJ_TYPE]) !nla[NFTA_OBJ_TYPE])
return -EINVAL; return -EINVAL;
table = nft_table_lookup(net, nla[NFTA_OBJ_TABLE], family, genmask); table = nft_table_lookup(net, nla[NFTA_OBJ_TABLE], family, genmask, 0);
if (IS_ERR(table)) { if (IS_ERR(table)) {
NL_SET_BAD_ATTR(extack, nla[NFTA_OBJ_TABLE]); NL_SET_BAD_ATTR(extack, nla[NFTA_OBJ_TABLE]);
return PTR_ERR(table); return PTR_ERR(table);
...@@ -6468,7 +6489,8 @@ static int nf_tables_delobj(struct net *net, struct sock *nlsk, ...@@ -6468,7 +6489,8 @@ static int nf_tables_delobj(struct net *net, struct sock *nlsk,
(!nla[NFTA_OBJ_NAME] && !nla[NFTA_OBJ_HANDLE])) (!nla[NFTA_OBJ_NAME] && !nla[NFTA_OBJ_HANDLE]))
return -EINVAL; return -EINVAL;
table = nft_table_lookup(net, nla[NFTA_OBJ_TABLE], family, genmask); table = nft_table_lookup(net, nla[NFTA_OBJ_TABLE], family, genmask,
NETLINK_CB(skb).portid);
if (IS_ERR(table)) { if (IS_ERR(table)) {
NL_SET_BAD_ATTR(extack, nla[NFTA_OBJ_TABLE]); NL_SET_BAD_ATTR(extack, nla[NFTA_OBJ_TABLE]);
return PTR_ERR(table); return PTR_ERR(table);
...@@ -6885,7 +6907,7 @@ static int nf_tables_newflowtable(struct net *net, struct sock *nlsk, ...@@ -6885,7 +6907,7 @@ static int nf_tables_newflowtable(struct net *net, struct sock *nlsk,
return -EINVAL; return -EINVAL;
table = nft_table_lookup(net, nla[NFTA_FLOWTABLE_TABLE], family, table = nft_table_lookup(net, nla[NFTA_FLOWTABLE_TABLE], family,
genmask); genmask, NETLINK_CB(skb).portid);
if (IS_ERR(table)) { if (IS_ERR(table)) {
NL_SET_BAD_ATTR(extack, nla[NFTA_FLOWTABLE_TABLE]); NL_SET_BAD_ATTR(extack, nla[NFTA_FLOWTABLE_TABLE]);
return PTR_ERR(table); return PTR_ERR(table);
...@@ -7069,7 +7091,7 @@ static int nf_tables_delflowtable(struct net *net, struct sock *nlsk, ...@@ -7069,7 +7091,7 @@ static int nf_tables_delflowtable(struct net *net, struct sock *nlsk,
return -EINVAL; return -EINVAL;
table = nft_table_lookup(net, nla[NFTA_FLOWTABLE_TABLE], family, table = nft_table_lookup(net, nla[NFTA_FLOWTABLE_TABLE], family,
genmask); genmask, NETLINK_CB(skb).portid);
if (IS_ERR(table)) { if (IS_ERR(table)) {
NL_SET_BAD_ATTR(extack, nla[NFTA_FLOWTABLE_TABLE]); NL_SET_BAD_ATTR(extack, nla[NFTA_FLOWTABLE_TABLE]);
return PTR_ERR(table); return PTR_ERR(table);
...@@ -7277,7 +7299,7 @@ static int nf_tables_getflowtable(struct net *net, struct sock *nlsk, ...@@ -7277,7 +7299,7 @@ static int nf_tables_getflowtable(struct net *net, struct sock *nlsk,
return -EINVAL; return -EINVAL;
table = nft_table_lookup(net, nla[NFTA_FLOWTABLE_TABLE], family, table = nft_table_lookup(net, nla[NFTA_FLOWTABLE_TABLE], family,
genmask); genmask, 0);
if (IS_ERR(table)) if (IS_ERR(table))
return PTR_ERR(table); return PTR_ERR(table);
...@@ -8988,21 +9010,25 @@ int __nft_release_basechain(struct nft_ctx *ctx) ...@@ -8988,21 +9010,25 @@ int __nft_release_basechain(struct nft_ctx *ctx)
} }
EXPORT_SYMBOL_GPL(__nft_release_basechain); EXPORT_SYMBOL_GPL(__nft_release_basechain);
static void __nft_release_hooks(struct net *net) static void __nft_release_hook(struct net *net, struct nft_table *table)
{ {
struct nft_table *table;
struct nft_chain *chain; struct nft_chain *chain;
list_for_each_entry(table, &net->nft.tables, list) {
list_for_each_entry(chain, &table->chains, list) list_for_each_entry(chain, &table->chains, list)
nf_tables_unregister_hook(net, table, chain); nf_tables_unregister_hook(net, table, chain);
}
} }
static void __nft_release_tables(struct net *net) static void __nft_release_hooks(struct net *net)
{
struct nft_table *table;
list_for_each_entry(table, &net->nft.tables, list)
__nft_release_hook(net, table);
}
static void __nft_release_table(struct net *net, struct nft_table *table)
{ {
struct nft_flowtable *flowtable, *nf; struct nft_flowtable *flowtable, *nf;
struct nft_table *table, *nt;
struct nft_chain *chain, *nc; struct nft_chain *chain, *nc;
struct nft_object *obj, *ne; struct nft_object *obj, *ne;
struct nft_rule *rule, *nr; struct nft_rule *rule, *nr;
...@@ -9012,7 +9038,6 @@ static void __nft_release_tables(struct net *net) ...@@ -9012,7 +9038,6 @@ static void __nft_release_tables(struct net *net)
.family = NFPROTO_NETDEV, .family = NFPROTO_NETDEV,
}; };
list_for_each_entry_safe(table, nt, &net->nft.tables, list) {
ctx.family = table->family; ctx.family = table->family;
ctx.table = table; ctx.table = table;
list_for_each_entry(chain, &table->chains, list) { list_for_each_entry(chain, &table->chains, list) {
...@@ -9046,9 +9071,57 @@ static void __nft_release_tables(struct net *net) ...@@ -9046,9 +9071,57 @@ static void __nft_release_tables(struct net *net)
} }
list_del(&table->list); list_del(&table->list);
nf_tables_table_destroy(&ctx); nf_tables_table_destroy(&ctx);
}
static void __nft_release_tables(struct net *net, u32 nlpid)
{
struct nft_table *table, *nt;
list_for_each_entry_safe(table, nt, &net->nft.tables, list) {
if (nft_table_has_owner(table) &&
nlpid != table->nlpid)
continue;
__nft_release_table(net, table);
} }
} }
static int nft_rcv_nl_event(struct notifier_block *this, unsigned long event,
void *ptr)
{
struct netlink_notify *n = ptr;
struct nft_table *table, *nt;
struct net *net = n->net;
bool release = false;
if (event != NETLINK_URELEASE || n->protocol != NETLINK_NETFILTER)
return NOTIFY_DONE;
mutex_lock(&net->nft.commit_mutex);
list_for_each_entry(table, &net->nft.tables, list) {
if (nft_table_has_owner(table) &&
n->portid == table->nlpid) {
__nft_release_hook(net, table);
release = true;
}
}
if (release) {
synchronize_rcu();
list_for_each_entry_safe(table, nt, &net->nft.tables, list) {
if (nft_table_has_owner(table) &&
n->portid == table->nlpid)
__nft_release_table(net, table);
}
}
mutex_unlock(&net->nft.commit_mutex);
return NOTIFY_DONE;
}
static struct notifier_block nft_nl_notifier = {
.notifier_call = nft_rcv_nl_event,
};
static int __net_init nf_tables_init_net(struct net *net) static int __net_init nf_tables_init_net(struct net *net)
{ {
INIT_LIST_HEAD(&net->nft.tables); INIT_LIST_HEAD(&net->nft.tables);
...@@ -9072,7 +9145,7 @@ static void __net_exit nf_tables_exit_net(struct net *net) ...@@ -9072,7 +9145,7 @@ static void __net_exit nf_tables_exit_net(struct net *net)
mutex_lock(&net->nft.commit_mutex); mutex_lock(&net->nft.commit_mutex);
if (!list_empty(&net->nft.commit_list)) if (!list_empty(&net->nft.commit_list))
__nf_tables_abort(net, NFNL_ABORT_NONE); __nf_tables_abort(net, NFNL_ABORT_NONE);
__nft_release_tables(net); __nft_release_tables(net, 0);
mutex_unlock(&net->nft.commit_mutex); mutex_unlock(&net->nft.commit_mutex);
WARN_ON_ONCE(!list_empty(&net->nft.tables)); WARN_ON_ONCE(!list_empty(&net->nft.tables));
WARN_ON_ONCE(!list_empty(&net->nft.module_list)); WARN_ON_ONCE(!list_empty(&net->nft.module_list));
...@@ -9096,43 +9169,50 @@ static int __init nf_tables_module_init(void) ...@@ -9096,43 +9169,50 @@ static int __init nf_tables_module_init(void)
err = nft_chain_filter_init(); err = nft_chain_filter_init();
if (err < 0) if (err < 0)
goto err1; goto err_chain_filter;
err = nf_tables_core_module_init(); err = nf_tables_core_module_init();
if (err < 0) if (err < 0)
goto err2; goto err_core_module;
err = register_netdevice_notifier(&nf_tables_flowtable_notifier); err = register_netdevice_notifier(&nf_tables_flowtable_notifier);
if (err < 0) if (err < 0)
goto err3; goto err_netdev_notifier;
err = rhltable_init(&nft_objname_ht, &nft_objname_ht_params); err = rhltable_init(&nft_objname_ht, &nft_objname_ht_params);
if (err < 0) if (err < 0)
goto err4; goto err_rht_objname;
err = nft_offload_init(); err = nft_offload_init();
if (err < 0) if (err < 0)
goto err5; goto err_offload;
err = netlink_register_notifier(&nft_nl_notifier);
if (err < 0)
goto err_netlink_notifier;
/* must be last */ /* must be last */
err = nfnetlink_subsys_register(&nf_tables_subsys); err = nfnetlink_subsys_register(&nf_tables_subsys);
if (err < 0) if (err < 0)
goto err6; goto err_nfnl_subsys;
nft_chain_route_init(); nft_chain_route_init();
return err; return err;
err6:
err_nfnl_subsys:
netlink_unregister_notifier(&nft_nl_notifier);
err_netlink_notifier:
nft_offload_exit(); nft_offload_exit();
err5: err_offload:
rhltable_destroy(&nft_objname_ht); rhltable_destroy(&nft_objname_ht);
err4: err_rht_objname:
unregister_netdevice_notifier(&nf_tables_flowtable_notifier); unregister_netdevice_notifier(&nf_tables_flowtable_notifier);
err3: err_netdev_notifier:
nf_tables_core_module_exit(); nf_tables_core_module_exit();
err2: err_core_module:
nft_chain_filter_fini(); nft_chain_filter_fini();
err1: err_chain_filter:
unregister_pernet_subsys(&nf_tables_net_ops); unregister_pernet_subsys(&nf_tables_net_ops);
return err; return err;
} }
...@@ -9140,6 +9220,7 @@ static int __init nf_tables_module_init(void) ...@@ -9140,6 +9220,7 @@ static int __init nf_tables_module_init(void)
static void __exit nf_tables_module_exit(void) static void __exit nf_tables_module_exit(void)
{ {
nfnetlink_subsys_unregister(&nf_tables_subsys); nfnetlink_subsys_unregister(&nf_tables_subsys);
netlink_unregister_notifier(&nft_nl_notifier);
nft_offload_exit(); nft_offload_exit();
unregister_netdevice_notifier(&nf_tables_flowtable_notifier); unregister_netdevice_notifier(&nf_tables_flowtable_notifier);
nft_chain_filter_fini(); nft_chain_filter_fini();
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment