⬢ DragonFlyBSD Kernel Audit
DF-3267 / fix.diff
← back to finding ↓ download raw
--- 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 */