diff --git a/client/allocrunner/taskrunner/getter/getter.go b/client/allocrunner/taskrunner/getter/getter.go index c256990d7..a7698d9b7 100644 --- a/client/allocrunner/taskrunner/getter/getter.go +++ b/client/allocrunner/taskrunner/getter/getter.go @@ -52,6 +52,7 @@ func getClient(src string, mode gg.ClientMode, dst string) *gg.Client { Dst: dst, Mode: mode, Getters: getters, + Umask: 060000000, } } diff --git a/client/allocrunner/taskrunner/getter/getter_test.go b/client/allocrunner/taskrunner/getter/getter_test.go index 0bb757cdc..ef961bbc1 100644 --- a/client/allocrunner/taskrunner/getter/getter_test.go +++ b/client/allocrunner/taskrunner/getter/getter_test.go @@ -8,12 +8,14 @@ import ( "os" "path/filepath" "reflect" + "runtime" "strings" "testing" "github.com/hashicorp/nomad/client/taskenv" "github.com/hashicorp/nomad/nomad/mock" "github.com/hashicorp/nomad/nomad/structs" + "github.com/stretchr/testify/require" ) // fakeReplacer is a noop version of taskenv.TaskEnv.ReplaceEnv @@ -214,6 +216,55 @@ func TestGetArtifact_Archive(t *testing.T) { checkContents(taskDir, expected, t) } +func TestGetArtifact_Setuid(t *testing.T) { + // Create the test server hosting the file to download + ts := httptest.NewServer(http.FileServer(http.Dir(filepath.Dir("./test-fixtures/")))) + defer ts.Close() + + // Create a temp directory to download into and create some of the same + // files that exist in the artifact to ensure they are overridden + taskDir, err := ioutil.TempDir("", "nomad-test") + require.NoError(t, err) + defer os.RemoveAll(taskDir) + + file := "setuid.tgz" + artifact := &structs.TaskArtifact{ + GetterSource: fmt.Sprintf("%s/%s", ts.URL, file), + GetterOptions: map[string]string{ + "checksum": "sha1:e892194748ecbad5d0f60c6c6b2db2bdaa384a90", + }, + } + + require.NoError(t, GetArtifact(taskEnv, artifact, taskDir)) + + var expected map[string]int + + if runtime.GOOS == "windows" { + // windows doesn't support Chmod changing file permissions. + expected = map[string]int{ + "public": 0666, + "private": 0666, + "setuid": 0666, + } + } else { + // Verify the unarchiving masked files properly. + expected = map[string]int{ + "public": 0666, + "private": 0600, + "setuid": 0755, + } + } + + for file, perm := range expected { + path := filepath.Join(taskDir, "setuid", file) + s, err := os.Stat(path) + require.NoError(t, err) + p := os.FileMode(perm) + o := s.Mode() + require.Equalf(t, p, o, "%s expected %o found %o", file, p, o) + } +} + func TestGetGetterUrl_Queries(t *testing.T) { cases := []struct { name string diff --git a/client/allocrunner/taskrunner/getter/test-fixtures/setuid.tgz b/client/allocrunner/taskrunner/getter/test-fixtures/setuid.tgz new file mode 100644 index 000000000..660d79779 Binary files /dev/null and b/client/allocrunner/taskrunner/getter/test-fixtures/setuid.tgz differ