mirror of
https://github.com/opnsense/src.git
synced 2026-06-06 23:32:52 -04:00
ipfw: pmod: avoid further rule processing after tcp-mod failures
m_pullup() here will have freed the mbuf chain, but we pass back an IP_FW_DENY without any signal that the outer loop should finish. Thus, rule processing continues without an mbuf and there's a chance that we conclude that the packet may pass (but there's no mbuf remaining) depending on the rules that follow it. PR: 284606 Reviewed by: ae (cherry picked from commit c0382512bfce872102d213b9bc2550de0bc30b67)
This commit is contained in:
parent
b7c3332cf8
commit
ffedf88a1c
1 changed files with 16 additions and 9 deletions
|
|
@ -58,7 +58,8 @@ VNET_DEFINE_STATIC(uint16_t, tcpmod_setmss_eid) = 0;
|
|||
#define V_tcpmod_setmss_eid VNET(tcpmod_setmss_eid)
|
||||
|
||||
static int
|
||||
tcpmod_setmss(struct mbuf **mp, struct tcphdr *tcp, int tlen, uint16_t mss)
|
||||
tcpmod_setmss(struct mbuf **mp, struct tcphdr *tcp, int tlen, uint16_t mss,
|
||||
int *done)
|
||||
{
|
||||
struct mbuf *m;
|
||||
u_char *cp;
|
||||
|
|
@ -73,8 +74,10 @@ tcpmod_setmss(struct mbuf **mp, struct tcphdr *tcp, int tlen, uint16_t mss)
|
|||
* TCP header with options.
|
||||
*/
|
||||
*mp = m = m_pullup(m, m->m_pkthdr.len);
|
||||
if (m == NULL)
|
||||
if (m == NULL) {
|
||||
*done = 1;
|
||||
return (ret);
|
||||
}
|
||||
}
|
||||
/* Parse TCP options. */
|
||||
for (tlen -= sizeof(struct tcphdr), cp = (u_char *)(tcp + 1);
|
||||
|
|
@ -115,7 +118,7 @@ tcpmod_setmss(struct mbuf **mp, struct tcphdr *tcp, int tlen, uint16_t mss)
|
|||
|
||||
#ifdef INET6
|
||||
static int
|
||||
tcpmod_ipv6_setmss(struct mbuf **mp, uint16_t mss)
|
||||
tcpmod_ipv6_setmss(struct mbuf **mp, uint16_t mss, int *done)
|
||||
{
|
||||
struct ip6_hdr *ip6;
|
||||
struct ip6_hbh *hbh;
|
||||
|
|
@ -143,13 +146,13 @@ tcpmod_ipv6_setmss(struct mbuf **mp, uint16_t mss)
|
|||
/* We must have TCP options and enough data in a packet. */
|
||||
if (hlen <= sizeof(struct tcphdr) || hlen > plen)
|
||||
return (IP_FW_DENY);
|
||||
return (tcpmod_setmss(mp, tcp, hlen, mss));
|
||||
return (tcpmod_setmss(mp, tcp, hlen, mss, done));
|
||||
}
|
||||
#endif /* INET6 */
|
||||
|
||||
#ifdef INET
|
||||
static int
|
||||
tcpmod_ipv4_setmss(struct mbuf **mp, uint16_t mss)
|
||||
tcpmod_ipv4_setmss(struct mbuf **mp, uint16_t mss, int *done)
|
||||
{
|
||||
struct tcphdr *tcp;
|
||||
struct ip *ip;
|
||||
|
|
@ -163,7 +166,7 @@ tcpmod_ipv4_setmss(struct mbuf **mp, uint16_t mss)
|
|||
/* We must have TCP options and enough data in a packet. */
|
||||
if (hlen <= sizeof(struct tcphdr) || hlen > plen)
|
||||
return (IP_FW_DENY);
|
||||
return (tcpmod_setmss(mp, tcp, hlen, mss));
|
||||
return (tcpmod_setmss(mp, tcp, hlen, mss, done));
|
||||
}
|
||||
#endif /* INET */
|
||||
|
||||
|
|
@ -207,19 +210,23 @@ ipfw_tcpmod(struct ip_fw_chain *chain, struct ip_fw_args *args,
|
|||
switch (args->f_id.addr_type) {
|
||||
#ifdef INET
|
||||
case 4:
|
||||
ret = tcpmod_ipv4_setmss(&args->m, htons(icmd->arg1));
|
||||
ret = tcpmod_ipv4_setmss(&args->m, htons(icmd->arg1),
|
||||
done);
|
||||
break;
|
||||
#endif
|
||||
#ifdef INET6
|
||||
case 6:
|
||||
ret = tcpmod_ipv6_setmss(&args->m, htons(icmd->arg1));
|
||||
ret = tcpmod_ipv6_setmss(&args->m, htons(icmd->arg1),
|
||||
done);
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
/*
|
||||
* We return zero in both @ret and @done on success, and ipfw_chk()
|
||||
* will update rule counters. Otherwise a packet will not be matched
|
||||
* by rule.
|
||||
* by rule. We passed @done around above in case we hit a fatal error
|
||||
* somewhere, we'll return non-zero but signal that rule processing
|
||||
* cannot succeed.
|
||||
*/
|
||||
return (ret);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue