5b1970468e
* landlock: git needs more files for private repositories This PR fixes artifact downloading so that git may work when cloning from private repositories. It needs - file read on /etc/passwd - dir read on /root/.ssh - file write on /root/.ssh/known_hosts Add these rules to the landlock rules for the artifact sandbox. * cr: use nonexistent instead of devnull Co-authored-by: Michael Schurter <mschurter@hashicorp.com> * cr: use go-homdir for looking up home directory * pr: pull go-homedir into explicit require * cr: fixup homedir tests in homeless root cases * cl: fix root test for real --------- Co-authored-by: Michael Schurter <mschurter@hashicorp.com>
164 lines
4 KiB
Go
164 lines
4 KiB
Go
//go:build linux
|
|
|
|
package getter
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
"syscall"
|
|
|
|
"github.com/mitchellh/go-homedir"
|
|
"github.com/shoenig/go-landlock"
|
|
"golang.org/x/sys/unix"
|
|
)
|
|
|
|
var (
|
|
// userUID is the current user's uid
|
|
userUID uint32
|
|
|
|
// userGID is the current user's gid
|
|
userGID uint32
|
|
)
|
|
|
|
func init() {
|
|
userUID = uint32(syscall.Getuid())
|
|
userGID = uint32(syscall.Getgid())
|
|
}
|
|
|
|
// attributes returns the system process attributes to run
|
|
// the sandbox process with
|
|
func attributes() *syscall.SysProcAttr {
|
|
uid, gid := credentials()
|
|
return &syscall.SysProcAttr{
|
|
Credential: &syscall.Credential{
|
|
Uid: uid,
|
|
Gid: gid,
|
|
},
|
|
}
|
|
}
|
|
|
|
// credentials returns the UID and GID of the user the child process
|
|
// will run as - for now this is always the same user the Nomad agent is
|
|
// running as.
|
|
func credentials() (uint32, uint32) {
|
|
return userUID, userGID
|
|
}
|
|
|
|
// findHomeDir returns the home directory as provided by os.UserHomeDir. In case
|
|
// os.UserHomeDir returns an error, we return /root if the current process is being
|
|
// run by root, or /dev/null otherwise.
|
|
func findHomeDir() string {
|
|
// When running as a systemd unit the process may not have the $HOME
|
|
// environment variable set, and os.UserHomeDir will return an error.
|
|
|
|
// if home is set, just use that
|
|
if home, err := homedir.Dir(); err == nil {
|
|
return home
|
|
}
|
|
|
|
// if we are the root user, use "/root"
|
|
if unix.Getuid() == 0 {
|
|
return "/root"
|
|
}
|
|
|
|
// nothing safe to do
|
|
return "/nonexistent"
|
|
}
|
|
|
|
// defaultEnvironment is the default minimal environment variables for Linux.
|
|
func defaultEnvironment(taskDir string) map[string]string {
|
|
tmpDir := filepath.Join(taskDir, "tmp")
|
|
homeDir := findHomeDir()
|
|
return map[string]string{
|
|
"PATH": "/usr/local/bin:/usr/bin:/bin",
|
|
"TMPDIR": tmpDir,
|
|
"HOME": homeDir,
|
|
}
|
|
}
|
|
|
|
// lockdown isolates this process to only be able to write and
|
|
// create files in the task's task directory.
|
|
// dir - the task directory
|
|
//
|
|
// Only applies to Linux, when available.
|
|
func lockdown(allocDir, taskDir string) error {
|
|
// landlock not present in the kernel, do not sandbox
|
|
if !landlock.Available() {
|
|
return nil
|
|
}
|
|
paths := []*landlock.Path{
|
|
landlock.DNS(),
|
|
landlock.Certs(),
|
|
landlock.Shared(),
|
|
landlock.Dir("/bin", "rx"),
|
|
landlock.Dir("/usr/bin", "rx"),
|
|
landlock.Dir("/usr/local/bin", "rx"),
|
|
landlock.Dir(allocDir, "rwc"),
|
|
landlock.Dir(taskDir, "rwc"),
|
|
}
|
|
|
|
paths = append(paths, additionalFilesForVCS()...)
|
|
locker := landlock.New(paths...)
|
|
return locker.Lock(landlock.Mandatory)
|
|
}
|
|
|
|
func additionalFilesForVCS() []*landlock.Path {
|
|
const (
|
|
sshDir = ".ssh" // git ssh
|
|
knownHosts = ".ssh/known_hosts" // git ssh
|
|
etcPasswd = "/etc/passwd" // git ssh
|
|
gitGlobalFile = "/etc/gitconfig" // https://git-scm.com/docs/git-config#SCOPES
|
|
hgGlobalFile = "/etc/mercurial/hgrc" // https://www.mercurial-scm.org/doc/hgrc.5.html#files
|
|
hgGlobalDir = "/etc/mercurial/hgrc.d" // https://www.mercurial-scm.org/doc/hgrc.5.html#files
|
|
)
|
|
return filesForVCS(
|
|
sshDir,
|
|
knownHosts,
|
|
etcPasswd,
|
|
gitGlobalFile,
|
|
hgGlobalFile,
|
|
hgGlobalDir,
|
|
)
|
|
}
|
|
|
|
func filesForVCS(
|
|
sshDir,
|
|
knownHosts,
|
|
etcPasswd,
|
|
gitGlobalFile,
|
|
hgGlobalFile,
|
|
hgGlobalDir string) []*landlock.Path {
|
|
|
|
// omit ssh if there is no home directory
|
|
home := findHomeDir()
|
|
sshDir = filepath.Join(home, sshDir)
|
|
knownHosts = filepath.Join(home, knownHosts)
|
|
|
|
// only add if a path exists
|
|
exists := func(p string) bool {
|
|
_, err := os.Stat(p)
|
|
return err == nil
|
|
}
|
|
|
|
result := make([]*landlock.Path, 0, 6)
|
|
if exists(sshDir) {
|
|
result = append(result, landlock.Dir(sshDir, "r"))
|
|
}
|
|
if exists(knownHosts) {
|
|
result = append(result, landlock.File(knownHosts, "rw"))
|
|
}
|
|
if exists(etcPasswd) {
|
|
result = append(result, landlock.File(etcPasswd, "r"))
|
|
}
|
|
if exists(gitGlobalFile) {
|
|
result = append(result, landlock.File(gitGlobalFile, "r"))
|
|
}
|
|
if exists(hgGlobalFile) {
|
|
result = append(result, landlock.File(hgGlobalFile, "r"))
|
|
}
|
|
if exists(hgGlobalDir) {
|
|
result = append(result, landlock.Dir(hgGlobalDir, "r"))
|
|
}
|
|
return result
|
|
}
|