From 05a828c47453dc36c8f333b18588299067c34fc7 Mon Sep 17 00:00:00 2001 From: Ophestra Date: Wed, 11 Feb 2026 00:40:54 +0900 Subject: [PATCH] internal/pkg: validate tar pathnames TContext no longer validates FileArtifact ahead of time, validation outcome is instead determined after consuming the reader to EOF. All data must therefore be treated as untrusted input until the reader is closed. Signed-off-by: Ophestra --- internal/pkg/tar.go | 43 +++++++++++++++++++++++++++---------------- 1 file changed, 27 insertions(+), 16 deletions(-) diff --git a/internal/pkg/tar.go b/internal/pkg/tar.go index 1215adb..77e4ee2 100644 --- a/internal/pkg/tar.go +++ b/internal/pkg/tar.go @@ -10,8 +10,7 @@ import ( "io/fs" "net/http" "os" - - "hakurei.app/container/check" + "path" ) const ( @@ -100,7 +99,6 @@ func (e DisallowedTypeflagError) Error() string { // Cure cures the [Artifact], producing a directory located at work. func (a *tarArtifact) Cure(t *TContext) (err error) { - temp := t.GetTempDir() var tr io.ReadCloser if tr, err = t.Open(a.f); err != nil { return @@ -137,14 +135,24 @@ func (a *tarArtifact) Cure(t *TContext) (err error) { } type dirTargetPerm struct { - path *check.Absolute + path string mode fs.FileMode } var madeDirectories []dirTargetPerm - if err = os.MkdirAll(temp.String(), 0700); err != nil { + if err = os.MkdirAll(t.GetTempDir().String(), 0700); err != nil { return } + var root *os.Root + if root, err = os.OpenRoot(t.GetTempDir().String()); err != nil { + return + } + defer func() { + closeErr := root.Close() + if err == nil { + err = closeErr + } + }() var header *tar.Header r := tar.NewReader(tr) @@ -158,9 +166,8 @@ func (a *tarArtifact) Cure(t *TContext) (err error) { } } - pathname := temp.Append(header.Name) if typeflag >= '0' && typeflag <= '9' && typeflag != tar.TypeDir { - if err = os.MkdirAll(pathname.Dir().String(), 0700); err != nil { + if err = root.MkdirAll(path.Dir(header.Name), 0700); err != nil { return } } @@ -168,8 +175,8 @@ func (a *tarArtifact) Cure(t *TContext) (err error) { switch typeflag { case tar.TypeReg: var f *os.File - if f, err = os.OpenFile( - pathname.String(), + if f, err = root.OpenFile( + header.Name, os.O_CREATE|os.O_EXCL|os.O_WRONLY, header.FileInfo().Mode()&0500, ); err != nil { @@ -184,26 +191,29 @@ func (a *tarArtifact) Cure(t *TContext) (err error) { break case tar.TypeLink: - if err = os.Link( - temp.Append(header.Linkname).String(), - pathname.String(), + if err = root.Link( + header.Linkname, + header.Name, ); err != nil { return } break case tar.TypeSymlink: - if err = os.Symlink(header.Linkname, pathname.String()); err != nil { + if err = root.Symlink( + header.Linkname, + header.Name, + ); err != nil { return } break case tar.TypeDir: madeDirectories = append(madeDirectories, dirTargetPerm{ - path: pathname, + path: header.Name, mode: header.FileInfo().Mode(), }) - if err = os.MkdirAll(pathname.String(), 0700); err != nil { + if err = root.MkdirAll(header.Name, 0700); err != nil { return } break @@ -220,7 +230,7 @@ func (a *tarArtifact) Cure(t *TContext) (err error) { } if err == nil { for _, e := range madeDirectories { - if err = os.Chmod(e.path.String(), e.mode&0500); err != nil { + if err = root.Chmod(e.path, e.mode&0500); err != nil { return } } @@ -228,6 +238,7 @@ func (a *tarArtifact) Cure(t *TContext) (err error) { return } + temp := t.GetTempDir() if err = os.Chmod(temp.String(), 0700); err != nil { return }