aboutsummaryrefslogtreecommitdiff
path: root/package/busybox/0004-udhcpc-check-that-4-byte-options-are-indeed-4-byte-closes-11506.patch
blob: bc1a48bf4b89c3f1fe2c952da5c20db9ebe588b6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
From 6d3b4bb24da9a07c263f3c1acf8df85382ff562c Mon Sep 17 00:00:00 2001
From: Denys Vlasenko <vda.linux@googlemail.com>
Date: Mon, 17 Dec 2018 18:07:18 +0100
Subject: udhcpc: check that 4-byte options are indeed 4-byte, closes 11506

function                                             old     new   delta
udhcp_get_option32                                     -      27     +27
udhcp_get_option                                     231     248     +17
------------------------------------------------------------------------------
(add/remove: 1/0 grow/shrink: 1/0 up/down: 44/0)               Total: 44 bytes

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
---
 networking/udhcp/common.c | 19 +++++++++++++++++++
 networking/udhcp/common.h |  4 ++++
 networking/udhcp/dhcpc.c  |  6 +++---
 networking/udhcp/dhcpd.c  |  6 +++---
 4 files changed, 29 insertions(+), 6 deletions(-)

diff --git a/networking/udhcp/common.c b/networking/udhcp/common.c
index e5fd74f91..41b05b855 100644
--- a/networking/udhcp/common.c
+++ b/networking/udhcp/common.c
@@ -272,6 +272,15 @@ uint8_t* FAST_FUNC udhcp_get_option(struct dhcp_packet *packet, int code)
 			goto complain; /* complain and return NULL */
 
 		if (optionptr[OPT_CODE] == code) {
+			if (optionptr[OPT_LEN] == 0) {
+				/* So far no valid option with length 0 known.
+				 * Having this check means that searching
+				 * for DHCP_MESSAGE_TYPE need not worry
+				 * that returned pointer might be unsafe
+				 * to dereference.
+				 */
+				goto complain; /* complain and return NULL */
+			}
 			log_option("option found", optionptr);
 			return optionptr + OPT_DATA;
 		}
@@ -289,6 +298,16 @@ uint8_t* FAST_FUNC udhcp_get_option(struct dhcp_packet *packet, int code)
 	return NULL;
 }
 
+uint8_t* FAST_FUNC udhcp_get_option32(struct dhcp_packet *packet, int code)
+{
+	uint8_t *r = udhcp_get_option(packet, code);
+	if (r) {
+		if (r[-1] != 4)
+			r = NULL;
+	}
+	return r;
+}
+
 /* Return the position of the 'end' option (no bounds checking) */
 int FAST_FUNC udhcp_end_option(uint8_t *optionptr)
 {
diff --git a/networking/udhcp/common.h b/networking/udhcp/common.h
index 7ad603d33..9511152ff 100644
--- a/networking/udhcp/common.h
+++ b/networking/udhcp/common.h
@@ -205,6 +205,10 @@ extern const uint8_t dhcp_option_lengths[] ALIGN1;
 unsigned FAST_FUNC udhcp_option_idx(const char *name, const char *option_strings);
 
 uint8_t *udhcp_get_option(struct dhcp_packet *packet, int code) FAST_FUNC;
+/* Same as above + ensures that option length is 4 bytes
+ * (returns NULL if size is different)
+ */
+uint8_t *udhcp_get_option32(struct dhcp_packet *packet, int code) FAST_FUNC;
 int udhcp_end_option(uint8_t *optionptr) FAST_FUNC;
 void udhcp_add_binary_option(struct dhcp_packet *packet, uint8_t *addopt) FAST_FUNC;
 #if ENABLE_UDHCPC || ENABLE_UDHCPD
diff --git a/networking/udhcp/dhcpc.c b/networking/udhcp/dhcpc.c
index 4b23e4d39..5b3fd531c 100644
--- a/networking/udhcp/dhcpc.c
+++ b/networking/udhcp/dhcpc.c
@@ -1691,7 +1691,7 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
  * They say ISC DHCP client supports this case.
  */
 				server_addr = 0;
-				temp = udhcp_get_option(&packet, DHCP_SERVER_ID);
+				temp = udhcp_get_option32(&packet, DHCP_SERVER_ID);
 				if (!temp) {
 					bb_error_msg("no server ID, using 0.0.0.0");
 				} else {
@@ -1718,7 +1718,7 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
 				struct in_addr temp_addr;
 				uint8_t *temp;
 
-				temp = udhcp_get_option(&packet, DHCP_LEASE_TIME);
+				temp = udhcp_get_option32(&packet, DHCP_LEASE_TIME);
 				if (!temp) {
 					bb_error_msg("no lease time with ACK, using 1 hour lease");
 					lease_seconds = 60 * 60;
@@ -1813,7 +1813,7 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
 					uint32_t svid;
 					uint8_t *temp;
 
-					temp = udhcp_get_option(&packet, DHCP_SERVER_ID);
+					temp = udhcp_get_option32(&packet, DHCP_SERVER_ID);
 					if (!temp) {
  non_matching_svid:
 						log1("received DHCP NAK with wrong"
diff --git a/networking/udhcp/dhcpd.c b/networking/udhcp/dhcpd.c
index a8cd3f03b..477856d11 100644
--- a/networking/udhcp/dhcpd.c
+++ b/networking/udhcp/dhcpd.c
@@ -640,7 +640,7 @@ static void add_server_options(struct dhcp_packet *packet)
 static uint32_t select_lease_time(struct dhcp_packet *packet)
 {
 	uint32_t lease_time_sec = server_config.max_lease_sec;
-	uint8_t *lease_time_opt = udhcp_get_option(packet, DHCP_LEASE_TIME);
+	uint8_t *lease_time_opt = udhcp_get_option32(packet, DHCP_LEASE_TIME);
 	if (lease_time_opt) {
 		move_from_unaligned32(lease_time_sec, lease_time_opt);
 		lease_time_sec = ntohl(lease_time_sec);
@@ -987,7 +987,7 @@ int udhcpd_main(int argc UNUSED_PARAM, char **argv)
 		}
 
 		/* Get SERVER_ID if present */
-		server_id_opt = udhcp_get_option(&packet, DHCP_SERVER_ID);
+		server_id_opt = udhcp_get_option32(&packet, DHCP_SERVER_ID);
 		if (server_id_opt) {
 			uint32_t server_id_network_order;
 			move_from_unaligned32(server_id_network_order, server_id_opt);
@@ -1011,7 +1011,7 @@ int udhcpd_main(int argc UNUSED_PARAM, char **argv)
 		}
 
 		/* Get REQUESTED_IP if present */
-		requested_ip_opt = udhcp_get_option(&packet, DHCP_REQUESTED_IP);
+		requested_ip_opt = udhcp_get_option32(&packet, DHCP_REQUESTED_IP);
 		if (requested_ip_opt) {
 			move_from_unaligned32(requested_nip, requested_ip_opt);
 		}
-- 
cgit v1.2.1