From 8a8005f7ca8973702b36e711993bfff89ca9600c Mon Sep 17 00:00:00 2001
From: Ben Hutchings <ben@decadent.org.uk>
Date: Thu, 28 Jan 2016 04:33:48 +0000
Subject: [PATCH] Add padding between odhcp6c_entry structures to ensure 32-bit
 alignment

struct odhcp6c_entry is not declared as __packed, so the compiler may
assume it is naturally aligned.

Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
---
 src/odhcp6c.c | 16 +++++++++-------
 src/odhcp6c.h |  8 ++++++++
 src/ra.c      |  5 +++--
 src/script.c  |  5 +++--
 4 files changed, 23 insertions(+), 11 deletions(-)

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..98d91dd 100644
--- a/src/odhcp6c.h
+++ b/src/odhcp6c.h
@@ -302,6 +302,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..2d442f6 100644
--- a/src/ra.c
+++ b/src/ra.c
@@ -444,8 +444,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 1533510..72add21 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++ = ' ';
 	}
-- 
2.25.1