From f853e9aa4ed4e3f1aa299cc9b123cda574707eaa Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Wed, 27 Feb 2013 15:19:23 +1100 Subject: [PATCH] syscall: Fix FD passing on OpenBSD Fixes #3349. R=bradfitz, dave, minux.ma CC=golang-dev https://golang.org/cl/7383056 --- src/pkg/syscall/passfd_test.go | 48 +++++++++++++++++++++++++++++++- src/pkg/syscall/sockcmsg_unix.go | 16 +++++------ 2 files changed, 54 insertions(+), 10 deletions(-) diff --git a/src/pkg/syscall/passfd_test.go b/src/pkg/syscall/passfd_test.go index 71a4a495f0..a0e5909507 100644 --- a/src/pkg/syscall/passfd_test.go +++ b/src/pkg/syscall/passfd_test.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build linux darwin freebsd netbsd +// +build linux darwin freebsd netbsd openbsd package syscall_test @@ -149,3 +149,49 @@ func passFDChild() { return } } + +// TestUnixRightsRoundtrip tests that UnixRights, ParseSocketControlMessage, +// and ParseUnixRights are able to successfully round-trip lists of file descriptors. +func TestUnixRightsRoundtrip(t *testing.T) { + testCases := [...][][]int{ + {{42}}, + {{1, 2}}, + {{3, 4, 5}}, + {{}}, + {{1, 2}, {3, 4, 5}, {}, {7}}, + } + for _, testCase := range testCases { + b := []byte{} + var n int + for _, fds := range testCase { + // Last assignment to n wins + n = len(b) + syscall.CmsgLen(4*len(fds)) + b = append(b, syscall.UnixRights(fds...)...) + } + // Truncate b + b = b[:n] + + scms, err := syscall.ParseSocketControlMessage(b) + if err != nil { + t.Fatalf("ParseSocketControlMessage: %v", err) + } + if len(scms) != len(testCase) { + t.Fatalf("expected %v SocketControlMessage; got scms = %#v", len(testCase), scms) + } + for i, scm := range scms { + gotFds, err := syscall.ParseUnixRights(&scm) + if err != nil { + t.Fatalf("ParseUnixRights: %v", err) + } + wantFds := testCase[i] + if len(gotFds) != len(wantFds) { + t.Fatalf("expected %v fds, got %#v", len(wantFds), gotFds) + } + for j, fd := range gotFds { + if fd != wantFds[j] { + t.Fatalf("expected fd %v, got %v", wantFds[j], fd) + } + } + } + } +} diff --git a/src/pkg/syscall/sockcmsg_unix.go b/src/pkg/syscall/sockcmsg_unix.go index 3af3068fd9..bc7cf2098f 100644 --- a/src/pkg/syscall/sockcmsg_unix.go +++ b/src/pkg/syscall/sockcmsg_unix.go @@ -10,7 +10,7 @@ package syscall import "unsafe" -// Round the length of a raw sockaddr up to align it propery. +// Round the length of a raw sockaddr up to align it properly. func cmsgAlignOf(salen int) int { salign := sizeofPtr // NOTE: It seems like 64-bit Darwin kernel still requires 32-bit @@ -18,9 +18,6 @@ func cmsgAlignOf(salen int) int { if darwinAMD64 { salign = 4 } - if salen == 0 { - return salign - } return (salen + salign - 1) & ^(salign - 1) } @@ -50,14 +47,15 @@ type SocketControlMessage struct { // messages. func ParseSocketControlMessage(b []byte) ([]SocketControlMessage, error) { var msgs []SocketControlMessage - for len(b) >= CmsgLen(0) { - h, dbuf, err := socketControlMessageHeaderAndData(b) + i := 0 + for i+CmsgLen(0) <= len(b) { + h, dbuf, err := socketControlMessageHeaderAndData(b[i:]) if err != nil { return nil, err } - m := SocketControlMessage{Header: *h, Data: dbuf[:int(h.Len)-cmsgAlignOf(SizeofCmsghdr)]} + m := SocketControlMessage{Header: *h, Data: dbuf} msgs = append(msgs, m) - b = b[cmsgAlignOf(int(h.Len)):] + i += cmsgAlignOf(int(h.Len)) } return msgs, nil } @@ -67,7 +65,7 @@ func socketControlMessageHeaderAndData(b []byte) (*Cmsghdr, []byte, error) { if h.Len < SizeofCmsghdr || int(h.Len) > len(b) { return nil, nil, EINVAL } - return h, b[cmsgAlignOf(SizeofCmsghdr):], nil + return h, b[cmsgAlignOf(SizeofCmsghdr):h.Len], nil } // UnixRights encodes a set of open file descriptors into a socket -- 2.48.1