utils: rework fw3_bitlen2netmask() IPv6 mask calculation
authorJo-Philipp Wich <jow@openwrt.org>
Thu, 18 Sep 2014 10:09:12 +0000 (12:09 +0200)
committerJo-Philipp Wich <jow@openwrt.org>
Thu, 18 Sep 2014 11:58:38 +0000 (13:58 +0200)
The previous code wrote beyound the end of the destination buffer under
certain circumstances, causing possible heap corruptions.

Rewrite the IPv6 mask calculation code to use a safe byte-wise assignment
loop instead of two memset() calls and one byte assignment in the middle.

Signed-off-by: Jo-Philipp Wich <jow@openwrt.org>
utils.c

diff --git a/utils.c b/utils.c
index 756633a7412c49a338b25507207a32f052dd5a36..71a0f13b269970d6162c6506ec161d43eeff2faf 100644 (file)
--- a/utils.c
+++ b/utils.c
@@ -774,6 +774,7 @@ bool
 fw3_bitlen2netmask(int family, int bits, void *mask)
 {
        int i;
+       uint8_t rem, b;
        struct in_addr *v4;
        struct in6_addr *v6;
 
@@ -783,18 +784,17 @@ fw3_bitlen2netmask(int family, int bits, void *mask)
                        return false;
 
                v6 = mask;
-               i = abs(bits);
+               rem = abs(bits);
 
-               memset(v6->s6_addr, 0xff, i / 8);
-
-               if (i < 128)
+               for (i = 0; i < sizeof(v6->s6_addr); i++)
                {
-                       memset(v6->s6_addr + (i / 8) + 1, 0, (128 - i) / 8);
-                       v6->s6_addr[i / 8] = 0xff << (8 - (i & 7));
+                       b = (rem > 8) ? 8 : rem;
+                       v6->s6_addr[i] = (uint8_t)(0xFF << (8 - b));
+                       rem -= b;
                }
 
                if (bits < 0)
-                       for (i = 0; i < 16; i++)
+                       for (i = 0; i < sizeof(v6->s6_addr); i++)
                                v6->s6_addr[i] = ~v6->s6_addr[i];
        }
        else