pf: Fix table entry counter toggling

When updating a table, pf will keep existing table entry structures
corresponding to addresses that are in both of the old and new tables.
However, the update may also enable or disable per-entry counters which
are allocated separately.  Thus when toggling PFR_TFLAG_COUNTERS, the
entries may be missing counters or may have unused counters allocated.

Fix the problem by modifying pfr_ina_commit() to transfer counters
from or to entries in the shadow table.

PR:		251414
Reported by:	sigsys@gmail.com
Reviewed by:	kp
MFC after:	1 week
Sponsored by:	The FreeBSD Foundation
Differential Revision:	https://reviews.freebsd.org/D27440
This commit is contained in:
Mark Johnston 2020-12-02 16:01:43 +00:00
parent 8d08cdc721
commit e6aed06fdf
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=368276

View File

@ -1641,6 +1641,7 @@ pfr_ina_commit(struct pfr_table *trs, u_int32_t ticket, int *nadd,
static void
pfr_commit_ktable(struct pfr_ktable *kt, long tzero)
{
counter_u64_t *pkc, *qkc;
struct pfr_ktable *shadow = kt->pfrkt_shadow;
int nflags;
@ -1662,14 +1663,17 @@ pfr_commit_ktable(struct pfr_ktable *kt, long tzero)
SLIST_INIT(&delq);
SLIST_INIT(&garbageq);
pfr_clean_node_mask(shadow, &addrq);
for (p = SLIST_FIRST(&addrq); p != NULL; p = next) {
next = SLIST_NEXT(p, pfrke_workq); /* XXX */
SLIST_FOREACH_SAFE(p, &addrq, pfrke_workq, next) {
pfr_copyout_addr(&ad, p);
q = pfr_lookup_addr(kt, &ad, 1);
if (q != NULL) {
if (q->pfrke_not != p->pfrke_not)
SLIST_INSERT_HEAD(&changeq, q,
pfrke_workq);
pkc = &p->pfrke_counters.pfrkc_counters;
qkc = &q->pfrke_counters.pfrkc_counters;
if ((*pkc == NULL) != (*qkc == NULL))
SWAP(counter_u64_t, *pkc, *qkc);
q->pfrke_mark = 1;
SLIST_INSERT_HEAD(&garbageq, p, pfrke_workq);
} else {