Skip to content

Instantly share code, notes, and snippets.

@win-t
Last active August 28, 2024 09:41
Show Gist options
  • Save win-t/c08556fc7091937981c71287eb9ee658 to your computer and use it in GitHub Desktop.
Save win-t/c08556fc7091937981c71287eb9ee658 to your computer and use it in GitHub Desktop.
golang: unix socket: get peer credential
package main
import (
"fmt"
"net"
"os"
)
func main() {
addr, _ := net.ResolveUnixAddr("unix", "@testabstractsocket")
client, err := net.DialUnix("unix", nil, addr)
if err != nil {
fmt.Println("Cannot dial", err.Error())
os.Exit(1)
}
defer client.Close()
fmt.Println("Connected!")
}
package main
import (
"fmt"
"net"
"os"
"syscall"
)
func main() {
addr, _ := net.ResolveUnixAddr("unix", "@testabstractsocket")
server, err := net.ListenUnix("unix", addr)
if err != nil {
fmt.Println("Cannot listen", err.Error())
os.Exit(1)
}
for {
client, err := server.AcceptUnix()
if err != nil {
fmt.Println("Cannot accept", err.Error())
continue
}
go serve(client)
}
}
func serve(client *net.UnixConn) {
defer client.Close()
f, err := client.File()
if err != nil {
fmt.Println("Cannot get underlying file", err.Error())
return
}
defer f.Close()
cred, err := syscall.GetsockoptUcred(int(f.Fd()), syscall.SOL_SOCKET, syscall.SO_PEERCRED)
if err != nil {
fmt.Println("Cannot get peer credential", err.Error())
return
}
if cred.Uid == 0 {
fmt.Println("root client connected, do something dangerous !")
} else {
fmt.Println("non-root client connected, do nothing !")
}
}
@win-t
Copy link
Author

win-t commented Jun 29, 2018

this gist is about a demonstration to show that it is not secure to use --net host on docker. Because some unix socket server implementation that listen on abstract address, may do client authentication based on peer UID.

build the server go build -o server server.go
build the client go build -o client client.go
run the server ./server
run the client ./client
run the client on docker docker run -it --rm -v $PWD:/shared --net host ubuntu bash -c "/shared/client"

when using --net host, container will use network namespace from host system, which also mean exposing host system abstract socket address.
From my machine running ss -xlpn | grep @ inside the container print

u_str  LISTEN     0      128    @/tmp/.X11-unix/X0 22609                 * 0                  
u_str  LISTEN     0      128    @/tmp/dbus-YKHGRmz2HN 22838                 * 0                  
u_str  LISTEN     0      128    @/tmp/.ICE-unix/892 21759                 * 0                  
u_str  LISTEN     0      128    @/containerd-shim/moby/9c7068439326bd8606b1ec1d88e12d3865bc4522e8b1367ae367abf383685718/shim.sock@ 120456   

there are bunch of abstract unix socket that can be connected from inside container as root

@win-t
Copy link
Author

win-t commented Jun 29, 2018

It doesn't affect unix socket that listens on filesystems, because filesystems is protected by mount namespace

@decentral1se
Copy link

Thanks for this! Totally adjacent but a really handy example on how to do socket auth!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment