docker_cli_cp_test.go 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245
  1. package main
  2. import (
  3. "fmt"
  4. "io/ioutil"
  5. "os"
  6. "os/exec"
  7. "path/filepath"
  8. "testing"
  9. )
  10. const (
  11. cpTestPathParent = "/some"
  12. cpTestPath = "/some/path"
  13. cpTestName = "test"
  14. cpFullPath = "/some/path/test"
  15. cpContainerContents = "holla, i am the container"
  16. cpHostContents = "hello, i am the host"
  17. )
  18. // Test for #5656
  19. // Check that garbage paths don't escape the container's rootfs
  20. func TestCpGarbagePath(t *testing.T) {
  21. out, exitCode, err := cmd(t, "run", "-d", "busybox", "/bin/sh", "-c", "mkdir -p '"+cpTestPath+"' && echo -n '"+cpContainerContents+"' > "+cpFullPath)
  22. if err != nil || exitCode != 0 {
  23. t.Fatal("failed to create a container", out, err)
  24. }
  25. cleanedContainerID := stripTrailingCharacters(out)
  26. defer deleteContainer(cleanedContainerID)
  27. out, _, err = cmd(t, "wait", cleanedContainerID)
  28. if err != nil || stripTrailingCharacters(out) != "0" {
  29. t.Fatal("failed to set up container", out, err)
  30. }
  31. if err := os.MkdirAll(cpTestPath, os.ModeDir); err != nil {
  32. t.Fatal(err)
  33. }
  34. hostFile, err := os.Create(cpFullPath)
  35. if err != nil {
  36. t.Fatal(err)
  37. }
  38. defer hostFile.Close()
  39. defer os.RemoveAll(cpTestPathParent)
  40. fmt.Fprintf(hostFile, "%s", cpHostContents)
  41. tmpdir, err := ioutil.TempDir("", "docker-integration")
  42. if err != nil {
  43. t.Fatal(err)
  44. }
  45. tmpname := filepath.Join(tmpdir, cpTestName)
  46. defer os.RemoveAll(tmpdir)
  47. path := filepath.Join("../../../../../../../../../../../../", cpFullPath)
  48. _, _, err = cmd(t, "cp", cleanedContainerID+":"+path, tmpdir)
  49. if err != nil {
  50. t.Fatalf("couldn't copy from garbage path: %s:%s %s", cleanedContainerID, path, err)
  51. }
  52. file, _ := os.Open(tmpname)
  53. defer file.Close()
  54. test, err := ioutil.ReadAll(file)
  55. if err != nil {
  56. t.Fatal(err)
  57. }
  58. if string(test) == cpHostContents {
  59. t.Errorf("output matched host file -- garbage path can escape container rootfs")
  60. }
  61. if string(test) != cpContainerContents {
  62. t.Errorf("output doesn't match the input for garbage path")
  63. }
  64. logDone("cp - garbage paths relative to container's rootfs")
  65. }
  66. // Check that relative paths are relative to the container's rootfs
  67. func TestCpRelativePath(t *testing.T) {
  68. out, exitCode, err := cmd(t, "run", "-d", "busybox", "/bin/sh", "-c", "mkdir -p '"+cpTestPath+"' && echo -n '"+cpContainerContents+"' > "+cpFullPath)
  69. if err != nil || exitCode != 0 {
  70. t.Fatal("failed to create a container", out, err)
  71. }
  72. cleanedContainerID := stripTrailingCharacters(out)
  73. defer deleteContainer(cleanedContainerID)
  74. out, _, err = cmd(t, "wait", cleanedContainerID)
  75. if err != nil || stripTrailingCharacters(out) != "0" {
  76. t.Fatal("failed to set up container", out, err)
  77. }
  78. if err := os.MkdirAll(cpTestPath, os.ModeDir); err != nil {
  79. t.Fatal(err)
  80. }
  81. hostFile, err := os.Create(cpFullPath)
  82. if err != nil {
  83. t.Fatal(err)
  84. }
  85. defer hostFile.Close()
  86. defer os.RemoveAll(cpTestPathParent)
  87. fmt.Fprintf(hostFile, "%s", cpHostContents)
  88. tmpdir, err := ioutil.TempDir("", "docker-integration")
  89. if err != nil {
  90. t.Fatal(err)
  91. }
  92. tmpname := filepath.Join(tmpdir, cpTestName)
  93. defer os.RemoveAll(tmpdir)
  94. path, _ := filepath.Rel("/", cpFullPath)
  95. _, _, err = cmd(t, "cp", cleanedContainerID+":"+path, tmpdir)
  96. if err != nil {
  97. t.Fatalf("couldn't copy from relative path: %s:%s %s", cleanedContainerID, path, err)
  98. }
  99. file, _ := os.Open(tmpname)
  100. defer file.Close()
  101. test, err := ioutil.ReadAll(file)
  102. if err != nil {
  103. t.Fatal(err)
  104. }
  105. if string(test) == cpHostContents {
  106. t.Errorf("output matched host file -- relative path can escape container rootfs")
  107. }
  108. if string(test) != cpContainerContents {
  109. t.Errorf("output doesn't match the input for relative path")
  110. }
  111. logDone("cp - relative paths relative to container's rootfs")
  112. }
  113. // Check that absolute paths are relative to the container's rootfs
  114. func TestCpAbsolutePath(t *testing.T) {
  115. out, exitCode, err := cmd(t, "run", "-d", "busybox", "/bin/sh", "-c", "mkdir -p '"+cpTestPath+"' && echo -n '"+cpContainerContents+"' > "+cpFullPath)
  116. if err != nil || exitCode != 0 {
  117. t.Fatal("failed to create a container", out, err)
  118. }
  119. cleanedContainerID := stripTrailingCharacters(out)
  120. defer deleteContainer(cleanedContainerID)
  121. out, _, err = cmd(t, "wait", cleanedContainerID)
  122. if err != nil || stripTrailingCharacters(out) != "0" {
  123. t.Fatal("failed to set up container", out, err)
  124. }
  125. if err := os.MkdirAll(cpTestPath, os.ModeDir); err != nil {
  126. t.Fatal(err)
  127. }
  128. hostFile, err := os.Create(cpFullPath)
  129. if err != nil {
  130. t.Fatal(err)
  131. }
  132. defer hostFile.Close()
  133. defer os.RemoveAll(cpTestPathParent)
  134. fmt.Fprintf(hostFile, "%s", cpHostContents)
  135. tmpdir, err := ioutil.TempDir("", "docker-integration")
  136. if err != nil {
  137. t.Fatal(err)
  138. }
  139. tmpname := filepath.Join(tmpdir, cpTestName)
  140. defer os.RemoveAll(tmpdir)
  141. path := cpFullPath
  142. _, _, err = cmd(t, "cp", cleanedContainerID+":"+path, tmpdir)
  143. if err != nil {
  144. t.Fatalf("couldn't copy from absolute path: %s:%s %s", cleanedContainerID, path, err)
  145. }
  146. file, _ := os.Open(tmpname)
  147. defer file.Close()
  148. test, err := ioutil.ReadAll(file)
  149. if err != nil {
  150. t.Fatal(err)
  151. }
  152. if string(test) == cpHostContents {
  153. t.Errorf("output matched host file -- absolute path can escape container rootfs")
  154. }
  155. if string(test) != cpContainerContents {
  156. t.Errorf("output doesn't match the input for absolute path")
  157. }
  158. logDone("cp - absolute paths relative to container's rootfs")
  159. }
  160. // Check that cp with unprivileged user doesn't return any error
  161. func TestCpUnprivilegedUser(t *testing.T) {
  162. out, exitCode, err := cmd(t, "run", "-d", "busybox", "/bin/sh", "-c", "touch "+cpTestName)
  163. if err != nil || exitCode != 0 {
  164. t.Fatal("failed to create a container", out, err)
  165. }
  166. cleanedContainerID := stripTrailingCharacters(out)
  167. defer deleteContainer(cleanedContainerID)
  168. out, _, err = cmd(t, "wait", cleanedContainerID)
  169. if err != nil || stripTrailingCharacters(out) != "0" {
  170. t.Fatal("failed to set up container", out, err)
  171. }
  172. tmpdir, err := ioutil.TempDir("", "docker-integration")
  173. if err != nil {
  174. t.Fatal(err)
  175. }
  176. defer os.RemoveAll(tmpdir)
  177. if err = os.Chmod(tmpdir, 0777); err != nil {
  178. t.Fatal(err)
  179. }
  180. path := cpTestName
  181. _, _, err = runCommandWithOutput(exec.Command("su", "unprivilegeduser", "-c", dockerBinary+" cp "+cleanedContainerID+":"+path+" "+tmpdir))
  182. if err != nil {
  183. t.Fatalf("couldn't copy with unprivileged user: %s:%s %s", cleanedContainerID, path, err)
  184. }
  185. logDone("cp - unprivileged user")
  186. }