aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKristof Provost <kp@FreeBSD.org>2021-01-13 18:30:01 +0000
committerKristof Provost <kp@FreeBSD.org>2021-01-13 18:49:42 +0000
commitea36212bf5711206bbaf5362a23ebb52c7f7e2a4 (patch)
tree046c28493102ade1aa2215296fe3494481e0ecfa
parentfdaf9cb942d995969b79eb8ad3fa91b7592198cd (diff)
pf: Don't hold PF_RULES_WLOCK during copyin() on DIOCRCLRTSTATS
We cannot hold a non-sleepable lock during copyin(). This means we can't safely count the table, so instead we fall back to the pf_ioctl_maxcount used in other ioctls to protect against overly large requests. Reported by: syzbot+81e380344d4a6c37d78a@syzkaller.appspotmail.com MFC after: 1 week
-rw-r--r--sys/netpfil/pf/pf_ioctl.c17
1 files changed, 8 insertions, 9 deletions
diff --git a/sys/netpfil/pf/pf_ioctl.c b/sys/netpfil/pf/pf_ioctl.c
index b6e2ec98ddce..60c38a980d1e 100644
--- a/sys/netpfil/pf/pf_ioctl.c
+++ b/sys/netpfil/pf/pf_ioctl.c
@@ -3363,36 +3363,35 @@ DIOCCHANGEADDR_error:
struct pfioc_table *io = (struct pfioc_table *)addr;
struct pfr_table *pfrts;
size_t totlen;
- int n;
if (io->pfrio_esize != sizeof(struct pfr_table)) {
error = ENODEV;
break;
}
- PF_RULES_WLOCK();
- n = pfr_table_count(&io->pfrio_table, io->pfrio_flags);
- if (n < 0) {
- PF_RULES_WUNLOCK();
- error = EINVAL;
+ if (io->pfrio_size < 0 || io->pfrio_size > pf_ioctl_maxcount ||
+ WOULD_OVERFLOW(io->pfrio_size, sizeof(struct pfr_table))) {
+ /* We used to count tables and use the minimum required
+ * size, so we didn't fail on overly large requests.
+ * Keep doing so. */
+ io->pfrio_size = pf_ioctl_maxcount;
break;
}
- io->pfrio_size = min(io->pfrio_size, n);
totlen = io->pfrio_size * sizeof(struct pfr_table);
pfrts = mallocarray(io->pfrio_size, sizeof(struct pfr_table),
M_TEMP, M_NOWAIT);
if (pfrts == NULL) {
error = ENOMEM;
- PF_RULES_WUNLOCK();
break;
}
error = copyin(io->pfrio_buffer, pfrts, totlen);
if (error) {
free(pfrts, M_TEMP);
- PF_RULES_WUNLOCK();
break;
}
+
+ PF_RULES_WLOCK();
error = pfr_clr_tstats(pfrts, io->pfrio_size,
&io->pfrio_nzero, io->pfrio_flags | PFR_FLAG_USERIOCTL);
PF_RULES_WUNLOCK();