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> MFC after: 1 week
This commit is contained in:
parent
c941e8c65d
commit
79f7745c09
@ -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 @@ ipf_check(void *ctx, ip_t *ip, int hlen, struct ifnet *ifp, int out
|
||||
|
||||
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);
|
||||
|
Loading…
Reference in New Issue
Block a user