99 "io/ioutil"
1010 "os"
1111 "path/filepath"
12+ "runtime"
1213 "syscall"
1314 "testing"
1415)
@@ -22,6 +23,11 @@ func symlink(t *testing.T, oldname, newname string) {
2223 }
2324}
2425
26+ type input struct {
27+ root , unsafe string
28+ expected string
29+ }
30+
2531// Test basic handling of symlink expansion.
2632func TestSymlink (t * testing.T ) {
2733 dir , err := ioutil .TempDir ("" , "TestSymlink" )
@@ -38,21 +44,26 @@ func TestSymlink(t *testing.T) {
3844 symlink (t , "../../../../../../../../../../../../../etc" , filepath .Join (dir , "etclink" ))
3945 symlink (t , "/../../../../../../../../../../../../../etc/passwd" , filepath .Join (dir , "passwd" ))
4046
41- for _ , test := range []struct {
42- root , unsafe string
43- expected string
44- }{
47+ rootOrVol := string (filepath .Separator )
48+ if vol := filepath .VolumeName (dir ); vol != "" {
49+ rootOrVol = vol + rootOrVol
50+ }
51+
52+ tc := []input {
4553 // Make sure that expansion with a root of '/' proceeds in the expected fashion.
46- {"/" , filepath .Join (dir , "passwd" ), "/etc/passwd" },
47- {"/" , filepath .Join (dir , "etclink" ), "/etc" },
48- {"/" , filepath .Join (dir , "etc" ), filepath .Join (dir , "somepath" )},
54+ {rootOrVol , filepath .Join (dir , "passwd" ), filepath .Join (rootOrVol , "etc" , "passwd" )},
55+ {rootOrVol , filepath .Join (dir , "etclink" ), filepath .Join (rootOrVol , "etc" )},
56+
57+ {rootOrVol , filepath .Join (dir , "etc" ), filepath .Join (dir , "somepath" )},
4958 // Now test scoped expansion.
5059 {dir , "passwd" , filepath .Join (dir , "somepath" , "passwd" )},
5160 {dir , "etclink" , filepath .Join (dir , "somepath" )},
5261 {dir , "etc" , filepath .Join (dir , "somepath" )},
5362 {dir , "etc/test" , filepath .Join (dir , "somepath" , "test" )},
5463 {dir , "etc/test/.." , filepath .Join (dir , "somepath" )},
55- } {
64+ }
65+
66+ for _ , test := range tc {
5667 got , err := SecureJoin (test .root , test .unsafe )
5768 if err != nil {
5869 t .Errorf ("securejoin(%q, %q): unexpected error: %v" , test .root , test .unsafe , err )
@@ -85,29 +96,31 @@ func TestNoSymlink(t *testing.T) {
8596 }
8697 defer os .RemoveAll (dir )
8798
88- for _ , test := range []struct {
89- root , unsafe string
90- }{
91- // TODO: Do we need to have some conditional FromSlash handling here?
92- {dir , "somepath" },
93- {dir , "even/more/path" },
94- {dir , "/this/is/a/path" },
95- {dir , "also/a/../path/././/with/some/./.././junk" },
96- {dir , "yetanother/../path/././/with/some/./.././junk../../../../../../../../../../../../etc/passwd" },
97- {dir , "/../../../../../../../../../../../../../../../../etc/passwd" },
98- {dir , "../../../../../../../../../../../../../../../../somedir" },
99- {dir , "../../../../../../../../../../../../../../../../" },
100- {dir , "./../../.././././../../../../../../../../../../../../../../../../etc passwd" },
101- } {
102- expected := filepath .Join (test .root , filepath .Clean (string (filepath .Separator )+ test .unsafe ))
99+ tc := []input {
100+ {dir , "somepath" , filepath .Join (dir , "somepath" )},
101+ {dir , "even/more/path" , filepath .Join (dir , "even" , "more" , "path" )},
102+ {dir , "/this/is/a/path" , filepath .Join (dir , "this" , "is" , "a" , "path" )},
103+ {dir , "also/a/../path/././/with/some/./.././junk" , filepath .Join (dir , "also" , "path" , "with" , "junk" )},
104+ {dir , "yetanother/../path/././/with/some/./.././junk../../../../../../../../../../../../etc/passwd" , filepath .Join (dir , "etc" , "passwd" )},
105+ {dir , "/../../../../../../../../../../../../../../../../etc/passwd" , filepath .Join (dir , "etc" , "passwd" )},
106+ {dir , "../../../../../../../../../../../../../../../../somedir" , filepath .Join (dir , "somedir" )},
107+ {dir , "../../../../../../../../../../../../../../../../" , filepath .Join (dir )},
108+ {dir , "./../../.././././../../../../../../../../../../../../../../../../etc passwd" , filepath .Join (dir , "etc passwd" )},
109+ }
110+
111+ if runtime .GOOS == "windows" {
112+ tc = append (tc , []input {
113+ {dir , "d:\\ etc\\ test" , filepath .Join (dir , "etc" , "test" )},
114+ }... )
115+ }
116+
117+ for _ , test := range tc {
103118 got , err := SecureJoin (test .root , test .unsafe )
104119 if err != nil {
105120 t .Errorf ("securejoin(%q, %q): unexpected error: %v" , test .root , test .unsafe , err )
106- continue
107121 }
108- if got != expected {
109- t .Errorf ("securejoin(%q, %q): expected %q, got %q" , test .root , test .unsafe , expected , got )
110- continue
122+ if got != test .expected {
123+ t .Errorf ("securejoin(%q, %q): expected %q, got %q" , test .root , test .unsafe , test .expected , got )
111124 }
112125 }
113126}
@@ -130,10 +143,7 @@ func TestNonLexical(t *testing.T) {
130143 symlink (t , "/../cousinparent/cousin" , filepath .Join (dir , "subdir" , "link2" ))
131144 symlink (t , "/../../../../../../../../../../../../../../../../cousinparent/cousin" , filepath .Join (dir , "subdir" , "link3" ))
132145
133- for _ , test := range []struct {
134- root , unsafe string
135- expected string
136- }{
146+ for _ , test := range []input {
137147 {dir , "subdir" , filepath .Join (dir , "subdir" )},
138148 {dir , "subdir/link/test" , filepath .Join (dir , "cousinparent" , "cousin" , "test" )},
139149 {dir , "subdir/link2/test" , filepath .Join (dir , "cousinparent" , "cousin" , "test" )},
@@ -188,7 +198,7 @@ func TestSymlinkLoop(t *testing.T) {
188198 } {
189199 got , err := SecureJoin (test .root , test .unsafe )
190200 if ! errors .Is (err , syscall .ELOOP ) {
191- t .Errorf ("securejoin(%q, %q): expected ELOOP, got %v & %q " , test .root , test .unsafe , err , got )
201+ t .Errorf ("securejoin(%q, %q): expected ELOOP, got %q & %v " , test .root , test .unsafe , got , err )
192202 continue
193203 }
194204 }
@@ -275,10 +285,7 @@ func TestSecureJoinVFS(t *testing.T) {
275285 symlink (t , "/../cousinparent/cousin" , filepath .Join (dir , "subdir" , "link2" ))
276286 symlink (t , "/../../../../../../../../../../../../../../../../cousinparent/cousin" , filepath .Join (dir , "subdir" , "link3" ))
277287
278- for _ , test := range []struct {
279- root , unsafe string
280- expected string
281- }{
288+ for _ , test := range []input {
282289 {dir , "subdir" , filepath .Join (dir , "subdir" )},
283290 {dir , "subdir/link/test" , filepath .Join (dir , "cousinparent" , "cousin" , "test" )},
284291 {dir , "subdir/link2/test" , filepath .Join (dir , "cousinparent" , "cousin" , "test" )},
0 commit comments