syscall: allow \x00-prefixed unix abstract socket to use full path length

Fixes #70893

Change-Id: Ia0aaa497dad335fe962d52d3f115d26e8046e36f
GitHub-Last-Rev: 7dd663678d
GitHub-Pull-Request: golang/go#71851
Reviewed-on: https://go-review.googlesource.com/c/go/+/650875
Reviewed-by: Ian Lance Taylor <iant@google.com>
Auto-Submit: Ian Lance Taylor <iant@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Damien Neil <dneil@google.com>
This commit is contained in:
Albert Sundjaja 2025-02-22 23:02:57 +00:00 committed by Gopher Robot
parent e382bf5b32
commit fda9183899
4 changed files with 71 additions and 20 deletions

View File

@ -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")

View File

@ -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")

View File

@ -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

View File

@ -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