Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

netfilter: ipset: Out of bound access in hash:net* types fixed

Dave Jones reported that KASan detected out of bounds access in hash:net*
types:

[ 23.139532] ==================================================================
[ 23.146130] BUG: KASan: out of bounds access in hash_net4_add_cidr+0x1db/0x220 at addr ffff8800d4844b58
[ 23.152937] Write of size 4 by task ipset/457
[ 23.159742] =============================================================================
[ 23.166672] BUG kmalloc-512 (Not tainted): kasan: bad access detected
[ 23.173641] -----------------------------------------------------------------------------
[ 23.194668] INFO: Allocated in hash_net_create+0x16a/0x470 age=7 cpu=1 pid=456
[ 23.201836] __slab_alloc.constprop.66+0x554/0x620
[ 23.208994] __kmalloc+0x2f2/0x360
[ 23.216105] hash_net_create+0x16a/0x470
[ 23.223238] ip_set_create+0x3e6/0x740
[ 23.230343] nfnetlink_rcv_msg+0x599/0x640
[ 23.237454] netlink_rcv_skb+0x14f/0x190
[ 23.244533] nfnetlink_rcv+0x3f6/0x790
[ 23.251579] netlink_unicast+0x272/0x390
[ 23.258573] netlink_sendmsg+0x5a1/0xa50
[ 23.265485] SYSC_sendto+0x1da/0x2c0
[ 23.272364] SyS_sendto+0xe/0x10
[ 23.279168] entry_SYSCALL_64_fastpath+0x12/0x6f

The bug is fixed in the patch and the testsuite is extended in ipset
to check cidr handling more thoroughly.

Signed-off-by: Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>

+8 -4
+8 -4
net/netfilter/ipset/ip_set_hash_gen.h
··· 152 152 #define SET_HOST_MASK(family) (family == AF_INET ? 32 : 128) 153 153 154 154 #ifdef IP_SET_HASH_WITH_NET0 155 + /* cidr from 0 to SET_HOST_MASK() value and c = cidr + 1 */ 155 156 #define NLEN(family) (SET_HOST_MASK(family) + 1) 157 + #define CIDR_POS(c) ((c) - 1) 156 158 #else 159 + /* cidr from 1 to SET_HOST_MASK() value and c = cidr + 1 */ 157 160 #define NLEN(family) SET_HOST_MASK(family) 161 + #define CIDR_POS(c) ((c) - 2) 158 162 #endif 159 163 160 164 #else ··· 309 305 } else if (h->nets[i].cidr[n] < cidr) { 310 306 j = i; 311 307 } else if (h->nets[i].cidr[n] == cidr) { 312 - h->nets[cidr - 1].nets[n]++; 308 + h->nets[CIDR_POS(cidr)].nets[n]++; 313 309 return; 314 310 } 315 311 } ··· 318 314 h->nets[i].cidr[n] = h->nets[i - 1].cidr[n]; 319 315 } 320 316 h->nets[i].cidr[n] = cidr; 321 - h->nets[cidr - 1].nets[n] = 1; 317 + h->nets[CIDR_POS(cidr)].nets[n] = 1; 322 318 } 323 319 324 320 static void ··· 329 325 for (i = 0; i < nets_length; i++) { 330 326 if (h->nets[i].cidr[n] != cidr) 331 327 continue; 332 - h->nets[cidr - 1].nets[n]--; 333 - if (h->nets[cidr - 1].nets[n] > 0) 328 + h->nets[CIDR_POS(cidr)].nets[n]--; 329 + if (h->nets[CIDR_POS(cidr)].nets[n] > 0) 334 330 return; 335 331 for (j = i; j < net_end && h->nets[j].cidr[n]; j++) 336 332 h->nets[j].cidr[n] = h->nets[j + 1].cidr[n];