github.com/vvnotw/moby@v1.13.1/pkg/archive/diff_test.go (about) 1 package archive 2 3 import ( 4 "archive/tar" 5 "io" 6 "io/ioutil" 7 "os" 8 "path/filepath" 9 "reflect" 10 "runtime" 11 "testing" 12 13 "github.com/docker/docker/pkg/ioutils" 14 ) 15 16 func TestApplyLayerInvalidFilenames(t *testing.T) { 17 // TODO Windows: Figure out how to fix this test. 18 if runtime.GOOS == "windows" { 19 t.Skip("Passes but hits breakoutError: platform and architecture is not supported") 20 } 21 for i, headers := range [][]*tar.Header{ 22 { 23 { 24 Name: "../victim/dotdot", 25 Typeflag: tar.TypeReg, 26 Mode: 0644, 27 }, 28 }, 29 { 30 { 31 // Note the leading slash 32 Name: "/../victim/slash-dotdot", 33 Typeflag: tar.TypeReg, 34 Mode: 0644, 35 }, 36 }, 37 } { 38 if err := testBreakout("applylayer", "docker-TestApplyLayerInvalidFilenames", headers); err != nil { 39 t.Fatalf("i=%d. %v", i, err) 40 } 41 } 42 } 43 44 func TestApplyLayerInvalidHardlink(t *testing.T) { 45 if runtime.GOOS == "windows" { 46 t.Skip("TypeLink support on Windows") 47 } 48 for i, headers := range [][]*tar.Header{ 49 { // try reading victim/hello (../) 50 { 51 Name: "dotdot", 52 Typeflag: tar.TypeLink, 53 Linkname: "../victim/hello", 54 Mode: 0644, 55 }, 56 }, 57 { // try reading victim/hello (/../) 58 { 59 Name: "slash-dotdot", 60 Typeflag: tar.TypeLink, 61 // Note the leading slash 62 Linkname: "/../victim/hello", 63 Mode: 0644, 64 }, 65 }, 66 { // try writing victim/file 67 { 68 Name: "loophole-victim", 69 Typeflag: tar.TypeLink, 70 Linkname: "../victim", 71 Mode: 0755, 72 }, 73 { 74 Name: "loophole-victim/file", 75 Typeflag: tar.TypeReg, 76 Mode: 0644, 77 }, 78 }, 79 { // try reading victim/hello (hardlink, symlink) 80 { 81 Name: "loophole-victim", 82 Typeflag: tar.TypeLink, 83 Linkname: "../victim", 84 Mode: 0755, 85 }, 86 { 87 Name: "symlink", 88 Typeflag: tar.TypeSymlink, 89 Linkname: "loophole-victim/hello", 90 Mode: 0644, 91 }, 92 }, 93 { // Try reading victim/hello (hardlink, hardlink) 94 { 95 Name: "loophole-victim", 96 Typeflag: tar.TypeLink, 97 Linkname: "../victim", 98 Mode: 0755, 99 }, 100 { 101 Name: "hardlink", 102 Typeflag: tar.TypeLink, 103 Linkname: "loophole-victim/hello", 104 Mode: 0644, 105 }, 106 }, 107 { // Try removing victim directory (hardlink) 108 { 109 Name: "loophole-victim", 110 Typeflag: tar.TypeLink, 111 Linkname: "../victim", 112 Mode: 0755, 113 }, 114 { 115 Name: "loophole-victim", 116 Typeflag: tar.TypeReg, 117 Mode: 0644, 118 }, 119 }, 120 } { 121 if err := testBreakout("applylayer", "docker-TestApplyLayerInvalidHardlink", headers); err != nil { 122 t.Fatalf("i=%d. %v", i, err) 123 } 124 } 125 } 126 127 func TestApplyLayerInvalidSymlink(t *testing.T) { 128 if runtime.GOOS == "windows" { 129 t.Skip("TypeSymLink support on Windows") 130 } 131 for i, headers := range [][]*tar.Header{ 132 { // try reading victim/hello (../) 133 { 134 Name: "dotdot", 135 Typeflag: tar.TypeSymlink, 136 Linkname: "../victim/hello", 137 Mode: 0644, 138 }, 139 }, 140 { // try reading victim/hello (/../) 141 { 142 Name: "slash-dotdot", 143 Typeflag: tar.TypeSymlink, 144 // Note the leading slash 145 Linkname: "/../victim/hello", 146 Mode: 0644, 147 }, 148 }, 149 { // try writing victim/file 150 { 151 Name: "loophole-victim", 152 Typeflag: tar.TypeSymlink, 153 Linkname: "../victim", 154 Mode: 0755, 155 }, 156 { 157 Name: "loophole-victim/file", 158 Typeflag: tar.TypeReg, 159 Mode: 0644, 160 }, 161 }, 162 { // try reading victim/hello (symlink, symlink) 163 { 164 Name: "loophole-victim", 165 Typeflag: tar.TypeSymlink, 166 Linkname: "../victim", 167 Mode: 0755, 168 }, 169 { 170 Name: "symlink", 171 Typeflag: tar.TypeSymlink, 172 Linkname: "loophole-victim/hello", 173 Mode: 0644, 174 }, 175 }, 176 { // try reading victim/hello (symlink, hardlink) 177 { 178 Name: "loophole-victim", 179 Typeflag: tar.TypeSymlink, 180 Linkname: "../victim", 181 Mode: 0755, 182 }, 183 { 184 Name: "hardlink", 185 Typeflag: tar.TypeLink, 186 Linkname: "loophole-victim/hello", 187 Mode: 0644, 188 }, 189 }, 190 { // try removing victim directory (symlink) 191 { 192 Name: "loophole-victim", 193 Typeflag: tar.TypeSymlink, 194 Linkname: "../victim", 195 Mode: 0755, 196 }, 197 { 198 Name: "loophole-victim", 199 Typeflag: tar.TypeReg, 200 Mode: 0644, 201 }, 202 }, 203 } { 204 if err := testBreakout("applylayer", "docker-TestApplyLayerInvalidSymlink", headers); err != nil { 205 t.Fatalf("i=%d. %v", i, err) 206 } 207 } 208 } 209 210 func TestApplyLayerWhiteouts(t *testing.T) { 211 // TODO Windows: Figure out why this test fails 212 if runtime.GOOS == "windows" { 213 t.Skip("Failing on Windows") 214 } 215 216 wd, err := ioutil.TempDir("", "graphdriver-test-whiteouts") 217 if err != nil { 218 return 219 } 220 defer os.RemoveAll(wd) 221 222 base := []string{ 223 ".baz", 224 "bar/", 225 "bar/bax", 226 "bar/bay/", 227 "baz", 228 "foo/", 229 "foo/.abc", 230 "foo/.bcd/", 231 "foo/.bcd/a", 232 "foo/cde/", 233 "foo/cde/def", 234 "foo/cde/efg", 235 "foo/fgh", 236 "foobar", 237 } 238 239 type tcase struct { 240 change, expected []string 241 } 242 243 tcases := []tcase{ 244 { 245 base, 246 base, 247 }, 248 { 249 []string{ 250 ".bay", 251 ".wh.baz", 252 "foo/", 253 "foo/.bce", 254 "foo/.wh..wh..opq", 255 "foo/cde/", 256 "foo/cde/efg", 257 }, 258 []string{ 259 ".bay", 260 ".baz", 261 "bar/", 262 "bar/bax", 263 "bar/bay/", 264 "foo/", 265 "foo/.bce", 266 "foo/cde/", 267 "foo/cde/efg", 268 "foobar", 269 }, 270 }, 271 { 272 []string{ 273 ".bay", 274 ".wh..baz", 275 ".wh.foobar", 276 "foo/", 277 "foo/.abc", 278 "foo/.wh.cde", 279 "bar/", 280 }, 281 []string{ 282 ".bay", 283 "bar/", 284 "bar/bax", 285 "bar/bay/", 286 "foo/", 287 "foo/.abc", 288 "foo/.bce", 289 }, 290 }, 291 { 292 []string{ 293 ".abc", 294 ".wh..wh..opq", 295 "foobar", 296 }, 297 []string{ 298 ".abc", 299 "foobar", 300 }, 301 }, 302 } 303 304 for i, tc := range tcases { 305 l, err := makeTestLayer(tc.change) 306 if err != nil { 307 t.Fatal(err) 308 } 309 310 _, err = UnpackLayer(wd, l, nil) 311 if err != nil { 312 t.Fatal(err) 313 } 314 err = l.Close() 315 if err != nil { 316 t.Fatal(err) 317 } 318 319 paths, err := readDirContents(wd) 320 if err != nil { 321 t.Fatal(err) 322 } 323 324 if !reflect.DeepEqual(tc.expected, paths) { 325 t.Fatalf("invalid files for layer %d: expected %q, got %q", i, tc.expected, paths) 326 } 327 } 328 329 } 330 331 func makeTestLayer(paths []string) (rc io.ReadCloser, err error) { 332 tmpDir, err := ioutil.TempDir("", "graphdriver-test-mklayer") 333 if err != nil { 334 return 335 } 336 defer func() { 337 if err != nil { 338 os.RemoveAll(tmpDir) 339 } 340 }() 341 for _, p := range paths { 342 if p[len(p)-1] == filepath.Separator { 343 if err = os.MkdirAll(filepath.Join(tmpDir, p), 0700); err != nil { 344 return 345 } 346 } else { 347 if err = ioutil.WriteFile(filepath.Join(tmpDir, p), nil, 0600); err != nil { 348 return 349 } 350 } 351 } 352 archive, err := Tar(tmpDir, Uncompressed) 353 if err != nil { 354 return 355 } 356 return ioutils.NewReadCloserWrapper(archive, func() error { 357 err := archive.Close() 358 os.RemoveAll(tmpDir) 359 return err 360 }), nil 361 } 362 363 func readDirContents(root string) ([]string, error) { 364 var files []string 365 err := filepath.Walk(root, func(path string, info os.FileInfo, err error) error { 366 if err != nil { 367 return err 368 } 369 if path == root { 370 return nil 371 } 372 rel, err := filepath.Rel(root, path) 373 if err != nil { 374 return err 375 } 376 if info.IsDir() { 377 rel = rel + "/" 378 } 379 files = append(files, rel) 380 return nil 381 }) 382 if err != nil { 383 return nil, err 384 } 385 return files, nil 386 }