From: Steven Barth Date: Sun, 31 Jan 2016 15:18:16 +0000 (+0100) Subject: Merge pull request #44 from bwhacks/alignment-fixes X-Git-Tag: debian/1.1+git20160131-1~5 X-Git-Url: https://git.decadent.org.uk/gitweb/?p=odhcp6c.git;a=commitdiff_plain;h=ec7f4701b348f5c4c3191ca83ecd8453c431c432;hp=3609bab1361ed3f92e19f7309dd6e7fd64bc4083 Merge pull request #44 from bwhacks/alignment-fixes Alignment fixes --- diff --git a/src/dhcpv6.c b/src/dhcpv6.c index c5f11f1..3e128bc 100644 --- a/src/dhcpv6.c +++ b/src/dhcpv6.c @@ -110,6 +110,14 @@ static uint8_t reconf_key[16]; static unsigned int client_options = 0; +static uint32_t ntohl_unaligned(const uint8_t *data) +{ + uint32_t buf; + + memcpy(&buf, data, sizeof(buf)); + return ntohl(buf); +} + int init_dhcpv6(const char *ifname, unsigned int options, int sol_timeout) { client_options = options; @@ -577,7 +585,9 @@ int dhcpv6_request(enum dhcpv6_msg type) // Receive rounds for (; len < 0 && (round_start < round_end); round_start = odhcp6c_get_milli_time()) { - uint8_t buf[1536], cmsg_buf[CMSG_SPACE(sizeof(struct in6_pktinfo))]; + uint8_t buf[1536]; + uint8_t cmsg_buf[CMSG_SPACE(sizeof(struct in6_pktinfo))] + __aligned(__alignof__(struct cmsghdr)); struct iovec iov = {buf, sizeof(buf)}; struct sockaddr_in6 addr; struct msghdr msg = {.msg_name = &addr, .msg_namelen = sizeof(addr), @@ -692,7 +702,8 @@ static bool dhcpv6_response_is_valid(const void *buf, ssize_t len, continue; md5_ctx_t md5; - uint8_t serverhash[16], secretbytes[64], hash[16]; + uint8_t serverhash[16], secretbytes[64]; + uint32_t hash[4]; memcpy(serverhash, r->key, sizeof(serverhash)); memset(r->key, 0, sizeof(r->key)); @@ -804,12 +815,12 @@ static int dhcpv6_handle_advert(enum dhcpv6_msg orig, const int rc, } else if (otype == DHCPV6_OPT_RECONF_ACCEPT) { cand.wants_reconfigure = true; } else if (otype == DHCPV6_OPT_SOL_MAX_RT && olen == 4) { - uint32_t sol_max_rt = ntohl(*((uint32_t *)odata)); + uint32_t sol_max_rt = ntohl_unaligned(odata); if (sol_max_rt >= DHCPV6_SOL_MAX_RT_MIN && sol_max_rt <= DHCPV6_SOL_MAX_RT_MAX) cand.sol_max_rt = sol_max_rt; } else if (otype == DHCPV6_OPT_INF_MAX_RT && olen == 4) { - uint32_t inf_max_rt = ntohl(*((uint32_t *)odata)); + uint32_t inf_max_rt = ntohl_unaligned(odata); if (inf_max_rt >= DHCPV6_INF_MAX_RT_MIN && inf_max_rt <= DHCPV6_INF_MAX_RT_MAX) cand.inf_max_rt = inf_max_rt; @@ -1027,7 +1038,7 @@ static int dhcpv6_handle_reply(enum dhcpv6_msg orig, _unused const int rc, } else if (otype == DHCPV6_OPT_SIP_SERVER_D) { odhcp6c_add_state(STATE_SIP_FQDN, odata, olen); } else if (otype == DHCPV6_OPT_INFO_REFRESH && olen >= 4) { - refresh = ntohl(*((uint32_t*)odata)); + refresh = ntohl_unaligned(odata); passthru = false; } else if (otype == DHCPV6_OPT_AUTH) { if (olen == -4 + sizeof(struct dhcpv6_auth_reconfigure)) { @@ -1044,13 +1055,13 @@ static int dhcpv6_handle_reply(enum dhcpv6_msg orig, _unused const int rc, odhcp6c_add_state(STATE_AFTR_NAME, odata, olen); passthru = false; } else if (otype == DHCPV6_OPT_SOL_MAX_RT && olen == 4) { - uint32_t sol_max_rt = ntohl(*((uint32_t *)odata)); + uint32_t sol_max_rt = ntohl_unaligned(odata); if (sol_max_rt >= DHCPV6_SOL_MAX_RT_MIN && sol_max_rt <= DHCPV6_SOL_MAX_RT_MAX) dhcpv6_retx[DHCPV6_MSG_SOLICIT].max_timeo = sol_max_rt; passthru = false; } else if (otype == DHCPV6_OPT_INF_MAX_RT && olen == 4) { - uint32_t inf_max_rt = ntohl(*((uint32_t *)odata)); + uint32_t inf_max_rt = ntohl_unaligned(odata); if (inf_max_rt >= DHCPV6_INF_MAX_RT_MIN && inf_max_rt <= DHCPV6_INF_MAX_RT_MAX) dhcpv6_retx[DHCPV6_MSG_INFO_REQ].max_timeo = inf_max_rt; diff --git a/src/odhcp6c.c b/src/odhcp6c.c index 59f6390..ba568bd 100644 --- a/src/odhcp6c.c +++ b/src/odhcp6c.c @@ -570,8 +570,9 @@ static struct odhcp6c_entry* odhcp6c_find_entry(enum odhcp6c_state state, const uint8_t *start = odhcp6c_get_state(state, &len); for (struct odhcp6c_entry *c = (struct odhcp6c_entry*)start; - (uint8_t*)c < &start[len] && &c->auxtarget[c->auxlen] <= &start[len]; - c = (struct odhcp6c_entry*)(&c->auxtarget[c->auxlen])) + (uint8_t*)c < &start[len] && + (uint8_t*)odhcp6c_next_entry(c) <= &start[len]; + c = odhcp6c_next_entry(c)) if (!memcmp(c, new, cmplen) && !memcmp(c->auxtarget, new->auxtarget, new->auxlen)) return c; @@ -604,10 +605,10 @@ bool odhcp6c_update_entry(enum odhcp6c_state state, struct odhcp6c_entry *new, x->t2 = new->t2; x->iaid = new->iaid; } else { - odhcp6c_add_state(state, new, sizeof(*new) + new->auxlen); + odhcp6c_add_state(state, new, odhcp6c_entry_size(new)); } } else if (x) { - odhcp6c_remove_state(state, ((uint8_t*)x) - start, sizeof(*x) + x->auxlen); + odhcp6c_remove_state(state, ((uint8_t*)x) - start, odhcp6c_entry_size(x)); } return true; } @@ -618,7 +619,8 @@ static void odhcp6c_expire_list(enum odhcp6c_state state, uint32_t elapsed) size_t len; uint8_t *start = odhcp6c_get_state(state, &len); for (struct odhcp6c_entry *c = (struct odhcp6c_entry*)start; - (uint8_t*)c < &start[len] && &c->auxtarget[c->auxlen] <= &start[len]; + (uint8_t*)c < &start[len] && + (uint8_t*)odhcp6c_next_entry(c) <= &start[len]; ) { if (c->t1 < elapsed) c->t1 = 0; @@ -641,10 +643,10 @@ static void odhcp6c_expire_list(enum odhcp6c_state state, uint32_t elapsed) c->valid -= elapsed; if (!c->valid) { - odhcp6c_remove_state(state, ((uint8_t*)c) - start, sizeof(*c) + c->auxlen); + odhcp6c_remove_state(state, ((uint8_t*)c) - start, odhcp6c_entry_size(c)); start = odhcp6c_get_state(state, &len); } else { - c = (struct odhcp6c_entry*)(&c->auxtarget[c->auxlen]); + c = odhcp6c_next_entry(c); } } } diff --git a/src/odhcp6c.h b/src/odhcp6c.h index 928f82f..08a816f 100644 --- a/src/odhcp6c.h +++ b/src/odhcp6c.h @@ -18,6 +18,7 @@ #define _unused __attribute__((unused)) #define _packed __attribute__((packed)) +#define __aligned(n) __attribute__((aligned(n))) #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) @@ -302,6 +303,14 @@ struct odhcp6c_entry { uint8_t auxtarget[]; }; +// Include padding after auxtarget to align the next entry +#define odhcp6c_entry_size(entry) \ + (sizeof(struct odhcp6c_entry) + (((entry)->auxlen + 3) & ~3)) + +#define odhcp6c_next_entry(entry) \ + ((struct odhcp6c_entry *)((uint8_t *)(entry) + odhcp6c_entry_size(entry))) + + struct odhcp6c_request_prefix { uint32_t iaid; uint16_t length; diff --git a/src/ra.c b/src/ra.c index 1c121e6..dd5962a 100644 --- a/src/ra.c +++ b/src/ra.c @@ -274,7 +274,8 @@ bool ra_process(void) { bool found = false; bool changed = false; - uint8_t buf[1500], cmsg_buf[128]; + uint8_t buf[1500] __aligned(4); + uint8_t cmsg_buf[128] __aligned(__alignof__(struct cmsghdr)); struct nd_router_advert *adv = (struct nd_router_advert*)buf; struct odhcp6c_entry *entry = alloca(sizeof(*entry) + 256); const struct in6_addr any = IN6ADDR_ANY_INIT; @@ -444,8 +445,9 @@ bool ra_process(void) size_t ra_dns_len; uint8_t *start = odhcp6c_get_state(states[i], &ra_dns_len); for (struct odhcp6c_entry *c = (struct odhcp6c_entry*)start; - (uint8_t*)c < &start[ra_dns_len] && &c->auxtarget[c->auxlen] <= &start[ra_dns_len]; - c = (struct odhcp6c_entry*)(&c->auxtarget[c->auxlen])) + (uint8_t*)c < &start[ra_dns_len] && + (uint8_t*)odhcp6c_next_entry(c) <= &start[ra_dns_len]; + c = odhcp6c_next_entry(c)) if (IN6_ARE_ADDR_EQUAL(&c->router, &from.sin6_addr) && c->valid > router_valid) c->valid = router_valid; diff --git a/src/script.c b/src/script.c index b20e94c..fdc050b 100644 --- a/src/script.c +++ b/src/script.c @@ -220,8 +220,9 @@ static void search_to_env(const char *name, const uint8_t *start, size_t len) *c++ = '='; for (struct odhcp6c_entry *e = (struct odhcp6c_entry*)start; - (uint8_t*)e < &start[len] && &e->auxtarget[e->auxlen] <= &start[len]; - e = (struct odhcp6c_entry*)(&e->auxtarget[e->auxlen])) { + (uint8_t*)e < &start[len] && + (uint8_t*)odhcp6c_next_entry(e) <= &start[len]; + e = odhcp6c_next_entry(e)) { c = mempcpy(c, e->auxtarget, e->auxlen); *c++ = ' '; }