Add safe guards for relative paths

Signed-off-by: Hidde Beydals <hello@hidde.co>
This commit is contained in:
Hidde Beydals 2020-12-15 00:49:35 +01:00
parent 1eb52ae235
commit bc890874e1
4 changed files with 25 additions and 20 deletions

View File

@ -22,11 +22,11 @@ import (
"io/ioutil" "io/ioutil"
"net/url" "net/url"
"os" "os"
"path"
"regexp" "regexp"
"strings" "strings"
"time" "time"
securejoin "github.com/cyphar/filepath-securejoin"
"github.com/fluxcd/pkg/apis/meta" "github.com/fluxcd/pkg/apis/meta"
"github.com/go-logr/logr" "github.com/go-logr/logr"
helmchart "helm.sh/helm/v3/pkg/chart" helmchart "helm.sh/helm/v3/pkg/chart"
@ -453,7 +453,10 @@ func (r *HelmChartReconciler) reconcileFromTarballArtifact(ctx context.Context,
f.Close() f.Close()
// Load the chart // Load the chart
chartPath := path.Join(tmpDir, chart.Spec.Chart) chartPath, err := securejoin.SecureJoin(tmpDir, chart.Spec.Chart)
if err != nil {
return sourcev1.HelmChartNotReady(chart, sourcev1.StorageOperationFailedReason, err.Error()), err
}
chartFileInfo, err := os.Stat(chartPath) chartFileInfo, err := os.Stat(chartPath)
if err != nil { if err != nil {
err = fmt.Errorf("chart location read error: %w", err) err = fmt.Errorf("chart location read error: %w", err)
@ -581,8 +584,9 @@ func (r *HelmChartReconciler) reconcileFromTarballArtifact(ctx context.Context,
// Construct dependencies for chart if any // Construct dependencies for chart if any
if len(dwr) > 0 { if len(dwr) > 0 {
dm := &helm.DependencyManager{ dm := &helm.DependencyManager{
Chart: helmChart, BaseDir: tmpDir,
ChartPath: chartPath, ChartPath: chartPath,
Chart: helmChart,
Dependencies: dwr, Dependencies: dwr,
} }
err = dm.Build() err = dm.Build()

1
go.mod
View File

@ -7,6 +7,7 @@ replace github.com/fluxcd/source-controller/api => ./api
require ( require (
github.com/Masterminds/semver/v3 v3.1.0 github.com/Masterminds/semver/v3 v3.1.0
github.com/blang/semver/v4 v4.0.0 github.com/blang/semver/v4 v4.0.0
github.com/cyphar/filepath-securejoin v0.2.2
github.com/fluxcd/pkg/apis/meta v0.5.0 github.com/fluxcd/pkg/apis/meta v0.5.0
github.com/fluxcd/pkg/gittestserver v0.1.0 github.com/fluxcd/pkg/gittestserver v0.1.0
github.com/fluxcd/pkg/helmtestserver v0.1.0 github.com/fluxcd/pkg/helmtestserver v0.1.0

View File

@ -20,11 +20,11 @@ import (
"context" "context"
"fmt" "fmt"
"os" "os"
"path"
"path/filepath" "path/filepath"
"strings" "strings"
"github.com/Masterminds/semver/v3" "github.com/Masterminds/semver/v3"
securejoin "github.com/cyphar/filepath-securejoin"
"golang.org/x/sync/errgroup" "golang.org/x/sync/errgroup"
helmchart "helm.sh/helm/v3/pkg/chart" helmchart "helm.sh/helm/v3/pkg/chart"
"helm.sh/helm/v3/pkg/chart/loader" "helm.sh/helm/v3/pkg/chart/loader"
@ -39,14 +39,15 @@ type DependencyWithRepository struct {
// DependencyManager manages dependencies for helm charts // DependencyManager manages dependencies for helm charts
type DependencyManager struct { type DependencyManager struct {
Chart *helmchart.Chart BaseDir string
ChartPath string ChartPath string
Chart *helmchart.Chart
Dependencies []*DependencyWithRepository Dependencies []*DependencyWithRepository
} }
// Build compiles and builds the chart dependencies // Build compiles and builds the chart dependencies
func (dm *DependencyManager) Build() error { func (dm *DependencyManager) Build() error {
if dm.Dependencies == nil { if len(dm.Dependencies) == 0 {
return nil return nil
} }
@ -54,17 +55,15 @@ func (dm *DependencyManager) Build() error {
errs, ctx := errgroup.WithContext(ctx) errs, ctx := errgroup.WithContext(ctx)
for _, item := range dm.Dependencies { for _, item := range dm.Dependencies {
dep := item.Dependency
chartRepo := item.Repo
errs.Go(func() error { errs.Go(func() error {
var ( var (
ch *helmchart.Chart ch *helmchart.Chart
err error err error
) )
if strings.HasPrefix(dep.Repository, "file://") { if strings.HasPrefix(item.Dependency.Repository, "file://") {
ch, err = chartForLocalDependency(dep, dm.ChartPath) ch, err = chartForLocalDependency(item.Dependency, dm.BaseDir, dm.ChartPath)
} else { } else {
ch, err = chartForRemoteDependency(dep, chartRepo) ch, err = chartForRemoteDependency(item.Dependency, item.Repo)
} }
if err != nil { if err != nil {
return err return err
@ -77,8 +76,9 @@ func (dm *DependencyManager) Build() error {
return errs.Wait() return errs.Wait()
} }
func chartForLocalDependency(dep *helmchart.Dependency, cp string) (*helmchart.Chart, error) { func chartForLocalDependency(dep *helmchart.Dependency, baseDir, chartPath string) (*helmchart.Chart, error) {
origPath, err := filepath.Abs(path.Join(cp, strings.TrimPrefix(dep.Repository, "file://"))) origPath, err := securejoin.SecureJoin(baseDir,
filepath.Join(strings.TrimPrefix(chartPath, baseDir), strings.TrimPrefix(dep.Repository, "file://")))
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -114,20 +114,19 @@ func chartForLocalDependency(dep *helmchart.Dependency, cp string) (*helmchart.C
return ch, nil return ch, nil
} }
func chartForRemoteDependency(dep *helmchart.Dependency, chartrepo *ChartRepository) (*helmchart.Chart, error) { func chartForRemoteDependency(dep *helmchart.Dependency, chartRepo *ChartRepository) (*helmchart.Chart, error) {
if chartrepo == nil { if chartRepo == nil {
err := fmt.Errorf("chartrepo should not be nil") return nil, fmt.Errorf("chartrepo should not be nil")
return nil, err
} }
// Lookup the chart version in the chart repository index // Lookup the chart version in the chart repository index
chartVer, err := chartrepo.Get(dep.Name, dep.Version) chartVer, err := chartRepo.Get(dep.Name, dep.Version)
if err != nil { if err != nil {
return nil, err return nil, err
} }
// Download chart // Download chart
res, err := chartrepo.DownloadChart(chartVer) res, err := chartRepo.DownloadChart(chartVer)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -108,8 +108,9 @@ func TestBuild_WithLocalChart(t *testing.T) {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
c := chartFixture c := chartFixture
dm := DependencyManager{ dm := DependencyManager{
Chart: &c, BaseDir: "./",
ChartPath: "testdata/charts/helmchart", ChartPath: "testdata/charts/helmchart",
Chart: &c,
Dependencies: []*DependencyWithRepository{ Dependencies: []*DependencyWithRepository{
{ {
Dependency: &tt.dep, Dependency: &tt.dep,