open-nomad/client/allocdir/fs_unix.go

112 lines
2.5 KiB
Go

// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0
//go:build unix
package allocdir
import (
"fmt"
"os"
"os/user"
"path/filepath"
"strconv"
"syscall"
"github.com/hashicorp/nomad/helper/users"
"golang.org/x/sys/unix"
)
var (
// SharedAllocContainerPath is the path inside container for mounted
// directory shared across tasks in a task group.
SharedAllocContainerPath = filepath.Join("/", SharedAllocName)
// TaskLocalContainerPath is the path inside a container for mounted directory
// for local storage.
TaskLocalContainerPath = filepath.Join("/", TaskLocal)
// TaskSecretsContainerPath is the path inside a container for mounted
// secrets directory
TaskSecretsContainerPath = filepath.Join("/", TaskSecrets)
)
// dropDirPermissions gives full access to a directory to all users and sets
// the owner to nobody.
func dropDirPermissions(path string, desired os.FileMode) error {
if err := os.Chmod(path, desired|0777); err != nil {
return fmt.Errorf("Chmod(%v) failed: %v", path, err)
}
// Can't change owner if not root.
if unix.Geteuid() != 0 {
return nil
}
u, err := users.Lookup("nobody")
if err != nil {
return fmt.Errorf("Unable to find nobody user: %w", err)
}
uid, err := getUid(u)
if err != nil {
return err
}
gid, err := getGid(u)
if err != nil {
return err
}
if err := os.Chown(path, uid, gid); err != nil {
return fmt.Errorf("Couldn't change owner/group of %v to (uid: %v, gid: %v): %v", path, uid, gid, err)
}
return nil
}
// getUid for a user
func getUid(u *user.User) (int, error) {
uid, err := strconv.Atoi(u.Uid)
if err != nil {
return 0, fmt.Errorf("Unable to convert Uid to an int: %v", err)
}
return uid, nil
}
// getGid for a user
func getGid(u *user.User) (int, error) {
gid, err := strconv.Atoi(u.Gid)
if err != nil {
return 0, fmt.Errorf("Unable to convert Gid to an int: %v", err)
}
return gid, nil
}
// linkOrCopy attempts to hardlink dst to src and fallsback to copying if the
// hardlink fails.
func linkOrCopy(src, dst string, uid, gid int, perm os.FileMode) error {
// Avoid link/copy if the file already exists in the chroot
// TODO 0.6 clean this up. This was needed because chroot creation fails
// when a process restarts.
if fileInfo, _ := os.Stat(dst); fileInfo != nil {
return nil
}
// Attempt to hardlink.
if err := os.Link(src, dst); err == nil {
return nil
}
return fileCopy(src, dst, uid, gid, perm)
}
func getOwner(fi os.FileInfo) (int, int) {
stat, ok := fi.Sys().(*syscall.Stat_t)
if !ok {
return -1, -1
}
return int(stat.Uid), int(stat.Gid)
}