@@ -3,11 +3,10 @@ package internal
33import (
44 "archive/tar"
55 "fmt"
6- securejoin "github.com/cyphar/filepath-securejoin"
76 "io"
8- "io/fs"
97 "os"
108 "path/filepath"
9+ "strings"
1110)
1211
1312func ExtractTarStream (r io.Reader , targetPath string ) error {
@@ -22,12 +21,13 @@ func ExtractTarStream(r io.Reader, targetPath string) error {
2221 return fmt .Errorf ("ExtractTarStream: Next() failed: %w" , err )
2322 }
2423
25- header .Name = filepath .FromSlash (header .Name )
26-
27- p , err := securejoin .SecureJoin (targetPath , header .Name )
28- if err != nil {
29- return err
24+ if ! validRelPath (header .Name ) {
25+ return fmt .Errorf ("tar contained invalid name error %q" , header .Name )
3026 }
27+
28+ p := filepath .FromSlash (header .Name )
29+ p = filepath .Join (targetPath , p )
30+
3131 err = os .MkdirAll (filepath .Dir (p ), 0755 )
3232 if err != nil {
3333 return err
@@ -39,6 +39,7 @@ func ExtractTarStream(r io.Reader, targetPath string) error {
3939 return fmt .Errorf ("ExtractTarStream: Mkdir() failed: %w" , err )
4040 }
4141 case tar .TypeReg :
42+ _ = os .Remove (p ) // we allow overwriting, which easily happens on case insensitive filesystems
4243 outFile , err := os .Create (p )
4344 if err != nil {
4445 return fmt .Errorf ("ExtractTarStream: Create() failed: %w" , err )
@@ -57,6 +58,7 @@ func ExtractTarStream(r io.Reader, targetPath string) error {
5758 return err
5859 }
5960 case tar .TypeSymlink :
61+ _ = os .Remove (p ) // we allow overwriting, which easily happens on case insensitive filesystems
6062 if err := os .Symlink (header .Linkname , p ); err != nil {
6163 return fmt .Errorf ("ExtractTarStream: Symlink() failed: %w" , err )
6264 }
@@ -67,74 +69,9 @@ func ExtractTarStream(r io.Reader, targetPath string) error {
6769 return nil
6870}
6971
70- func AddToTar (tw * tar.Writer , pth string , name string , filter func (h * tar.Header , size int64 ) (* tar.Header , error )) error {
71- fi , err := os .Lstat (pth )
72- if err != nil {
73- return err
74- }
75-
76- var linkName string
77- if fi .Mode ().Type () == fs .ModeSymlink {
78- x , err := os .Readlink (pth )
79- if err != nil {
80- return err
81- }
82- linkName = x
83- }
84-
85- h , err := tar .FileInfoHeader (fi , linkName )
86- if err != nil {
87- return err
88- }
89- h .Name = filepath .ToSlash (name )
90-
91- if filter != nil {
92- s := fi .Size ()
93- if fi .IsDir () {
94- s = 0
95- }
96- h , err = filter (h , s )
97- if err != nil {
98- return err
99- }
100- if h == nil {
101- return nil
102- }
103- }
104-
105- err = tw .WriteHeader (h )
106- if err != nil {
107- return err
108- }
109-
110- if fi .Mode ().Type () == fs .ModeSymlink {
111- return nil
112- }
113-
114- if fi .Mode ().IsDir () {
115- des , err := os .ReadDir (pth )
116- if err != nil {
117- return err
118- }
119- for _ , d := range des {
120- err = AddToTar (tw , filepath .Join (pth , d .Name ()), filepath .Join (name , d .Name ()), filter )
121- if err != nil {
122- return err
123- }
124- }
125- return nil
126- } else if fi .Mode ().IsRegular () {
127- f , err := os .Open (pth )
128- if err != nil {
129- return err
130- }
131- defer f .Close ()
132- _ , err = io .Copy (tw , f )
133- if err != nil {
134- return err
135- }
136- return nil
137- } else {
138- return fmt .Errorf ("unsupported file type/mode %s" , fi .Mode ().String ())
72+ func validRelPath (p string ) bool {
73+ if p == "" || strings .Contains (p , `\` ) || strings .HasPrefix (p , "/" ) || strings .Contains (p , "../" ) {
74+ return false
13975 }
76+ return true
14077}
0 commit comments