Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 21 additions & 2 deletions go/pkg/client/cas_download.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"path/filepath"
"sort"
"strconv"
"strings"
"sync"
"time"

Expand Down Expand Up @@ -147,7 +148,21 @@ func (c *Client) DownloadOutputs(ctx context.Context, outs map[string]*TreeOutpu
}
}
for _, out := range symlinks {
if err := os.Symlink(out.SymlinkTarget, filepath.Join(outDir, out.Path)); err != nil {
symlinkPath, err := getAbsPath(outDir, out.Path)
if err != nil {
return fullStats, err
}
// Validate that the symlink target resolves within outDir to prevent
// symlink-based path traversal (e.g. target = "/etc/shadow").
target := out.SymlinkTarget
if !filepath.IsAbs(target) {
target = filepath.Join(filepath.Dir(symlinkPath), target)
}
target = filepath.Clean(target)
if target != outDir && !strings.HasPrefix(target, outDir+string(filepath.Separator)) {
return fullStats, fmt.Errorf("symlink target %q resolves to %q which is outside output directory %q", out.SymlinkTarget, target, outDir)
}
if err := os.Symlink(out.SymlinkTarget, symlinkPath); err != nil {
return fullStats, err
}
}
Expand Down Expand Up @@ -522,7 +537,11 @@ func (c *Client) DownloadActionOutputs(ctx context.Context, resPb *repb.ActionRe
}
// Remove the existing output directories before downloading.
for _, dir := range resPb.OutputDirectories {
if err := os.RemoveAll(filepath.Join(outDir, dir.Path)); err != nil {
absPath, err := getAbsPath(outDir, dir.Path)
if err != nil {
return nil, err
}
if err := os.RemoveAll(absPath); err != nil {
return nil, err
}
}
Expand Down