Skip to content

Commit

Permalink
Merge pull request #2553 from hashicorp/b-2552-chown-on-copy
Browse files Browse the repository at this point in the history
Chown files when copying into chroot
  • Loading branch information
schmichael authored Apr 19, 2017
2 parents 3a20e7c + 75c3863 commit 55965cb
Show file tree
Hide file tree
Showing 5 changed files with 59 additions and 14 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down
44 changes: 36 additions & 8 deletions client/allocdir/alloc_dir.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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 {
Expand All @@ -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
Expand Down Expand Up @@ -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
}
Expand All @@ -456,24 +476,30 @@ 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
// is the file passed to this function, and the last element is the root of the
// 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))
Expand All @@ -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
Expand Down
13 changes: 11 additions & 2 deletions client/allocdir/fs_unix.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"os/user"
"path/filepath"
"strconv"
"syscall"

"golang.org/x/sys/unix"
)
Expand Down Expand Up @@ -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.
Expand All @@ -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)
}
9 changes: 7 additions & 2 deletions client/allocdir/fs_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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
}
6 changes: 4 additions & 2 deletions client/allocdir/task_dir.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}

Expand Down Expand Up @@ -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
}
}
Expand Down

0 comments on commit 55965cb

Please sign in to comment.