Commit a51b9199 authored by Jozsef Kadlecsik's avatar Jozsef Kadlecsik Committed by Pablo Neira Ayuso

netfilter: ipset: Alignment problem between 64bit kernel 32bit userspace

Sven-Haegar Koch reported the issue:

sims:~# iptables -A OUTPUT -m set --match-set testset src -j ACCEPT
iptables: Invalid argument. Run `dmesg' for more information.

In syslog:
x_tables: ip_tables: set.3 match: invalid size 48 (kernel) != (user) 32

which was introduced by the counter extension in ipset.

The patch fixes the alignment issue with introducing a new set match
revision with the fixed underlying 'struct ip_set_counter_match'
structure.
Signed-off-by: default avatarJozsef Kadlecsik <kadlec@blackhole.kfki.hu>
Signed-off-by: default avatarPablo Neira Ayuso <pablo@netfilter.org>
parent 86ac79c7
...@@ -256,11 +256,17 @@ enum { ...@@ -256,11 +256,17 @@ enum {
IPSET_COUNTER_GT, IPSET_COUNTER_GT,
}; };
struct ip_set_counter_match { /* Backward compatibility for set match v3 */
struct ip_set_counter_match0 {
__u8 op; __u8 op;
__u64 value; __u64 value;
}; };
struct ip_set_counter_match {
__aligned_u64 value;
__u8 op;
};
/* Interface to iptables/ip6tables */ /* Interface to iptables/ip6tables */
#define SO_IP_SET 83 #define SO_IP_SET 83
......
...@@ -66,8 +66,8 @@ struct xt_set_info_target_v2 { ...@@ -66,8 +66,8 @@ struct xt_set_info_target_v2 {
struct xt_set_info_match_v3 { struct xt_set_info_match_v3 {
struct xt_set_info match_set; struct xt_set_info match_set;
struct ip_set_counter_match packets; struct ip_set_counter_match0 packets;
struct ip_set_counter_match bytes; struct ip_set_counter_match0 bytes;
__u32 flags; __u32 flags;
}; };
...@@ -81,4 +81,13 @@ struct xt_set_info_target_v3 { ...@@ -81,4 +81,13 @@ struct xt_set_info_target_v3 {
__u32 timeout; __u32 timeout;
}; };
/* Revision 4 match */
struct xt_set_info_match_v4 {
struct xt_set_info match_set;
struct ip_set_counter_match packets;
struct ip_set_counter_match bytes;
__u32 flags;
};
#endif /*_XT_SET_H*/ #endif /*_XT_SET_H*/
...@@ -157,7 +157,7 @@ set_match_v1_destroy(const struct xt_mtdtor_param *par) ...@@ -157,7 +157,7 @@ set_match_v1_destroy(const struct xt_mtdtor_param *par)
/* Revision 3 match */ /* Revision 3 match */
static bool static bool
match_counter(u64 counter, const struct ip_set_counter_match *info) match_counter0(u64 counter, const struct ip_set_counter_match0 *info)
{ {
switch (info->op) { switch (info->op) {
case IPSET_COUNTER_NONE: case IPSET_COUNTER_NONE:
...@@ -192,14 +192,60 @@ set_match_v3(const struct sk_buff *skb, struct xt_action_param *par) ...@@ -192,14 +192,60 @@ set_match_v3(const struct sk_buff *skb, struct xt_action_param *par)
if (!(ret && opt.cmdflags & IPSET_FLAG_MATCH_COUNTERS)) if (!(ret && opt.cmdflags & IPSET_FLAG_MATCH_COUNTERS))
return ret; return ret;
if (!match_counter(opt.ext.packets, &info->packets)) if (!match_counter0(opt.ext.packets, &info->packets))
return 0; return 0;
return match_counter(opt.ext.bytes, &info->bytes); return match_counter0(opt.ext.bytes, &info->bytes);
} }
#define set_match_v3_checkentry set_match_v1_checkentry #define set_match_v3_checkentry set_match_v1_checkentry
#define set_match_v3_destroy set_match_v1_destroy #define set_match_v3_destroy set_match_v1_destroy
/* Revision 4 match */
static bool
match_counter(u64 counter, const struct ip_set_counter_match *info)
{
switch (info->op) {
case IPSET_COUNTER_NONE:
return true;
case IPSET_COUNTER_EQ:
return counter == info->value;
case IPSET_COUNTER_NE:
return counter != info->value;
case IPSET_COUNTER_LT:
return counter < info->value;
case IPSET_COUNTER_GT:
return counter > info->value;
}
return false;
}
static bool
set_match_v4(const struct sk_buff *skb, struct xt_action_param *par)
{
const struct xt_set_info_match_v4 *info = par->matchinfo;
ADT_OPT(opt, par->family, info->match_set.dim,
info->match_set.flags, info->flags, UINT_MAX);
int ret;
if (info->packets.op != IPSET_COUNTER_NONE ||
info->bytes.op != IPSET_COUNTER_NONE)
opt.cmdflags |= IPSET_FLAG_MATCH_COUNTERS;
ret = match_set(info->match_set.index, skb, par, &opt,
info->match_set.flags & IPSET_INV_MATCH);
if (!(ret && opt.cmdflags & IPSET_FLAG_MATCH_COUNTERS))
return ret;
if (!match_counter(opt.ext.packets, &info->packets))
return 0;
return match_counter(opt.ext.bytes, &info->bytes);
}
#define set_match_v4_checkentry set_match_v1_checkentry
#define set_match_v4_destroy set_match_v1_destroy
/* Revision 0 interface: backward compatible with netfilter/iptables */ /* Revision 0 interface: backward compatible with netfilter/iptables */
static unsigned int static unsigned int
...@@ -573,6 +619,27 @@ static struct xt_match set_matches[] __read_mostly = { ...@@ -573,6 +619,27 @@ static struct xt_match set_matches[] __read_mostly = {
.destroy = set_match_v3_destroy, .destroy = set_match_v3_destroy,
.me = THIS_MODULE .me = THIS_MODULE
}, },
/* new revision for counters support: update, match */
{
.name = "set",
.family = NFPROTO_IPV4,
.revision = 4,
.match = set_match_v4,
.matchsize = sizeof(struct xt_set_info_match_v4),
.checkentry = set_match_v4_checkentry,
.destroy = set_match_v4_destroy,
.me = THIS_MODULE
},
{
.name = "set",
.family = NFPROTO_IPV6,
.revision = 4,
.match = set_match_v4,
.matchsize = sizeof(struct xt_set_info_match_v4),
.checkentry = set_match_v4_checkentry,
.destroy = set_match_v4_destroy,
.me = THIS_MODULE
},
}; };
static struct xt_target set_targets[] __read_mostly = { static struct xt_target set_targets[] __read_mostly = {
......
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