vfs

package
v0.0.7 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 9, 2024 License: Apache-2.0 Imports: 9 Imported by: 0

README

vfs

Package vfs extends the default Golang FS abstraction to support secured write operations.

Constants

const (
    Separator = string(filepath.Separator)
    SelfDir   = "."
    ParentDir = ".."
    FakeRoot  = "/"
)

Types

type ConfirmedDir

type ConfirmedDir string

ConfirmedDir is a clean, absolute, delinkified path that was confirmed to point to an existing directory.

func ConfirmDir

func ConfirmDir(root FileSystem, path string) (ConfirmedDir, error)

ConfirmDir returns an error if the user-specified path is not an existing directory on root. Otherwise, ConfirmDir returns path, which can be relative, as a ConfirmedDir and all that implies.

// Chroot to temporary directory
root, err := Chroot(os.TempDir())
if err != nil {
    panic(err)
}

// Use the filesystem to resolve the real target path.
cdir, err := ConfirmDir(root, ".")
if err != nil {
    panic(err)
}

Output:

/
func NewTmpConfirmedDir

func NewTmpConfirmedDir() (ConfirmedDir, error)

NewTmpConfirmedDir returns a temporary dir, else error. The directory is cleaned, no symlinks, etc. so it's returned as a ConfirmedDir.

// Create and resolve a confirmed temporary directory
// For MacOS, the final directory is resolved from its symbolic link.
cdir, err := NewTmpConfirmedDir()
if err != nil {
    panic(err)
}

// Try to escape from the confirmed directory
cdir1 := cdir.Join("../etc/password")

// Check new path validity
isValid := cdir.HasPrefix(ConfirmedDir(cdir1))

Output:

false
func (ConfirmedDir) HasPrefix

func (d ConfirmedDir) HasPrefix(path ConfirmedDir) bool

HasPrefix ensure that the given path has the confirmed directory as prefix.

func (ConfirmedDir) Join

func (d ConfirmedDir) Join(path string) string

Join the given path to the confirmed directory.

func (ConfirmedDir) String

func (d ConfirmedDir) String() string

type ConstraintError

type ConstraintError struct { ... }

ConstraintError records an error and the operation and file that violated it.

func (*ConstraintError) Error

func (e *ConstraintError) Error() string

Error returns the formatted error string for the ConstraintError.

func (*ConstraintError) Unwrap

func (e *ConstraintError) Unwrap() error

Unwrap implements error unwrapping.

type File

type File interface { ... }

File represents the file writer interface.

type FileSystem

type FileSystem interface { ... }

FileSystem extends the default read-only filesystem abstraction to add write operations.

func Chroot

func Chroot(root string) (FileSystem, error)

Chroot returns a chrooted filesystem assuming an OS base filesystem as root filesystem.

// Chroot to temporary directory
root, err := Chroot(os.TempDir())
if err != nil {
    panic(err)
}

// Chroot is compatible with Go fs.FS abstraction
if err := fs.WalkDir(root, ".", func(path string, d fs.DirEntry, err error) error {
    // Do something
    return nil
}); err != nil {
    panic(err)
}

// Provides filesystem isolation to prevent path traversal.
err = root.Mkdir("../wrong", 0o700)

fsErr := &ConstraintError{}
switch {
case err == nil:
    // No error
case errors.As(err, &fsErr):
    // Constraint error
default:
    // Other error
}

Output:

IsConstraintError => true
func ChrootFS

func ChrootFS(root FileSystem, path string) (FileSystem, error)

ChrootFS creates a chrooted filesystem instance from the given filesystem and the path. The path must be a directory part of the given root filesystem to be used.


// Chroot to temporary directory
root, err := Chroot(os.TempDir())
if err != nil {
    panic(err)
}

// Create a chroot from a parent filesystem.
subRoot, err := ChrootFS(root, "var")
if err != nil {
    panic(err)
}

// Try to open an out of chroot file will raise a ConstraintError.
_, err = subRoot.Open("../etc/passwd")
switch {
case err == nil:
    // No error
default:
    // Other error
}

func OS

func OS() FileSystem

OS returns a new instance of the OS filesystem.


// Create a host writeable filesystem without constraints.
root := OS()

// Create a chroot from a parent filesystem.
subRoot, err := ChrootFS(root, "/etc/datadog")
if err != nil {
    panic(err)
}

// Try to open an out of chroot file will raise a ConstraintError.
_, err = subRoot.Open("../passwd")
switch {
case err == nil:
    // No error
default:
    // Other error
}

type SymlinkFS

type SymlinkFS interface { ... }

SymlinkFS extends the default filesystem abstraction to add symbolic link operations. (target Go 1.23)

https://github.com/golang/go/issues/49580

Documentation

Overview

Package vfs extends the default Golang FS abstraction to support secured write operations.

Index

Examples

Constants

View Source
const (
	Separator = string(filepath.Separator)
	SelfDir   = "."
	ParentDir = ".."
	FakeRoot  = "/"
)

Variables

This section is empty.

Functions

This section is empty.

Types

type ConfirmedDir

type ConfirmedDir string

ConfirmedDir is a clean, absolute, delinkified path that was confirmed to point to an existing directory.

func ConfirmDir

func ConfirmDir(root FileSystem, path string) (ConfirmedDir, error)

ConfirmDir returns an error if the user-specified path is not an existing directory on root. Otherwise, ConfirmDir returns path, which can be relative, as a ConfirmedDir and all that implies.

Example
// Chroot to temporary directory
root, err := Chroot(os.TempDir())
if err != nil {
	panic(err)
}

// Use the filesystem to resolve the real target path.
cdir, err := ConfirmDir(root, ".")
if err != nil {
	panic(err)
}
Output:

