aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCy Schubert <cy@FreeBSD.org>2023-02-02 00:49:08 +0000
committerCy Schubert <cy@FreeBSD.org>2023-02-09 21:20:51 +0000
commit351f2f68852ac3e1d0ef745dc024dd745b07a34f (patch)
tree59e52535acdb9401cd58b6a8323f621c7d305d2a
parent272b2e191eadbd267e173e0ed4d9e19e48c97674 (diff)
downloadsrc-351f2f68852ac3e1d0ef745dc024dd745b07a34f.tar.gz
src-351f2f68852ac3e1d0ef745dc024dd745b07a34f.zip
ipfilter: Fix use after free on packet with broken lengths
Under the scenario with a packet with length of 67 bytes, a header length using the default of 20 bytes and a TCP data offset (th_off) of 48 will cause m_pullup() to fail to make sure bytes are arragned contiguously. m_pullup() will free the mbuf chain and return a null. ipfilter stores the resultant mbuf address (or the resulting NULL) in its fr_info_t structure. Unfortuntely the eroneous packet is not flagged for drop. This results in a kernel page fault at line 410 of sys/netinet/ip_fastfwd.c as it tries to use a now previously freed, by m_pullup(), mbuf. PR: 266442 Reported by: Robert Morris <rtm@lcs.mit.edu> (cherry picked from commit 79f7745c098a766d34a4e072cdd1a06e6d0829d5)
-rw-r--r--sys/netpfil/ipfilter/netinet/fil.c13
1 files changed, 12 insertions, 1 deletions
diff --git a/sys/netpfil/ipfilter/netinet/fil.c b/sys/netpfil/ipfilter/netinet/fil.c
index 4fa90f64fb33..3cf9111340a3 100644
--- a/sys/netpfil/ipfilter/netinet/fil.c
+++ b/sys/netpfil/ipfilter/netinet/fil.c
@@ -1113,8 +1113,10 @@ ipf_pr_pullup(fr_info_t *fin, int plen)
if (M_LEN(fin->fin_m) < plen + fin->fin_ipoff) {
#if defined(_KERNEL)
if (ipf_pullup(fin->fin_m, fin, plen) == NULL) {
- DT(ipf_pullup_fail);
+ DT1(ipf_pullup_fail, fr_info_t *, fin);
LBUMP(ipf_stats[fin->fin_out].fr_pull[1]);
+ fin->fin_reason = FRB_PULLUP;
+ fin->fin_flx |= FI_BAD;
return (-1);
}
LBUMP(ipf_stats[fin->fin_out].fr_pull[0]);
@@ -1127,6 +1129,7 @@ ipf_pr_pullup(fr_info_t *fin, int plen)
*fin->fin_mp = NULL;
fin->fin_m = NULL;
fin->fin_ip = NULL;
+ fin->fin_flx |= FI_BAD;
return (-1);
#endif
}
@@ -3180,6 +3183,14 @@ finished:
SPL_X(s);
+ if (fin->fin_m == NULL && fin->fin_flx & FI_BAD &&
+ fin->fin_reason == FRB_PULLUP) {
+ /* m_pullup() has freed the mbuf */
+ LBUMP(ipf_stats[out].fr_blocked[fin->fin_reason]);
+ return (-1);
+ }
+
+
#ifdef _KERNEL
if (FR_ISPASS(pass))
return (0);