On Thu, Jul 21, 2022 at 11:13:28AM +0200, Moritz Buhl wrote: > Hi tech, > > for the other two DIOCX ioctls syzkaller showed that it is possible > to grab netlock while doing copyin. > > The same problem should exist for DIOCXCOMMIT but syzkaller didn't > find it yet. > > In case anybody can reproduce the witness lock order reversals the > syzkaller can produce, the diff below might address the problem. > > mbuhl
OK bluhm@ > Index: sys/net/pf_ioctl.c > =================================================================== > RCS file: /cvs/src/sys/net/pf_ioctl.c,v > retrieving revision 1.383 > diff -u -p -r1.383 pf_ioctl.c > --- sys/net/pf_ioctl.c 20 Jul 2022 09:33:11 -0000 1.383 > +++ sys/net/pf_ioctl.c 20 Jul 2022 18:17:45 -0000 > @@ -2621,13 +2621,9 @@ pfioctl(dev_t dev, u_long cmd, caddr_t a > } > ioe = malloc(sizeof(*ioe), M_TEMP, M_WAITOK); > table = malloc(sizeof(*table), M_TEMP, M_WAITOK); > - NET_LOCK(); > - PF_LOCK(); > /* first makes sure everything will succeed */ > for (i = 0; i < io->size; i++) { > if (copyin(io->array+i, ioe, sizeof(*ioe))) { > - PF_UNLOCK(); > - NET_UNLOCK(); > free(table, M_TEMP, sizeof(*table)); > free(ioe, M_TEMP, sizeof(*ioe)); > error = EFAULT; > @@ -2635,13 +2631,13 @@ pfioctl(dev_t dev, u_long cmd, caddr_t a > } > if (strnlen(ioe->anchor, sizeof(ioe->anchor)) == > sizeof(ioe->anchor)) { > - PF_UNLOCK(); > - NET_UNLOCK(); > free(table, M_TEMP, sizeof(*table)); > free(ioe, M_TEMP, sizeof(*ioe)); > error = ENAMETOOLONG; > goto fail; > } > + NET_LOCK(); > + PF_LOCK(); > switch (ioe->type) { > case PF_TRANS_TABLE: > rs = pf_find_ruleset(ioe->anchor); > @@ -2677,7 +2673,11 @@ pfioctl(dev_t dev, u_long cmd, caddr_t a > error = EINVAL; > goto fail; > } > + PF_UNLOCK(); > + NET_UNLOCK(); > } > + NET_LOCK(); > + PF_LOCK(); > > /* > * Checked already in DIOCSETLIMIT, but check again as the > @@ -2696,9 +2696,9 @@ pfioctl(dev_t dev, u_long cmd, caddr_t a > } > /* now do the commit - no errors should happen here */ > for (i = 0; i < io->size; i++) { > + PF_UNLOCK(); > + NET_UNLOCK(); > if (copyin(io->array+i, ioe, sizeof(*ioe))) { > - PF_UNLOCK(); > - NET_UNLOCK(); > free(table, M_TEMP, sizeof(*table)); > free(ioe, M_TEMP, sizeof(*ioe)); > error = EFAULT; > @@ -2706,13 +2706,13 @@ pfioctl(dev_t dev, u_long cmd, caddr_t a > } > if (strnlen(ioe->anchor, sizeof(ioe->anchor)) == > sizeof(ioe->anchor)) { > - PF_UNLOCK(); > - NET_UNLOCK(); > free(table, M_TEMP, sizeof(*table)); > free(ioe, M_TEMP, sizeof(*ioe)); > error = ENAMETOOLONG; > goto fail; > } > + NET_LOCK(); > + PF_LOCK(); > switch (ioe->type) { > case PF_TRANS_TABLE: > memset(table, 0, sizeof(*table));