connmark: Fix alignment when adding rules

The structs that make up a message sent to the kernel have all to be
aligned with XT_ALIGN.  That was not necessarily the case when
initializing the complete message as struct.

Fixes #1212.
This commit is contained in:
Tobias Brunner
2016-03-03 17:20:09 +01:00
parent efd7fa7be1
commit c4cb652a56
+124 -112
View File
@@ -1,4 +1,7 @@
/* /*
* Copyright (C) 2015 Tobias Brunner
* Hochschule fuer Technik Rapperswil
*
* Copyright (C) 2014 Martin Willi * Copyright (C) 2014 Martin Willi
* Copyright (C) 2014 revosec AG * Copyright (C) 2014 revosec AG
* *
@@ -25,6 +28,14 @@
#include <linux/netfilter/xt_policy.h> #include <linux/netfilter/xt_policy.h>
#include <linux/netfilter/xt_CONNMARK.h> #include <linux/netfilter/xt_CONNMARK.h>
/**
* Add a struct at the current position in the buffer
*/
#define ADD_STRUCT(pos, st, ...) ({\
typeof(pos) _cur = pos; pos += XT_ALIGN(sizeof(st));\
*(st*)_cur = (st){ __VA_ARGS__ };\
(st*)_cur;\
})
typedef struct private_connmark_listener_t private_connmark_listener_t; typedef struct private_connmark_listener_t private_connmark_listener_t;
@@ -108,54 +119,54 @@ static bool manage_pre_esp_in_udp(private_connmark_listener_t *this,
u_int mark, u_int32_t spi, u_int mark, u_int32_t spi,
host_t *dst, host_t *src) host_t *dst, host_t *src)
{ {
struct { u_int16_t match_size = XT_ALIGN(sizeof(struct ipt_entry_match)) +
struct ipt_entry e; XT_ALIGN(sizeof(struct xt_udp));
struct ipt_entry_match m; u_int16_t target_offset = XT_ALIGN(sizeof(struct ipt_entry)) + match_size;
struct xt_udp udp; u_int16_t target_size = XT_ALIGN(sizeof(struct ipt_entry_target)) +
struct ipt_entry_target t; XT_ALIGN(sizeof(struct xt_mark_tginfo2));
struct xt_mark_tginfo2 tm; u_int16_t entry_size = target_offset + target_size;
} ipt = { u_char ipt[entry_size], *pos = ipt;
.e = { struct ipt_entry *e;
.target_offset = XT_ALIGN(sizeof(ipt.e) + sizeof(ipt.m) +
sizeof(ipt.udp)), memset(ipt, 0, sizeof(ipt));
.next_offset = sizeof(ipt), e = ADD_STRUCT(pos, struct ipt_entry,
.target_offset = target_offset,
.next_offset = entry_size,
.ip = { .ip = {
.proto = IPPROTO_UDP, .proto = IPPROTO_UDP,
}, },
}, );
.m = { if (!host2in(dst, &e->ip.dst, &e->ip.dmsk) ||
!host2in(src, &e->ip.src, &e->ip.smsk))
{
return FALSE;
}
ADD_STRUCT(pos, struct ipt_entry_match,
.u = { .u = {
.user = { .user = {
.match_size = XT_ALIGN(sizeof(ipt.m) + sizeof(ipt.udp)), .match_size = match_size,
.name = "udp", .name = "udp",
}, },
}, },
}, );
.udp = { ADD_STRUCT(pos, struct xt_udp,
.spts = { src->get_port(src), src->get_port(src) }, .spts = { src->get_port(src), src->get_port(src) },
.dpts = { dst->get_port(dst), dst->get_port(dst) }, .dpts = { dst->get_port(dst), dst->get_port(dst) },
}, );
.t = { ADD_STRUCT(pos, struct ipt_entry_target,
.u = { .u = {
.user = { .user = {
.target_size = XT_ALIGN(sizeof(ipt.t) + sizeof(ipt.tm)), .target_size = target_size,
.name = "MARK", .name = "MARK",
.revision = 2, .revision = 2,
}, },
}, },
}, );
.tm = { ADD_STRUCT(pos, struct xt_mark_tginfo2,
.mark = mark, .mark = mark,
.mask = ~0, .mask = ~0,
}, );
}; return manage_rule(ipth, "PREROUTING", add, e);
if (!host2in(dst, &ipt.e.ip.dst, &ipt.e.ip.dmsk) ||
!host2in(src, &ipt.e.ip.src, &ipt.e.ip.smsk))
{
return FALSE;
}
return manage_rule(ipth, "PREROUTING", add, &ipt.e);
} }
/** /**
@@ -166,53 +177,53 @@ static bool manage_pre_esp(private_connmark_listener_t *this,
u_int mark, u_int32_t spi, u_int mark, u_int32_t spi,
host_t *dst, host_t *src) host_t *dst, host_t *src)
{ {
struct { u_int16_t match_size = XT_ALIGN(sizeof(struct ipt_entry_match)) +
struct ipt_entry e; XT_ALIGN(sizeof(struct xt_esp));
struct ipt_entry_match m; u_int16_t target_offset = XT_ALIGN(sizeof(struct ipt_entry)) + match_size;
struct xt_esp esp; u_int16_t target_size = XT_ALIGN(sizeof(struct ipt_entry_target)) +
struct ipt_entry_target t; XT_ALIGN(sizeof(struct xt_mark_tginfo2));
struct xt_mark_tginfo2 tm; u_int16_t entry_size = target_offset + target_size;
} ipt = { u_char ipt[entry_size], *pos = ipt;
.e = { struct ipt_entry *e;
.target_offset = XT_ALIGN(sizeof(ipt.e) + sizeof(ipt.m) +
sizeof(ipt.esp)), memset(ipt, 0, sizeof(ipt));
.next_offset = sizeof(ipt), e = ADD_STRUCT(pos, struct ipt_entry,
.target_offset = target_offset,
.next_offset = entry_size,
.ip = { .ip = {
.proto = IPPROTO_ESP, .proto = IPPROTO_ESP,
}, },
}, );
.m = { if (!host2in(dst, &e->ip.dst, &e->ip.dmsk) ||
!host2in(src, &e->ip.src, &e->ip.smsk))
{
return FALSE;
}
ADD_STRUCT(pos, struct ipt_entry_match,
.u = { .u = {
.user = { .user = {
.match_size = XT_ALIGN(sizeof(ipt.m) + sizeof(ipt.esp)), .match_size = match_size,
.name = "esp", .name = "esp",
}, },
}, },
}, );
.esp = { ADD_STRUCT(pos, struct xt_esp,
.spis = { htonl(spi), htonl(spi) }, .spis = { htonl(spi), htonl(spi) },
}, );
.t = { ADD_STRUCT(pos, struct ipt_entry_target,
.u = { .u = {
.user = { .user = {
.target_size = XT_ALIGN(sizeof(ipt.t) + sizeof(ipt.tm)), .target_size = target_size,
.name = "MARK", .name = "MARK",
.revision = 2, .revision = 2,
}, },
}, },
}, );
.tm = { ADD_STRUCT(pos, struct xt_mark_tginfo2,
.mark = mark, .mark = mark,
.mask = ~0, .mask = ~0,
}, );
}; return manage_rule(ipth, "PREROUTING", add, e);
if (!host2in(dst, &ipt.e.ip.dst, &ipt.e.ip.dmsk) ||
!host2in(src, &ipt.e.ip.src, &ipt.e.ip.smsk))
{
return FALSE;
}
return manage_rule(ipth, "PREROUTING", add, &ipt.e);
} }
/** /**
@@ -238,27 +249,34 @@ static bool manage_in(private_connmark_listener_t *this,
u_int mark, u_int32_t spi, u_int mark, u_int32_t spi,
traffic_selector_t *dst, traffic_selector_t *src) traffic_selector_t *dst, traffic_selector_t *src)
{ {
struct { u_int16_t match_size = XT_ALIGN(sizeof(struct ipt_entry_match)) +
struct ipt_entry e; XT_ALIGN(sizeof(struct xt_policy_info));
struct ipt_entry_match m; u_int16_t target_offset = XT_ALIGN(sizeof(struct ipt_entry)) + match_size;
struct xt_policy_info p; u_int16_t target_size = XT_ALIGN(sizeof(struct ipt_entry_target)) +
struct ipt_entry_target t; XT_ALIGN(sizeof(struct xt_connmark_tginfo1));
struct xt_connmark_tginfo1 cm; u_int16_t entry_size = target_offset + target_size;
} ipt = { u_char ipt[entry_size], *pos = ipt;
.e = { struct ipt_entry *e;
.target_offset = XT_ALIGN(sizeof(ipt.e) + sizeof(ipt.m) +
sizeof(ipt.p)), memset(ipt, 0, sizeof(ipt));
.next_offset = sizeof(ipt), e = ADD_STRUCT(pos, struct ipt_entry,
}, .target_offset = target_offset,
.m = { .next_offset = entry_size,
);
if (!ts2in(dst, &e->ip.dst, &e->ip.dmsk) ||
!ts2in(src, &e->ip.src, &e->ip.smsk))
{
return FALSE;
}
ADD_STRUCT(pos, struct ipt_entry_match,
.u = { .u = {
.user = { .user = {
.match_size = XT_ALIGN(sizeof(ipt.m) + sizeof(ipt.p)), .match_size = match_size,
.name = "policy", .name = "policy",
}, },
}, },
}, );
.p = { ADD_STRUCT(pos, struct xt_policy_info,
.pol = { .pol = {
{ {
.spi = spi, .spi = spi,
@@ -267,30 +285,23 @@ static bool manage_in(private_connmark_listener_t *this,
}, },
.len = 1, .len = 1,
.flags = XT_POLICY_MATCH_IN, .flags = XT_POLICY_MATCH_IN,
}, );
.t = { ADD_STRUCT(pos, struct ipt_entry_target,
.u = { .u = {
.user = { .user = {
.target_size = XT_ALIGN(sizeof(ipt.t) + sizeof(ipt.cm)), .target_size = target_size,
.name = "CONNMARK", .name = "CONNMARK",
.revision = 1, .revision = 1,
}, },
}, },
}, );
.cm = { ADD_STRUCT(pos, struct xt_connmark_tginfo1,
.ctmark = mark, .ctmark = mark,
.ctmask = ~0, .ctmask = ~0,
.nfmask = ~0, .nfmask = ~0,
.mode = XT_CONNMARK_SET, .mode = XT_CONNMARK_SET,
}, );
}; return manage_rule(ipth, "INPUT", add, e);
if (!ts2in(dst, &ipt.e.ip.dst, &ipt.e.ip.dmsk) ||
!ts2in(src, &ipt.e.ip.src, &ipt.e.ip.smsk))
{
return FALSE;
}
return manage_rule(ipth, "INPUT", add, &ipt.e);
} }
/** /**
@@ -300,37 +311,38 @@ static bool manage_out(private_connmark_listener_t *this,
struct iptc_handle *ipth, bool add, struct iptc_handle *ipth, bool add,
traffic_selector_t *dst, traffic_selector_t *src) traffic_selector_t *dst, traffic_selector_t *src)
{ {
struct { u_int16_t target_offset = XT_ALIGN(sizeof(struct ipt_entry));
struct ipt_entry e; u_int16_t target_size = XT_ALIGN(sizeof(struct ipt_entry_target)) +
struct ipt_entry_target t; XT_ALIGN(sizeof(struct xt_connmark_tginfo1));
struct xt_connmark_tginfo1 cm; u_int16_t entry_size = target_offset + target_size;
} ipt = { u_char ipt[entry_size], *pos = ipt;
.e = { struct ipt_entry *e;
.target_offset = XT_ALIGN(sizeof(ipt.e)),
.next_offset = sizeof(ipt), memset(ipt, 0, sizeof(ipt));
}, e = ADD_STRUCT(pos, struct ipt_entry,
.t = { .target_offset = target_offset,
.next_offset = entry_size,
);
if (!ts2in(dst, &e->ip.dst, &e->ip.dmsk) ||
!ts2in(src, &e->ip.src, &e->ip.smsk))
{
return FALSE;
}
ADD_STRUCT(pos, struct ipt_entry_target,
.u = { .u = {
.user = { .user = {
.target_size = XT_ALIGN(sizeof(ipt.t) + sizeof(ipt.cm)), .target_size = target_size,
.name = "CONNMARK", .name = "CONNMARK",
.revision = 1, .revision = 1,
}, },
}, },
}, );
.cm = { ADD_STRUCT(pos, struct xt_connmark_tginfo1,
.ctmask = ~0, .ctmask = ~0,
.nfmask = ~0, .nfmask = ~0,
.mode = XT_CONNMARK_RESTORE, .mode = XT_CONNMARK_RESTORE,
}, );
}; return manage_rule(ipth, "OUTPUT", add, e);
if (!ts2in(dst, &ipt.e.ip.dst, &ipt.e.ip.dmsk) ||
!ts2in(src, &ipt.e.ip.src, &ipt.e.ip.smsk))
{
return FALSE;
}
return manage_rule(ipth, "OUTPUT", add, &ipt.e);
} }
/** /**