Refactor of symlink tests to remove testdata dir

Signed-off-by: Tibor Vass <teabee89@gmail.com>
This commit is contained in:
Tibor Vass 2014-11-30 11:39:28 -05:00
parent ae3c4f8582
commit 7235750de8
8 changed files with 132 additions and 170 deletions

View file

@ -3,248 +3,217 @@
package symlink package symlink
import ( import (
"fmt"
"io/ioutil" "io/ioutil"
"os" "os"
"path/filepath" "path/filepath"
"testing" "testing"
) )
func abs(t *testing.T, p string) string { type dirOrLink struct {
o, err := filepath.Abs(p) path string
if err != nil { target string
t.Fatal(err)
}
return o
} }
func TestFollowSymLinkNormal(t *testing.T) { func makeFs(tmpdir string, fs []dirOrLink) error {
link := "testdata/fs/a/d/c/data" for _, s := range fs {
s.path = filepath.Join(tmpdir, s.path)
if s.target == "" {
os.MkdirAll(s.path, 0755)
continue
}
if err := os.MkdirAll(filepath.Dir(s.path), 0755); err != nil {
return err
}
if err := os.Symlink(s.target, s.path); err != nil && !os.IsExist(err) {
return err
}
}
return nil
}
rewrite, err := FollowSymlinkInScope(link, "testdata") func testSymlink(tmpdir, path, expected, scope string) error {
rewrite, err := FollowSymlinkInScope(filepath.Join(tmpdir, path), filepath.Join(tmpdir, scope))
if err != nil {
return err
}
expected, err = filepath.Abs(filepath.Join(tmpdir, expected))
if err != nil {
return err
}
if expected != rewrite {
return fmt.Errorf("Expected %q got %q", expected, rewrite)
}
return nil
}
func TestFollowSymlinkNormal(t *testing.T) {
tmpdir, err := ioutil.TempDir("", "TestFollowSymlinkNormal")
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
defer os.RemoveAll(tmpdir)
if expected := abs(t, "testdata/b/c/data"); expected != rewrite { if err := makeFs(tmpdir, []dirOrLink{{path: "testdata/fs/a/d", target: "/b"}}); err != nil {
t.Fatalf("Expected %s got %s", expected, rewrite) t.Fatal(err)
}
if err := testSymlink(tmpdir, "testdata/fs/a/d/c/data", "testdata/b/c/data", "testdata"); err != nil {
t.Fatal(err)
} }
} }
func TestFollowSymLinkRelativePath(t *testing.T) { func TestFollowSymlinkRelativePath(t *testing.T) {
link := "testdata/fs/i" tmpdir, err := ioutil.TempDir("", "TestFollowSymlinkRelativePath")
rewrite, err := FollowSymlinkInScope(link, "testdata")
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
defer os.RemoveAll(tmpdir)
if expected := abs(t, "testdata/fs/a"); expected != rewrite { if err := makeFs(tmpdir, []dirOrLink{{path: "testdata/fs/i", target: "a"}}); err != nil {
t.Fatalf("Expected %s got %s", expected, rewrite) t.Fatal(err)
}
if err := testSymlink(tmpdir, "testdata/fs/i", "testdata/fs/a", "testdata"); err != nil {
t.Fatal(err)
} }
} }
func TestFollowSymLinkUnderLinkedDir(t *testing.T) { func TestFollowSymlinkUnderLinkedDir(t *testing.T) {
dir, err := ioutil.TempDir("", "docker-fs-test") tmpdir, err := ioutil.TempDir("", "TestFollowSymlinkUnderLinkedDir")
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
defer os.RemoveAll(dir) defer os.RemoveAll(tmpdir)
if err := makeFs(tmpdir, []dirOrLink{
os.Mkdir(filepath.Join(dir, "realdir"), 0700) {path: "linkdir", target: "realdir"},
os.Symlink("realdir", filepath.Join(dir, "linkdir")) {path: "linkdir/foo/bar"},
}); err != nil {
linkDir := filepath.Join(dir, "linkdir", "foo")
dirUnderLinkDir := filepath.Join(dir, "linkdir", "foo", "bar")
os.MkdirAll(dirUnderLinkDir, 0700)
rewrite, err := FollowSymlinkInScope(dirUnderLinkDir, linkDir)
if err != nil {
t.Fatal(err) t.Fatal(err)
} }
if err := testSymlink(tmpdir, "linkdir/foo/bar", "linkdir/foo/bar", "linkdir/foo"); err != nil {
if rewrite != dirUnderLinkDir { t.Fatal(err)
t.Fatalf("Expected %s got %s", dirUnderLinkDir, rewrite)
} }
} }
func TestFollowSymLinkRandomString(t *testing.T) { func TestFollowSymlinkRandomString(t *testing.T) {
if _, err := FollowSymlinkInScope("toto", "testdata"); err == nil { if _, err := FollowSymlinkInScope("toto", "testdata"); err == nil {
t.Fatal("Random string should fail but didn't") t.Fatal("Random string should fail but didn't")
} }
} }
func TestFollowSymLinkLastLink(t *testing.T) { func TestFollowSymlinkLastLink(t *testing.T) {
link := "testdata/fs/a/d" tmpdir, err := ioutil.TempDir("", "TestFollowSymlinkLastLink")
rewrite, err := FollowSymlinkInScope(link, "testdata")
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
defer os.RemoveAll(tmpdir)
if expected := abs(t, "testdata/b"); expected != rewrite { if err := makeFs(tmpdir, []dirOrLink{{path: "testdata/fs/a/d", target: "/b"}}); err != nil {
t.Fatalf("Expected %s got %s", expected, rewrite) t.Fatal(err)
}
if err := testSymlink(tmpdir, "testdata/fs/a/d", "testdata/b", "testdata"); err != nil {
t.Fatal(err)
} }
} }
func TestFollowSymLinkRelativeLink(t *testing.T) { func TestFollowSymlinkRelativeLink(t *testing.T) {
link := "testdata/fs/a/e/c/data" tmpdir, err := ioutil.TempDir("", "TestFollowSymlinkRelativeLink")
rewrite, err := FollowSymlinkInScope(link, "testdata")
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
defer os.RemoveAll(tmpdir)
if expected := abs(t, "testdata/fs/b/c/data"); expected != rewrite { if err := makeFs(tmpdir, []dirOrLink{{path: "testdata/fs/a/e", target: "../b"}}); err != nil {
t.Fatalf("Expected %s got %s", expected, rewrite) t.Fatal(err)
}
if err := testSymlink(tmpdir, "testdata/fs/a/e/c/data", "testdata/fs/b/c/data", "testdata"); err != nil {
t.Fatal(err)
} }
} }
func TestFollowSymLinkRelativeLinkScope(t *testing.T) { func TestFollowSymlinkRelativeLinkScope(t *testing.T) {
tmpdir, err := ioutil.TempDir("", "TestFollowSymlinkRelativeLinkScope")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(tmpdir)
if err := makeFs(tmpdir, []dirOrLink{{path: "testdata/fs/a/f", target: "../../../../test"}}); err != nil {
t.Fatal(err)
}
// avoid letting symlink f lead us out of the "testdata" scope // avoid letting symlink f lead us out of the "testdata" scope
// we don't normalize because symlink f is in scope and there is no // we don't normalize because symlink f is in scope and there is no
// information leak // information leak
{ if err := testSymlink(tmpdir, "testdata/fs/a/f", "testdata/test", "testdata"); err != nil {
link := "testdata/fs/a/f" t.Fatal(err)
rewrite, err := FollowSymlinkInScope(link, "testdata")
if err != nil {
t.Fatal(err)
}
if expected := abs(t, "testdata/test"); expected != rewrite {
t.Fatalf("Expected %s got %s", expected, rewrite)
}
} }
// avoid letting symlink f lead us out of the "testdata/fs" scope // avoid letting symlink f lead us out of the "testdata/fs" scope
// we don't normalize because symlink f is in scope and there is no // we don't normalize because symlink f is in scope and there is no
// information leak // information leak
{ if err := testSymlink(tmpdir, "testdata/fs/a/f", "testdata/fs/test", "testdata/fs"); err != nil {
link := "testdata/fs/a/f" t.Fatal(err)
rewrite, err := FollowSymlinkInScope(link, "testdata/fs")
if err != nil {
t.Fatal(err)
}
if expected := abs(t, "testdata/fs/test"); expected != rewrite {
t.Fatalf("Expected %s got %s", expected, rewrite)
}
} }
// avoid letting symlink g (pointed at by symlink h) take out of scope // avoid letting symlink g (pointed at by symlink h) take out of scope
// TODO: we should probably normalize to scope here because ../[....]/root // TODO: we should probably normalize to scope here because ../[....]/root
// is out of scope and we leak information // is out of scope and we leak information
{ if err := makeFs(tmpdir, []dirOrLink{
link := "testdata/fs/b/h" {path: "testdata/fs/b/h", target: "../g"},
{path: "testdata/fs/g", target: "../../../../../../../../../../../../root"},
rewrite, err := FollowSymlinkInScope(link, "testdata") }); err != nil {
if err != nil { t.Fatal(err)
t.Fatal(err) }
} if err := testSymlink(tmpdir, "testdata/fs/b/h", "testdata/root", "testdata"); err != nil {
t.Fatal(err)
if expected := abs(t, "testdata/root"); expected != rewrite {
t.Fatalf("Expected %s got %s", expected, rewrite)
}
} }
// avoid letting allowing symlink e lead us to ../b // avoid letting allowing symlink e lead us to ../b
// normalize to the "testdata/fs/a" // normalize to the "testdata/fs/a"
{ if err := makeFs(tmpdir, []dirOrLink{
link := "testdata/fs/a/e" {path: "testdata/fs/a/e", target: "../b"},
}); err != nil {
rewrite, err := FollowSymlinkInScope(link, "testdata/fs/a") t.Fatal(err)
if err != nil { }
t.Fatal(err) if err := testSymlink(tmpdir, "testdata/fs/a/e", "testdata/fs/a/b", "testdata/fs/a"); err != nil {
} t.Fatal(err)
if expected := abs(t, "testdata/fs/a"); expected != rewrite {
t.Fatalf("Expected %s got %s", expected, rewrite)
}
} }
// avoid letting symlink -> ../directory/file escape from scope // avoid letting symlink -> ../directory/file escape from scope
// normalize to "testdata/fs/j" // normalize to "testdata/fs/j"
{ if err := makeFs(tmpdir, []dirOrLink{{path: "testdata/fs/j/k", target: "../i/a"}}); err != nil {
link := "testdata/fs/j/k" t.Fatal(err)
}
rewrite, err := FollowSymlinkInScope(link, "testdata/fs/j") if err := testSymlink(tmpdir, "testdata/fs/j/k", "testdata/fs/j/i/a", "testdata/fs/j"); err != nil {
if err != nil { t.Fatal(err)
t.Fatal(err)
}
if expected := abs(t, "testdata/fs/j"); expected != rewrite {
t.Fatalf("Expected %s got %s", expected, rewrite)
}
} }
// make sure we don't allow escaping to / // make sure we don't allow escaping to /
// normalize to dir // normalize to dir
{ if err := makeFs(tmpdir, []dirOrLink{{path: "foo", target: "/"}}); err != nil {
dir, err := ioutil.TempDir("", "docker-fs-test") t.Fatal(err)
if err != nil { }
t.Fatal(err) if err := testSymlink(tmpdir, "foo", "", ""); err != nil {
} t.Fatal(err)
defer os.RemoveAll(dir)
linkFile := filepath.Join(dir, "foo")
os.Mkdir(filepath.Join(dir, ""), 0700)
os.Symlink("/", linkFile)
rewrite, err := FollowSymlinkInScope(linkFile, dir)
if err != nil {
t.Fatal(err)
}
if rewrite != dir {
t.Fatalf("Expected %s got %s", dir, rewrite)
}
} }
// make sure we don't allow escaping to / // make sure we don't allow escaping to /
// normalize to dir // normalize to dir
{ if err := makeFs(filepath.Join(tmpdir, "dir", "subdir"), []dirOrLink{{path: "foo", target: "/../../"}}); err != nil {
dir, err := ioutil.TempDir("", "docker-fs-test") t.Fatal(err)
if err != nil { }
t.Fatal(err) if err := testSymlink(tmpdir, "foo", "", ""); err != nil {
} t.Fatal(err)
defer os.RemoveAll(dir)
linkFile := filepath.Join(dir, "foo")
os.Mkdir(filepath.Join(dir, ""), 0700)
os.Symlink("/../../", linkFile)
rewrite, err := FollowSymlinkInScope(linkFile, dir)
if err != nil {
t.Fatal(err)
}
if rewrite != dir {
t.Fatalf("Expected %s got %s", dir, rewrite)
}
} }
// make sure we stay in scope without leaking information // make sure we stay in scope without leaking information
// this also checks for escaping to / // this also checks for escaping to /
// normalize to dir // normalize to dir
{ if err := makeFs(filepath.Join(tmpdir, "dir", "subdir"), []dirOrLink{{path: "foo", target: "../../"}}); err != nil {
dir, err := ioutil.TempDir("", "docker-fs-test") t.Fatal(err)
if err != nil { }
t.Fatal(err) if err := testSymlink(tmpdir, "foo", "", ""); err != nil {
} t.Fatal(err)
defer os.RemoveAll(dir) }
linkFile := filepath.Join(dir, "foo") if err := makeFs(tmpdir, []dirOrLink{{path: "bar/foo", target: "baz/target"}}); err != nil {
os.Mkdir(filepath.Join(dir, ""), 0700) t.Fatal(err)
os.Symlink("../../", linkFile) }
if err := testSymlink(tmpdir, "bar/foo", "bar/baz/target", ""); err != nil {
rewrite, err := FollowSymlinkInScope(linkFile, dir) t.Fatal(err)
if err != nil {
t.Fatal(err)
}
if rewrite != dir {
t.Fatalf("Expected %s got %s", dir, rewrite)
}
} }
} }

View file

@ -1 +0,0 @@
/b

View file

@ -1 +0,0 @@
../b

View file

@ -1 +0,0 @@
../../../../test

View file

@ -1 +0,0 @@
../g

View file

@ -1 +0,0 @@
../../../../../../../../../../../../root

View file

@ -1 +0,0 @@
a

View file

@ -1 +0,0 @@
../i/a