Skip to content

Commit

Permalink
fixes #213 Want options to set permissions on IPC socket
Browse files Browse the repository at this point in the history
This adds new options only available on UNIX systems to set
the permissions and ownership of the UNIX domain socket.
It also adds fixes to work better when testing with WSL
by forcing the sockets to be created in a temp dir.
  • Loading branch information
gdamore committed Oct 4, 2020
1 parent e0b0da2 commit 5699831
Show file tree
Hide file tree
Showing 3 changed files with 93 additions and 2 deletions.
7 changes: 5 additions & 2 deletions internal/test/addrs.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ package test

import (
"fmt"
"os"
"path/filepath"
"sync/atomic"
"time"
)
Expand All @@ -31,10 +33,11 @@ func NextPort() uint32 {
return atomic.AddUint32(&currPort, 1)
}

// AddrTestIPC returns a test IPC address. It will be in the current
// AddrTestIPC returns a test IPC address. It will be in the temporary
// directory.
func AddrTestIPC() string {
return (fmt.Sprintf("ipc://mangostest%d", NextPort()))
temp := filepath.ToSlash(os.TempDir())
return fmt.Sprintf("ipc://%s/mangostest%d", temp, NextPort())
}

// AddrTestWSS returns a websocket over TLS address.
Expand Down
65 changes: 65 additions & 0 deletions transport/ipc/ipc_unix.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,29 @@ const (
Transport = ipcTran(0)
)

const (
// OptionIpcSocketPermissions is used to set the permissions on the
// UNIX domain socket via chmod. The argument is a uint32, and
// represents the mode passed to chmod(). This is
// done on the server side. Be aware that relying on
// socket permissions for enforcement is not portable.
OptionIpcSocketPermissions = "UNIX-IPC-CHMOD"

// OptionIpcSocketOwner is used to set the socket owner by
// using chown on the server socket. This will only work if
// the process has permission. The argument is an int.
// If this fails to set at socket creation time,
// no error is reported.
OptionIpcSocketOwner = "UNIX-IPC-OWNER"

// OptionIpcSocketGroup is used to set the socket group by
// using chown on the server socket. This will only work if
// the process has permission. The argument is an int.
// If this fails to set at socket creation time,
// no error is reported.
OptionIpcSocketGroup = "UNIX-IPC-GROUP"
)

func init() {
transport.RegisterTransport(Transport)
}
Expand Down Expand Up @@ -98,6 +121,11 @@ type listener struct {
closeq chan struct{}
closed bool
maxRecvSize int
owner int
group int
chown bool
mode uint32
chmod bool
once sync.Once
lock sync.Mutex
}
Expand All @@ -114,6 +142,14 @@ func (l *listener) Listen() error {
}
listener, err := net.ListenUnix("unix", l.addr)

if l.chown {
os.Chown(l.addr.String(), l.owner, l.group)

}
if l.chmod {
os.Chmod(l.addr.String(), os.FileMode(l.mode))
}

if err != nil && (isSyscallError(err, syscall.EADDRINUSE) || isSyscallError(err, syscall.EEXIST)) {
l.removeStaleIPC()
listener, err = net.ListenUnix("unix", l.addr)
Expand Down Expand Up @@ -189,7 +225,34 @@ func (l *listener) SetOption(n string, v interface{}) error {
return nil
}
return mangos.ErrBadValue
case OptionIpcSocketPermissions:
if b, ok := v.(uint32); ok && b&uint32(os.ModePerm) == v {
l.mode = b
l.chmod = true
return nil
}
if b, ok := v.(os.FileMode); ok && b&os.ModePerm == v {
l.mode = uint32(b)
l.chmod = true
return nil
}
return mangos.ErrBadValue
case OptionIpcSocketOwner:
if b, ok := v.(int); ok {
l.owner = b
l.chown = true
return nil
}
return mangos.ErrBadValue
case OptionIpcSocketGroup:
if b, ok := v.(int); ok {
l.group = b
l.chown = true
return nil
}
return mangos.ErrBadValue
}

return mangos.ErrBadOption
}

Expand Down Expand Up @@ -253,6 +316,8 @@ func (t ipcTran) NewListener(addr string, sock mangos.Socket) (transport.Listene
proto: sock.Info(),
closeq: make(chan struct{}),
hs: transport.NewConnHandshaker(),
owner: os.Geteuid(),
group: os.Getegid(),
}

if addr, err = transport.StripScheme(t, addr); err != nil {
Expand Down
23 changes: 23 additions & 0 deletions transport/ipc/ipc_unix_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"errors"
"net"
"os"
"strings"
"syscall"
"testing"
"time"
Expand Down Expand Up @@ -184,3 +185,25 @@ func TestIpcSendAbort(t *testing.T) {
time.Sleep(time.Millisecond * 100)
MustSucceed(t, c.Close())
}

func TestIpcListenerOptions(t *testing.T) {
sock := GetMockSocket()
defer MustClose(t, sock)
addr := AddrTestIPC()
l, e := tran.NewListener(addr, sock)
MustSucceed(t, e)

MustBeError(t, l.SetOption(OptionIpcSocketOwner, true), mangos.ErrBadValue)
MustBeError(t, l.SetOption(OptionIpcSocketGroup, true), mangos.ErrBadValue)
MustBeError(t, l.SetOption(OptionIpcSocketPermissions, true), mangos.ErrBadValue)
MustBeError(t, l.SetOption(OptionIpcSocketPermissions, os.ModeDir), mangos.ErrBadValue)
MustSucceed(t, l.SetOption(OptionIpcSocketPermissions, uint32(0642)))
MustSucceed(t, l.SetOption(OptionIpcSocketPermissions, os.FileMode(0642)))
MustSucceed(t, l.SetOption(OptionIpcSocketOwner, 0))
MustSucceed(t, l.SetOption(OptionIpcSocketGroup, 0))

MustSucceed(t, l.Listen())
i, e := os.Stat(strings.TrimPrefix(addr, "ipc://"))
MustSucceed(t, e)
MustBeTrue(t, i.Mode() & os.ModePerm == 0642)
}

0 comments on commit 5699831

Please sign in to comment.