From 228e98dd6303af11925235af4cf3c3ec450f3f41 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Thu, 27 Apr 2000 10:28:06 +0000 Subject: Alignment fixes (requires kernel patch). --- extensions/libipt_DNAT.c | 2 +- extensions/libipt_SNAT.c | 2 +- include/libiptc/libiptc.h | 8 +++- iptables.c | 64 ++++++++++++++++-------------- libiptc/libiptc.c | 99 +++++++++++++++++++++++++---------------------- 5 files changed, 95 insertions(+), 80 deletions(-) diff --git a/extensions/libipt_DNAT.c b/extensions/libipt_DNAT.c index 6251cf1c..af08cc0a 100644 --- a/extensions/libipt_DNAT.c +++ b/extensions/libipt_DNAT.c @@ -53,7 +53,7 @@ append_range(struct ipt_natinfo *info, const struct ip_nat_range *range) if (!info) exit_error(OTHER_PROBLEM, "Out of memory\n"); - info->t.target_size = size; + info->t.u.target_size = size; info->mr.range[info->mr.rangesize] = *range; info->mr.rangesize++; diff --git a/extensions/libipt_SNAT.c b/extensions/libipt_SNAT.c index f769cd4e..e1d27523 100644 --- a/extensions/libipt_SNAT.c +++ b/extensions/libipt_SNAT.c @@ -53,7 +53,7 @@ append_range(struct ipt_natinfo *info, const struct ip_nat_range *range) if (!info) exit_error(OTHER_PROBLEM, "Out of memory\n"); - info->t.target_size = size; + info->t.u.target_size = size; info->mr.range[info->mr.rangesize] = *range; info->mr.rangesize++; diff --git a/include/libiptc/libiptc.h b/include/libiptc/libiptc.h index 9058cffc..fa0a4eaf 100644 --- a/include/libiptc/libiptc.h +++ b/include/libiptc/libiptc.h @@ -6,9 +6,13 @@ #include #ifndef IPT_MIN_ALIGN -#define IPT_MIN_ALIGN (__alignof__(struct ipt_entry_match)) +/* ipt_entry has pointers and u_int64_t's in it, so if you align to + it, you'll also align to any crazy matches and targets someone + might write */ +#define IPT_MIN_ALIGN (__alignof__(struct ipt_entry)) #endif -#define IPT_ALIGN(s) (((s) + (IPT_MIN_ALIGN-1)) & ~(IPT_MIN_ALIGN-1)) + +#define IPT_ALIGN(s) (((s) + ((IPT_MIN_ALIGN)-1)) & ~((IPT_MIN_ALIGN)-1)) typedef char ipt_chainlabel[32]; diff --git a/iptables.c b/iptables.c index c4846fd9..eab710e8 100644 --- a/iptables.c +++ b/iptables.c @@ -1014,14 +1014,14 @@ print_match(const struct ipt_entry_match *m, const struct ipt_ip *ip, int numeric) { - struct iptables_match *match = find_match(m->u.name, 1); + struct iptables_match *match = find_match(m->u.user.name, 1); if (match) { if (match->print) match->print(ip, m, numeric); } else { - if (m->u.name[0]) - printf("UNKNOWN match `%s' ", m->u.name); + if (m->u.user.name[0]) + printf("UNKNOWN match `%s' ", m->u.user.name); } /* Don't stop iterating. */ return 0; @@ -1150,9 +1150,9 @@ print_firewall(const struct ipt_entry *fw, if (target->print) /* Print the target information. */ target->print(&fw->ip, t, format & FMT_NUMERIC); - } else if (t->target_size != sizeof(*t)) + } else if (t->u.target_size != sizeof(*t)) printf("[%u bytes of unknown target data] ", - t->target_size - sizeof(*t)); + t->u.target_size - sizeof(*t)); if (!(format & FMT_NONEWLINE)) fputc('\n', stdout); @@ -1165,7 +1165,7 @@ print_firewall_line(const struct ipt_entry *fw, struct ipt_entry_target *t; t = ipt_get_target((struct ipt_entry *)fw); - print_firewall(fw, t->u.name, 0, FMT_PRINT_RULE, h); + print_firewall(fw, t->u.user.name, 0, FMT_PRINT_RULE, h); } static int @@ -1462,19 +1462,19 @@ generate_entry(const struct ipt_entry *fw, size = sizeof(struct ipt_entry); for (m = matches; m; m = m->next) - size += m->m->match_size; + size += m->m->u.match_size; - e = fw_malloc(size + target->target_size); + e = fw_malloc(size + target->u.target_size); *e = *fw; e->target_offset = size; - e->next_offset = size + target->target_size; + e->next_offset = size + target->u.target_size; size = 0; for (m = matches; m; m = m->next) { - memcpy(e->elems + size, m->m, m->m->match_size); - size += m->m->match_size; + memcpy(e->elems + size, m->m, m->m->u.match_size); + size += m->m->u.match_size; } - memcpy(e->elems + size, target, target->target_size); + memcpy(e->elems + size, target, target->u.target_size); return e; } @@ -1678,12 +1678,14 @@ int do_command(int argc, char *argv[], char **table, iptc_handle_t *handle) target = find_target(jumpto, 1); if (target) { - size_t size = sizeof(struct ipt_entry_target) - + IPT_ALIGN(target->size); + size_t size; + + size = IPT_ALIGN(sizeof(struct ipt_entry_target) + + target->size); target->t = fw_calloc(1, size); - target->t->target_size = size; - strcpy(target->t->u.name, jumpto); + target->t->u.target_size = size; + strcpy(target->t->u.user.name, jumpto); target->init(target->t, &fw.nfcache); } break; @@ -1735,11 +1737,13 @@ int do_command(int argc, char *argv[], char **table, iptc_handle_t *handle) exit_error(PARAMETER_PROBLEM, "Couldn't load match `%s'", optarg); else { - size_t size = sizeof(struct ipt_entry_match) - + IPT_ALIGN(m->size); + size_t size; + + size = IPT_ALIGN(sizeof(struct ipt_entry_match) + + m->size); m->m = fw_calloc(1, size); - m->m->match_size = size; - strcpy(m->m->u.name, optarg); + m->m->u.match_size = size; + strcpy(m->m->u.user.name, optarg); m->init(m->m, &fw.nfcache); } break; @@ -1812,12 +1816,14 @@ int do_command(int argc, char *argv[], char **table, iptc_handle_t *handle) && !find_match(protocol, 0) && (m = find_match(protocol, 1))) { /* Try loading protocol */ - size_t size = sizeof(struct ipt_entry_match) - + IPT_ALIGN(m->size); + size_t size; + + size = IPT_ALIGN(sizeof(struct ipt_entry_match) + + m->size); m->m = fw_calloc(1, size); - m->m->match_size = size; - strcpy(m->m->u.name, protocol); + m->m->u.match_size = size; + strcpy(m->m->u.user.name, protocol); m->init(m->m, &fw.nfcache); optind--; @@ -1935,10 +1941,10 @@ int do_command(int argc, char *argv[], char **table, iptc_handle_t *handle) "Can't find standard target\n"); size = sizeof(struct ipt_entry_target) - + IPT_ALIGN(target->size); + + target->size; target->t = fw_calloc(1, size); - target->t->target_size = size; - strcpy(target->t->u.name, jumpto); + target->t->u.target_size = size; + strcpy(target->t->u.user.name, jumpto); target->init(target->t, &fw.nfcache); } @@ -1947,8 +1953,8 @@ int do_command(int argc, char *argv[], char **table, iptc_handle_t *handle) /* Don't know it. Must be extension with no options? */ - unknown_target.target_size = sizeof(unknown_target); - strcpy(unknown_target.u.name, jumpto); + unknown_target.u.target_size = sizeof(unknown_target); + strcpy(unknown_target.u.user.name, jumpto); e = generate_entry(&fw, iptables_matches, &unknown_target); diff --git a/libiptc/libiptc.c b/libiptc/libiptc.c index fee3a042..019de66f 100644 --- a/libiptc/libiptc.c +++ b/libiptc/libiptc.c @@ -199,7 +199,7 @@ get_errorlabel(iptc_handle_t h, unsigned int offset) struct ipt_entry *e; e = get_entry(h, offset); - if (strcmp(ipt_get_target(e)->u.name, IPT_ERROR_TARGET) != 0) { + if (strcmp(ipt_get_target(e)->u.user.name, IPT_ERROR_TARGET) != 0) { fprintf(stderr, "ERROR: offset %u not an error node!\n", offset); abort(); @@ -313,7 +313,7 @@ iptc_init(const char *tablename) static inline int print_match(const struct ipt_entry_match *m) { - printf("Match name: `%s'\n", m->u.name); + printf("Match name: `%s'\n", m->u.user.name); return 0; } @@ -359,8 +359,8 @@ dump_entry(struct ipt_entry *e, const iptc_handle_t handle) IPT_MATCH_ITERATE(e, print_match); t = ipt_get_target(e); - printf("Target name: `%s' [%u]\n", t->u.name, t->target_size); - if (strcmp(t->u.name, IPT_STANDARD_TARGET) == 0) { + printf("Target name: `%s' [%u]\n", t->u.user.name, t->u.target_size); + if (strcmp(t->u.user.name, IPT_STANDARD_TARGET) == 0) { int pos = *(int *)t->data; if (pos < 0) printf("verdict=%s\n", @@ -371,7 +371,7 @@ dump_entry(struct ipt_entry *e, const iptc_handle_t handle) : "UNKNOWN"); else printf("verdict=%u\n", pos); - } else if (strcmp(t->u.name, IPT_ERROR_TARGET) == 0) + } else if (strcmp(t->u.user.name, IPT_ERROR_TARGET) == 0) printf("error=`%s'\n", t->data); printf("\n"); @@ -432,7 +432,7 @@ add_chain(struct ipt_entry *e, iptc_handle_t h, struct ipt_entry **prev) /* We know this is the start of a new chain if it's an ERROR target, or a hook entry point */ - if (strcmp(ipt_get_target(e)->u.name, IPT_ERROR_TARGET) == 0) { + if (strcmp(ipt_get_target(e)->u.user.name, IPT_ERROR_TARGET) == 0) { /* prev was last entry in previous chain */ h->cache_chain_heads[h->cache_num_chains-1].end = *prev; @@ -551,7 +551,7 @@ get_chain_end(const iptc_handle_t handle, unsigned int start) /* We hit a user chain label */ t = ipt_get_target(e); - if (strcmp(t->u.name, IPT_ERROR_TARGET) == 0) + if (strcmp(t->u.user.name, IPT_ERROR_TARGET) == 0) return last_off; } /* SHOULD NEVER HAPPEN */ @@ -667,8 +667,8 @@ target_name(iptc_handle_t handle, const struct ipt_entry *ce) /* To avoid const warnings */ struct ipt_entry *e = (struct ipt_entry *)ce; - if (strcmp(ipt_get_target(e)->u.name, IPT_STANDARD_TARGET) != 0) - return ipt_get_target(e)->u.name; + if (strcmp(ipt_get_target(e)->u.user.name, IPT_STANDARD_TARGET) != 0) + return ipt_get_target(e)->u.user.name; /* Standard target: evaluate */ spos = *(int *)ipt_get_target(e)->data; @@ -753,7 +753,7 @@ correct_verdict(struct ipt_entry *e, /* Trap: insert of fall-through rule. Don't change fall-through verdict to jump-over-next-rule. */ - if (strcmp(t->target.u.name, IPT_STANDARD_TARGET) == 0 + if (strcmp(t->target.u.user.name, IPT_STANDARD_TARGET) == 0 && t->verdict > (int)offset && !(curr == offset && t->verdict == curr + e->next_offset)) { @@ -914,13 +914,13 @@ standard_map(struct ipt_entry *e, int verdict) t = (struct ipt_standard_target *)ipt_get_target(e); - if (t->target.target_size != IPT_ALIGN(sizeof(struct ipt_standard_target))) { + if (t->target.u.target_size != sizeof(struct ipt_standard_target)) { errno = EINVAL; return 0; } /* memset for memcmp convenience on delete/replace */ - memset(t->target.u.name, 0, IPT_FUNCTION_MAXNAMELEN); - strcpy(t->target.u.name, IPT_STANDARD_TARGET); + memset(t->target.u.user.name, 0, IPT_FUNCTION_MAXNAMELEN); + strcpy(t->target.u.user.name, IPT_STANDARD_TARGET); t->verdict = verdict; return 1; @@ -939,18 +939,18 @@ map_target(const iptc_handle_t handle, *old = *t; /* Maybe it's empty (=> fall through) */ - if (strcmp(t->u.name, "") == 0) + if (strcmp(t->u.user.name, "") == 0) return standard_map(e, offset + e->next_offset); /* Maybe it's a standard target name... */ - else if (strcmp(t->u.name, IPTC_LABEL_ACCEPT) == 0) + else if (strcmp(t->u.user.name, IPTC_LABEL_ACCEPT) == 0) return standard_map(e, -NF_ACCEPT - 1); - else if (strcmp(t->u.name, IPTC_LABEL_DROP) == 0) + else if (strcmp(t->u.user.name, IPTC_LABEL_DROP) == 0) return standard_map(e, -NF_DROP - 1); - else if (strcmp(t->u.name, IPTC_LABEL_QUEUE) == 0) + else if (strcmp(t->u.user.name, IPTC_LABEL_QUEUE) == 0) return standard_map(e, -NF_QUEUE - 1); - else if (strcmp(t->u.name, IPTC_LABEL_RETURN) == 0) + else if (strcmp(t->u.user.name, IPTC_LABEL_RETURN) == 0) return standard_map(e, IPT_RETURN); - else if (iptc_builtin(t->u.name, handle)) { + else if (iptc_builtin(t->u.user.name, handle)) { /* Can't jump to builtins. */ errno = EINVAL; return 0; @@ -958,16 +958,16 @@ map_target(const iptc_handle_t handle, /* Maybe it's an existing chain name. */ struct chain_cache *c; - c = find_label(t->u.name, handle); + c = find_label(t->u.user.name, handle); if (c) return standard_map(e, entry2offset(handle, c->start)); } /* Must be a module? If not, kernel will reject... */ /* memset to all 0 for your memcmp convenience. */ - memset(t->u.name + strlen(t->u.name), + memset(t->u.user.name + strlen(t->u.user.name), 0, - IPT_FUNCTION_MAXNAMELEN - strlen(t->u.name)); + IPT_FUNCTION_MAXNAMELEN - strlen(t->u.user.name)); return 1; } @@ -1100,15 +1100,15 @@ match_different(const struct ipt_entry_match *a, /* Offset of b is the same as a. */ b = (void *)b_elems + ((unsigned char *)a - a_elems); - if (a->match_size != b->match_size) + if (a->u.match_size != b->u.match_size) return 1; - if (strcmp(a->u.name, b->u.name) != 0) + if (strcmp(a->u.user.name, b->u.user.name) != 0) return 1; *maskptr += sizeof(*a); - for (i = 0; i < a->match_size - sizeof(*a); i++) + for (i = 0; i < a->u.match_size - sizeof(*a); i++) if (((a->data[i] ^ b->data[i]) & (*maskptr)[i]) != 0) return 1; *maskptr += i; @@ -1171,14 +1171,14 @@ is_same(const struct ipt_entry *a, const struct ipt_entry *b, ta = ipt_get_target((struct ipt_entry *)a); tb = ipt_get_target((struct ipt_entry *)b); - if (ta->target_size != tb->target_size) + if (ta->u.target_size != tb->u.target_size) return 0; - if (strcmp(ta->u.name, tb->u.name) != 0) + if (strcmp(ta->u.user.name, tb->u.user.name) != 0) return 0; mptr += sizeof(*ta); if (target_different(ta->data, tb->data, - ta->target_size - sizeof(*ta), mptr)) + ta->u.target_size - sizeof(*ta), mptr)) return 0; return 1; @@ -1369,15 +1369,15 @@ iptc_create_chain(const ipt_chainlabel chain, iptc_handle_t *handle) newc.head.target_offset = sizeof(struct ipt_entry); newc.head.next_offset = sizeof(struct ipt_entry) + sizeof(struct ipt_error_target); - strcpy(newc.name.t.u.name, IPT_ERROR_TARGET); - newc.name.t.target_size = sizeof(struct ipt_error_target); + strcpy(newc.name.t.u.user.name, IPT_ERROR_TARGET); + newc.name.t.u.target_size = sizeof(struct ipt_error_target); strcpy(newc.name.error, chain); newc.ret.target_offset = sizeof(struct ipt_entry); newc.ret.next_offset = sizeof(struct ipt_entry)+sizeof(struct ipt_standard_target); - strcpy(newc.target.target.u.name, IPT_STANDARD_TARGET); - newc.target.target.target_size = sizeof(struct ipt_standard_target); + strcpy(newc.target.target.u.user.name, IPT_STANDARD_TARGET); + newc.target.target.u.target_size = sizeof(struct ipt_standard_target); newc.target.verdict = IPT_RETURN; /* Add just before terminal entry */ @@ -1393,7 +1393,7 @@ count_ref(struct ipt_entry *e, unsigned int offset, unsigned int *ref) { struct ipt_standard_target *t; - if (strcmp(ipt_get_target(e)->u.name, IPT_STANDARD_TARGET) == 0) { + if (strcmp(ipt_get_target(e)->u.user.name, IPT_STANDARD_TARGET) == 0) { t = (struct ipt_standard_target *)ipt_get_target(e); if (t->verdict == offset) @@ -1765,9 +1765,10 @@ unconditional(const struct ipt_ip *ip) static inline int check_match(const struct ipt_entry_match *m, unsigned int *off) { - assert(m->match_size >= sizeof(struct ipt_entry_match)); + assert(m->u.match_size >= sizeof(struct ipt_entry_match)); + assert(IPT_ALIGN(m->u.match_size) == m->u.match_size); - (*off) += m->match_size; + (*off) += m->u.match_size; return 0; } @@ -1789,11 +1790,14 @@ check_entry(const struct ipt_entry *e, unsigned int *i, unsigned int *off, t = (struct ipt_standard_target *) ipt_get_target((struct ipt_entry *)e); - assert(t->target.target_size == e->next_offset - e->target_offset); - assert(!iptc_is_chain(t->target.u.name, h)); - - if (strcmp(t->target.u.name, IPT_STANDARD_TARGET) == 0) { - assert(t->target.target_size + /* next_offset will have to be multiple of entry alignment. */ + assert(e->next_offset == IPT_ALIGN(e->next_offset)); + assert(e->target_offset == IPT_ALIGN(e->target_offset)); + assert(t->target.u.target_size == IPT_ALIGN(t->target.u.target_size)); + assert(!iptc_is_chain(t->target.u.user.name, h)); + + if (strcmp(t->target.u.user.name, IPT_STANDARD_TARGET) == 0) { + assert(t->target.u.target_size == IPT_ALIGN(sizeof(struct ipt_standard_target))); assert(t->verdict == -NF_DROP-1 @@ -1806,7 +1810,7 @@ check_entry(const struct ipt_entry *e, unsigned int *i, unsigned int *off, int idx; idx = entry2index(h, te); - assert(strcmp(ipt_get_target(te)->u.name, + assert(strcmp(ipt_get_target(te)->u.user.name, IPT_ERROR_TARGET) != 0); assert(te != e); @@ -1814,7 +1818,7 @@ check_entry(const struct ipt_entry *e, unsigned int *i, unsigned int *off, /* Prior node must be error node, or this node. */ assert(t->verdict == entry2offset(h, e)+e->next_offset || strcmp(ipt_get_target(index2entry(h, idx-1)) - ->u.name, IPT_ERROR_TARGET) + ->u.user.name, IPT_ERROR_TARGET) == 0); } @@ -1824,8 +1828,8 @@ check_entry(const struct ipt_entry *e, unsigned int *i, unsigned int *off, *was_return = 1; else *was_return = 0; - } else if (strcmp(t->target.u.name, IPT_ERROR_TARGET) == 0) { - assert(t->target.target_size + } else if (strcmp(t->target.u.user.name, IPT_ERROR_TARGET) == 0) { + assert(t->target.u.target_size == IPT_ALIGN(sizeof(struct ipt_error_target))); /* If this is in user area, previous must have been return */ @@ -1837,7 +1841,7 @@ check_entry(const struct ipt_entry *e, unsigned int *i, unsigned int *off, else *was_return = 0; if (*off == user_offset) - assert(strcmp(t->target.u.name, IPT_ERROR_TARGET) == 0); + assert(strcmp(t->target.u.user.name, IPT_ERROR_TARGET) == 0); (*off) += e->next_offset; (*i)++; @@ -1926,7 +1930,7 @@ do_check(iptc_handle_t h, unsigned int line) assert(e->next_offset == sizeof(*e) + sizeof(*t)); t = (struct ipt_standard_target *)ipt_get_target(e); - assert(strcmp(t->target.u.name, IPT_STANDARD_TARGET) == 0); + assert(strcmp(t->target.u.user.name, IPT_STANDARD_TARGET)==0); assert(t->verdict == -NF_DROP-1 || t->verdict == -NF_ACCEPT-1); /* Hooks and underflows must be valid entries */ @@ -1954,7 +1958,8 @@ do_check(iptc_handle_t h, unsigned int line) assert(n == h->entries.size); /* Final entry must be error node */ - assert(strcmp(ipt_get_target(index2entry(h, h->new_number-1))->u.name, + assert(strcmp(ipt_get_target(index2entry(h, h->new_number-1)) + ->u.user.name, IPT_ERROR_TARGET) == 0); } #endif /*NDEBUG*/ -- cgit v1.2.3