Skip to content

Commit bc89087

Browse files
committed
Add safe guards for relative paths
Signed-off-by: Hidde Beydals <[email protected]>
1 parent 1eb52ae commit bc89087

File tree

4 files changed

+25
-20
lines changed

4 files changed

+25
-20
lines changed

controllers/helmchart_controller.go

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,11 @@ import (
2222
"io/ioutil"
2323
"net/url"
2424
"os"
25-
"path"
2625
"regexp"
2726
"strings"
2827
"time"
2928

29+
securejoin "github.com/cyphar/filepath-securejoin"
3030
"github.com/fluxcd/pkg/apis/meta"
3131
"github.com/go-logr/logr"
3232
helmchart "helm.sh/helm/v3/pkg/chart"
@@ -453,7 +453,10 @@ func (r *HelmChartReconciler) reconcileFromTarballArtifact(ctx context.Context,
453453
f.Close()
454454

455455
// Load the chart
456-
chartPath := path.Join(tmpDir, chart.Spec.Chart)
456+
chartPath, err := securejoin.SecureJoin(tmpDir, chart.Spec.Chart)
457+
if err != nil {
458+
return sourcev1.HelmChartNotReady(chart, sourcev1.StorageOperationFailedReason, err.Error()), err
459+
}
457460
chartFileInfo, err := os.Stat(chartPath)
458461
if err != nil {
459462
err = fmt.Errorf("chart location read error: %w", err)
@@ -581,8 +584,9 @@ func (r *HelmChartReconciler) reconcileFromTarballArtifact(ctx context.Context,
581584
// Construct dependencies for chart if any
582585
if len(dwr) > 0 {
583586
dm := &helm.DependencyManager{
584-
Chart: helmChart,
587+
BaseDir: tmpDir,
585588
ChartPath: chartPath,
589+
Chart: helmChart,
586590
Dependencies: dwr,
587591
}
588592
err = dm.Build()

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ replace github.com/fluxcd/source-controller/api => ./api
77
require (
88
github.com/Masterminds/semver/v3 v3.1.0
99
github.com/blang/semver/v4 v4.0.0
10+
github.com/cyphar/filepath-securejoin v0.2.2
1011
github.com/fluxcd/pkg/apis/meta v0.5.0
1112
github.com/fluxcd/pkg/gittestserver v0.1.0
1213
github.com/fluxcd/pkg/helmtestserver v0.1.0

internal/helm/dependency_manager.go

Lines changed: 15 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,11 @@ import (
2020
"context"
2121
"fmt"
2222
"os"
23-
"path"
2423
"path/filepath"
2524
"strings"
2625

2726
"github.com/Masterminds/semver/v3"
27+
securejoin "github.com/cyphar/filepath-securejoin"
2828
"golang.org/x/sync/errgroup"
2929
helmchart "helm.sh/helm/v3/pkg/chart"
3030
"helm.sh/helm/v3/pkg/chart/loader"
@@ -39,32 +39,31 @@ type DependencyWithRepository struct {
3939

4040
// DependencyManager manages dependencies for helm charts
4141
type DependencyManager struct {
42-
Chart *helmchart.Chart
42+
BaseDir string
4343
ChartPath string
44+
Chart *helmchart.Chart
4445
Dependencies []*DependencyWithRepository
4546
}
4647

4748
// Build compiles and builds the chart dependencies
4849
func (dm *DependencyManager) Build() error {
49-
if dm.Dependencies == nil {
50+
if len(dm.Dependencies) == 0 {
5051
return nil
5152
}
5253

5354
ctx := context.Background()
5455
errs, ctx := errgroup.WithContext(ctx)
5556

5657
for _, item := range dm.Dependencies {
57-
dep := item.Dependency
58-
chartRepo := item.Repo
5958
errs.Go(func() error {
6059
var (
6160
ch *helmchart.Chart
6261
err error
6362
)
64-
if strings.HasPrefix(dep.Repository, "file://") {
65-
ch, err = chartForLocalDependency(dep, dm.ChartPath)
63+
if strings.HasPrefix(item.Dependency.Repository, "file://") {
64+
ch, err = chartForLocalDependency(item.Dependency, dm.BaseDir, dm.ChartPath)
6665
} else {
67-
ch, err = chartForRemoteDependency(dep, chartRepo)
66+
ch, err = chartForRemoteDependency(item.Dependency, item.Repo)
6867
}
6968
if err != nil {
7069
return err
@@ -77,8 +76,9 @@ func (dm *DependencyManager) Build() error {
7776
return errs.Wait()
7877
}
7978

80-
func chartForLocalDependency(dep *helmchart.Dependency, cp string) (*helmchart.Chart, error) {
81-
origPath, err := filepath.Abs(path.Join(cp, strings.TrimPrefix(dep.Repository, "file://")))
79+
func chartForLocalDependency(dep *helmchart.Dependency, baseDir, chartPath string) (*helmchart.Chart, error) {
80+
origPath, err := securejoin.SecureJoin(baseDir,
81+
filepath.Join(strings.TrimPrefix(chartPath, baseDir), strings.TrimPrefix(dep.Repository, "file://")))
8282
if err != nil {
8383
return nil, err
8484
}
@@ -114,20 +114,19 @@ func chartForLocalDependency(dep *helmchart.Dependency, cp string) (*helmchart.C
114114
return ch, nil
115115
}
116116

117-
func chartForRemoteDependency(dep *helmchart.Dependency, chartrepo *ChartRepository) (*helmchart.Chart, error) {
118-
if chartrepo == nil {
119-
err := fmt.Errorf("chartrepo should not be nil")
120-
return nil, err
117+
func chartForRemoteDependency(dep *helmchart.Dependency, chartRepo *ChartRepository) (*helmchart.Chart, error) {
118+
if chartRepo == nil {
119+
return nil, fmt.Errorf("chartrepo should not be nil")
121120
}
122121

123122
// Lookup the chart version in the chart repository index
124-
chartVer, err := chartrepo.Get(dep.Name, dep.Version)
123+
chartVer, err := chartRepo.Get(dep.Name, dep.Version)
125124
if err != nil {
126125
return nil, err
127126
}
128127

129128
// Download chart
130-
res, err := chartrepo.DownloadChart(chartVer)
129+
res, err := chartRepo.DownloadChart(chartVer)
131130
if err != nil {
132131
return nil, err
133132
}

internal/helm/dependency_manager_test.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,8 +108,9 @@ func TestBuild_WithLocalChart(t *testing.T) {
108108
t.Run(tt.name, func(t *testing.T) {
109109
c := chartFixture
110110
dm := DependencyManager{
111-
Chart: &c,
111+
BaseDir: "./",
112112
ChartPath: "testdata/charts/helmchart",
113+
Chart: &c,
113114
Dependencies: []*DependencyWithRepository{
114115
{
115116
Dependency: &tt.dep,

0 commit comments

Comments
 (0)