DF-3267 / fix.diff
--- a/sys/net/pf/pf_ioctl.c +++ b/sys/net/pf/pf_ioctl.c @@ -2325,9 +2325,17 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) if (pca->action == PF_CHANGE_REMOVE) { + /* + * Removing the last pool address of a live rule + * leaves rpool->cur NULL, which pf_map_addr() + * (pf.c:2693) and pf_set_rt_ifp() (pf.c:3642/3649) + * dereference on the packet path. + */ + if (TAILQ_NEXT(oldpa, entries) == NULL && + TAILQ_FIRST(&pool->list) == oldpa) { + error = EINVAL; + break; + } TAILQ_REMOVE(&pool->list, oldpa, entries); pfi_dynaddr_remove(&oldpa->addr); pf_tbladdr_remove(&oldpa->addr); pfi_kif_unref(oldpa->kif, PFI_KIF_REF_RULE); kfree(oldpa, M_PFPOOLADDRPL); } else { @@ -2331,8 +2339,12 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) pool->cur = TAILQ_FIRST(&pool->list); + if (pool->cur == NULL) { + error = EINVAL; + break; + } PF_ACPY(&pool->counter, &pool->cur->addr.v.a.addr, pca->af); break; --- a/sys/net/pf/pf.c +++ b/sys/net/pf/pf.c @@ -2690,9 +2690,14 @@ pf_map_addr(sa_family_t af, struct pf_rule *r, struct pf_addr *saddr, struct pf_pool *rpool = &r->rpool; struct pf_pooladdr *acur = rpool->cur; struct pf_pooladdr *cur; struct pf_addr *raddr; struct pf_addr *rmask; struct pf_addr counter; struct pf_src_node k; int cpu = mycpu->gd_cpuid; int tblidx; + + if (acur == NULL) + return (1); /* emptied pool: no address available */ bzero(hash, sizeof(hash)); /* avoid gcc warnings */ |