[peter at p12n.org: dhcp 3.0.3 theoretical alignment bug]

Andrew Pollock apollock at debian.org
Tue Aug 30 11:10:13 UTC 2005


Hi,

Spent some time investigating a bug in 3.0.2 that seemed to be partially
fixed (but without anything appropriate that I could see in the release
notes in 3.0.3).

regards

Andrew

----- Forwarded message from Peter Samuelson <peter at p12n.org> -----

From: Peter Samuelson <peter at p12n.org>
To: dhcp-server at isc.org
Cc: apollock at debian.org
Subject: dhcp 3.0.3 theoretical alignment bug
Date: Tue, 30 Aug 2005 01:11:09 -0500
User-Agent: Mutt/1.5.9i


So, I was helping someone track down a pointer alignment bug in dhcp
3.0.2, and it turned out to be fixed in dhcp 3.0.3.  However, there is
another bug of exactly the same type, in the same function, *not* fixed
in 3.0.3.  Why it does not trigger in the same situation, I don't know.

The 3.0.2 bug was in decode_udp_ip_header(): 'struct ip *ip', which was
changed to a stack variable 'struct ip ip' and copied from the input
buffer, for proper struct alignment.  The related variable 'struct
udphdr *udp' was not changed in the same way and I think it should have
been.

Practical result: the UDP checksum in the input buffer is no longer
zeroed.  I didn't check to see if this mattered.


diff -urNad dhcp-3.0.3/common/packet.c dhcp3-3.0.3/common/packet.c
--- dhcp-3.0.3/common/packet.c
+++ dhcp-3.0.3/common/packet.c
@@ -219,7 +219,7 @@
 {
   unsigned char *data;
   struct ip ip;
-  struct udphdr *udp;
+  struct udphdr udp;
   u_int32_t ip_len = (buf [bufix] & 0xf) << 2;
   u_int32_t sum, usum;
   static int ip_packets_seen;
@@ -233,7 +233,7 @@
   int ignore = 0;
 
   memcpy(&ip, buf + bufix, sizeof (struct ip));
-  udp = (struct udphdr *)(buf + bufix + ip_len);
+  memcpy(&udp, buf + bufix + ip_len, sizeof (struct udphdr));
 
 #ifdef USERLAND_FILTER
   /* Is it a UDP packet? */
@@ -241,13 +241,13 @@
 	  return -1;
 
   /* Is it to the port we're serving? */
-  if (udp -> uh_dport != local_port)
+  if (udp.uh_dport != local_port)
 	  return -1;
 #endif /* USERLAND_FILTER */
 
-  ulen = ntohs (udp -> uh_ulen);
-  if (ulen < sizeof *udp ||
-      ((unsigned char *)udp) + ulen > buf + bufix + buflen) {
+  ulen = ntohs (udp.uh_ulen);
+  if (ulen < sizeof udp ||
+      ((unsigned char *)&udp) + ulen > buf + bufix + buflen) {
 	  log_info ("bogus UDP packet length: %d", ulen);
 	  return -1;
   }
@@ -281,8 +281,8 @@
      header and the data.   If the UDP checksum field is zero, we're
      not supposed to do a checksum. */
 
-  data = buf + bufix + ip_len + sizeof *udp;
-  len = ulen - sizeof *udp;
+  data = buf + bufix + ip_len + sizeof udp;
+  len = ulen - sizeof udp;
   ++udp_packets_length_checked;
   if (len + data > buf + bufix + buflen) {
 	  ++udp_packets_length_overflow;
@@ -302,14 +302,14 @@
 	  log_debug ("accepting packet with data after udp payload.");
   if (len + data > buf + bufix + buflen) {
 	  log_debug ("dropping packet with bogus uh_ulen %ld",
-		     (long)(len + sizeof *udp));
+		     (long)(len + sizeof udp));
 	  return -1;
   }
 
-  usum = udp -> uh_sum;
-  udp -> uh_sum = 0;
+  usum = udp.uh_sum;
+  udp.uh_sum = 0;
 
-  sum = wrapsum (checksum ((unsigned char *)udp, sizeof *udp,
+  sum = wrapsum (checksum ((unsigned char *)&udp, sizeof udp,
 			   checksum (data, len,
 				     checksum ((unsigned char *)
 					       &ip.ip_src,
@@ -330,8 +330,8 @@
   }
 
   /* Copy out the port... */
-  memcpy (&from -> sin_port, &udp -> uh_sport, sizeof udp -> uh_sport);
+  memcpy (&from -> sin_port, &udp.uh_sport, sizeof udp.uh_sport);
 
-  return ip_len + sizeof *udp;
+  return ip_len + sizeof udp;
 }
 #endif /* PACKET_DECODING */



----- End forwarded message -----


More information about the dhcp-hackers mailing list