@@ -21,6 +21,7 @@ import (
2121 "fmt"
2222 "io"
2323 "os"
24+ pathpkg "path"
2425 "path/filepath"
2526 "strings"
2627
@@ -50,7 +51,10 @@ func unpackTar(tr *tar.Reader, path string, whitelist []string) error {
5051 if err != nil {
5152 return errors .Wrap (err , "Error getting next tar header" )
5253 }
53- target := filepath .Clean (filepath .Join (path , header .Name ))
54+ target , err := ResolvePathInRoot (path , header .Name , false )
55+ if err != nil {
56+ return errors .Wrap (err , "resolving tar entry path" )
57+ }
5458 // Make sure the target isn't part of the whitelist
5559 if checkWhitelist (target , whitelist ) {
5660 continue
@@ -60,7 +64,7 @@ func unpackTar(tr *tar.Reader, path string, whitelist []string) error {
6064
6165 // if its a dir and it doesn't exist create it
6266 case tar .TypeDir :
63- if _ , err := os .Stat (target ); os .IsNotExist (err ) {
67+ if _ , err := os .Lstat (target ); os .IsNotExist (err ) {
6468 if mode .Perm ()& (1 << (uint (7 ))) == 0 {
6569 logrus .Debugf ("Write permission bit not set on %s by default; setting manually" , target )
6670 originalMode := mode
@@ -93,7 +97,7 @@ func unpackTar(tr *tar.Reader, path string, whitelist []string) error {
9397 }
9498 // It's possible we end up creating files that can't be overwritten based on their permissions.
9599 // Explicitly delete an existing file before continuing.
96- if _ , err := os .Stat (target ); ! os .IsNotExist (err ) {
100+ if _ , err := os .Lstat (target ); ! os .IsNotExist (err ) {
97101 logrus .Debugf ("Removing %s for overwrite" , target )
98102 if err := os .Remove (target ); err != nil {
99103 logrus .Errorf ("error removing file %s" , target )
@@ -118,9 +122,12 @@ func unpackTar(tr *tar.Reader, path string, whitelist []string) error {
118122 }
119123 currFile .Close ()
120124 case tar .TypeSymlink :
125+ if _ , err := ResolvePathInRoot (path , tarLinkTarget (header .Name , header .Linkname ), true ); err != nil {
126+ return errors .Wrap (err , "resolving tar symlink path" )
127+ }
121128 // It's possible we end up creating files that can't be overwritten based on their permissions.
122129 // Explicitly delete an existing file before continuing.
123- if _ , err := os .Stat (target ); ! os .IsNotExist (err ) {
130+ if _ , err := os .Lstat (target ); ! os .IsNotExist (err ) {
124131 logrus .Debugf ("Removing %s to create symlink" , target )
125132 if err := os .RemoveAll (target ); err != nil {
126133 logrus .Debugf ("Unable to remove %s: %s" , target , err )
@@ -131,11 +138,16 @@ func unpackTar(tr *tar.Reader, path string, whitelist []string) error {
131138 logrus .Errorf ("Failed to create symlink between %s and %s: %s" , header .Linkname , target , err )
132139 }
133140 case tar .TypeLink :
134- linkname := filepath .Clean (filepath .Join (path , header .Linkname ))
141+ linkname , err := ResolvePathInRoot (path , header .Linkname , false )
142+ if err != nil {
143+ return errors .Wrap (err , "resolving tar hard link path" )
144+ }
135145 // Check if the linkname already exists
136146 if _ , err := os .Stat (linkname ); ! os .IsNotExist (err ) {
137147 // If it exists, create the hard link
138- resolveHardlink (linkname , target )
148+ if err := resolveHardlink (path , linkname , target ); err != nil {
149+ return errors .Wrap (err , fmt .Sprintf ("Unable to create hard link from %s to %s" , linkname , target ))
150+ }
139151 } else {
140152 hardlinks .Store (target , linkname )
141153 }
@@ -148,7 +160,7 @@ func unpackTar(tr *tar.Reader, path string, whitelist []string) error {
148160 logrus .Info ("Resolving hard links" )
149161 if _ , err := os .Stat (linkname ); ! os .IsNotExist (err ) {
150162 // If it exists, create the hard link
151- if err := resolveHardlink (linkname , target ); err != nil {
163+ if err := resolveHardlink (path , linkname , target ); err != nil {
152164 resolveError .Store (errors .Wrap (err , fmt .Sprintf ("Unable to create hard link from %s to %s" , linkname , target )))
153165 return false
154166 }
@@ -168,7 +180,36 @@ func unpackTar(tr *tar.Reader, path string, whitelist []string) error {
168180 return nil
169181}
170182
171- func resolveHardlink (linkname , target string ) error {
183+ func tarLinkTarget (name , linkname string ) string {
184+ if pathpkg .IsAbs (filepath .ToSlash (linkname )) {
185+ return linkname
186+ }
187+ return pathpkg .Join (pathpkg .Dir (filepath .ToSlash (name )), filepath .ToSlash (linkname ))
188+ }
189+
190+ func resolveHardlink (root , linkname , target string ) error {
191+ info , err := os .Lstat (linkname )
192+ if err != nil {
193+ return err
194+ }
195+ if info .Mode ()& os .ModeSymlink != 0 {
196+ linkTarget , err := os .Readlink (linkname )
197+ if err != nil {
198+ return err
199+ }
200+ relLink , err := filepath .Rel (root , linkname )
201+ if err != nil {
202+ return err
203+ }
204+ if _ , err := ResolvePathInRoot (root , tarLinkTarget (relLink , linkTarget ), true ); err != nil {
205+ return err
206+ }
207+ if err := os .Symlink (linkTarget , target ); err != nil {
208+ return err
209+ }
210+ logrus .Debugf ("Created symlink from %s to %s for hard link source %s" , linkTarget , target , linkname )
211+ return nil
212+ }
172213 if err := os .Link (linkname , target ); err != nil {
173214 return err
174215 }
0 commit comments