doc/share/security/patches/SA-20:10/ipfw.11.patch
Gordon Tetlow 9b4c8884f1 Add EN-20:07, SA-20:10, and SA-20:11.
Approved by:	so
2020-04-21 16:29:32 +00:00

136 lines
3 KiB
Diff

--- sys/netpfil/ipfw/ip_fw2.c.orig
+++ sys/netpfil/ipfw/ip_fw2.c
@@ -328,50 +328,71 @@
return (flags_match(cmd, bits));
}
+/*
+ * Parse TCP options. The logic copied from tcp_dooptions().
+ */
static int
-tcpopts_match(struct tcphdr *tcp, ipfw_insn *cmd)
+tcpopts_parse(const struct tcphdr *tcp, uint16_t *mss)
{
+ const u_char *cp = (const u_char *)(tcp + 1);
int optlen, bits = 0;
- u_char *cp = (u_char *)(tcp + 1);
- int x = (tcp->th_off << 2) - sizeof(struct tcphdr);
+ int cnt = (tcp->th_off << 2) - sizeof(struct tcphdr);
- for (; x > 0; x -= optlen, cp += optlen) {
+ for (; cnt > 0; cnt -= optlen, cp += optlen) {
int opt = cp[0];
if (opt == TCPOPT_EOL)
break;
if (opt == TCPOPT_NOP)
optlen = 1;
else {
+ if (cnt < 2)
+ break;
optlen = cp[1];
- if (optlen <= 0)
+ if (optlen < 2 || optlen > cnt)
break;
}
switch (opt) {
-
default:
break;
case TCPOPT_MAXSEG:
+ if (optlen != TCPOLEN_MAXSEG)
+ break;
bits |= IP_FW_TCPOPT_MSS;
+ if (mss != NULL)
+ *mss = be16dec(cp + 2);
break;
case TCPOPT_WINDOW:
- bits |= IP_FW_TCPOPT_WINDOW;
+ if (optlen == TCPOLEN_WINDOW)
+ bits |= IP_FW_TCPOPT_WINDOW;
break;
case TCPOPT_SACK_PERMITTED:
+ if (optlen == TCPOLEN_SACK_PERMITTED)
+ bits |= IP_FW_TCPOPT_SACK;
+ break;
+
case TCPOPT_SACK:
- bits |= IP_FW_TCPOPT_SACK;
+ if (optlen > 2 && (optlen - 2) % TCPOLEN_SACK == 0)
+ bits |= IP_FW_TCPOPT_SACK;
break;
case TCPOPT_TIMESTAMP:
- bits |= IP_FW_TCPOPT_TS;
+ if (optlen == TCPOLEN_TIMESTAMP)
+ bits |= IP_FW_TCPOPT_TS;
break;
-
}
}
- return (flags_match(cmd, bits));
+ return (bits);
+}
+
+static int
+tcpopts_match(struct tcphdr *tcp, ipfw_insn *cmd)
+{
+
+ return (flags_match(cmd, tcpopts_parse(tcp, NULL)));
}
static int
@@ -1419,17 +1440,31 @@
* this way).
*/
#define PULLUP_TO(_len, p, T) PULLUP_LEN(_len, p, sizeof(T))
-#define PULLUP_LEN(_len, p, T) \
+#define _PULLUP_LOCKED(_len, p, T, unlock) \
do { \
int x = (_len) + T; \
if ((m)->m_len < x) { \
args->m = m = m_pullup(m, x); \
- if (m == NULL) \
+ if (m == NULL) { \
+ unlock; \
goto pullup_failed; \
+ } \
} \
p = (mtod(m, char *) + (_len)); \
} while (0)
+#define PULLUP_LEN(_len, p, T) _PULLUP_LOCKED(_len, p, T, )
+#define PULLUP_LEN_LOCKED(_len, p, T) \
+ _PULLUP_LOCKED(_len, p, T, IPFW_PF_RUNLOCK(chain)); \
+ UPDATE_POINTERS()
+/*
+ * In case pointers got stale after pullups, update them.
+ */
+#define UPDATE_POINTERS() \
+do { \
+ ip = mtod(m, struct ip *); \
+} while (0)
+
/*
* if we have an ether header,
*/
@@ -2255,7 +2290,7 @@
case O_TCPOPTS:
if (proto == IPPROTO_TCP && offset == 0 && ulp){
- PULLUP_LEN(hlen, ulp,
+ PULLUP_LEN_LOCKED(hlen, ulp,
(TCP(ulp)->th_off << 2));
match = tcpopts_match(TCP(ulp), cmd);
}
@@ -3106,6 +3141,7 @@
} /* end of inner loop, scan opcodes */
#undef PULLUP_LEN
+#undef PULLUP_LEN_LOCKED
if (done)
break;