summaryrefslogtreecommitdiffstats
path: root/iptables.c
diff options
context:
space:
mode:
authorJan Engelhardt <jengelh@medozas.de>2009-10-27 02:59:33 +0100
committerJan Engelhardt <jengelh@medozas.de>2009-10-29 19:04:00 +0100
commit4f0d7b660e0ae8f678142fd2a1722b27ad472169 (patch)
treeecd74d135b8d32ecdae966b08ef5e371bc99c84f /iptables.c
parent7c4d668c9c2ee007c82063b7fc784cbbf46b2ec4 (diff)
iptables: fix undersized deletion mask creation
The mask created for the -D rulespec is simply too small. xtables_targets points to whatever target has last been loaded, so xtables_targets->size is quite almost wrong, as we need to use the size of the target for the specific rule that is about to be deleted. This bug existed ever since iptables history is tracked, and requires certain circumstances to be visible, where the deletion operation is one. Furthermore, multiple userspace target extensions must have been loaded, and a target B whose .size is smaller than the target A of the rule we are about to delete must have been loaded more recently than target A. The minimal testcase is (rule 60007 gets wrongly removed) *nat -F -X -A POSTROUTING -p udp -j SNAT --to 192.168.1.1:60007 -A POSTROUTING -p udp -j SNAT --to 192.168.1.1:60008 -A POSTROUTING -p udp -j CONNMARK --set-mark 0 -D POSTROUTING -p udp -j SNAT --to 192.168.1.1:60008 COMMIT References: http://bugzilla.netfilter.org/show_bug.cgi?id=606 Signed-off-by: Jan Engelhardt <jengelh@medozas.de>
Diffstat (limited to 'iptables.c')
-rw-r--r--iptables.c14
1 files changed, 8 insertions, 6 deletions
diff --git a/iptables.c b/iptables.c
index 72287218..11601719 100644
--- a/iptables.c
+++ b/iptables.c
@@ -805,7 +805,8 @@ insert_entry(const ipt_chainlabel chain,
}
static unsigned char *
-make_delete_mask(struct xtables_rule_match *matches)
+make_delete_mask(struct xtables_rule_match *matches,
+ const struct xtables_target *target)
{
/* Establish mask for comparison */
unsigned int size;
@@ -818,7 +819,7 @@ make_delete_mask(struct xtables_rule_match *matches)
mask = xtables_calloc(1, size
+ IPT_ALIGN(sizeof(struct ipt_entry_target))
- + xtables_targets->size);
+ + target->size);
memset(mask, 0xFF, sizeof(struct ipt_entry));
mptr = mask + sizeof(struct ipt_entry);
@@ -832,7 +833,7 @@ make_delete_mask(struct xtables_rule_match *matches)
memset(mptr, 0xFF,
IPT_ALIGN(sizeof(struct ipt_entry_target))
- + xtables_targets->userspacesize);
+ + target->userspacesize);
return mask;
}
@@ -848,13 +849,14 @@ delete_entry(const ipt_chainlabel chain,
const struct in_addr dmasks[],
int verbose,
struct iptc_handle *handle,
- struct xtables_rule_match *matches)
+ struct xtables_rule_match *matches,
+ const struct xtables_target *target)
{
unsigned int i, j;
int ret = 1;
unsigned char *mask;
- mask = make_delete_mask(matches);
+ mask = make_delete_mask(matches, target);
for (i = 0; i < nsaddrs; i++) {
fw->ip.src.s_addr = saddrs[i].s_addr;
fw->ip.smsk.s_addr = smasks[i].s_addr;
@@ -1979,7 +1981,7 @@ int do_command(int argc, char *argv[], char **table, struct iptc_handle **handle
nsaddrs, saddrs, smasks,
ndaddrs, daddrs, dmasks,
options&OPT_VERBOSE,
- *handle, matches);
+ *handle, matches, target);
break;
case CMD_DELETE_NUM:
ret = iptc_delete_num_entry(chain, rulenum - 1, *handle);