feat(server): activate projected authentication safely
This commit is contained in:
@@ -0,0 +1,74 @@
|
||||
//go:build linux
|
||||
|
||||
package setup
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
func currentEffectiveUID() int { return os.Geteuid() }
|
||||
|
||||
func ensureProjectedAuthDirectories(canonicalRoot, runtimeRoot string) error {
|
||||
parent := filepath.Dir(canonicalRoot)
|
||||
canonicalName, runtimeName := filepath.Base(canonicalRoot), filepath.Base(runtimeRoot)
|
||||
if parent != filepath.Dir(runtimeRoot) || canonicalName == runtimeName || canonicalName == "." || runtimeName == "." {
|
||||
return errors.New("projected authentication directory layout is invalid")
|
||||
}
|
||||
parentFD, err := unix.Open(parent, unix.O_RDONLY|unix.O_DIRECTORY|unix.O_NOFOLLOW|unix.O_CLOEXEC, 0)
|
||||
if err != nil {
|
||||
return errors.New("projected authentication parent is unavailable")
|
||||
}
|
||||
defer unix.Close(parentFD)
|
||||
if err := requireProjectedDirectoryMetadata(parentFD, 0, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := ensureProjectedAuthDirectoryAt(parentFD, canonicalName, 0, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := ensureProjectedAuthDirectoryAt(parentFD, runtimeName, 10001, 10001); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := unix.Fsync(parentFD); err != nil {
|
||||
return errors.New("projected authentication parent could not be synchronized")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func ensureProjectedAuthDirectoryAt(parentFD int, name string, uid, gid int) error {
|
||||
fd, err := unix.Openat(parentFD, name, unix.O_RDONLY|unix.O_DIRECTORY|unix.O_NOFOLLOW|unix.O_CLOEXEC, 0)
|
||||
if err != nil && !errors.Is(err, unix.ENOENT) {
|
||||
return errors.New("projected authentication directory is unavailable")
|
||||
}
|
||||
if errors.Is(err, unix.ENOENT) {
|
||||
if err := unix.Mkdirat(parentFD, name, 0o700); err != nil && !errors.Is(err, unix.EEXIST) {
|
||||
return errors.New("projected authentication directory could not be created")
|
||||
}
|
||||
fd, err = unix.Openat(parentFD, name, unix.O_RDONLY|unix.O_DIRECTORY|unix.O_NOFOLLOW|unix.O_CLOEXEC, 0)
|
||||
if err != nil {
|
||||
return errors.New("projected authentication directory is unavailable")
|
||||
}
|
||||
}
|
||||
defer unix.Close(fd)
|
||||
if err := unix.Fchown(fd, uid, gid); err != nil {
|
||||
return errors.New("projected authentication directory ownership could not be set")
|
||||
}
|
||||
if err := unix.Fchmod(fd, 0o700); err != nil {
|
||||
return errors.New("projected authentication directory mode could not be set")
|
||||
}
|
||||
if err := unix.Fsync(fd); err != nil {
|
||||
return errors.New("projected authentication directory could not be synchronized")
|
||||
}
|
||||
return requireProjectedDirectoryMetadata(fd, uint32(uid), uint32(gid))
|
||||
}
|
||||
|
||||
func requireProjectedDirectoryMetadata(fd int, uid, gid uint32) error {
|
||||
var metadata unix.Stat_t
|
||||
if err := unix.Fstat(fd, &metadata); err != nil || metadata.Mode&unix.S_IFMT != unix.S_IFDIR || metadata.Mode&0o777 != 0o700 || metadata.Uid != uid || metadata.Gid != gid {
|
||||
return errors.New("projected authentication directory metadata is invalid")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user