Skip to content
Snippets Groups Projects
Select Git revision
  • 82eece008c0e648892ef07998c93dd66f32a1bf6
  • master default protected
  • v0.2.2
  • v0.2.1
  • v0.2.0
5 results

version.mk

Blame
  • README.md 7.08 KiB

    filepath-securejoin

    Go Documentation Build Status

    Old API

    This library was originally just an implementation of SecureJoin which was intended to be included in the Go standard library as a safer filepath.Join that would restrict the path lookup to be inside a root directory.

    The implementation was based on code that existed in several container runtimes. Unfortunately, this API is fundamentally unsafe against attackers that can modify path components after SecureJoin returns and before the caller uses the path, allowing for some fairly trivial TOCTOU attacks.

    SecureJoin (and SecureJoinVFS) are still provided by this library to support legacy users, but new users are strongly suggested to avoid using SecureJoin and instead use the new api or switch to libpathrs.

    With the above limitations in mind, this library guarantees the following:

    • If no error is set, the resulting string must be a child path of root and will not contain any symlink path components (they will all be expanded).

    • When expanding symlinks, all symlink path components must be resolved relative to the provided root. In particular, this can be considered a userspace implementation of how chroot(2) operates on file paths. Note that these symlinks will not be expanded lexically (filepath.Clean is not called on the input before processing).

    • Non-existent path components are unaffected by SecureJoin (similar to filepath.EvalSymlinks's semantics).

    • The returned path will always be filepath.Cleaned and thus not contain any .. components.

    A (trivial) implementation of this function on GNU/Linux systems could be done with the following (note that this requires root privileges and is far more opaque than the implementation in this library, and also requires that readlink is inside the root path and is trustworthy):

    package securejoin
    
    import (
    	"os/exec"
    	"path/filepath"
    )
    
    func SecureJoin(root, unsafePath string) (string, error) {
    	unsafePath = string(filepath.Separator) + unsafePath
    	cmd := exec.Command("chroot", root,
    		"readlink", "--canonicalize-missing", "--no-newline", unsafePath)
    	output, err := cmd.CombinedOutput()
    	if err != nil {
    		return "", err
    	}
    	expanded := string(output)
    	return filepath.Join(root, expanded), nil
    }