diff options
author | Kristof Provost <kp@FreeBSD.org> | 2024-09-26 15:53:53 +0000 |
---|---|---|
committer | Kristof Provost <kp@FreeBSD.org> | 2024-10-10 12:10:39 +0000 |
commit | 7d0f8cd93bce786728a1fff8b2e2184c8e48f3b2 (patch) | |
tree | 5642675dfaeb4b5f721ebd6103b1a56da364b422 | |
parent | ee9f418c804184feb7139a0b4dac396b4934a8e7 (diff) | |
download | src-7d0f8cd93bce.tar.gz src-7d0f8cd93bce.zip |
pf: ensure that we won't enter an endless loop
ensure that we won't enter an endless loop while iterating over
an address pool. problem found and solution tested by claudio.
ok claudio, henning, "reads fine" to zinke
Obtained from: OpenBSD, mikeb <mikeb@openbsd.org>, e4fc4bddb9
Sponsored by: Rubicon Communications, LLC ("Netgate")
Differential Revision: https://reviews.freebsd.org/D46927
-rw-r--r-- | sys/netpfil/pf/pf_table.c | 19 |
1 files changed, 15 insertions, 4 deletions
diff --git a/sys/netpfil/pf/pf_table.c b/sys/netpfil/pf/pf_table.c index 690cb6d9ab90..77bd466ec2b3 100644 --- a/sys/netpfil/pf/pf_table.c +++ b/sys/netpfil/pf/pf_table.c @@ -2245,7 +2245,7 @@ pfr_pool_get(struct pfr_ktable *kt, int *pidx, struct pf_addr *counter, struct pf_addr addr, cur, mask, umask_addr; union sockaddr_union uaddr, umask; struct pfr_kentry *ke, *ke2 = NULL; - int idx = -1, use_counter = 0; + int startidx, idx = -1, loop = 0, use_counter = 0; MPASS(pidx != NULL); MPASS(counter != NULL); @@ -2272,18 +2272,29 @@ pfr_pool_get(struct pfr_ktable *kt, int *pidx, struct pf_addr *counter, use_counter = 1; if (idx < 0) idx = 0; + startidx = idx; _next_block: - ke = pfr_kentry_byidx(kt, idx, af); - if (ke == NULL) { + if (loop && startidx == idx) { pfr_kstate_counter_add(&kt->pfrkt_nomatch, 1); return (1); } + + ke = pfr_kentry_byidx(kt, idx, af); + if (ke == NULL) { + /* we don't have this idx, try looping */ + if (loop || (ke = pfr_kentry_byidx(kt, 0, af)) == NULL) { + pfr_kstate_counter_add(&kt->pfrkt_nomatch, 1); + return (1); + } + idx = 0; + loop++; + } pfr_prepare_network(&umask, af, ke->pfrke_net); pfr_sockaddr_to_pf_addr(&ke->pfrke_sa, &cur); pfr_sockaddr_to_pf_addr(&umask, &mask); - if (use_counter) { + if (use_counter && !PF_AZERO(counter, af)) { /* is supplied address within block? */ if (!PF_MATCHA(0, &cur, &mask, counter, af)) { /* no, go to next block in table */ |