From 4cc49383369b92c6782965203dd7c6f756272115 Mon Sep 17 00:00:00 2001 From: kp Date: Sun, 26 Apr 2020 16:16:39 +0000 Subject: [PATCH] pf: Improve input validation If we pass an anchor name which doesn't exist pfr_table_count() returns -1, which leads to an overflow in mallocarray() and thus a panic. Explicitly check that pfr_table_count() does not return an error. Reported-by: syzbot+bd09d55d897d63d5f4f4@syzkaller.appspotmail.com Reviewed by: melifaro MFC after: 1 week Differential Revision: https://reviews.freebsd.org/D24539 --- sys/netpfil/pf/pf_ioctl.c | 33 +++++++++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/sys/netpfil/pf/pf_ioctl.c b/sys/netpfil/pf/pf_ioctl.c index af7116befff7..6db6c60821c1 100644 --- a/sys/netpfil/pf/pf_ioctl.c +++ b/sys/netpfil/pf/pf_ioctl.c @@ -3008,7 +3008,8 @@ pfioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags, struct thread *td case DIOCRGETTABLES: { struct pfioc_table *io = (struct pfioc_table *)addr; struct pfr_table *pfrts; - size_t totlen, n; + size_t totlen; + int n; if (io->pfrio_esize != sizeof(struct pfr_table)) { error = ENODEV; @@ -3016,6 +3017,11 @@ pfioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags, struct thread *td } PF_RULES_RLOCK(); n = pfr_table_count(&io->pfrio_table, io->pfrio_flags); + if (n < 0) { + PF_RULES_RUNLOCK(); + error = EINVAL; + break; + } io->pfrio_size = min(io->pfrio_size, n); totlen = io->pfrio_size * sizeof(struct pfr_table); @@ -3039,7 +3045,8 @@ pfioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags, struct thread *td case DIOCRGETTSTATS: { struct pfioc_table *io = (struct pfioc_table *)addr; struct pfr_tstats *pfrtstats; - size_t totlen, n; + size_t totlen; + int n; if (io->pfrio_esize != sizeof(struct pfr_tstats)) { error = ENODEV; @@ -3047,6 +3054,11 @@ pfioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags, struct thread *td } PF_RULES_WLOCK(); n = pfr_table_count(&io->pfrio_table, io->pfrio_flags); + if (n < 0) { + PF_RULES_WUNLOCK(); + error = EINVAL; + break; + } io->pfrio_size = min(io->pfrio_size, n); totlen = io->pfrio_size * sizeof(struct pfr_tstats); @@ -3069,7 +3081,8 @@ pfioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags, struct thread *td case DIOCRCLRTSTATS: { struct pfioc_table *io = (struct pfioc_table *)addr; struct pfr_table *pfrts; - size_t totlen, n; + size_t totlen; + int n; if (io->pfrio_esize != sizeof(struct pfr_table)) { error = ENODEV; @@ -3078,6 +3091,11 @@ pfioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags, struct thread *td PF_RULES_WLOCK(); n = pfr_table_count(&io->pfrio_table, io->pfrio_flags); + if (n < 0) { + PF_RULES_WUNLOCK(); + error = EINVAL; + break; + } io->pfrio_size = min(io->pfrio_size, n); totlen = io->pfrio_size * sizeof(struct pfr_table); @@ -3104,7 +3122,8 @@ pfioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags, struct thread *td case DIOCRSETTFLAGS: { struct pfioc_table *io = (struct pfioc_table *)addr; struct pfr_table *pfrts; - size_t totlen, n; + size_t totlen; + int n; if (io->pfrio_esize != sizeof(struct pfr_table)) { error = ENODEV; @@ -3113,6 +3132,12 @@ pfioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags, struct thread *td PF_RULES_RLOCK(); n = pfr_table_count(&io->pfrio_table, io->pfrio_flags); + if (n < 0) { + PF_RULES_RUNLOCK(); + error = EINVAL; + break; + } + io->pfrio_size = min(io->pfrio_size, n); PF_RULES_RUNLOCK();