/

func NewTmpConfirmedDir

func NewTmpConfirmedDir() (ConfirmedDir, error)

NewTmpConfirmedDir returns a temporary dir, else error. The directory is cleaned, no symlinks, etc. so it's returned as a ConfirmedDir.

Example
// Create and resolve a confirmed temporary directory
// For MacOS, the final directory is resolved from its symbolic link.
cdir, err := NewTmpConfirmedDir()
if err != nil {
	panic(err)
}

// Try to escape from the confirmed directory
cdir1 := cdir.Join("../etc/password")

// Check new path validity
isValid := cdir.HasPrefix(ConfirmedDir(cdir1))
Output:

false

func (ConfirmedDir) HasPrefix

func (d ConfirmedDir) HasPrefix(path ConfirmedDir) bool

HasPrefix ensure that the given path has the confirmed directory as prefix.

func (ConfirmedDir) Join

func (d ConfirmedDir) Join(path string) string

Join the given path to the confirmed directory.

func (ConfirmedDir) String

func (d ConfirmedDir) String() string

type ConstraintError

type ConstraintError struct {
	Op   string
	Path string
	Err  error
}

ConstraintError records an error and the operation and file that violated it.

func (*ConstraintError) Error

func (e *ConstraintError) Error() string

Error returns the formatted error string for the ConstraintError.

func (*ConstraintError) Unwrap

func (e *ConstraintError) Unwrap() error

Unwrap implements error unwrapping.

type File

type File interface {
	fs.File
	io.Writer
}

File represents the file writer interface.

type FileSystem

type FileSystem interface {
	fs.FS
	fs.StatFS
	fs.ReadDirFS
	fs.ReadFileFS
	fs.GlobFS
	SymlinkFS

	// Create a file.
	Create(name string) (File, error)
	// Mkdir creates a directory form the given path.
	Mkdir(path string, perm fs.FileMode) error
	// MkdirAll creats a directory path with all intermediary directories.
	MkdirAll(path string, perm fs.FileMode) error
	// IsDir returns true if the path is a directory.
	IsDir(path string) bool
	// Exists is true if the path exists in the filesystem.
	Exists(path string) bool
	// Chmod changes the filemode of the given path.
	Chmod(name string, mode fs.FileMode) error
	// Chowwn changes the owner of the given path.
	Chown(name string, uid, gid int) error
	// Chtimes changes the access and modification times of the given path.
	Chtimes(name string, atime, mtime time.Time) error
	// Symlink creates a symbolink link.
	Symlink(path, name string) error
	// Link creates a hardlink.
	Link(path, name string) error
	// RemoveAll removes all path elements from the given path from the filesystem.
	RemoveAll(path string) error
	// Remove remove the given path from the filesystem.
	Remove(path string) error
	// Resolve the given path to return a real/delinked absolute path.
	Resolve(path string) (ConfirmedDir, string, error)
	// Truncate changes the size of the given file.
	Truncate(path string, size int64) error
	// WriteFile writes given data to the given path as a file with the given filemode.
	WriteFile(path string, data []byte, perm fs.FileMode) error
	// WalkDir the filesystem form the given path.
	WalkDir(path string, walkFn fs.WalkDirFunc) error
}

FileSystem extends the default read-only filesystem abstraction to add write operations.

func Chroot

func Chroot(root string) (FileSystem, error)

Chroot returns a chrooted filesystem assuming an OS base filesystem as root filesystem.

Example
// Chroot to temporary directory
root, err := Chroot(os.TempDir())
if err != nil {
	panic(err)
}

// Chroot is compatible with Go fs.FS abstraction
if err := fs.WalkDir(root, ".", func(path string, d fs.DirEntry, err error) error {
	// Do something
	return nil
}); err != nil {
	panic(err)
}

// Provides filesystem isolation to prevent path traversal.
err = root.Mkdir("../wrong", 0o700)

fsErr := &ConstraintError{}
switch {
case err == nil:
	// No error
case errors.As(err, &fsErr):
	// Constraint error
default:
	// Other error
}
Output:

IsConstraintError => true

func ChrootFS

func ChrootFS(root FileSystem, path string) (FileSystem, error)

ChrootFS creates a chrooted filesystem instance from the given filesystem and the path. The path must be a directory part of the given root filesystem to be used.

Example
// Chroot to temporary directory
root, err := Chroot(os.TempDir())
if err != nil {
	panic(err)
}

// Create a chroot from a parent filesystem.
subRoot, err := ChrootFS(root, "var")
if err != nil {
	panic(err)
}

// Try to open an out of chroot file will raise a ConstraintError.
_, err = subRoot.Open("../etc/passwd")
switch {
case err == nil:
	// No error
default:
	// Other error
}
Output:

func OS

func OS() FileSystem

OS returns a new instance of the OS filesystem.

Example
// Create a host writeable filesystem without constraints.
root := OS()

// Create a chroot from a parent filesystem.
subRoot, err := ChrootFS(root, "/etc/datadog")
if err != nil {
	panic(err)
}

// Try to open an out of chroot file will raise a ConstraintError.
_, err = subRoot.Open("../passwd")
switch {
case err == nil:
	// No error
default:
	// Other error
}
Output:

type SymlinkFS added in v0.0.4

type SymlinkFS interface {
	fs.FS

	// ReadLink returns the destination of the named symbolic link.
	ReadLink(name string) (string, error)

	// Lstat returns a FileInfo describing the file without following any
	// symbolic links.
	// If there is an error, it should be of type *PathError.
	Lstat(name string) (fs.FileInfo, error)
}

SymlinkFS extends the default filesystem abstraction to add symbolic link operations. (target Go 1.23)

https://github.com/golang/go/issues/49580

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL