From 1272bf9dcd53ea65c09668fb4c76e65deb740072 Mon Sep 17 00:00:00 2001 From: Mikio Hara Date: Tue, 19 Mar 2019 18:36:27 +0900 Subject: [PATCH] ipv4: work around FreeBSD 11.3 or 12 kernel running COMPAT_FREEBSD32 On FreeBSD 11.3 or 12 kernel running COMPAT_FREEBSD32, it looks like the system call recvmsg always returns an incorrect length for the out-of-band data. This change adjusts the length when it looks incorrect and the running kernel is FreeBSD 11.3 or above. Fixes golang/go#30899. Change-Id: Ia58d8b4bd4caf3783d2e38161ee4afd1a64ca522 Reviewed-on: https://go-review.googlesource.com/c/net/+/168297 Run-TryBot: Mikio Hara TryBot-Result: Gobot Gobot Reviewed-by: Ian Lance Taylor --- ipv4/batch.go | 6 ++++++ ipv4/helper.go | 15 ++++++++++++++- ipv4/packet.go | 3 +++ ipv4/payload_cmsg.go | 3 +++ ipv4/sys_ssmreq.go | 2 -- 5 files changed, 26 insertions(+), 3 deletions(-) diff --git a/ipv4/batch.go b/ipv4/batch.go index fbe0cfd5..1a3a4fc0 100644 --- a/ipv4/batch.go +++ b/ipv4/batch.go @@ -89,6 +89,9 @@ func (c *payloadHandler) ReadBatch(ms []Message, flags int) (int, error) { n = 0 err = &net.OpError{Op: "read", Net: c.PacketConn.LocalAddr().Network(), Source: c.PacketConn.LocalAddr(), Err: err} } + if compatFreeBSD32 && ms[0].NN > 0 { + adjustFreeBSD32(&ms[0]) + } return n, err } } @@ -152,6 +155,9 @@ func (c *packetHandler) ReadBatch(ms []Message, flags int) (int, error) { n = 0 err = &net.OpError{Op: "read", Net: c.IPConn.LocalAddr().Network(), Source: c.IPConn.LocalAddr(), Err: err} } + if compatFreeBSD32 && ms[0].NN > 0 { + adjustFreeBSD32(&ms[0]) + } return n, err } } diff --git a/ipv4/helper.go b/ipv4/helper.go index d0549523..a4457d60 100644 --- a/ipv4/helper.go +++ b/ipv4/helper.go @@ -8,6 +8,8 @@ import ( "errors" "net" "runtime" + + "golang.org/x/net/internal/socket" ) var ( @@ -23,9 +25,20 @@ var ( errNotImplemented = errors.New("not implemented on " + runtime.GOOS + "/" + runtime.GOARCH) // See http://www.freebsd.org/doc/en/books/porters-handbook/freebsd-versions.html. - freebsdVersion uint32 + freebsdVersion uint32 + compatFreeBSD32 bool // 386 emulation on amd64 ) +// See golang.org/issue/30899. +func adjustFreeBSD32(m *socket.Message) { + if freebsdVersion >= 1103000 { + l := (m.NN + 4 - 1) &^ (4 - 1) + if m.NN < l && l <= len(m.OOB) { + m.NN = l + } + } +} + func boolint(b bool) int { if b { return 1 diff --git a/ipv4/packet.go b/ipv4/packet.go index 30e09515..7d784e06 100644 --- a/ipv4/packet.go +++ b/ipv4/packet.go @@ -46,6 +46,9 @@ func (c *packetHandler) ReadFrom(b []byte) (h *Header, p []byte, cm *ControlMess return nil, nil, nil, &net.OpError{Op: "read", Net: c.IPConn.LocalAddr().Network(), Source: c.IPConn.LocalAddr(), Err: err} } if m.NN > 0 { + if compatFreeBSD32 { + adjustFreeBSD32(&m) + } cm = new(ControlMessage) if err := cm.Parse(m.OOB[:m.NN]); err != nil { return nil, nil, nil, &net.OpError{Op: "read", Net: c.IPConn.LocalAddr().Network(), Source: c.IPConn.LocalAddr(), Err: err} diff --git a/ipv4/payload_cmsg.go b/ipv4/payload_cmsg.go index e8b21c54..06930671 100644 --- a/ipv4/payload_cmsg.go +++ b/ipv4/payload_cmsg.go @@ -49,6 +49,9 @@ func (c *payloadHandler) ReadFrom(b []byte) (n int, cm *ControlMessage, src net. return 0, nil, nil, &net.OpError{Op: "read", Net: c.PacketConn.LocalAddr().Network(), Source: c.PacketConn.LocalAddr(), Err: errInvalidConnType} } if m.NN > 0 { + if compatFreeBSD32 { + adjustFreeBSD32(&m) + } cm = new(ControlMessage) if err := cm.Parse(m.OOB[:m.NN]); err != nil { return 0, nil, nil, &net.OpError{Op: "read", Net: c.PacketConn.LocalAddr().Network(), Source: c.PacketConn.LocalAddr(), Err: err} diff --git a/ipv4/sys_ssmreq.go b/ipv4/sys_ssmreq.go index 95eea2b6..eeced7f3 100644 --- a/ipv4/sys_ssmreq.go +++ b/ipv4/sys_ssmreq.go @@ -13,8 +13,6 @@ import ( "golang.org/x/net/internal/socket" ) -var compatFreeBSD32 bool // 386 emulation on amd64 - func (so *sockOpt) setGroupReq(c *socket.Conn, ifi *net.Interface, grp net.IP) error { var gr groupReq if ifi != nil {