]> asedeno.scripts.mit.edu Git - linux.git/commitdiff
netfilter: ipset: use bitmap infrastructure completely
authorKadlecsik József <kadlec@blackhole.kfki.hu>
Sun, 19 Jan 2020 21:06:49 +0000 (22:06 +0100)
committerPablo Neira Ayuso <pablo@netfilter.org>
Mon, 20 Jan 2020 16:41:45 +0000 (17:41 +0100)
The bitmap allocation did not use full unsigned long sizes
when calculating the required size and that was triggered by KASAN
as slab-out-of-bounds read in several places. The patch fixes all
of them.

Reported-by: syzbot+fabca5cbf5e54f3fe2de@syzkaller.appspotmail.com
Reported-by: syzbot+827ced406c9a1d9570ed@syzkaller.appspotmail.com
Reported-by: syzbot+190d63957b22ef673ea5@syzkaller.appspotmail.com
Reported-by: syzbot+dfccdb2bdb4a12ad425e@syzkaller.appspotmail.com
Reported-by: syzbot+df0d0f5895ef1f41a65b@syzkaller.appspotmail.com
Reported-by: syzbot+b08bd19bb37513357fd4@syzkaller.appspotmail.com
Reported-by: syzbot+53cdd0ec0bbabd53370a@syzkaller.appspotmail.com
Signed-off-by: Jozsef Kadlecsik <kadlec@netfilter.org>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
include/linux/netfilter/ipset/ip_set.h
net/netfilter/ipset/ip_set_bitmap_gen.h
net/netfilter/ipset/ip_set_bitmap_ip.c
net/netfilter/ipset/ip_set_bitmap_ipmac.c
net/netfilter/ipset/ip_set_bitmap_port.c

index 4d8b1eaf7708ddbd274aa3fe6912fec34c420faa..908d38dbcb91f0b1e7040b230c2506fb3f67f14e 100644 (file)
@@ -426,13 +426,6 @@ ip6addrptr(const struct sk_buff *skb, bool src, struct in6_addr *addr)
               sizeof(*addr));
 }
 
               sizeof(*addr));
 }
 
-/* Calculate the bytes required to store the inclusive range of a-b */
-static inline int
-bitmap_bytes(u32 a, u32 b)
-{
-       return 4 * ((((b - a + 8) / 8) + 3) / 4);
-}
-
 /* How often should the gc be run by default */
 #define IPSET_GC_TIME                  (3 * 60)
 
 /* How often should the gc be run by default */
 #define IPSET_GC_TIME                  (3 * 60)
 
index 077a2cb65fcb38ce8f3d40414289dc341c9da236..26ab0e9612d82579b6e89c99704c5bbe063c0e1b 100644 (file)
@@ -75,7 +75,7 @@ mtype_flush(struct ip_set *set)
 
        if (set->extensions & IPSET_EXT_DESTROY)
                mtype_ext_cleanup(set);
 
        if (set->extensions & IPSET_EXT_DESTROY)
                mtype_ext_cleanup(set);
-       memset(map->members, 0, map->memsize);
+       bitmap_zero(map->members, map->elements);
        set->elements = 0;
        set->ext_size = 0;
 }
        set->elements = 0;
        set->ext_size = 0;
 }
index abe8f77d7d23cd003ad022e57179d410a5074d2a..0a2196f591064e68754b34548ff614d61a3d44e5 100644 (file)
@@ -37,7 +37,7 @@ MODULE_ALIAS("ip_set_bitmap:ip");
 
 /* Type structure */
 struct bitmap_ip {
 
 /* Type structure */
 struct bitmap_ip {
-       void *members;          /* the set members */
+       unsigned long *members; /* the set members */
        u32 first_ip;           /* host byte order, included in range */
        u32 last_ip;            /* host byte order, included in range */
        u32 elements;           /* number of max elements in the set */
        u32 first_ip;           /* host byte order, included in range */
        u32 last_ip;            /* host byte order, included in range */
        u32 elements;           /* number of max elements in the set */
@@ -220,7 +220,7 @@ init_map_ip(struct ip_set *set, struct bitmap_ip *map,
            u32 first_ip, u32 last_ip,
            u32 elements, u32 hosts, u8 netmask)
 {
            u32 first_ip, u32 last_ip,
            u32 elements, u32 hosts, u8 netmask)
 {
-       map->members = ip_set_alloc(map->memsize);
+       map->members = bitmap_zalloc(elements, GFP_KERNEL | __GFP_NOWARN);
        if (!map->members)
                return false;
        map->first_ip = first_ip;
        if (!map->members)
                return false;
        map->first_ip = first_ip;
@@ -322,7 +322,7 @@ bitmap_ip_create(struct net *net, struct ip_set *set, struct nlattr *tb[],
        if (!map)
                return -ENOMEM;
 
        if (!map)
                return -ENOMEM;
 
-       map->memsize = bitmap_bytes(0, elements - 1);
+       map->memsize = BITS_TO_LONGS(elements) * sizeof(unsigned long);
        set->variant = &bitmap_ip;
        if (!init_map_ip(set, map, first_ip, last_ip,
                         elements, hosts, netmask)) {
        set->variant = &bitmap_ip;
        if (!init_map_ip(set, map, first_ip, last_ip,
                         elements, hosts, netmask)) {
index b618713297da56178f84d309c0e17242f0220c30..739e343efaf63193a23666e52b615fc40658f681 100644 (file)
@@ -42,7 +42,7 @@ enum {
 
 /* Type structure */
 struct bitmap_ipmac {
 
 /* Type structure */
 struct bitmap_ipmac {
-       void *members;          /* the set members */
+       unsigned long *members; /* the set members */
        u32 first_ip;           /* host byte order, included in range */
        u32 last_ip;            /* host byte order, included in range */
        u32 elements;           /* number of max elements in the set */
        u32 first_ip;           /* host byte order, included in range */
        u32 last_ip;            /* host byte order, included in range */
        u32 elements;           /* number of max elements in the set */
@@ -299,7 +299,7 @@ static bool
 init_map_ipmac(struct ip_set *set, struct bitmap_ipmac *map,
               u32 first_ip, u32 last_ip, u32 elements)
 {
 init_map_ipmac(struct ip_set *set, struct bitmap_ipmac *map,
               u32 first_ip, u32 last_ip, u32 elements)
 {
-       map->members = ip_set_alloc(map->memsize);
+       map->members = bitmap_zalloc(elements, GFP_KERNEL | __GFP_NOWARN);
        if (!map->members)
                return false;
        map->first_ip = first_ip;
        if (!map->members)
                return false;
        map->first_ip = first_ip;
@@ -360,7 +360,7 @@ bitmap_ipmac_create(struct net *net, struct ip_set *set, struct nlattr *tb[],
        if (!map)
                return -ENOMEM;
 
        if (!map)
                return -ENOMEM;
 
-       map->memsize = bitmap_bytes(0, elements - 1);
+       map->memsize = BITS_TO_LONGS(elements) * sizeof(unsigned long);
        set->variant = &bitmap_ipmac;
        if (!init_map_ipmac(set, map, first_ip, last_ip, elements)) {
                kfree(map);
        set->variant = &bitmap_ipmac;
        if (!init_map_ipmac(set, map, first_ip, last_ip, elements)) {
                kfree(map);
index 23d6095cb196d0aadde8d6266cc06a086dd57940..b49978dd810dcb7794e4ae6c760adaff0f9fb200 100644 (file)
@@ -30,7 +30,7 @@ MODULE_ALIAS("ip_set_bitmap:port");
 
 /* Type structure */
 struct bitmap_port {
 
 /* Type structure */
 struct bitmap_port {
-       void *members;          /* the set members */
+       unsigned long *members; /* the set members */
        u16 first_port;         /* host byte order, included in range */
        u16 last_port;          /* host byte order, included in range */
        u32 elements;           /* number of max elements in the set */
        u16 first_port;         /* host byte order, included in range */
        u16 last_port;          /* host byte order, included in range */
        u32 elements;           /* number of max elements in the set */
@@ -231,7 +231,7 @@ static bool
 init_map_port(struct ip_set *set, struct bitmap_port *map,
              u16 first_port, u16 last_port)
 {
 init_map_port(struct ip_set *set, struct bitmap_port *map,
              u16 first_port, u16 last_port)
 {
-       map->members = ip_set_alloc(map->memsize);
+       map->members = bitmap_zalloc(map->elements, GFP_KERNEL | __GFP_NOWARN);
        if (!map->members)
                return false;
        map->first_port = first_port;
        if (!map->members)
                return false;
        map->first_port = first_port;
@@ -271,7 +271,7 @@ bitmap_port_create(struct net *net, struct ip_set *set, struct nlattr *tb[],
                return -ENOMEM;
 
        map->elements = elements;
                return -ENOMEM;
 
        map->elements = elements;
-       map->memsize = bitmap_bytes(0, map->elements);
+       map->memsize = BITS_TO_LONGS(elements) * sizeof(unsigned long);
        set->variant = &bitmap_port;
        if (!init_map_port(set, map, first_port, last_port)) {
                kfree(map);
        set->variant = &bitmap_port;
        if (!init_map_port(set, map, first_port, last_port)) {
                kfree(map);