diff --git a/sys/net/ipfw3_basic/ip_fw3_sync.c b/sys/net/ipfw3_basic/ip_fw3_sync.c --- a/sys/net/ipfw3_basic/ip_fw3_sync.c +++ b/sys/net/ipfw3_basic/ip_fw3_sync.c @@ -137,19 +137,31 @@ ip_fw3_ctl_sync_centre_conf(struct sockopt *sopt) { struct ipfw3_ioc_sync_centre *ioc_centre; - int size; + size_t size, need; ioc_centre = sopt->sopt_val; - size = ioc_centre->count * LEN_SYNC_EDGE; + /* DF-0701: validate count vs MAX_EDGES (centre_socks[] bound) and vs + sopt_valsize (user buffer only holds sopt_valsize bytes; old bcopy read + count*LEN_SYNC_EDGE off the end of sopt_val). size_t so count*LEN_SYNC_EDGE + cannot wrap a signed int and cause a tiny kmalloc + huge bcopy. */ + if (ioc_centre->count < 0 || ioc_centre->count > MAX_EDGES) + return EINVAL; + need = sizeof(*ioc_centre) + (size_t)ioc_centre->count * LEN_SYNC_EDGE; + if (sopt->sopt_valsize < need) + return EINVAL; + size = (size_t)ioc_centre->count * LEN_SYNC_EDGE; if (fw3_sync_ctx.count == 0) { fw3_sync_ctx.edges = kmalloc(size, M_IPFW3_SYNC, M_NOWAIT | M_ZERO); } else { fw3_sync_ctx.edges = krealloc(fw3_sync_ctx.edges, size, M_TEMP, M_WAITOK); } + if (fw3_sync_ctx.edges == NULL) { + fw3_sync_ctx.count = 0; + return ENOMEM; + } fw3_sync_ctx.count = ioc_centre->count; - bcopy(ioc_centre->edges, fw3_sync_ctx.edges, - ioc_centre->count * LEN_SYNC_EDGE); + bcopy(ioc_centre->edges, fw3_sync_ctx.edges, size); return 0; }