Fun with buffer overrruns.

In get_option(): don't read past the end of the option buffer.

Also add a small unittest to verify sane behaviour for the above.
The dhcpcd code is not easily refactored into a library, nor is it
entirely possible to include some header files directly since some
structures use C++ reserved keywords ("new") for variable names.

In print_option(): use of snprintf() returns the length that
/would/ have been written.  Add checks that the output buffer
is not overrun when printing.

Bug: 18356137
Bug: 18356135
Change-Id: I0f907b8a952208749226ba034a416d773e068f8a
diff --git a/dhcp.c b/dhcp.c
index 53f4795..0a1d220 100644
--- a/dhcp.c
+++ b/dhcp.c
@@ -313,7 +313,11 @@
 	const uint8_t *op = NULL;
 	int bl = 0;
 
-	while (p < e) {
+	/* DHCP Options are in TLV format with T and L each being a single
+	 * byte.  In general, here we have p -> T, ol=p+1 -> L, op -> V.
+	 * We must make sure there is enough room to read both T and L.
+	 */
+	while (p + 1 < e) {
 		o = *p++;
 		if (o == opt) {
 			if (op) {
@@ -328,7 +332,7 @@
 				memcpy(bp, op, ol);
 				bp += ol;
 			}
-			ol = *p;
+			ol = (p + *p < e) ? *p : e - (p + 1);
 			op = p + 1;
 			bl += ol;
 		}
@@ -1362,6 +1366,10 @@
 			data += sizeof(addr.s_addr);
 		} else
 			l = 0;
+		if (len <= l) {
+			bytes += len;
+			break;
+		}
 		len -= l;
 		bytes += l;
 		s += l;