summaryrefslogtreecommitdiffstats
path: root/kernel/ip_set_core.c
diff options
context:
space:
mode:
authorJozsef Kadlecsik <kadlec@blackhole.kfki.hu>2011-01-27 12:44:17 +0100
committerJozsef Kadlecsik <kadlec@blackhole.kfki.hu>2011-01-27 12:44:17 +0100
commitb84145e442d1b8adec11648d09b2b45ccbe31c4e (patch)
tree59c3b8e8fdc76f06c398e7488fd2bbd2c859de2a /kernel/ip_set_core.c
parent9113631680f783fc1a920c3320ba1ed3ca527562 (diff)
Move the type specifici attribute validation to the core
The type specific attribute validation can be moved to the ipset core. That way it's done centrally and thus can be eliminated from the individual set types (suggested by Patrick McHardy).
Diffstat (limited to 'kernel/ip_set_core.c')
-rw-r--r--kernel/ip_set_core.c86
1 files changed, 58 insertions, 28 deletions
diff --git a/kernel/ip_set_core.c b/kernel/ip_set_core.c
index 4392680..bef659a 100644
--- a/kernel/ip_set_core.c
+++ b/kernel/ip_set_core.c
@@ -621,10 +621,11 @@ ip_set_create(struct sock *ctnl, struct sk_buff *skb,
{
struct ip_set *set, *clash;
ip_set_id_t index = IPSET_INVALID_ID;
+ struct nlattr *tb[IPSET_ATTR_CREATE_MAX+1] = {};
const char *name, *typename;
u8 family, revision;
u32 flags = flag_exist(nlh);
- int ret = 0, len;
+ int ret = 0;
if (unlikely(protocol_failed(attr) ||
attr[IPSET_ATTR_SETNAME] == NULL ||
@@ -669,11 +670,16 @@ ip_set_create(struct sock *ctnl, struct sk_buff *skb,
/*
* Without holding any locks, create private part.
*/
- len = attr[IPSET_ATTR_DATA] ? nla_len(attr[IPSET_ATTR_DATA]) : 0;
- pr_debug("data len: %u\n", len);
- ret = set->type->create(set, attr[IPSET_ATTR_DATA] ?
- nla_data(attr[IPSET_ATTR_DATA]) : NULL, len,
- flags);
+ if (attr[IPSET_ATTR_DATA] &&
+ nla_parse(tb, IPSET_ATTR_CREATE_MAX,
+ nla_data(attr[IPSET_ATTR_DATA]),
+ nla_len(attr[IPSET_ATTR_DATA]),
+ set->type->create_policy)) {
+ ret = -IPSET_ERR_PROTOCOL;
+ goto put_out;
+ }
+
+ ret = set->type->create(set, tb, flags);
if (ret != 0)
goto put_out;
@@ -1101,19 +1107,17 @@ static const struct nla_policy ip_set_adt_policy[IPSET_ATTR_CMD_MAX + 1] = {
};
static int
-call_ad(struct sk_buff *skb, const struct nlattr *const attr[],
- struct ip_set *set, const struct nlattr *nla,
- enum ipset_adt adt, u32 flags)
+call_ad(struct sk_buff *skb, struct ip_set *set,
+ struct nlattr *tb[], enum ipset_adt adt,
+ u32 flags, bool use_lineno)
{
- struct nlattr *head = nla_data(nla);
- int ret, len = nla_len(nla), retried = 0;
+ int ret, retried = 0;
u32 lineno = 0;
bool eexist = flags & IPSET_FLAG_EXIST;
do {
write_lock_bh(&set->lock);
- ret = set->variant->uadt(set, head, len, adt,
- &lineno, flags);
+ ret = set->variant->uadt(set, tb, adt, &lineno, flags);
write_unlock_bh(&set->lock);
} while (ret == -EAGAIN &&
set->variant->resize &&
@@ -1121,7 +1125,7 @@ call_ad(struct sk_buff *skb, const struct nlattr *const attr[],
if (!ret || (ret == -IPSET_ERR_EXIST && eexist))
return 0;
- if (lineno && attr[IPSET_ATTR_LINENO]) {
+ if (lineno && use_lineno) {
/* Error in restore/batch mode: send back lineno */
struct nlmsghdr *nlh = nlmsg_hdr(skb);
int min_len = NLMSG_SPACE(sizeof(struct nfgenmsg));
@@ -1147,8 +1151,10 @@ ip_set_uadd(struct sock *ctnl, struct sk_buff *skb,
const struct nlattr * const attr[])
{
struct ip_set *set;
+ struct nlattr *tb[IPSET_ATTR_ADT_MAX+1] = {};
const struct nlattr *nla;
u32 flags = flag_exist(nlh);
+ bool use_lineno;
int ret = 0;
if (unlikely(protocol_failed(attr) ||
@@ -1166,18 +1172,27 @@ ip_set_uadd(struct sock *ctnl, struct sk_buff *skb,
if (set == NULL)
return -ENOENT;
+ use_lineno = !!attr[IPSET_ATTR_LINENO];
if (attr[IPSET_ATTR_DATA]) {
- ret = call_ad(skb, attr,
- set, attr[IPSET_ATTR_DATA], IPSET_ADD, flags);
+ if (nla_parse(tb, IPSET_ATTR_ADT_MAX,
+ nla_data(attr[IPSET_ATTR_DATA]),
+ nla_len(attr[IPSET_ATTR_DATA]),
+ set->type->adt_policy))
+ return -IPSET_ERR_PROTOCOL;
+ ret = call_ad(skb, set, tb, IPSET_ADD, flags, use_lineno);
} else {
int nla_rem;
nla_for_each_nested(nla, attr[IPSET_ATTR_ADT], nla_rem) {
+ memset(tb, 0, sizeof(tb));
if (nla_type(nla) != IPSET_ATTR_DATA ||
- !flag_nested(nla))
+ !flag_nested(nla) ||
+ nla_parse(tb, IPSET_ATTR_ADT_MAX,
+ nla_data(nla), nla_len(nla),
+ set->type->adt_policy))
return -IPSET_ERR_PROTOCOL;
- ret = call_ad(skb, attr,
- set, nla, IPSET_ADD, flags);
+ ret = call_ad(skb, set, tb, IPSET_ADD,
+ flags, use_lineno);
if (ret < 0)
return ret;
}
@@ -1191,8 +1206,10 @@ ip_set_udel(struct sock *ctnl, struct sk_buff *skb,
const struct nlattr * const attr[])
{
struct ip_set *set;
+ struct nlattr *tb[IPSET_ATTR_ADT_MAX+1] = {};
const struct nlattr *nla;
u32 flags = flag_exist(nlh);
+ bool use_lineno;
int ret = 0;
if (unlikely(protocol_failed(attr) ||
@@ -1210,18 +1227,27 @@ ip_set_udel(struct sock *ctnl, struct sk_buff *skb,
if (set == NULL)
return -ENOENT;
+ use_lineno = !!attr[IPSET_ATTR_LINENO];
if (attr[IPSET_ATTR_DATA]) {
- ret = call_ad(skb, attr,
- set, attr[IPSET_ATTR_DATA], IPSET_DEL, flags);
+ if (nla_parse(tb, IPSET_ATTR_ADT_MAX,
+ nla_data(attr[IPSET_ATTR_DATA]),
+ nla_len(attr[IPSET_ATTR_DATA]),
+ set->type->adt_policy))
+ return -IPSET_ERR_PROTOCOL;
+ ret = call_ad(skb, set, tb, IPSET_DEL, flags, use_lineno);
} else {
int nla_rem;
nla_for_each_nested(nla, attr[IPSET_ATTR_ADT], nla_rem) {
+ memset(tb, 0, sizeof(*tb));
if (nla_type(nla) != IPSET_ATTR_DATA ||
- !flag_nested(nla))
+ !flag_nested(nla) ||
+ nla_parse(tb, IPSET_ATTR_ADT_MAX,
+ nla_data(nla), nla_len(nla),
+ set->type->adt_policy))
return -IPSET_ERR_PROTOCOL;
- ret = call_ad(skb, attr,
- set, nla, IPSET_DEL, flags);
+ ret = call_ad(skb, set, tb, IPSET_DEL,
+ flags, use_lineno);
if (ret < 0)
return ret;
}
@@ -1235,6 +1261,7 @@ ip_set_utest(struct sock *ctnl, struct sk_buff *skb,
const struct nlattr * const attr[])
{
struct ip_set *set;
+ struct nlattr *tb[IPSET_ATTR_ADT_MAX+1] = {};
int ret = 0;
if (unlikely(protocol_failed(attr) ||
@@ -1247,11 +1274,14 @@ ip_set_utest(struct sock *ctnl, struct sk_buff *skb,
if (set == NULL)
return -ENOENT;
+ if (nla_parse(tb, IPSET_ATTR_ADT_MAX,
+ nla_data(attr[IPSET_ATTR_DATA]),
+ nla_len(attr[IPSET_ATTR_DATA]),
+ set->type->adt_policy))
+ return -IPSET_ERR_PROTOCOL;
+
read_lock_bh(&set->lock);
- ret = set->variant->uadt(set,
- nla_data(attr[IPSET_ATTR_DATA]),
- nla_len(attr[IPSET_ATTR_DATA]),
- IPSET_TEST, NULL, 0);
+ ret = set->variant->uadt(set, tb, IPSET_TEST, NULL, 0);
read_unlock_bh(&set->lock);
/* Userspace can't trigger element to be re-added */
if (ret == -EAGAIN)