From f3a753b5d08950d5841ff29dc67c3de26fb7ab37 Mon Sep 17 00:00:00 2001 From: mbuhl Date: Fri, 29 Apr 2022 09:55:43 +0000 Subject: [PATCH] Release PF und NET lock before calling copyout for DIOCIGETIFACES. OK sashan@ Reported-by: syzbot+b6afd166e314799e3809@syzkaller.appspotmail.com --- sys/net/pf_if.c | 12 +++--------- sys/net/pf_ioctl.c | 20 ++++++++++++++++---- sys/net/pfvar.h | 4 ++-- 3 files changed, 21 insertions(+), 15 deletions(-) diff --git a/sys/net/pf_if.c b/sys/net/pf_if.c index 7d12cfe934d..e5dd4ad963b 100644 --- a/sys/net/pf_if.c +++ b/sys/net/pf_if.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pf_if.c,v 1.103 2021/12/26 01:00:32 sashan Exp $ */ +/* $OpenBSD: pf_if.c,v 1.104 2022/04/29 09:55:43 mbuhl Exp $ */ /* * Copyright 2005 Henning Brauer @@ -755,7 +755,7 @@ pfi_update_status(const char *name, struct pf_status *pfs) } } -int +void pfi_get_ifaces(const char *name, struct pfi_kif *buf, int *size) { struct pfi_kif *p, *nextp; @@ -768,17 +768,11 @@ pfi_get_ifaces(const char *name, struct pfi_kif *buf, int *size) if (*size > n++) { if (!p->pfik_tzero) p->pfik_tzero = gettime(); - pfi_kif_ref(p, PFI_KIF_REF_RULE); - if (copyout(p, buf++, sizeof(*buf))) { - pfi_kif_unref(p, PFI_KIF_REF_RULE); - return (EFAULT); - } + memcpy(buf++, p, sizeof(*buf)); nextp = RB_NEXT(pfi_ifhead, &pfi_ifs, p); - pfi_kif_unref(p, PFI_KIF_REF_RULE); } } *size = n; - return (0); } int diff --git a/sys/net/pf_ioctl.c b/sys/net/pf_ioctl.c index b6d9a26545e..8315b115474 100644 --- a/sys/net/pf_ioctl.c +++ b/sys/net/pf_ioctl.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pf_ioctl.c,v 1.379 2022/04/09 13:15:44 mbuhl Exp $ */ +/* $OpenBSD: pf_ioctl.c,v 1.380 2022/04/29 09:55:43 mbuhl Exp $ */ /* * Copyright (c) 2001 Daniel Hartmeier @@ -2921,18 +2921,30 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) break; case DIOCIGETIFACES: { - struct pfioc_iface *io = (struct pfioc_iface *)addr; + struct pfioc_iface *io = (struct pfioc_iface *)addr; + struct pfi_kif *kif_buf; + int apfiio_size = io->pfiio_size; if (io->pfiio_esize != sizeof(struct pfi_kif)) { error = ENODEV; goto fail; } + + if ((kif_buf = mallocarray(sizeof(*kif_buf), apfiio_size, + M_TEMP, M_WAITOK|M_CANFAIL)) == NULL) { + error = EINVAL; + goto fail; + } + NET_LOCK(); PF_LOCK(); - error = pfi_get_ifaces(io->pfiio_name, io->pfiio_buffer, - &io->pfiio_size); + pfi_get_ifaces(io->pfiio_name, kif_buf, &io->pfiio_size); PF_UNLOCK(); NET_UNLOCK(); + if (copyout(kif_buf, io->pfiio_buffer, sizeof(*kif_buf) * + io->pfiio_size)) + error = EFAULT; + free(kif_buf, M_TEMP, sizeof(*kif_buf) * apfiio_size); break; } diff --git a/sys/net/pfvar.h b/sys/net/pfvar.h index 4abcbaf0b90..93394e6da5c 100644 --- a/sys/net/pfvar.h +++ b/sys/net/pfvar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: pfvar.h,v 1.506 2022/04/21 15:22:49 sashan Exp $ */ +/* $OpenBSD: pfvar.h,v 1.507 2022/04/29 09:55:43 mbuhl Exp $ */ /* * Copyright (c) 2001 Daniel Hartmeier @@ -1879,7 +1879,7 @@ int pfi_dynaddr_setup(struct pf_addr_wrap *, sa_family_t); void pfi_dynaddr_remove(struct pf_addr_wrap *); void pfi_dynaddr_copyout(struct pf_addr_wrap *); void pfi_update_status(const char *, struct pf_status *); -int pfi_get_ifaces(const char *, struct pfi_kif *, int *); +void pfi_get_ifaces(const char *, struct pfi_kif *, int *); int pfi_set_flags(const char *, int); int pfi_clear_flags(const char *, int); void pfi_xcommit(void); -- 2.20.1