e87dd3
From 591ed1e90503817938ccf5f127e677a8dd48b6d8 Mon Sep 17 00:00:00 2001
e87dd3
From: Simon Kelley <simon@thekelleys.org.uk>
e87dd3
Date: Mon, 11 Jul 2016 18:18:42 +0100
e87dd3
Subject: [PATCH] Fix bad behaviour with some DHCP option arrangements.
e87dd3
e87dd3
The check that there's enough space to store the DHCP agent-id
e87dd3
at the end of the packet could succeed when it should fail
e87dd3
if the END option is in either of the oprion-overload areas.
e87dd3
That could overwrite legit options in the request and cause
e87dd3
bad behaviour. It's highly unlikely that any sane DHCP client
e87dd3
would trigger this bug, and it's never been seen, but this
e87dd3
fixes the problem.
e87dd3
e87dd3
Also fix off-by-one in bounds checking of option processing.
e87dd3
Worst case scenario on that is a read one byte beyond the
e87dd3
end off a buffer with a crafted packet, and maybe therefore
e87dd3
a SIGV crash if the memory after the buffer is not mapped.
e87dd3
e87dd3
Thanks to Timothy Becker for spotting these.
e87dd3
---
e87dd3
 src/rfc2131.c | 5 +++--
e87dd3
 1 file changed, 3 insertions(+), 2 deletions(-)
e87dd3
e87dd3
diff --git a/src/rfc2131.c b/src/rfc2131.c
e87dd3
index b7c167e..8b99d4b 100644
e87dd3
--- a/src/rfc2131.c
e87dd3
+++ b/src/rfc2131.c
e87dd3
@@ -186,7 +186,8 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
e87dd3
 	     be enough free space at the end of the packet to copy the option. */
e87dd3
 	  unsigned char *sopt;
e87dd3
 	  unsigned int total = option_len(opt) + 2;
e87dd3
-	  unsigned char *last_opt = option_find(mess, sz, OPTION_END, 0);
e87dd3
+	  unsigned char *last_opt = option_find1(&mess->options[0] + sizeof(u32), ((unsigned char *)mess) + sz,
e87dd3
+						 OPTION_END, 0);
e87dd3
 	  if (last_opt && last_opt < end - total)
e87dd3
 	    {
e87dd3
 	      end -= total;
e87dd3
@@ -1606,7 +1607,7 @@ static unsigned char *option_find1(unsigned char *p, unsigned char *end, int opt
e87dd3
 {
e87dd3
   while (1) 
e87dd3
     {
e87dd3
-      if (p > end)
e87dd3
+      if (p >= end)
e87dd3
 	return NULL;
e87dd3
       else if (*p == OPTION_END)
e87dd3
 	return opt == OPTION_END ? p : NULL;
e87dd3
-- 
e87dd3
2.9.3
e87dd3