Merge pull request #2553 from hashicorp/b-2552-chown-on-copy

Chown files when copying into chroot
This commit is contained in:
Michael Schurter 2017-04-19 12:38:26 -07:00 committed by GitHub
commit 291f4f0b44
5 changed files with 59 additions and 14 deletions

View File

@ -19,6 +19,7 @@ BUG FIXES:
* client/artifact: Honor netrc [GH-2524] * client/artifact: Honor netrc [GH-2524]
* client/artifact: Handle tars where file in directory is listed before * client/artifact: Handle tars where file in directory is listed before
directory [GH-2524] directory [GH-2524]
* driver/exec: Properly set file/dir ownership in chroots [GH-2552]
* server: Reject non-TLS clients when TLS enabled [GH-2525] * server: Reject non-TLS clients when TLS enabled [GH-2525]
* server: Fix a panic in plan evaluation with partial failures and all_at_once * server: Fix a panic in plan evaluation with partial failures and all_at_once
set [GH-2544] set [GH-2544]

View File

@ -17,6 +17,12 @@ import (
"github.com/hpcloud/tail/watch" "github.com/hpcloud/tail/watch"
) )
const (
// idUnsupported is what the uid/gid will be set to on platforms (eg
// Windows) that don't support integer ownership identifiers.
idUnsupported = -1
)
var ( var (
// The name of the directory that is shared across tasks in a task group. // The name of the directory that is shared across tasks in a task group.
SharedAllocName = "alloc" SharedAllocName = "alloc"
@ -385,7 +391,9 @@ func getFileWatcher(path string) watch.FileWatcher {
return watch.NewPollingFileWatcher(path) return watch.NewPollingFileWatcher(path)
} }
func fileCopy(src, dst string, perm os.FileMode) error { // fileCopy from src to dst setting the permissions and owner (if uid & gid are
// both greater than 0)
func fileCopy(src, dst string, uid, gid int, perm os.FileMode) error {
// Do a simple copy. // Do a simple copy.
srcFile, err := os.Open(src) srcFile, err := os.Open(src)
if err != nil { if err != nil {
@ -400,7 +408,13 @@ func fileCopy(src, dst string, perm os.FileMode) error {
defer dstFile.Close() defer dstFile.Close()
if _, err := io.Copy(dstFile, srcFile); err != nil { if _, err := io.Copy(dstFile, srcFile); err != nil {
return fmt.Errorf("Couldn't copy %v to %v: %v", src, dst, err) return fmt.Errorf("Couldn't copy %q to %q: %v", src, dst, err)
}
if uid != idUnsupported && gid != idUnsupported {
if err := dstFile.Chown(uid, gid); err != nil {
return fmt.Errorf("Couldn't copy %q to %q: %v", src, dst, err)
}
} }
return nil return nil
@ -448,6 +462,12 @@ func createDir(basePath, relPath string) error {
if err := os.MkdirAll(destDir, fi.Perm); err != nil { if err := os.MkdirAll(destDir, fi.Perm); err != nil {
return err return err
} }
if fi.Uid != idUnsupported && fi.Gid != idUnsupported {
if err := os.Chown(destDir, fi.Uid, fi.Gid); err != nil {
return err
}
}
} }
return nil return nil
} }
@ -456,6 +476,10 @@ func createDir(basePath, relPath string) error {
type fileInfo struct { type fileInfo struct {
Name string Name string
Perm os.FileMode Perm os.FileMode
// Uid and Gid are unsupported on Windows
Uid int
Gid int
} }
// splitPath stats each subdirectory of a path. The first element of the array // splitPath stats each subdirectory of a path. The first element of the array
@ -463,17 +487,19 @@ type fileInfo struct {
// path. // path.
func splitPath(path string) ([]fileInfo, error) { func splitPath(path string) ([]fileInfo, error) {
var mode os.FileMode var mode os.FileMode
i, err := os.Stat(path) fi, err := os.Stat(path)
// If the path is not present in the host then we respond with the most // If the path is not present in the host then we respond with the most
// flexible permission. // flexible permission.
uid, gid := idUnsupported, idUnsupported
if err != nil { if err != nil {
mode = os.ModePerm mode = os.ModePerm
} else { } else {
mode = i.Mode() uid, gid = getOwner(fi)
mode = fi.Mode()
} }
var dirs []fileInfo var dirs []fileInfo
dirs = append(dirs, fileInfo{Name: path, Perm: mode}) dirs = append(dirs, fileInfo{Name: path, Perm: mode, Uid: uid, Gid: gid})
currentDir := path currentDir := path
for { for {
dir := filepath.Dir(filepath.Clean(currentDir)) dir := filepath.Dir(filepath.Clean(currentDir))
@ -483,13 +509,15 @@ func splitPath(path string) ([]fileInfo, error) {
// We try to find the permission of the file in the host. If the path is not // We try to find the permission of the file in the host. If the path is not
// present in the host then we respond with the most flexible permission. // present in the host then we respond with the most flexible permission.
i, err = os.Stat(dir) uid, gid := idUnsupported, idUnsupported
fi, err := os.Stat(dir)
if err != nil { if err != nil {
mode = os.ModePerm mode = os.ModePerm
} else { } else {
mode = i.Mode() uid, gid = getOwner(fi)
mode = fi.Mode()
} }
dirs = append(dirs, fileInfo{Name: dir, Perm: mode}) dirs = append(dirs, fileInfo{Name: dir, Perm: mode, Uid: uid, Gid: gid})
currentDir = dir currentDir = dir
} }
return dirs, nil return dirs, nil

View File

@ -8,6 +8,7 @@ import (
"os/user" "os/user"
"path/filepath" "path/filepath"
"strconv" "strconv"
"syscall"
"golang.org/x/sys/unix" "golang.org/x/sys/unix"
) )
@ -82,7 +83,7 @@ func getGid(u *user.User) (int, error) {
// linkOrCopy attempts to hardlink dst to src and fallsback to copying if the // linkOrCopy attempts to hardlink dst to src and fallsback to copying if the
// hardlink fails. // hardlink fails.
func linkOrCopy(src, dst string, perm os.FileMode) error { func linkOrCopy(src, dst string, uid, gid int, perm os.FileMode) error {
// Avoid link/copy if the file already exists in the chroot // Avoid link/copy if the file already exists in the chroot
// TODO 0.6 clean this up. This was needed because chroot creation fails // TODO 0.6 clean this up. This was needed because chroot creation fails
// when a process restarts. // when a process restarts.
@ -94,5 +95,13 @@ func linkOrCopy(src, dst string, perm os.FileMode) error {
return nil return nil
} }
return fileCopy(src, dst, perm) 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)
} }

View File

@ -21,8 +21,8 @@ var (
) )
// linkOrCopy is always copies dst to src on Windows. // linkOrCopy is always copies dst to src on Windows.
func linkOrCopy(src, dst string, perm os.FileMode) error { func linkOrCopy(src, dst string, uid, gid int, perm os.FileMode) error {
return fileCopy(src, dst, perm) return fileCopy(src, dst, uid, gid, perm)
} }
// The windows version does nothing currently. // The windows version does nothing currently.
@ -70,3 +70,8 @@ func MountSpecialDirs(taskDir string) error {
func unmountSpecialDirs(taskDir string) error { func unmountSpecialDirs(taskDir string) error {
return nil return nil
} }
// getOwner doesn't work on Windows as Windows doesn't use int user IDs
func getOwner(os.FileInfo) (int, int) {
return idUnsupported, idUnsupported
}

View File

@ -163,7 +163,8 @@ func (t *TaskDir) embedDirs(entries map[string]string) error {
// Copy the file. // Copy the file.
taskEntry := filepath.Join(t.Dir, dest) taskEntry := filepath.Join(t.Dir, dest)
if err := linkOrCopy(source, taskEntry, s.Mode().Perm()); err != nil { uid, gid := getOwner(s)
if err := linkOrCopy(source, taskEntry, uid, gid, s.Mode().Perm()); err != nil {
return err return err
} }
@ -217,7 +218,8 @@ func (t *TaskDir) embedDirs(entries map[string]string) error {
continue continue
} }
if err := linkOrCopy(hostEntry, taskEntry, entry.Mode().Perm()); err != nil { uid, gid := getOwner(entry)
if err := linkOrCopy(hostEntry, taskEntry, uid, gid, entry.Mode().Perm()); err != nil {
return err return err
} }
} }