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