mirror of
https://github.com/tbsdtv/linux_media.git
synced 2025-07-23 12:43:29 +02:00
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: David S. Miller <davem@davemloft.net>
This commit is contained in:
@@ -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 {
|
|||||||
*/
|
*/
|
||||||
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 {
|
|||||||
* @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 {
|
|||||||
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,
|
|||||||
|
|
||||||
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,8 +519,13 @@ 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,
|
|||||||
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,
|
|||||||
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)
|
|||||||
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,
|
|||||||
|
|
||||||
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,
|
|||||||
|
|
||||||
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,
|
|||||||
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)
|
|||||||
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,
|
|||||||
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,
|
|||||||
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,
|
|||||||
|
|
||||||
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,
|
|||||||
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,
|
|||||||
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,
|
|||||||
|
|
||||||
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,
|
|||||||
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,
|
|||||||
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,
|
|||||||
|
|
||||||
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,
|
|||||||
|
|
||||||
/* 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,
|
|||||||
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,
|
|||||||
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,
|
|||||||
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,
|
|||||||
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,
|
|||||||
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,
|
|||||||
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,
|
|||||||
!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,
|
|||||||
!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,
|
|||||||
(!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,
|
|||||||
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,
|
|||||||
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,
|
|||||||
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)
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(__nft_release_basechain);
|
EXPORT_SYMBOL_GPL(__nft_release_basechain);
|
||||||
|
|
||||||
|
static void __nft_release_hook(struct net *net, struct nft_table *table)
|
||||||
|
{
|
||||||
|
struct nft_chain *chain;
|
||||||
|
|
||||||
|
list_for_each_entry(chain, &table->chains, list)
|
||||||
|
nf_tables_unregister_hook(net, table, chain);
|
||||||
|
}
|
||||||
|
|
||||||
static void __nft_release_hooks(struct net *net)
|
static void __nft_release_hooks(struct net *net)
|
||||||
{
|
{
|
||||||
struct nft_table *table;
|
struct nft_table *table;
|
||||||
struct nft_chain *chain;
|
|
||||||
|
|
||||||
list_for_each_entry(table, &net->nft.tables, list) {
|
list_for_each_entry(table, &net->nft.tables, list)
|
||||||
list_for_each_entry(chain, &table->chains, list)
|
__nft_release_hook(net, table);
|
||||||
nf_tables_unregister_hook(net, table, chain);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __nft_release_tables(struct net *net)
|
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,43 +9038,90 @@ static void __nft_release_tables(struct net *net)
|
|||||||
.family = NFPROTO_NETDEV,
|
.family = NFPROTO_NETDEV,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
ctx.family = table->family;
|
||||||
|
ctx.table = table;
|
||||||
|
list_for_each_entry(chain, &table->chains, list) {
|
||||||
|
ctx.chain = chain;
|
||||||
|
list_for_each_entry_safe(rule, nr, &chain->rules, list) {
|
||||||
|
list_del(&rule->list);
|
||||||
|
chain->use--;
|
||||||
|
nf_tables_rule_release(&ctx, rule);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
list_for_each_entry_safe(flowtable, nf, &table->flowtables, list) {
|
||||||
|
list_del(&flowtable->list);
|
||||||
|
table->use--;
|
||||||
|
nf_tables_flowtable_destroy(flowtable);
|
||||||
|
}
|
||||||
|
list_for_each_entry_safe(set, ns, &table->sets, list) {
|
||||||
|
list_del(&set->list);
|
||||||
|
table->use--;
|
||||||
|
nft_set_destroy(&ctx, set);
|
||||||
|
}
|
||||||
|
list_for_each_entry_safe(obj, ne, &table->objects, list) {
|
||||||
|
nft_obj_del(obj);
|
||||||
|
table->use--;
|
||||||
|
nft_obj_destroy(&ctx, obj);
|
||||||
|
}
|
||||||
|
list_for_each_entry_safe(chain, nc, &table->chains, list) {
|
||||||
|
ctx.chain = chain;
|
||||||
|
nft_chain_del(chain);
|
||||||
|
table->use--;
|
||||||
|
nf_tables_chain_destroy(&ctx);
|
||||||
|
}
|
||||||
|
list_del(&table->list);
|
||||||
|
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) {
|
list_for_each_entry_safe(table, nt, &net->nft.tables, list) {
|
||||||
ctx.family = table->family;
|
if (nft_table_has_owner(table) &&
|
||||||
ctx.table = table;
|
nlpid != table->nlpid)
|
||||||
list_for_each_entry(chain, &table->chains, list) {
|
continue;
|
||||||
ctx.chain = chain;
|
|
||||||
list_for_each_entry_safe(rule, nr, &chain->rules, list) {
|
__nft_release_table(net, table);
|
||||||
list_del(&rule->list);
|
|
||||||
chain->use--;
|
|
||||||
nf_tables_rule_release(&ctx, rule);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
list_for_each_entry_safe(flowtable, nf, &table->flowtables, list) {
|
|
||||||
list_del(&flowtable->list);
|
|
||||||
table->use--;
|
|
||||||
nf_tables_flowtable_destroy(flowtable);
|
|
||||||
}
|
|
||||||
list_for_each_entry_safe(set, ns, &table->sets, list) {
|
|
||||||
list_del(&set->list);
|
|
||||||
table->use--;
|
|
||||||
nft_set_destroy(&ctx, set);
|
|
||||||
}
|
|
||||||
list_for_each_entry_safe(obj, ne, &table->objects, list) {
|
|
||||||
nft_obj_del(obj);
|
|
||||||
table->use--;
|
|
||||||
nft_obj_destroy(&ctx, obj);
|
|
||||||
}
|
|
||||||
list_for_each_entry_safe(chain, nc, &table->chains, list) {
|
|
||||||
ctx.chain = chain;
|
|
||||||
nft_chain_del(chain);
|
|
||||||
table->use--;
|
|
||||||
nf_tables_chain_destroy(&ctx);
|
|
||||||
}
|
|
||||||
list_del(&table->list);
|
|
||||||
nf_tables_table_destroy(&ctx);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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)
|
|||||||
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)
|
|||||||
|
|
||||||
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 @@ err1:
|
|||||||
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();
|
||||||
|
Reference in New Issue
Block a user