92d4a05534
This PR eliminates code specific to looking up and caching the uid/gid/user.User object associated with the nobody user in an init block. This code existed before adding the generic users cache and was meant to optimize the one search path we knew would happen often. Now that we have the cache, seems reasonable to eliminate this init block and use the cache instead like for any other user. Also fixes a constraint on the podman (and other) drivers, where building without CGO became problematic on some OS like Fedora IoT where the nobody user cannot be found with the pure-Go standard library. Fixes github.com/hashicorp/nomad-driver-podman/issues/228
112 lines
2.5 KiB
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)
|
|
}
|