- 论坛徽章:
- 0
|
- buffer overflow is discovered in parsing TCP options,
- in both tcp_sack() and tcp_options() functions,
- implemented in nf_conntrack_proto_tcp.c of linux-2.6.22/23.x
- /* in linux-2.6.23.8/net/netfilter/nf_conntrack_proto_tcp.c */
- static void tcp_options(const struct sk_buff *skb,
- unsigned int dataoff,
- struct tcphdr *tcph,
- struct ip_ct_tcp_state *state)
- {
- unsigned char buff[(15 *4) - sizeof(struct tcphdr)];
- unsigned char *ptr;
- int length = (tcph->doff *4) - sizeof(struct tcphdr);
- if (!length)
- return;
- /*
- If 108-byte TCP SYN packet is received in
- the manner of two frags:
- farg-I, 20-byte-IP + 20-byte-TCP + 24-byte-TCP_OPT
- and tcp->doff assigned to 0xf
- farg-II, 20-byte-IP + 16-byte-TCP_OPT + 28-byte-TRASH
- then the `ptr' is forcedly assigned to `buff',
- and sizeof(buff) is 40-byte.
- */
- ptr = skb_header_pointer(skb, dataoff + sizeof(struct tcphdr),
- length, buff);
- BUG_ON(ptr == NULL);
- state->td_scale = state->flags = 0;
- /*
- the 40-byte-TCP_OPT is simply filled, and
- copied into `buff' by skb_header_pointer(),
- buff[0 ... 38] = TCPOPT_NOP ;
- buff[39] = TCPOPT_WINDOW ;
- */
- while (length > 0) {
- int opcode = *ptr++;
- int opsize;
- switch (opcode) {
- case TCPOPT_EOL:
- return;
- case TCPOPT_NOP: /* Ref: RFC 793 section 3.1 */
- length--;
- continue;
- default:
- /*
- if (opcode == TCPOPT_WINDOW)
- buff overflow ;/
- */
- opsize = *ptr++;
- if (opsize < 2) /* silly options */
- return;
- if (opsize > length)
- break; /* don't parse partial options */
- if (opcode == TCPOPT_SACK_PERM
- && opsize == TCPOLEN_SACK_PERM)
- state->flags |= IP_CT_TCP_FLAG_SACK_PERM;
- else if (opcode == TCPOPT_WINDOW
- && opsize == TCPOLEN_WINDOW) {
- state->td_scale = *(u_int8_t *)ptr;
- if (state->td_scale > 14) {
- /* See RFC1323 */
- state->td_scale = 14;
- }
- state->flags |= IP_CT_TCP_FLAG_WINDOW_SCALE;
- }
- ptr += opsize - 2;
- length -= opsize;
- }
- }
- }
复制代码 |
|