浏览代码

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 <mikioh.public.networking@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
Mikio Hara 6 年之前
父节点
当前提交
1272bf9dcd
共有 5 个文件被更改,包括 26 次插入3 次删除
  1. 6 0
      ipv4/batch.go
  2. 14 1
      ipv4/helper.go
  3. 3 0
      ipv4/packet.go
  4. 3 0
      ipv4/payload_cmsg.go
  5. 0 2
      ipv4/sys_ssmreq.go

+ 6 - 0
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
 	}
 }

+ 14 - 1
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

+ 3 - 0
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}

+ 3 - 0
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}

+ 0 - 2
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 {