--- sys/net/pf/pf_ioctl.c +++ sys/net/pf/pf_ioctl.c @@ -2311,6 +2311,18 @@ } if (pca->action == PF_CHANGE_REMOVE) { + /* + * Do not allow the last address of a pool to be + * removed. Rules that use the pool (nat/rdr/binat, + * route-to) would be left with rpool.cur == NULL, + * taking a NULL dereference in the PF_ACPY below + * and in pf_map_addr() on the packet path. + */ + if (TAILQ_FIRST(&pool->list) == oldpa && + TAILQ_NEXT(oldpa, entries) == NULL) { + error = EBUSY; + break; + } TAILQ_REMOVE(&pool->list, oldpa, entries); pfi_dynaddr_remove(&oldpa->addr); pf_tbladdr_remove(&oldpa->addr); @@ -2328,8 +2340,9 @@ } pool->cur = TAILQ_FIRST(&pool->list); - PF_ACPY(&pool->counter, &pool->cur->addr.v.a.addr, - pca->af); + if (pool->cur != NULL) + PF_ACPY(&pool->counter, &pool->cur->addr.v.a.addr, + pca->af); break; }