Skip to content

x/net/icmp: descriptor closed twice (bad file descriptor error) #16969

@adzeitor

Description

@adzeitor

What version of Go are you using (go version)?

go version go1.7 linux/amd64

What operating system and processor architecture are you using (go env)?

GOARCH="amd64"
GOOS="linux"

What did you do?

Ping 127.0.0.1 (localhost) with many goroutines. Try run few times:

package main

import (
    "fmt"
    "log"
    "net"
    "os"

    "golang.org/x/net/icmp"
    "golang.org/x/net/ipv4"
    "golang.org/x/net/ipv6"
)

func doPing(host string) error {
    network := "udp4"
    address := "0.0.0.0"
    protocol := 1 // Internet Control Message
    mtype := ipv4.ICMPTypeEcho

    c, err := icmp.ListenPacket(network, address)
    if err != nil {
        return err
    }

    defer c.Close()

    dst := &net.UDPAddr{IP: net.ParseIP(host)}

    wm := icmp.Message{
        Type: mtype, Code: 0,
        Body: &icmp.Echo{
            ID: os.Getpid() & 0xffff, Seq: 1 << uint(0),
            Data: []byte("ello gov'nor"),
        },
    }

    wb, err := wm.Marshal(nil)
    if err != nil {
        return err
    }

    if n, err := c.WriteTo(wb, dst); err != nil {
        return err
    } else if n != len(wb) {
        return fmt.Errorf("got %v; want %v", n, len(wb))
    }

    rb := make([]byte, 1500)
    n, peer, err := c.ReadFrom(rb)
    if err != nil {
        return err
    }
    rm, err := icmp.ParseMessage(protocol, rb[:n])
    if err != nil {
        return err
    }
    switch rm.Type {
    case ipv4.ICMPTypeEchoReply, ipv6.ICMPTypeEchoReply:
        return nil
    default:
        return fmt.Errorf("got %+v from %v; want echo reply", rm, peer)
    }
}

func main() {
    for i := 1; i < 1000; i++ {
        go func() {
            err := doPing("127.0.0.1")
            if err != nil {
                log.Fatal(err)
            }
        }()
    }
}

What did you expect to see?

Nothing. No errors.

What did you see instead?

Maybe second close happens on another reused connection fd.

2016/09/02 18:51:08 file file+net datagram-oriented icmp: getsockopt: bad file descriptor

Minimal program to strace

package main
import "golang.org/x/net/icmp"

func main() {
  c, _ := icmp.ListenPacket("udp4", "0.0.0.0")
  c.Close()
}
socket(AF_INET, SOCK_STREAM, IPPROTO_TCP) = 3
close(3)                                = 0
socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP) = 3
setsockopt(3, SOL_IPV6, IPV6_V6ONLY, [1], 4) = 0
bind(3, {sa_family=AF_INET6, sin6_port=htons(0), inet_pton(AF_INET6, "::1", &sin6_addr), sin6_flowinfo=0, sin6_scope_id=0}, 28) = 0
socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP) = 4
setsockopt(4, SOL_IPV6, IPV6_V6ONLY, [0], 4) = 0
bind(4, {sa_family=AF_INET6, sin6_port=htons(0), inet_pton(AF_INET6, "::ffff:127.0.0.1", &sin6_addr), sin6_flowinfo=0, sin6_scope_id=0}, 28) = 0
close(4)                                = 0
close(3)                                = 0
socket(AF_INET, SOCK_DGRAM, IPPROTO_ICMP) = 3
bind(3, {sa_family=AF_INET, sin_port=htons(0), sin_addr=inet_addr("0.0.0.0")}, 16) = 0
fcntl(3, F_DUPFD_CLOEXEC, 0)            = 4
fcntl(4, F_GETFL)                       = 0x2 (flags O_RDWR)
fcntl(4, F_SETFL, O_RDWR|O_NONBLOCK)    = 0
getsockopt(4, SOL_SOCKET, SO_TYPE, [2], [4]) = 0
getsockname(4, {sa_family=AF_INET, sin_port=htons(20618), sin_addr=inet_addr("0.0.0.0")}, [16]) = 0
getpeername(4, 0xc42004dbc8, 0xc42004dbc4) = -1 ENOTCONN (Transport endpoint is not connected)
epoll_create1(EPOLL_CLOEXEC)            = 5
epoll_ctl(5, EPOLL_CTL_ADD, 4, {EPOLLIN|EPOLLOUT|EPOLLRDHUP|EPOLLET, {u32=3043491584, u64=140255200542464}}) = 0
close(3)                                = 0
close(3)                                = -1 EBADF (Bad file descriptor)
epoll_ctl(5, EPOLL_CTL_DEL, 4, 0xc42004dda4) = 0
close(4)                                = 0
exit_group(0)                           = ?
+++ exited with 0 +++

Possible fix

When this defer syscall.Close(s) removed from icmp/listen_posix.go:69, no multiple closes on fd happens.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions