123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347 |
- // +build linux
- /*
- Copyright 2017 The Kubernetes Authors.
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- */
- package subpath
- import (
- "io/ioutil"
- "os"
- "path/filepath"
- "strings"
- "testing"
- "golang.org/x/sys/unix"
- "k8s.io/utils/nsenter"
- nsutil "k8s.io/kubernetes/pkg/volume/util/nsenter"
- )
- func TestCheckDeviceInode(t *testing.T) {
- testDir, err := ioutil.TempDir("", "nsenter-mounter-device-")
- if err != nil {
- t.Fatalf("Cannot create temporary directory: %s", err)
- }
- defer os.RemoveAll(testDir)
- tests := []struct {
- name string
- srcPath string
- dstPath string
- expectError string
- }{
- {
- name: "the same file",
- srcPath: filepath.Join(testDir, "1"),
- dstPath: filepath.Join(testDir, "1"),
- expectError: "",
- },
- {
- name: "different file on the same FS",
- srcPath: filepath.Join(testDir, "2.1"),
- dstPath: filepath.Join(testDir, "2.2"),
- expectError: "different inode",
- },
- {
- name: "different file on different device",
- srcPath: filepath.Join(testDir, "3"),
- // /proc is always on a different "device" than /tmp (or $TEMP)
- dstPath: "/proc/self/status",
- expectError: "different device",
- },
- }
- for _, test := range tests {
- if err := ioutil.WriteFile(test.srcPath, []byte{}, 0644); err != nil {
- t.Errorf("Test %q: cannot create srcPath %s: %s", test.name, test.srcPath, err)
- continue
- }
- // Don't create dst if it exists
- if _, err := os.Stat(test.dstPath); os.IsNotExist(err) {
- if err := ioutil.WriteFile(test.dstPath, []byte{}, 0644); err != nil {
- t.Errorf("Test %q: cannot create dstPath %s: %s", test.name, test.dstPath, err)
- continue
- }
- } else if err != nil {
- t.Errorf("Test %q: cannot check existence of dstPath %s: %s", test.name, test.dstPath, err)
- continue
- }
- fd, err := unix.Open(test.srcPath, unix.O_CREAT, 0644)
- if err != nil {
- t.Errorf("Test %q: cannot open srcPath %s: %s", test.name, test.srcPath, err)
- continue
- }
- err = checkDeviceInode(fd, test.dstPath)
- if test.expectError == "" && err != nil {
- t.Errorf("Test %q: expected no error, got %s", test.name, err)
- }
- if test.expectError != "" {
- if err == nil {
- t.Errorf("Test %q: expected error, got none", test.name)
- } else {
- if !strings.Contains(err.Error(), test.expectError) {
- t.Errorf("Test %q: expected error %q, got %q", test.name, test.expectError, err)
- }
- }
- }
- }
- }
- func newFakeNsenterMounter(tmpdir string, t *testing.T) (*nsutil.Mounter, string, string, *nsenter.Nsenter, error) {
- rootfsPath := filepath.Join(tmpdir, "rootfs")
- if err := os.Mkdir(rootfsPath, 0755); err != nil {
- return nil, "", "", nil, err
- }
- ne, err := nsenter.NewFakeNsenter(rootfsPath)
- if err != nil {
- return nil, "", "", nil, err
- }
- varlibPath := filepath.Join(tmpdir, "/var/lib/kubelet")
- if err := os.MkdirAll(varlibPath, 0755); err != nil {
- return nil, "", "", nil, err
- }
- return nsutil.NewMounter(varlibPath, ne), rootfsPath, varlibPath, ne, nil
- }
- func TestNsenterSafeMakeDir(t *testing.T) {
- tests := []struct {
- name string
- prepare func(base, rootfs, varlib string) (expectedDir string, err error)
- subdir string
- expectError bool
- // If true, "base" directory for SafeMakeDir will be /var/lib/kubelet
- baseIsVarLib bool
- }{
- {
- name: "simple directory",
- // evaluated in base
- subdir: "some/subdirectory/structure",
- prepare: func(base, rootfs, varlib string) (expectedDir string, err error) {
- // expected to be created in /roots/
- expectedDir = filepath.Join(rootfs, base, "some/subdirectory/structure")
- return expectedDir, nil
- },
- },
- {
- name: "simple existing directory",
- // evaluated in base
- subdir: "some/subdirectory/structure",
- prepare: func(base, rootfs, varlib string) (expectedDir string, err error) {
- // On the host: directory exists
- hostPath := filepath.Join(base, "some/subdirectory/structure")
- if err := os.MkdirAll(hostPath, 0755); err != nil {
- return "", err
- }
- // In rootfs: directory exists
- kubeletPath := filepath.Join(rootfs, hostPath)
- if err := os.MkdirAll(kubeletPath, 0755); err != nil {
- return "", err
- }
- // expected to be created in /roots/
- expectedDir = kubeletPath
- return expectedDir, nil
- },
- },
- {
- name: "absolute symlink into safe place",
- // evaluated in base
- subdir: "some/subdirectory/structure",
- prepare: func(base, rootfs, varlib string) (expectedDir string, err error) {
- // On the host: /base/other/subdirectory exists, /base/some is link to /base/other
- hostPath := filepath.Join(base, "other/subdirectory")
- if err := os.MkdirAll(hostPath, 0755); err != nil {
- return "", err
- }
- somePath := filepath.Join(base, "some")
- otherPath := filepath.Join(base, "other")
- if err := os.Symlink(otherPath, somePath); err != nil {
- return "", err
- }
- // In rootfs: /base/other/subdirectory exists
- kubeletPath := filepath.Join(rootfs, hostPath)
- if err := os.MkdirAll(kubeletPath, 0755); err != nil {
- return "", err
- }
- // expected 'structure' to be created
- expectedDir = filepath.Join(rootfs, hostPath, "structure")
- return expectedDir, nil
- },
- },
- {
- name: "relative symlink into safe place",
- // evaluated in base
- subdir: "some/subdirectory/structure",
- prepare: func(base, rootfs, varlib string) (expectedDir string, err error) {
- // On the host: /base/other/subdirectory exists, /base/some is link to other
- hostPath := filepath.Join(base, "other/subdirectory")
- if err := os.MkdirAll(hostPath, 0755); err != nil {
- return "", err
- }
- somePath := filepath.Join(base, "some")
- if err := os.Symlink("other", somePath); err != nil {
- return "", err
- }
- // In rootfs: /base/other/subdirectory exists
- kubeletPath := filepath.Join(rootfs, hostPath)
- if err := os.MkdirAll(kubeletPath, 0755); err != nil {
- return "", err
- }
- // expected 'structure' to be created
- expectedDir = filepath.Join(rootfs, hostPath, "structure")
- return expectedDir, nil
- },
- },
- {
- name: "symlink into unsafe place",
- // evaluated in base
- subdir: "some/subdirectory/structure",
- prepare: func(base, rootfs, varlib string) (expectedDir string, err error) {
- // On the host: /base/some is link to /bin/other
- somePath := filepath.Join(base, "some")
- if err := os.Symlink("/bin", somePath); err != nil {
- return "", err
- }
- return "", nil
- },
- expectError: true,
- },
- {
- name: "simple directory in /var/lib/kubelet",
- // evaluated in varlib
- subdir: "some/subdirectory/structure",
- baseIsVarLib: true,
- prepare: func(base, rootfs, varlib string) (expectedDir string, err error) {
- // expected to be created in /base/var/lib/kubelet, not in /rootfs!
- expectedDir = filepath.Join(varlib, "some/subdirectory/structure")
- return expectedDir, nil
- },
- },
- {
- name: "safe symlink in /var/lib/kubelet",
- // evaluated in varlib
- subdir: "some/subdirectory/structure",
- baseIsVarLib: true,
- prepare: func(base, rootfs, varlib string) (expectedDir string, err error) {
- // On the host: /varlib/kubelet/other/subdirectory exists, /varlib/some is link to other
- hostPath := filepath.Join(varlib, "other/subdirectory")
- if err := os.MkdirAll(hostPath, 0755); err != nil {
- return "", err
- }
- somePath := filepath.Join(varlib, "some")
- if err := os.Symlink("other", somePath); err != nil {
- return "", err
- }
- // expected to be created in /base/var/lib/kubelet, not in /rootfs!
- expectedDir = filepath.Join(varlib, "other/subdirectory/structure")
- return expectedDir, nil
- },
- },
- {
- name: "unsafe symlink in /var/lib/kubelet",
- // evaluated in varlib
- subdir: "some/subdirectory/structure",
- baseIsVarLib: true,
- prepare: func(base, rootfs, varlib string) (expectedDir string, err error) {
- // On the host: /varlib/some is link to /bin
- somePath := filepath.Join(varlib, "some")
- if err := os.Symlink("/bin", somePath); err != nil {
- return "", err
- }
- return "", nil
- },
- expectError: true,
- },
- }
- for _, test := range tests {
- tmpdir, err := ioutil.TempDir("", "nsenter-get-safedir-")
- if err != nil {
- t.Error(err)
- continue
- }
- defer os.RemoveAll(tmpdir)
- mounter, rootfs, varlib, ne, err := newFakeNsenterMounter(tmpdir, t)
- if err != nil {
- t.Error(err)
- continue
- }
- fsp := NewNSEnter(mounter, ne, varlib)
- // Prepare base directory for the test
- testBase := filepath.Join(tmpdir, "base")
- if err := os.Mkdir(testBase, 0755); err != nil {
- t.Error(err)
- continue
- }
- // Prepare base directory also in /rootfs
- rootfsBase := filepath.Join(rootfs, testBase)
- if err := os.MkdirAll(rootfsBase, 0755); err != nil {
- t.Error(err)
- continue
- }
- expectedDir := ""
- if test.prepare != nil {
- expectedDir, err = test.prepare(testBase, rootfs, varlib)
- if err != nil {
- t.Error(err)
- continue
- }
- }
- if test.baseIsVarLib {
- // use /var/lib/kubelet as the test base so we can test creating
- // subdirs there directly in /var/lib/kubenet and not in
- // /rootfs/var/lib/kubelet
- testBase = varlib
- }
- err = fsp.SafeMakeDir(test.subdir, testBase, 0755)
- if err != nil && !test.expectError {
- t.Errorf("Test %q: unexpected error: %s", test.name, err)
- }
- if test.expectError {
- if err == nil {
- t.Errorf("Test %q: expected error, got none", test.name)
- } else {
- if !strings.Contains(err.Error(), "is outside of allowed base") {
- t.Errorf("Test %q: expected error to contain \"is outside of allowed base\", got this one instead: %s", test.name, err)
- }
- }
- }
- if expectedDir != "" {
- _, err := os.Stat(expectedDir)
- if err != nil {
- t.Errorf("Test %q: expected %q to exist, got error: %s", test.name, expectedDir, err)
- }
- }
- }
- }
|