mirror of
https://github.com/gohugoio/hugo.git
synced 2026-08-24 15:28:54 +00:00
Fix prevention of direct symlink reads in resources.Get
* Note for themes, this is only an issue for themes stored locally, e.g. below `themes/...`. Themes mounted as modules from GitHub gets symlinks stripped away. * Thas was also not an issue for file reading walking one or more directories. * This is an regression introduced in `v0.123.0`.
This commit is contained in:
@@ -106,6 +106,22 @@ func (fs *baseFileDecoratorFs) Stat(name string) (os.FileInfo, error) {
|
||||
return fim.(os.FileInfo), nil
|
||||
}
|
||||
|
||||
func (fs *baseFileDecoratorFs) LstatIfPossible(name string) (os.FileInfo, bool, error) {
|
||||
if lstater, ok := fs.Fs.(afero.Lstater); ok {
|
||||
fi, ok, err := lstater.LstatIfPossible(name)
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
fim, err := fs.decorate(fi, name)
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
return fim.(os.FileInfo), ok, nil
|
||||
}
|
||||
fi, err := fs.Stat(name)
|
||||
return fi, false, err
|
||||
}
|
||||
|
||||
func (fs *baseFileDecoratorFs) Open(name string) (afero.File, error) {
|
||||
return fs.open(name)
|
||||
}
|
||||
|
||||
@@ -267,3 +267,13 @@ func ReadDirWithContext(ctx context.Context, f DirOnlyOps, count int) ([]iofs.Di
|
||||
}
|
||||
return v, ctx, nil
|
||||
}
|
||||
|
||||
// LstatIfPossible tries to use LstatIfPossible if the filesystem supports it, otherwise it falls back to Stat.
|
||||
func LstatIfPossible(fs afero.Fs, name string) (os.FileInfo, error) {
|
||||
if lstater, ok := fs.(afero.Lstater); ok {
|
||||
fi, _, err := lstater.LstatIfPossible(name)
|
||||
return fi, err
|
||||
}
|
||||
fi, err := fs.Stat(name)
|
||||
return fi, err
|
||||
}
|
||||
|
||||
@@ -724,11 +724,16 @@ func (fs *RootMappingFs) statRoot(root *RootMapping, filename string) (FileMetaI
|
||||
}
|
||||
|
||||
filename = root.filename(filename)
|
||||
fi, err := fs.Fs.Stat(filename)
|
||||
fi, err := LstatIfPossible(fs.Fs, filename)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Don't allow symlinks to escape the mount.
|
||||
if fi.Mode()&os.ModeSymlink != 0 {
|
||||
return nil, os.ErrNotExist
|
||||
}
|
||||
|
||||
var opener func() (afero.File, error)
|
||||
if !fi.IsDir() {
|
||||
// Open the file directly.
|
||||
|
||||
@@ -237,6 +237,21 @@ var commonTestScriptsParam = testscript.Params{
|
||||
ts.Fatalf("failed to write file: %v", err)
|
||||
}
|
||||
},
|
||||
// ln creates a symlink, but throws an error on Windows.
|
||||
"ln": func(ts *testscript.TestScript, neg bool, args []string) {
|
||||
if runtime.GOOS == "windows" {
|
||||
ts.Fatalf("ln is not supported on Windows")
|
||||
}
|
||||
if len(args) != 2 {
|
||||
ts.Fatalf("usage: ln TARGET LINKNAME")
|
||||
}
|
||||
target := ts.MkAbs(args[0])
|
||||
linkname := ts.MkAbs(args[1])
|
||||
err := os.Symlink(target, linkname)
|
||||
if err != nil {
|
||||
ts.Fatalf("failed to create symlink: %v", err)
|
||||
}
|
||||
},
|
||||
|
||||
// httpget checks that a HTTP resource's body matches (if it compiles as a regexp) or contains all of the strings given as arguments.
|
||||
"httpget": func(ts *testscript.TestScript, neg bool, args []string) {
|
||||
@@ -314,6 +329,10 @@ var commonTestScriptsParam = testscript.Params{
|
||||
if !ok {
|
||||
ts.Fatalf("stat %s: %v", filename, err)
|
||||
}
|
||||
if ok && neg {
|
||||
// OK.
|
||||
continue
|
||||
}
|
||||
if fi.Size() == 0 {
|
||||
ts.Fatalf("%s is empty", filename)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
[windows] skip
|
||||
|
||||
ln ./rootfile.txt ./themes/mytheme/assets/modassetsymlink.txt
|
||||
ln ./rootfile.txt ./themes/mytheme/static/modstaticsymlink.txt
|
||||
ln ./README.md ./content/pagesymlink.md
|
||||
|
||||
hugo
|
||||
|
||||
grep 'OK' public/index.html
|
||||
! grep 'FAIL' public/index.html
|
||||
|
||||
tree public
|
||||
|
||||
stdout modassetok
|
||||
! stdout modassetsymlink
|
||||
stdout 'modstatictok'
|
||||
! stdout 'modstaticsymlink'
|
||||
stdout pageok
|
||||
! stdout pagesymlink
|
||||
|
||||
-- hugo.toml --
|
||||
disableKinds = ["taxonomy", "term", "rss"]
|
||||
[[module.imports]]
|
||||
path = 'mytheme'
|
||||
-- README.md --
|
||||
Read me.
|
||||
-- layouts/all.html --
|
||||
{{ with resources.Get "modassetok.txt"}}OK {{ .Publish }}{{ else }}FAIL{{ end }}
|
||||
{{ with resources.Get "modassetsymlink.txt"}}FAIL {{ .Publish }}{{ else }}OK{{ end }}
|
||||
Page: {{ .RelPermalink }}|{{ .Content }}|
|
||||
-- content/pageok.md --
|
||||
-- themes/mytheme/assets/modassetok.txt --
|
||||
Content.
|
||||
-- themes/mytheme/static/modstatictok.txt --
|
||||
Content.
|
||||
-- rootfile.txt --
|
||||
Roo Content.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user