Add base idea for denying write access to certain files; ref pterodactyl/panel#569
This commit is contained in:
@@ -91,11 +91,10 @@ func (fs *Filesystem) DecompressFile(dir string, file string) error {
|
||||
return errors.New(fmt.Sprintf("could not parse underlying data source with type %s", reflect.TypeOf(s).String()))
|
||||
}
|
||||
|
||||
p, err := fs.SafePath(filepath.Join(dir, name))
|
||||
if err != nil {
|
||||
return errors.WithMessage(err, "failed to generate a safe path to server file")
|
||||
p := filepath.Join(dir, name)
|
||||
if err := fs.IsIgnored(p); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return errors.WithMessage(fs.Writefile(p, f), "could not extract file from archive")
|
||||
})
|
||||
if err != nil {
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
package filesystem
|
||||
|
||||
import (
|
||||
"emperror.dev/errors"
|
||||
"fmt"
|
||||
"github.com/apex/log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"emperror.dev/errors"
|
||||
"github.com/apex/log"
|
||||
)
|
||||
|
||||
type ErrorCode string
|
||||
@@ -15,6 +16,7 @@ const (
|
||||
ErrCodeDiskSpace ErrorCode = "E_NODISK"
|
||||
ErrCodeUnknownArchive ErrorCode = "E_UNKNFMT"
|
||||
ErrCodePathResolution ErrorCode = "E_BADPATH"
|
||||
ErrCodeDenylistFile ErrorCode = "E_DENYLIST"
|
||||
)
|
||||
|
||||
type Error struct {
|
||||
@@ -32,6 +34,8 @@ func (e *Error) Error() string {
|
||||
return "filesystem: not enough disk space"
|
||||
case ErrCodeUnknownArchive:
|
||||
return "filesystem: unknown archive format"
|
||||
case ErrCodeDenylistFile:
|
||||
return "filesystem: file access prohibited: denylist"
|
||||
case ErrCodePathResolution:
|
||||
r := e.resolved
|
||||
if r == "" {
|
||||
|
||||
@@ -18,6 +18,7 @@ import (
|
||||
"github.com/karrick/godirwalk"
|
||||
"github.com/pterodactyl/wings/config"
|
||||
"github.com/pterodactyl/wings/system"
|
||||
ignore "github.com/sabhiram/go-gitignore"
|
||||
)
|
||||
|
||||
type Filesystem struct {
|
||||
@@ -26,6 +27,7 @@ type Filesystem struct {
|
||||
lookupInProgress *system.AtomicBool
|
||||
diskUsed int64
|
||||
diskCheckInterval time.Duration
|
||||
denylist *ignore.GitIgnore
|
||||
|
||||
// The maximum amount of disk space (in bytes) that this Filesystem instance can use.
|
||||
diskLimit int64
|
||||
@@ -37,13 +39,14 @@ type Filesystem struct {
|
||||
}
|
||||
|
||||
// Creates a new Filesystem instance for a given server.
|
||||
func New(root string, size int64) *Filesystem {
|
||||
func New(root string, size int64, denylist []string) *Filesystem {
|
||||
return &Filesystem{
|
||||
root: root,
|
||||
diskLimit: size,
|
||||
diskCheckInterval: time.Duration(config.Get().System.DiskCheckInterval),
|
||||
lastLookupTime: &usageLookupTime{},
|
||||
lookupInProgress: system.NewAtomicBool(false),
|
||||
denylist: ignore.CompileIgnoreLines(denylist...),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,13 +2,29 @@ package filesystem
|
||||
|
||||
import (
|
||||
"context"
|
||||
"golang.org/x/sync/errgroup"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"golang.org/x/sync/errgroup"
|
||||
)
|
||||
|
||||
// Checks if the given file or path is in the server's file denylist. If so, an Error
|
||||
// is returned, otherwise nil is returned.
|
||||
func (fs *Filesystem) IsIgnored(paths ...string) error {
|
||||
for _, p := range paths {
|
||||
sp, err := fs.SafePath(p)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if fs.denylist.MatchesPath(sp) {
|
||||
return &Error{code: ErrCodeDenylistFile, path: p, resolved: sp}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Normalizes a directory being passed in to ensure the user is not able to escape
|
||||
// from their data directory. After normalization if the directory is still within their home
|
||||
// path it is returned. If they managed to "escape" an error will be returned.
|
||||
|
||||
Reference in New Issue
Block a user