This commit is contained in:
parent
dd04bdb49e
commit
ce1b557ea9
@ -91,3 +91,41 @@ func TestUnixEmptyAllowedUIDsRejectConnection(t *testing.T) {
|
||||
t.Fatalf("response = %+v", response)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnixListenRejectsWritableControlDirectory(t *testing.T) {
|
||||
parent := t.TempDir() + "/control"
|
||||
if err := os.Mkdir(parent, 0700); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := os.Chmod(parent, 0777); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, err := ListenUnix(parent+"/control.sock", []uint32{uint32(os.Getuid())}); err == nil {
|
||||
t.Fatal("writable control directory was accepted")
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnixControlSocketUsesRestrictedPermissions(t *testing.T) {
|
||||
parent := t.TempDir() + "/control"
|
||||
path := parent + "/control.sock"
|
||||
server, err := ListenUnix(path, []uint32{uint32(os.Getuid())})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer server.Close()
|
||||
|
||||
parentInfo, err := os.Stat(parent)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if parentInfo.Mode().Perm() != 0750 {
|
||||
t.Fatalf("control directory permissions = %04o, want 0750", parentInfo.Mode().Perm())
|
||||
}
|
||||
socketInfo, err := os.Lstat(path)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if socketInfo.Mode().Perm() != 0600 {
|
||||
t.Fatalf("control socket permissions = %04o, want 0600", socketInfo.Mode().Perm())
|
||||
}
|
||||
}
|
||||
|
||||
@ -30,8 +30,8 @@ func ListenUnix(path string, allowedUIDs []uint32) (*UnixServer, error) {
|
||||
if err := os.MkdirAll(parent, 0750); err != nil {
|
||||
return nil, fmt.Errorf("create control directory: %w", err)
|
||||
}
|
||||
if info, err := os.Lstat(parent); err != nil || info.Mode()&os.ModeSymlink != 0 || !info.IsDir() {
|
||||
return nil, fmt.Errorf("control directory is not secure")
|
||||
if err := validateControlDirectory(parent); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := os.Chmod(parent, 0750); err != nil {
|
||||
return nil, fmt.Errorf("set control directory permissions: %w", err)
|
||||
@ -40,6 +40,9 @@ func ListenUnix(path string, allowedUIDs []uint32) (*UnixServer, error) {
|
||||
if info.Mode()&os.ModeSymlink != 0 || info.Mode()&os.ModeSocket == 0 {
|
||||
return nil, fmt.Errorf("control path is not a socket")
|
||||
}
|
||||
if err := validateControlSocketOwner(info); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if conn, dialErr := net.DialTimeout("unix", path, 100*time.Millisecond); dialErr == nil {
|
||||
_ = conn.Close()
|
||||
return nil, fmt.Errorf("control socket is already active")
|
||||
@ -66,6 +69,29 @@ func ListenUnix(path string, allowedUIDs []uint32) (*UnixServer, error) {
|
||||
return &UnixServer{listener: listener, path: path, allowed: allowed}, nil
|
||||
}
|
||||
|
||||
func validateControlDirectory(path string) error {
|
||||
info, err := os.Lstat(path)
|
||||
if err != nil || info.Mode()&os.ModeSymlink != 0 || !info.IsDir() {
|
||||
return fmt.Errorf("control directory is not secure")
|
||||
}
|
||||
if info.Mode().Perm()&0o022 != 0 {
|
||||
return fmt.Errorf("control directory must not be writable by group or other users")
|
||||
}
|
||||
return validateControlOwner(info, "control directory")
|
||||
}
|
||||
|
||||
func validateControlSocketOwner(info os.FileInfo) error {
|
||||
return validateControlOwner(info, "control socket")
|
||||
}
|
||||
|
||||
func validateControlOwner(info os.FileInfo, resource string) error {
|
||||
stat, ok := info.Sys().(*syscall.Stat_t)
|
||||
if !ok || stat.Uid != uint32(os.Geteuid()) {
|
||||
return fmt.Errorf("%s owner does not match service identity", resource)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *UnixServer) Serve(ctx context.Context, handler ResetHandler, guard *SessionGuard) error {
|
||||
if s == nil || s.listener == nil || handler == nil || guard == nil {
|
||||
return ErrInvalidRequest
|
||||
|
||||
Loading…
Reference in New Issue
Block a user