Fix panic when logging raw packets via sniffer.

Sniffer assumed that outgoing packets have transport headers, but
users can write packets via SOCK_RAW with arbitrary transport headers that
netstack doesn't know about. We now explicitly check for the presence of network
and transport headers before assuming they exist.

PiperOrigin-RevId: 280594395
This commit is contained in:
Kevin Krakauer 2019-11-14 22:54:01 -08:00 committed by gVisor bot
parent af323eb7c1
commit 23574b1b87
1 changed files with 147 additions and 144 deletions

View File

@ -118,7 +118,7 @@ func NewWithFile(lower stack.LinkEndpoint, file *os.File, snapLen uint32) (stack
// logs the packet before forwarding to the actual dispatcher.
func (e *endpoint) DeliverNetworkPacket(linkEP stack.LinkEndpoint, remote, local tcpip.LinkAddress, protocol tcpip.NetworkProtocolNumber, pkt tcpip.PacketBuffer) {
if atomic.LoadUint32(&LogPackets) == 1 && e.file == nil {
logPacket("recv", protocol, pkt.Data.First(), nil)
logPacket("recv", protocol, pkt, nil)
}
if e.file != nil && atomic.LoadUint32(&LogPacketsToFile) == 1 {
vs := pkt.Data.Views()
@ -195,7 +195,7 @@ func (e *endpoint) GSOMaxSize() uint32 {
func (e *endpoint) dumpPacket(gso *stack.GSO, protocol tcpip.NetworkProtocolNumber, pkt tcpip.PacketBuffer) {
if atomic.LoadUint32(&LogPackets) == 1 && e.file == nil {
logPacket("send", protocol, pkt.Header.View(), gso)
logPacket("send", protocol, pkt, gso)
}
if e.file != nil && atomic.LoadUint32(&LogPacketsToFile) == 1 {
hdrBuf := pkt.Header.View()
@ -247,7 +247,7 @@ func (e *endpoint) WritePackets(r *stack.Route, gso *stack.GSO, hdrs []stack.Pac
// WriteRawPacket implements stack.LinkEndpoint.WriteRawPacket.
func (e *endpoint) WriteRawPacket(vv buffer.VectorisedView) *tcpip.Error {
if atomic.LoadUint32(&LogPackets) == 1 && e.file == nil {
logPacket("send", 0, buffer.View("[raw packet, no header available]"), nil /* gso */)
logPacket("send raw packet", 0, tcpip.PacketBuffer{}, nil /* gso */)
}
if e.file != nil && atomic.LoadUint32(&LogPacketsToFile) == 1 {
length := vv.Size()
@ -289,7 +289,7 @@ func logVectorisedView(vv buffer.VectorisedView, length int, buf *bytes.Buffer)
// Wait implements stack.LinkEndpoint.Wait.
func (*endpoint) Wait() {}
func logPacket(prefix string, protocol tcpip.NetworkProtocolNumber, b buffer.View, gso *stack.GSO) {
func logPacket(prefix string, protocol tcpip.NetworkProtocolNumber, pkt tcpip.PacketBuffer, gso *stack.GSO) {
// Figure out the network layer info.
var transProto uint8
src := tcpip.Address("unknown")
@ -298,28 +298,28 @@ func logPacket(prefix string, protocol tcpip.NetworkProtocolNumber, b buffer.Vie
size := uint16(0)
var fragmentOffset uint16
var moreFragments bool
if pkt.NetworkHeader != nil {
switch protocol {
case header.IPv4ProtocolNumber:
ipv4 := header.IPv4(b)
ipv4 := header.IPv4(pkt.NetworkHeader)
fragmentOffset = ipv4.FragmentOffset()
moreFragments = ipv4.Flags()&header.IPv4FlagMoreFragments == header.IPv4FlagMoreFragments
src = ipv4.SourceAddress()
dst = ipv4.DestinationAddress()
transProto = ipv4.Protocol()
size = ipv4.TotalLength() - uint16(ipv4.HeaderLength())
b = b[ipv4.HeaderLength():]
id = int(ipv4.ID())
case header.IPv6ProtocolNumber:
ipv6 := header.IPv6(b)
ipv6 := header.IPv6(pkt.NetworkHeader)
src = ipv6.SourceAddress()
dst = ipv6.DestinationAddress()
transProto = ipv6.NextHeader()
size = ipv6.PayloadLength()
b = b[header.IPv6MinimumSize:]
case header.ARPProtocolNumber:
arp := header.ARP(b)
arp := header.ARP(pkt.NetworkHeader)
log.Infof(
"%s arp %v (%v) -> %v (%v) valid:%v",
prefix,
@ -332,16 +332,18 @@ func logPacket(prefix string, protocol tcpip.NetworkProtocolNumber, b buffer.Vie
log.Infof("%s unknown network protocol", prefix)
return
}
}
// Figure out the transport layer info.
transName := "unknown"
srcPort := uint16(0)
dstPort := uint16(0)
details := ""
if pkt.TransportHeader != nil {
switch tcpip.TransportProtocolNumber(transProto) {
case header.ICMPv4ProtocolNumber:
transName = "icmp"
icmp := header.ICMPv4(b)
icmp := header.ICMPv4(pkt.TransportHeader)
icmpType := "unknown"
if fragmentOffset == 0 {
switch icmp.Type() {
@ -374,7 +376,7 @@ func logPacket(prefix string, protocol tcpip.NetworkProtocolNumber, b buffer.Vie
case header.ICMPv6ProtocolNumber:
transName = "icmp"
icmp := header.ICMPv6(b)
icmp := header.ICMPv6(pkt.TransportHeader)
icmpType := "unknown"
switch icmp.Type() {
case header.ICMPv6DstUnreachable:
@ -405,7 +407,7 @@ func logPacket(prefix string, protocol tcpip.NetworkProtocolNumber, b buffer.Vie
case header.UDPProtocolNumber:
transName = "udp"
udp := header.UDP(b)
udp := header.UDP(pkt.TransportHeader)
if fragmentOffset == 0 && len(udp) >= header.UDPMinimumSize {
srcPort = udp.SourcePort()
dstPort = udp.DestinationPort()
@ -415,7 +417,7 @@ func logPacket(prefix string, protocol tcpip.NetworkProtocolNumber, b buffer.Vie
case header.TCPProtocolNumber:
transName = "tcp"
tcp := header.TCP(b)
tcp := header.TCP(pkt.TransportHeader)
if fragmentOffset == 0 && len(tcp) >= header.TCPMinimumSize {
offset := int(tcp.DataOffset())
if offset < header.TCPMinimumSize {
@ -451,6 +453,7 @@ func logPacket(prefix string, protocol tcpip.NetworkProtocolNumber, b buffer.Vie
log.Infof("%s %v -> %v unknown transport protocol: %d", prefix, src, dst, transProto)
return
}
}
if gso != nil {
details += fmt.Sprintf(" gso: %+v", gso)