Skip to content

Commit

Permalink
Merge pull request #217 from flaviojs/fix-buffer-overflow-eth_switch
Browse files Browse the repository at this point in the history
Fix buffer overflow in eth_switch.
  • Loading branch information
grossmj authored Apr 3, 2024
2 parents 40a1618 + d3bc782 commit d435d97
Show file tree
Hide file tree
Showing 2 changed files with 153 additions and 3 deletions.
42 changes: 39 additions & 3 deletions common/eth_switch.c
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ static void dot1q_pop_tag(m_uint8_t *pkt,ethsw_packet_t *sp)
static void ethsw_iv_access(ethsw_table_t *t,ethsw_packet_t *sp,
netio_desc_t *op)
{
m_uint8_t pkt[ETHSW_MAX_PKT_SIZE+4];
m_uint8_t *pkt;

switch(op->vlan_port_type) {
/* Access -> Access: no special treatment */
Expand All @@ -116,8 +116,14 @@ static void ethsw_iv_access(ethsw_table_t *t,ethsw_packet_t *sp,
if (op->vlan_id == sp->input_vlan) {
netio_send(op,sp->pkt,sp->pkt_len);
} else {
pkt = malloc(sp->pkt_len+4);
if (pkt == NULL) {
perror("ethsw_iv_access: dot1q");
break;
}
dot1q_push_tag(pkt,sp,op->vlan_id,sp->input_port->ethertype);
netio_send(op,pkt,sp->pkt_len+4);
free(pkt);
}
break;

Expand All @@ -131,7 +137,7 @@ static void ethsw_iv_access(ethsw_table_t *t,ethsw_packet_t *sp,
static void ethsw_iv_dot1q(ethsw_table_t *t,ethsw_packet_t *sp,
netio_desc_t *op)
{
m_uint8_t pkt[ETHSW_MAX_PKT_SIZE+4];
m_uint8_t *pkt;

/* If we don't have an input tag, we work temporarily as an access port */
if (!sp->input_tag) {
Expand All @@ -142,15 +148,27 @@ static void ethsw_iv_dot1q(ethsw_table_t *t,ethsw_packet_t *sp,
switch(op->vlan_port_type) {
/* 802.1Q -> Access: pop tag */
case ETHSW_PORT_TYPE_ACCESS:
pkt = malloc(sp->pkt_len-4);
if (pkt == NULL) {
perror("ethsw_iv_dot1q: access");
break;
}
dot1q_pop_tag(pkt,sp);
netio_send(op,pkt,sp->pkt_len-4);
free(pkt);
break;

/* 802.1Q -> 802.1Q: pop tag if native VLAN in output otherwise no-op */
case ETHSW_PORT_TYPE_DOT1Q:
if (op->vlan_id == sp->input_vlan) {
pkt = malloc(sp->pkt_len-4);
if (pkt == NULL) {
perror("ethsw_iv_dot1q: dot1q");
break;
}
dot1q_pop_tag(pkt,sp);
netio_send(op,pkt,sp->pkt_len-4);
free(pkt);
} else {
netio_send(op,sp->pkt,sp->pkt_len);
}
Expand All @@ -162,8 +180,14 @@ static void ethsw_iv_dot1q(ethsw_table_t *t,ethsw_packet_t *sp,
*/
case ETHSW_PORT_TYPE_QINQ:
if (op->vlan_id == sp->input_vlan) {
pkt = malloc(sp->pkt_len-4);
if (pkt == NULL) {
perror("ethsw_iv_dot1q: qinq");
break;
}
dot1q_pop_tag(pkt,sp);
netio_send(op,pkt,sp->pkt_len-4);
free(pkt);
}
break;

Expand All @@ -177,13 +201,19 @@ static void ethsw_iv_dot1q(ethsw_table_t *t,ethsw_packet_t *sp,
static void ethsw_iv_qinq(ethsw_table_t *t,ethsw_packet_t *sp,
netio_desc_t *op)
{
m_uint8_t pkt[ETHSW_MAX_PKT_SIZE+4];
m_uint8_t *pkt;

switch(op->vlan_port_type) {
/* QinQ -> 802.1Q: push outer tag */
case ETHSW_PORT_TYPE_DOT1Q:
pkt = malloc(sp->pkt_len+4);
if (pkt == NULL) {
perror("ethsw_iv_qinq: dot1q");
break;
}
dot1q_push_tag(pkt,sp,sp->input_port->vlan_id,sp->input_port->ethertype);
netio_send(op,pkt,sp->pkt_len+4);
free(pkt);
break;

/*
Expand All @@ -192,8 +222,14 @@ static void ethsw_iv_qinq(ethsw_table_t *t,ethsw_packet_t *sp,
*/
case ETHSW_PORT_TYPE_QINQ:
if (sp->input_port->vlan_id == op->vlan_id) {
pkt = malloc(sp->pkt_len-4);
if (pkt == NULL) {
perror("ethsw_iv_qinq: qinq");
break;
}
dot1q_pop_tag(pkt,sp);
netio_send(op,pkt,sp->pkt_len-4);
free(pkt);
}
break;

Expand Down
114 changes: 114 additions & 0 deletions test/issue-105-linux.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
#!/usr/bin/env python3
# -*- coding: utf8 -*-
#
# test script for issue #105 "Ethernet switch crashes on JumboFrames+dot1q"
# @see https://github.com/GNS3/dynamips/issues/105
#
# assumes a linux OS and dynamips in ../build/stable

linux_setup = """
sudo ip link add vl0 type veth peer name vl1
sudo ip link add vr0 type veth peer name vr1
sudo ip l set up vl0 mtu 9000
sudo ip l set up vr0 mtu 9000
sudo ip netns add left
sudo ip netns add right
sudo ip link set dev vl1 netns left
sudo ip link set dev vr1 netns right
sudo ip netns exec left ip link set vl1 up mtu 9000
sudo ip netns exec right ip link set vr1 up mtu 9000
sudo ip netns exec left ip addr add 10.0.0.1/24 dev vl1
sudo ip netns exec right ip addr add 10.0.0.2/24 dev vr1
"""

linux_cleanup = """
sudo ip netns del right
sudo ip netns del left
"""

hypervisor = """
ethsw create sw1
nio create_gen_eth E10 vl0
nio create_udp E11 10001 127.0.0.1 20001
ethsw add_nio sw1 E10
ethsw add_nio sw1 E11
ethsw set_access_port sw1 E10 10
ethsw set_dot1q_port sw1 E11 1
ethsw create sw2
nio create_gen_eth E20 vr0
nio create_udp E21 20001 127.0.0.1 10001
ethsw add_nio sw2 E20
ethsw add_nio sw2 E21
ethsw set_access_port sw2 E20 10
ethsw set_dot1q_port sw2 E21 1
"""

# success: all pings work
# fail: buffer overflow in dynamips
linux_test = """
sudo ip netns exec left ping 10.0.0.2 -s 8000 -c 10
"""

import subprocess
import time

def sleep(secs=0.1):
time.sleep(secs) # give some time to other processes

def each_line(code):
for line in code.split("\n"):
line = line.strip()
if line == "":
continue
yield line

def run_script(script, prefix=""):
for line in each_line(script):
print(prefix, line)
subprocess.run(line.split())
sleep()

def dynamips_hypervisor():
# stdin needs to be a PIPE to protect the script console
dynamips = subprocess.Popen(
["sudo", "./dynamips", "-H", "10000"],
cwd="../build/stable",
text=True,
stdin=subprocess.PIPE,
stderr=subprocess.STDOUT)
sleep(1) # extra time for 1st time stuff
return dynamips

def telnet_hypervisor():
telnet = subprocess.Popen(
["telnet", "127.0.0.1", "10000"],
text=True,
stdin=subprocess.PIPE,
stderr=subprocess.STDOUT)
def run_script(script, prefix=""):
for line in each_line(script):
print(prefix, line)
telnet.stdin.write(line + "\n")
telnet.stdin.flush()
sleep()
telnet.run_script = run_script
sleep()
return telnet


run_script(linux_setup, prefix="[SETUP]")
print("[DYNAMIPS.START]")
with dynamips_hypervisor() as dynamips:
print("[TELNET.START]")
with telnet_hypervisor() as telnet:
telnet.run_script(hypervisor, prefix="[TELNET]")
print("[TELNET.STOP]")
run_script(linux_test, prefix="[TEST]")
dynamips.terminate()
sleep()
dynamips.kill()
print("[DYNAMIPS.STOP]")
run_script(linux_cleanup, prefix="[CLEANUP]")

0 comments on commit d435d97

Please sign in to comment.