internal/pkg: validate tar pathnames
All checks were successful
Test / Create distribution (push) Successful in 59s
Test / Sandbox (push) Successful in 2m35s
Test / ShareFS (push) Successful in 3m59s
Test / Hpkg (push) Successful in 4m46s
Test / Sandbox (race detector) (push) Successful in 5m2s
Test / Hakurei (race detector) (push) Successful in 5m57s
Test / Hakurei (push) Successful in 4m24s
Test / Flake checks (push) Successful in 1m50s

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 <cat@gensokyo.uk>
This commit is contained in:
2026-02-11 00:40:54 +09:00
parent 0061d11f93
commit 05a828c474

View File

@@ -10,8 +10,7 @@ import (
"io/fs" "io/fs"
"net/http" "net/http"
"os" "os"
"path"
"hakurei.app/container/check"
) )
const ( const (
@@ -100,7 +99,6 @@ func (e DisallowedTypeflagError) Error() string {
// Cure cures the [Artifact], producing a directory located at work. // Cure cures the [Artifact], producing a directory located at work.
func (a *tarArtifact) Cure(t *TContext) (err error) { func (a *tarArtifact) Cure(t *TContext) (err error) {
temp := t.GetTempDir()
var tr io.ReadCloser var tr io.ReadCloser
if tr, err = t.Open(a.f); err != nil { if tr, err = t.Open(a.f); err != nil {
return return
@@ -137,14 +135,24 @@ func (a *tarArtifact) Cure(t *TContext) (err error) {
} }
type dirTargetPerm struct { type dirTargetPerm struct {
path *check.Absolute path string
mode fs.FileMode mode fs.FileMode
} }
var madeDirectories []dirTargetPerm var madeDirectories []dirTargetPerm
if err = os.MkdirAll(temp.String(), 0700); err != nil { if err = os.MkdirAll(t.GetTempDir().String(), 0700); err != nil {
return 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 var header *tar.Header
r := tar.NewReader(tr) 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 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 return
} }
} }
@@ -168,8 +175,8 @@ func (a *tarArtifact) Cure(t *TContext) (err error) {
switch typeflag { switch typeflag {
case tar.TypeReg: case tar.TypeReg:
var f *os.File var f *os.File
if f, err = os.OpenFile( if f, err = root.OpenFile(
pathname.String(), header.Name,
os.O_CREATE|os.O_EXCL|os.O_WRONLY, os.O_CREATE|os.O_EXCL|os.O_WRONLY,
header.FileInfo().Mode()&0500, header.FileInfo().Mode()&0500,
); err != nil { ); err != nil {
@@ -184,26 +191,29 @@ func (a *tarArtifact) Cure(t *TContext) (err error) {
break break
case tar.TypeLink: case tar.TypeLink:
if err = os.Link( if err = root.Link(
temp.Append(header.Linkname).String(), header.Linkname,
pathname.String(), header.Name,
); err != nil { ); err != nil {
return return
} }
break break
case tar.TypeSymlink: case tar.TypeSymlink:
if err = os.Symlink(header.Linkname, pathname.String()); err != nil { if err = root.Symlink(
header.Linkname,
header.Name,
); err != nil {
return return
} }
break break
case tar.TypeDir: case tar.TypeDir:
madeDirectories = append(madeDirectories, dirTargetPerm{ madeDirectories = append(madeDirectories, dirTargetPerm{
path: pathname, path: header.Name,
mode: header.FileInfo().Mode(), mode: header.FileInfo().Mode(),
}) })
if err = os.MkdirAll(pathname.String(), 0700); err != nil { if err = root.MkdirAll(header.Name, 0700); err != nil {
return return
} }
break break
@@ -220,7 +230,7 @@ func (a *tarArtifact) Cure(t *TContext) (err error) {
} }
if err == nil { if err == nil {
for _, e := range madeDirectories { 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 return
} }
} }
@@ -228,6 +238,7 @@ func (a *tarArtifact) Cure(t *TContext) (err error) {
return return
} }
temp := t.GetTempDir()
if err = os.Chmod(temp.String(), 0700); err != nil { if err = os.Chmod(temp.String(), 0700); err != nil {
return return
} }