sd-dhcp-lease: fix reading unaligned memory
authorYu Watanabe <watanabe.yu+github@gmail.com>
Sun, 30 Jan 2022 20:04:52 +0000 (05:04 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Tue, 1 Feb 2022 03:23:55 +0000 (12:23 +0900)
The destination address was read twice, one is for prefixlen, and
other is for destination address itself. And for prefixlen, the address
might be read from unaligned buffer.

This also modernizes the code.

src/libsystemd-network/sd-dhcp-lease.c

index 5a40eb94d327cdbf37ca3fdb0f0edff81637c6c8..fd5701b118920847d070caf4c00a8b45648e6e16 100644 (file)
@@ -468,41 +468,48 @@ static int lease_parse_sip_server(const uint8_t *option, size_t len, struct in_a
 }
 
 static int lease_parse_routes(
-                const uint8_t *option, size_t len,
-                struct sd_dhcp_route **routes, size_t *routes_size) {
+                const uint8_t *option,
+                size_t len,
+                struct sd_dhcp_route **routes,
+                size_t *routes_size) {
 
-        struct in_addr addr;
+        int r;
 
         assert(option || len <= 0);
         assert(routes);
         assert(routes_size);
 
-        if (len <= 0)
-                return 0;
-
         if (len % 8 != 0)
                 return -EINVAL;
 
-        if (!GREEDY_REALLOC(*routes, *routes_size + (len / 8)))
-                return -ENOMEM;
-
         while (len >= 8) {
-                struct sd_dhcp_route *route = *routes + *routes_size;
-                int r;
-
-                route->option = SD_DHCP_OPTION_STATIC_ROUTE;
-                r = in4_addr_default_prefixlen((struct in_addr*) option, &route->dst_prefixlen);
-                if (r < 0)
-                        return -EINVAL;
+                struct in_addr dst, gw;
+                uint8_t prefixlen;
 
-                assert_se(lease_parse_be32(option, 4, &addr.s_addr) >= 0);
-                route->dst_addr = inet_makeaddr(inet_netof(addr), 0);
+                assert_se(lease_parse_be32(option, 4, &dst.s_addr) >= 0);
                 option += 4;
 
-                assert_se(lease_parse_be32(option, 4, &route->gw_addr.s_addr) >= 0);
+                assert_se(lease_parse_be32(option, 4, &gw.s_addr) >= 0);
                 option += 4;
 
                 len -= 8;
+
+                r = in4_addr_default_prefixlen(&dst, &prefixlen);
+                if (r < 0)
+                        return -EINVAL;
+
+                (void) in4_addr_mask(&dst, prefixlen);
+
+                if (!GREEDY_REALLOC(*routes, *routes_size + 1))
+                        return -ENOMEM;
+
+                (*routes)[*routes_size] = (struct sd_dhcp_route) {
+                        .dst_addr = dst,
+                        .gw_addr = gw,
+                        .dst_prefixlen = prefixlen,
+                        .option = SD_DHCP_OPTION_STATIC_ROUTE,
+                };
+
                 (*routes_size)++;
         }