pf: Fix panic on invalid DIOCRSETTFLAGS

If during DIOCRSETTFLAGS pfrio_buffer is NULL copyin() will fault, which we're
not allowed to do with a lock held.
We must count the number of entries in the table and release the lock during
copyin(). Only then can we re-acquire the lock. Note that this is safe, because
pfr_set_tflags() will check if the table and entries exist.

This was discovered by a local syzcaller instance.

MFC after:	1 week
Event:		Aberdeen hackathon 2019
This commit is contained in:
Kristof Provost 2019-04-17 16:42:54 +00:00
parent b6539d47bd
commit f5e0d9fcb4
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=346319

View File

@ -3103,24 +3103,24 @@ pfioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags, struct thread *td
break;
}
PF_RULES_WLOCK();
PF_RULES_RLOCK();
n = pfr_table_count(&io->pfrio_table, io->pfrio_flags);
io->pfrio_size = min(io->pfrio_size, n);
PF_RULES_RUNLOCK();
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_set_tflags(pfrts, io->pfrio_size,
io->pfrio_setflag, io->pfrio_clrflag, &io->pfrio_nchange,
&io->pfrio_ndel, io->pfrio_flags | PFR_FLAG_USERIOCTL);