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: Handle tars where file in directory is listed before
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: Fix a panic in plan evaluation with partial failures and all_at_once
set [GH-2544]

View File

@ -17,6 +17,12 @@ import (
"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 (
// The name of the directory that is shared across tasks in a task group.
SharedAllocName = "alloc"
@ -385,7 +391,9 @@ func getFileWatcher(path string) watch.FileWatcher {
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.
srcFile, err := os.Open(src)
if err != nil {
@ -400,7 +408,13 @@ func fileCopy(src, dst string, perm os.FileMode) error {
defer dstFile.Close()
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
@ -448,6 +462,12 @@ func createDir(basePath, relPath string) error {
if err := os.MkdirAll(destDir, fi.Perm); err != nil {
return err
}
if fi.Uid != idUnsupported && fi.Gid != idUnsupported {
if err := os.Chown(destDir, fi.Uid, fi.Gid); err != nil {
return err
}
}
}
return nil
}
@ -456,6 +476,10 @@ func createDir(basePath, relPath string) error {
type fileInfo struct {
Name string
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
@ -463,17 +487,19 @@ type fileInfo struct {
// path.
func splitPath(path string) ([]fileInfo, error) {
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
// flexible permission.
uid, gid := idUnsupported, idUnsupported
if err != nil {
mode = os.ModePerm
} else {
mode = i.Mode()
uid, gid = getOwner(fi)
mode = fi.Mode()
}
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
for {
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
// 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 {
mode = os.ModePerm
} 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
}
return dirs, nil

View File

@ -8,6 +8,7 @@ import (
"os/user"
"path/filepath"
"strconv"
"syscall"
"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
// 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
// TODO 0.6 clean this up. This was needed because chroot creation fails
// when a process restarts.
@ -94,5 +95,13 @@ func linkOrCopy(src, dst string, perm os.FileMode) error {
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.
func linkOrCopy(src, dst string, perm os.FileMode) error {
return fileCopy(src, dst, perm)
func linkOrCopy(src, dst string, uid, gid int, perm os.FileMode) error {
return fileCopy(src, dst, uid, gid, perm)
}
// The windows version does nothing currently.
@ -70,3 +70,8 @@ func MountSpecialDirs(taskDir string) error {
func unmountSpecialDirs(taskDir string) error {
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.
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
}
@ -217,7 +218,8 @@ func (t *TaskDir) embedDirs(entries map[string]string) error {
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
}
}