ensure file doesn't escape

This commit is contained in:
Alex Dadgar
2016-12-18 15:48:30 -08:00
parent c308ef7e49
commit 732cce5d4a
3 changed files with 56 additions and 12 deletions

View File

@@ -411,7 +411,7 @@ func (d *AllocDir) LogDir() string {
// List returns the list of files at a path relative to the alloc dir
func (d *AllocDir) List(path string) ([]*AllocFileInfo, error) {
if escapes, err := structs.PathEscapesAllocDir(path); err != nil {
if escapes, err := structs.PathEscapesAllocDir("", path); err != nil {
return nil, fmt.Errorf("Failed to check if path escapes alloc directory: %v", err)
} else if escapes {
return nil, fmt.Errorf("Path escapes the alloc directory")
@@ -437,7 +437,7 @@ func (d *AllocDir) List(path string) ([]*AllocFileInfo, error) {
// Stat returns information about the file at a path relative to the alloc dir
func (d *AllocDir) Stat(path string) (*AllocFileInfo, error) {
if escapes, err := structs.PathEscapesAllocDir(path); err != nil {
if escapes, err := structs.PathEscapesAllocDir("", path); err != nil {
return nil, fmt.Errorf("Failed to check if path escapes alloc directory: %v", err)
} else if escapes {
return nil, fmt.Errorf("Path escapes the alloc directory")
@@ -460,7 +460,7 @@ func (d *AllocDir) Stat(path string) (*AllocFileInfo, error) {
// ReadAt returns a reader for a file at the path relative to the alloc dir
func (d *AllocDir) ReadAt(path string, offset int64) (io.ReadCloser, error) {
if escapes, err := structs.PathEscapesAllocDir(path); err != nil {
if escapes, err := structs.PathEscapesAllocDir("", path); err != nil {
return nil, fmt.Errorf("Failed to check if path escapes alloc directory: %v", err)
} else if escapes {
return nil, fmt.Errorf("Path escapes the alloc directory")
@@ -489,7 +489,7 @@ func (d *AllocDir) ReadAt(path string, offset int64) (io.ReadCloser, error) {
// BlockUntilExists blocks until the passed file relative the allocation
// directory exists. The block can be cancelled with the passed tomb.
func (d *AllocDir) BlockUntilExists(path string, t *tomb.Tomb) (chan error, error) {
if escapes, err := structs.PathEscapesAllocDir(path); err != nil {
if escapes, err := structs.PathEscapesAllocDir("", path); err != nil {
return nil, fmt.Errorf("Failed to check if path escapes alloc directory: %v", err)
} else if escapes {
return nil, fmt.Errorf("Path escapes the alloc directory")
@@ -510,7 +510,7 @@ func (d *AllocDir) BlockUntilExists(path string, t *tomb.Tomb) (chan error, erro
// allocation directory. The offset should be the last read offset. The tomb is
// used to clean up the watch.
func (d *AllocDir) ChangeEvents(path string, curOffset int64, t *tomb.Tomb) (*watch.FileChanges, error) {
if escapes, err := structs.PathEscapesAllocDir(path); err != nil {
if escapes, err := structs.PathEscapesAllocDir("", path); err != nil {
return nil, fmt.Errorf("Failed to check if path escapes alloc directory: %v", err)
} else if escapes {
return nil, fmt.Errorf("Path escapes the alloc directory")

View File

@@ -1706,6 +1706,18 @@ func (d *DispatchInputConfig) Copy() *DispatchInputConfig {
return nd
}
func (d *DispatchInputConfig) Validate() error {
// Verify the destination doesn't escape
escaped, err := PathEscapesAllocDir("task/local/", d.File)
if err != nil {
return fmt.Errorf("invalid destination path: %v", err)
} else if escaped {
return fmt.Errorf("destination escapes allocation directory")
}
return nil
}
var (
defaultServiceJobRestartPolicy = RestartPolicy{
Delay: 15 * time.Second,
@@ -2462,6 +2474,13 @@ func (t *Task) Validate(ephemeralDisk *EphemeralDisk) error {
}
}
// Validate the dispatch input block if there
if t.DispatchInput != nil {
if err := t.DispatchInput.Validate(); err != nil {
mErr.Errors = append(mErr.Errors, err)
}
}
return mErr.ErrorOrNil()
}
@@ -2603,7 +2622,7 @@ func (t *Template) Validate() error {
}
// Verify the destination doesn't escape
escaped, err := PathEscapesAllocDir(t.DestPath)
escaped, err := PathEscapesAllocDir("task", t.DestPath)
if err != nil {
mErr.Errors = append(mErr.Errors, fmt.Errorf("invalid destination path: %v", err))
} else if escaped {
@@ -2955,14 +2974,16 @@ func (ta *TaskArtifact) GoString() string {
}
// PathEscapesAllocDir returns if the given path escapes the allocation
// directory
func PathEscapesAllocDir(path string) (bool, error) {
// directory. The prefix allows adding a prefix if the path will be joined, for
// example a "task/local" prefix may be provided if the path will be joined
// against that prefix.
func PathEscapesAllocDir(prefix, path string) (bool, error) {
// Verify the destination doesn't escape the tasks directory
alloc, err := filepath.Abs(filepath.Join("/", "foo/", "bar/"))
alloc, err := filepath.Abs(filepath.Join("/", "alloc-dir/", "alloc-id/"))
if err != nil {
return false, err
}
abs, err := filepath.Abs(filepath.Join(alloc, path))
abs, err := filepath.Abs(filepath.Join(alloc, prefix, path))
if err != nil {
return false, err
}
@@ -2981,7 +3002,7 @@ func (ta *TaskArtifact) Validate() error {
mErr.Errors = append(mErr.Errors, fmt.Errorf("source must be specified"))
}
escaped, err := PathEscapesAllocDir(ta.RelativeDest)
escaped, err := PathEscapesAllocDir("task", ta.RelativeDest)
if err != nil {
mErr.Errors = append(mErr.Errors, fmt.Errorf("invalid destination path: %v", err))
} else if escaped {

View File

@@ -1267,7 +1267,7 @@ func TestTaskArtifact_Validate_Dest(t *testing.T) {
t.Fatalf("unexpected error: %v", err)
}
valid.RelativeDest = "local/../.."
valid.RelativeDest = "local/../../.."
if err := valid.Validate(); err == nil {
t.Fatalf("expected error: %v", err)
}
@@ -1482,3 +1482,26 @@ func TestConstructorConfig_Canonicalize(t *testing.T) {
t.Fatalf("Canonicalize failed")
}
}
func TestDispatchInputConfig_Validate(t *testing.T) {
d := &DispatchInputConfig{
File: "foo",
}
// task/local/haha
if err := d.Validate(); err != nil {
t.Fatalf("bad: %v", err)
}
// task/haha
d.File = "../haha"
if err := d.Validate(); err != nil {
t.Fatalf("bad: %v", err)
}
// ../haha
d.File = "../../../haha"
if err := d.Validate(); err == nil {
t.Fatalf("bad: %v", err)
}
}