From bf56a3fe47ef43441c098ef11d553fb5ce78673a Mon Sep 17 00:00:00 2001 From: Kristof Provost Date: Sun, 25 Feb 2018 08:56:44 +0000 Subject: [PATCH] pf: Cope with overly large net.pf.states_hashsize If the user configures a states_hashsize or source_nodes_hashsize value we may not have enough memory to allocate this. This used to lock up pf, because these allocations used M_WAITOK. Cope with this by attempting the allocation with M_NOWAIT and falling back to the default sizes (with M_WAITOK) if these fail. PR: 209475 Submitted by: Fehmi Noyan Isi MFC after: 3 weeks Differential Revision: https://reviews.freebsd.org/D14367 --- sys/net/pfvar.h | 1 + sys/netpfil/pf/pf.c | 39 ++++++++++++++++++++++++++++++++------- 2 files changed, 33 insertions(+), 7 deletions(-) diff --git a/sys/net/pfvar.h b/sys/net/pfvar.h index c9b1d1db1ad..5ea6114def1 100644 --- a/sys/net/pfvar.h +++ b/sys/net/pfvar.h @@ -1467,6 +1467,7 @@ struct pf_idhash { extern u_long pf_hashmask; extern u_long pf_srchashmask; #define PF_HASHSIZ (32768) +#define PF_SRCHASHSIZ (PF_HASHSIZ/4) VNET_DECLARE(struct pf_keyhash *, pf_keyhash); VNET_DECLARE(struct pf_idhash *, pf_idhash); #define V_pf_keyhash VNET(pf_keyhash) diff --git a/sys/netpfil/pf/pf.c b/sys/netpfil/pf/pf.c index c91cc514a94..6f1634604e9 100644 --- a/sys/netpfil/pf/pf.c +++ b/sys/netpfil/pf/pf.c @@ -790,7 +790,7 @@ pf_initialize() if (pf_hashsize == 0 || !powerof2(pf_hashsize)) pf_hashsize = PF_HASHSIZ; if (pf_srchashsize == 0 || !powerof2(pf_srchashsize)) - pf_srchashsize = PF_HASHSIZ / 4; + pf_srchashsize = PF_SRCHASHSIZ; V_pf_hashseed = arc4random(); @@ -804,10 +804,25 @@ pf_initialize() V_pf_state_key_z = uma_zcreate("pf state keys", sizeof(struct pf_state_key), pf_state_key_ctor, NULL, NULL, NULL, UMA_ALIGN_PTR, 0); - V_pf_keyhash = malloc(pf_hashsize * sizeof(struct pf_keyhash), - M_PFHASH, M_WAITOK | M_ZERO); - V_pf_idhash = malloc(pf_hashsize * sizeof(struct pf_idhash), - M_PFHASH, M_WAITOK | M_ZERO); + + V_pf_keyhash = mallocarray(pf_hashsize, sizeof(struct pf_keyhash), + M_PFHASH, M_NOWAIT | M_ZERO); + V_pf_idhash = mallocarray(pf_hashsize, sizeof(struct pf_idhash), + M_PFHASH, M_NOWAIT | M_ZERO); + if (V_pf_keyhash == NULL || V_pf_idhash == NULL) { + printf("pf: Unable to allocate memory for " + "state_hashsize %lu.\n", pf_hashsize); + + free(V_pf_keyhash, M_PFHASH); + free(V_pf_idhash, M_PFHASH); + + pf_hashsize = PF_HASHSIZ; + V_pf_keyhash = mallocarray(pf_hashsize, + sizeof(struct pf_keyhash), M_PFHASH, M_WAITOK | M_ZERO); + V_pf_idhash = mallocarray(pf_hashsize, + sizeof(struct pf_idhash), M_PFHASH, M_WAITOK | M_ZERO); + } + pf_hashmask = pf_hashsize - 1; for (i = 0, kh = V_pf_keyhash, ih = V_pf_idhash; i <= pf_hashmask; i++, kh++, ih++) { @@ -822,8 +837,18 @@ pf_initialize() V_pf_limits[PF_LIMIT_SRC_NODES].zone = V_pf_sources_z; uma_zone_set_max(V_pf_sources_z, PFSNODE_HIWAT); uma_zone_set_warning(V_pf_sources_z, "PF source nodes limit reached"); - V_pf_srchash = malloc(pf_srchashsize * sizeof(struct pf_srchash), - M_PFHASH, M_WAITOK|M_ZERO); + + V_pf_srchash = mallocarray(pf_srchashsize, + sizeof(struct pf_srchash), M_PFHASH, M_NOWAIT | M_ZERO); + if (V_pf_srchash == NULL) { + printf("pf: Unable to allocate memory for " + "source_hashsize %lu.\n", pf_srchashsize); + + pf_srchashsize = PF_SRCHASHSIZ; + V_pf_srchash = mallocarray(pf_srchashsize, + sizeof(struct pf_srchash), M_PFHASH, M_WAITOK | M_ZERO); + } + pf_srchashmask = pf_srchashsize - 1; for (i = 0, sh = V_pf_srchash; i <= pf_srchashmask; i++, sh++) mtx_init(&sh->lock, "pf_srchash", NULL, MTX_DEF); -- 2.45.2