Ensure rel path never traverses outside Storage
Signed-off-by: Hidde Beydals <hello@hidde.co>
This commit is contained in:
		
							parent
							
								
									08ce0c95fc
								
							
						
					
					
						commit
						f28f86a8ee
					
				|  | @ -29,6 +29,7 @@ import ( | ||||||
| 	"strings" | 	"strings" | ||||||
| 	"time" | 	"time" | ||||||
| 
 | 
 | ||||||
|  | 	securejoin "github.com/cyphar/filepath-securejoin" | ||||||
| 	"github.com/go-git/go-git/v5/plumbing/format/gitignore" | 	"github.com/go-git/go-git/v5/plumbing/format/gitignore" | ||||||
| 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||||||
| 
 | 
 | ||||||
|  | @ -87,8 +88,7 @@ func (s Storage) SetArtifactURL(artifact *sourcev1.Artifact) { | ||||||
| 	artifact.URL = fmt.Sprintf(format, s.Hostname, strings.TrimLeft(artifact.Path, "/")) | 	artifact.URL = fmt.Sprintf(format, s.Hostname, strings.TrimLeft(artifact.Path, "/")) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // SetHostname sets the hostname of the given URL string to the current Storage.Hostname
 | // SetHostname sets the hostname of the given URL string to the current Storage.Hostname and returns the result.
 | ||||||
| // and returns the result.
 |  | ||||||
| func (s Storage) SetHostname(URL string) string { | func (s Storage) SetHostname(URL string) string { | ||||||
| 	u, err := url.Parse(URL) | 	u, err := url.Parse(URL) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
|  | @ -110,8 +110,7 @@ func (s *Storage) RemoveAll(artifact sourcev1.Artifact) error { | ||||||
| 	return os.RemoveAll(dir) | 	return os.RemoveAll(dir) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // RemoveAllButCurrent removes all files for the given v1beta1.Artifact base dir,
 | // RemoveAllButCurrent removes all files for the given v1beta1.Artifact base dir, excluding the current one.
 | ||||||
| // excluding the current one.
 |  | ||||||
| func (s *Storage) RemoveAllButCurrent(artifact sourcev1.Artifact) error { | func (s *Storage) RemoveAllButCurrent(artifact sourcev1.Artifact) error { | ||||||
| 	localPath := s.LocalPath(artifact) | 	localPath := s.LocalPath(artifact) | ||||||
| 	dir := filepath.Dir(localPath) | 	dir := filepath.Dir(localPath) | ||||||
|  | @ -136,8 +135,7 @@ func (s *Storage) RemoveAllButCurrent(artifact sourcev1.Artifact) error { | ||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // ArtifactExist returns a boolean indicating whether the v1beta1.Artifact exists in storage
 | // ArtifactExist returns a boolean indicating whether the v1beta1.Artifact exists in storage and is a regular file.
 | ||||||
| // and is a regular file.
 |  | ||||||
| func (s *Storage) ArtifactExist(artifact sourcev1.Artifact) bool { | func (s *Storage) ArtifactExist(artifact sourcev1.Artifact) bool { | ||||||
| 	fi, err := os.Lstat(s.LocalPath(artifact)) | 	fi, err := os.Lstat(s.LocalPath(artifact)) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
|  | @ -146,14 +144,13 @@ func (s *Storage) ArtifactExist(artifact sourcev1.Artifact) bool { | ||||||
| 	return fi.Mode().IsRegular() | 	return fi.Mode().IsRegular() | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // ArchiveFileFilter must return true if a file should not be included
 | // ArchiveFileFilter must return true if a file should not be included in the archive after inspecting the given path
 | ||||||
| // in the archive after inspecting the given path and/or os.FileInfo.
 | // and/or os.FileInfo.
 | ||||||
| type ArchiveFileFilter func(p string, fi os.FileInfo) bool | type ArchiveFileFilter func(p string, fi os.FileInfo) bool | ||||||
| 
 | 
 | ||||||
| // SourceIgnoreFilter returns an ArchiveFileFilter that filters out
 | // SourceIgnoreFilter returns an ArchiveFileFilter that filters out files matching sourceignore.VCSPatterns and any of
 | ||||||
| // files matching sourceignore.VCSPatterns and any of the provided
 | // the provided patterns.
 | ||||||
| // patterns. If an empty gitignore.Pattern slice is given, the matcher
 | // If an empty gitignore.Pattern slice is given, the matcher is set to sourceignore.NewDefaultMatcher.
 | ||||||
| // is set to sourceignore.NewDefaultMatcher.
 |  | ||||||
| func SourceIgnoreFilter(ps []gitignore.Pattern, domain []string) ArchiveFileFilter { | func SourceIgnoreFilter(ps []gitignore.Pattern, domain []string) ArchiveFileFilter { | ||||||
| 	matcher := sourceignore.NewDefaultMatcher(ps, domain) | 	matcher := sourceignore.NewDefaultMatcher(ps, domain) | ||||||
| 	if len(ps) > 0 { | 	if len(ps) > 0 { | ||||||
|  | @ -167,10 +164,9 @@ func SourceIgnoreFilter(ps []gitignore.Pattern, domain []string) ArchiveFileFilt | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // Archive atomically archives the given directory as a tarball to the
 | // Archive atomically archives the given directory as a tarball to the given v1beta1.Artifact path, excluding
 | ||||||
| // given v1beta1.Artifact path, excluding directories and any
 | // directories and any ArchiveFileFilter matches.
 | ||||||
| // ArchiveFileFilter matches. If successful, it sets the checksum and
 | // If successful, it sets the checksum and last update time on the artifact.
 | ||||||
| // last update time on the artifact.
 |  | ||||||
| func (s *Storage) Archive(artifact *sourcev1.Artifact, dir string, filter ArchiveFileFilter) (err error) { | func (s *Storage) Archive(artifact *sourcev1.Artifact, dir string, filter ArchiveFileFilter) (err error) { | ||||||
| 	if f, err := os.Stat(dir); os.IsNotExist(err) || !f.IsDir() { | 	if f, err := os.Stat(dir); os.IsNotExist(err) || !f.IsDir() { | ||||||
| 		return fmt.Errorf("invalid dir path: %s", dir) | 		return fmt.Errorf("invalid dir path: %s", dir) | ||||||
|  | @ -345,9 +341,8 @@ func (s *Storage) Copy(artifact *sourcev1.Artifact, reader io.Reader) (err error | ||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // CopyFromPath atomically copies the contents of the given path to the path of
 | // CopyFromPath atomically copies the contents of the given path to the path of the v1beta1.Artifact.
 | ||||||
| // the v1beta1.Artifact. If successful, the checksum and last update time on the
 | // If successful, the checksum and last update time on the artifact is set.
 | ||||||
| // artifact is set.
 |  | ||||||
| func (s *Storage) CopyFromPath(artifact *sourcev1.Artifact, path string) (err error) { | func (s *Storage) CopyFromPath(artifact *sourcev1.Artifact, path string) (err error) { | ||||||
| 	f, err := os.Open(path) | 	f, err := os.Open(path) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
|  | @ -357,10 +352,10 @@ func (s *Storage) CopyFromPath(artifact *sourcev1.Artifact, path string) (err er | ||||||
| 	return s.Copy(artifact, f) | 	return s.Copy(artifact, f) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // CopyToPath copies the contents of the given artifact to the path.
 | // CopyToPath copies the contents in the (sub)path of the given artifact to the given path.
 | ||||||
| func (s *Storage) CopyToPath(artifact *sourcev1.Artifact, subPath, toPath string) error { | func (s *Storage) CopyToPath(artifact *sourcev1.Artifact, subPath, toPath string) error { | ||||||
| 	// create a tmp directory to store artifact
 | 	// create a tmp directory to store artifact
 | ||||||
| 	tmp, err := os.MkdirTemp("", "flux-include") | 	tmp, err := os.MkdirTemp("", "flux-include-") | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
|  | @ -375,7 +370,7 @@ func (s *Storage) CopyToPath(artifact *sourcev1.Artifact, subPath, toPath string | ||||||
| 	defer f.Close() | 	defer f.Close() | ||||||
| 
 | 
 | ||||||
| 	// untar the artifact
 | 	// untar the artifact
 | ||||||
| 	untarPath := filepath.Join(tmp, "tar") | 	untarPath := filepath.Join(tmp, "unpack") | ||||||
| 	if _, err = untar.Untar(f, untarPath); err != nil { | 	if _, err = untar.Untar(f, untarPath); err != nil { | ||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
|  | @ -386,15 +381,17 @@ func (s *Storage) CopyToPath(artifact *sourcev1.Artifact, subPath, toPath string | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// copy the artifact content to the destination dir
 | 	// copy the artifact content to the destination dir
 | ||||||
| 	fromPath := filepath.Join(untarPath, subPath) | 	fromPath, err := securejoin.SecureJoin(untarPath, subPath) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
| 	if err := fs.RenameWithFallback(fromPath, toPath); err != nil { | 	if err := fs.RenameWithFallback(fromPath, toPath); err != nil { | ||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // Symlink creates or updates a symbolic link for the given v1beta1.Artifact
 | // Symlink creates or updates a symbolic link for the given v1beta1.Artifact and returns the URL for the symlink.
 | ||||||
| // and returns the URL for the symlink.
 |  | ||||||
| func (s *Storage) Symlink(artifact sourcev1.Artifact, linkName string) (string, error) { | func (s *Storage) Symlink(artifact sourcev1.Artifact, linkName string) (string, error) { | ||||||
| 	localPath := s.LocalPath(artifact) | 	localPath := s.LocalPath(artifact) | ||||||
| 	dir := filepath.Dir(localPath) | 	dir := filepath.Dir(localPath) | ||||||
|  | @ -431,13 +428,16 @@ func (s *Storage) Lock(artifact sourcev1.Artifact) (unlock func(), err error) { | ||||||
| 	return mutex.Lock() | 	return mutex.Lock() | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // LocalPath returns the local path of the given artifact (that is: relative to
 | // LocalPath returns the secure local path of the given artifact (that is: relative to the Storage.BasePath).
 | ||||||
| // the Storage.BasePath).
 |  | ||||||
| func (s *Storage) LocalPath(artifact sourcev1.Artifact) string { | func (s *Storage) LocalPath(artifact sourcev1.Artifact) string { | ||||||
| 	if artifact.Path == "" { | 	if artifact.Path == "" { | ||||||
| 		return "" | 		return "" | ||||||
| 	} | 	} | ||||||
| 	return filepath.Join(s.BasePath, artifact.Path) | 	path, err := securejoin.SecureJoin(s.BasePath, artifact.Path) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return "" | ||||||
|  | 	} | ||||||
|  | 	return path | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // newHash returns a new SHA1 hash.
 | // newHash returns a new SHA1 hash.
 | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue