From fda918389947d32e854ddfc8c972b88bd31369c4 Mon Sep 17 00:00:00 2001 From: Albert Sundjaja Date: Sat, 22 Feb 2025 23:02:57 +0000 Subject: [PATCH] syscall: allow \x00-prefixed unix abstract socket to use full path length Fixes #70893 Change-Id: Ia0aaa497dad335fe962d52d3f115d26e8046e36f GitHub-Last-Rev: 7dd663678d8aecdfac94541a570dfbd1aa2577e7 GitHub-Pull-Request: golang/go#71851 Reviewed-on: https://go-review.googlesource.com/c/go/+/650875 Reviewed-by: Ian Lance Taylor Auto-Submit: Ian Lance Taylor LUCI-TryBot-Result: Go LUCI Reviewed-by: Damien Neil --- src/net/unixsock_linux_test.go | 17 +++++++++++++++++ src/net/unixsock_windows_test.go | 22 ++++++++++++++++++++++ src/syscall/syscall_linux.go | 26 ++++++++++++++++---------- src/syscall/syscall_windows.go | 26 ++++++++++++++++---------- 4 files changed, 71 insertions(+), 20 deletions(-) diff --git a/src/net/unixsock_linux_test.go b/src/net/unixsock_linux_test.go index d04007cef3..fa50ba7bd5 100644 --- a/src/net/unixsock_linux_test.go +++ b/src/net/unixsock_linux_test.go @@ -49,6 +49,23 @@ func TestUnixAutobindClose(t *testing.T) { ln.Close() } +func TestUnixAbstractLongNameNulStart(t *testing.T) { + // Create an abstract socket name that starts with a null byte ("\x00") + // whose length is the maximum of RawSockaddrUnix Path len + paddedAddr := make([]byte, len(syscall.RawSockaddrUnix{}.Path)) + copy(paddedAddr, "\x00abstract_test") + + la, err := ResolveUnixAddr("unix", string(paddedAddr)) + if err != nil { + t.Fatal(err) + } + c, err := ListenUnix("unix", la) + if err != nil { + t.Fatal(err) + } + c.Close() +} + func TestUnixgramLinuxAbstractLongName(t *testing.T) { if !testableNetwork("unixgram") { t.Skip("abstract unix socket long name test") diff --git a/src/net/unixsock_windows_test.go b/src/net/unixsock_windows_test.go index 511ba6f2df..4c1a8d7e7e 100644 --- a/src/net/unixsock_windows_test.go +++ b/src/net/unixsock_windows_test.go @@ -10,6 +10,7 @@ import ( "internal/syscall/windows" "os" "reflect" + "syscall" "testing" ) @@ -69,6 +70,27 @@ func TestUnixConnLocalWindows(t *testing.T) { } } +func TestUnixAbstractLongNameNulStart(t *testing.T) { + if !windows.SupportUnixSocket() { + t.Skip("unix test") + } + + // Create an abstract socket name that starts with a null byte ("\x00") + // whose length is the maximum of RawSockaddrUnix Path len + paddedAddr := make([]byte, len(syscall.RawSockaddrUnix{}.Path)) + copy(paddedAddr, "\x00abstract_test") + + la, err := ResolveUnixAddr("unix", string(paddedAddr)) + if err != nil { + t.Fatal(err) + } + c, err := ListenUnix("unix", la) + if err != nil { + t.Fatal(err) + } + c.Close() +} + func TestModeSocket(t *testing.T) { if !windows.SupportUnixSocket() { t.Skip("unix test") diff --git a/src/syscall/syscall_linux.go b/src/syscall/syscall_linux.go index 57d84748fe..d733ca9bf9 100644 --- a/src/syscall/syscall_linux.go +++ b/src/syscall/syscall_linux.go @@ -550,23 +550,29 @@ func (sa *SockaddrUnix) sockaddr() (unsafe.Pointer, _Socklen, error) { if n > len(sa.raw.Path) { return nil, 0, EINVAL } - if n == len(sa.raw.Path) && name[0] != '@' { + // Abstract addresses start with NUL. + // '@' is also a valid way to specify abstract addresses. + isAbstract := n > 0 && (name[0] == '@' || name[0] == '\x00') + + // Non-abstract named addresses are NUL terminated. + // The length can't use the full capacity as we need to add NUL. + if n == len(sa.raw.Path) && !isAbstract { return nil, 0, EINVAL } sa.raw.Family = AF_UNIX for i := 0; i < n; i++ { sa.raw.Path[i] = int8(name[i]) } - // length is family (uint16), name, NUL. - sl := _Socklen(2) - if n > 0 { - sl += _Socklen(n) + 1 - } - if sa.raw.Path[0] == '@' || (sa.raw.Path[0] == 0 && sl > 3) { - // Check sl > 3 so we don't change unnamed socket behavior. + // Length is family + name (+ NUL if non-abstract). + // Family is of type uint16 (2 bytes). + sl := _Socklen(2 + n) + if isAbstract { + // Abstract addresses are not NUL terminated. + // We rewrite '@' prefix to NUL here. sa.raw.Path[0] = 0 - // Don't count trailing NUL for abstract address. - sl-- + } else if n > 0 { + // Add NUL for non-abstract named addresses. + sl++ } return unsafe.Pointer(&sa.raw), sl, nil diff --git a/src/syscall/syscall_windows.go b/src/syscall/syscall_windows.go index 344f6c325c..7a349ddd34 100644 --- a/src/syscall/syscall_windows.go +++ b/src/syscall/syscall_windows.go @@ -858,23 +858,29 @@ func (sa *SockaddrUnix) sockaddr() (unsafe.Pointer, int32, error) { if n > len(sa.raw.Path) { return nil, 0, EINVAL } - if n == len(sa.raw.Path) && name[0] != '@' { + // Abstract addresses start with NUL. + // '@' is also a valid way to specify abstract addresses. + isAbstract := n > 0 && (name[0] == '@' || name[0] == '\x00') + + // Non-abstract named addresses are NUL terminated. + // The length can't use the full capacity as we need to add NUL. + if n == len(sa.raw.Path) && !isAbstract { return nil, 0, EINVAL } sa.raw.Family = AF_UNIX for i := 0; i < n; i++ { sa.raw.Path[i] = int8(name[i]) } - // length is family (uint16), name, NUL. - sl := int32(2) - if n > 0 { - sl += int32(n) + 1 - } - if sa.raw.Path[0] == '@' || (sa.raw.Path[0] == 0 && sl > 3) { - // Check sl > 3 so we don't change unnamed socket behavior. + // Length is family + name (+ NUL if non-abstract). + // Family is of type uint16 (2 bytes). + sl := int32(2 + n) + if isAbstract { + // Abstract addresses are not NUL terminated. + // We rewrite '@' prefix to NUL here. sa.raw.Path[0] = 0 - // Don't count trailing NUL for abstract address. - sl-- + } else if n > 0 { + // Add NUL for non-abstract named addresses. + sl++ } return unsafe.Pointer(&sa.raw), sl, nil -- 2.50.0