Skip to content

Commit 58362b0

Browse files
Yisaerodaysec
andauthored
fix(core): Enforce safe path validation user Input (#3911)
Signed-off-by: Jörmungandrk <github@zerodaysec.org> Signed-off-by: Song Gao <disxiaofei@163.com> Co-authored-by: Jörmungandrk <47859767+odaysec@users.noreply.github.com>
1 parent feab3a4 commit 58362b0

7 files changed

Lines changed: 48 additions & 0 deletions

File tree

internal/pkg/filex/zip.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,15 @@ import (
2323
"path/filepath"
2424

2525
"github.com/pingcap/failpoint"
26+
27+
"github.com/lf-edge/ekuiper/v2/pkg/path"
2628
)
2729

2830
func UnzipTo(f *zip.File, folder, name string) (err error) {
31+
// Validate name to avoid path traversal and directory escape
32+
if err := path.VerifyFileName(name); err != nil {
33+
return err
34+
}
2935
defer func() {
3036
failpoint.Inject("UnzipToErr", func() {
3137
err = errors.New("UnzipToErr")

internal/plugin/native/manager.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -824,6 +824,10 @@ func (rr *Manager) loadRuntime(t plugin2.PluginType, soName, soFilepath, symbolN
824824

825825
// Return the lowercase version of so name. It may be upper case in path.
826826
func (rr *Manager) getSoFilePath(t plugin2.PluginType, name string, isSoName bool) (string, error) {
827+
// Validate plugin name to prevent path traversal or absolute paths
828+
if strings.Contains(name, "/") || strings.Contains(name, "\\") || strings.Contains(name, "..") || strings.HasPrefix(name, ".") || strings.HasPrefix(name, "-") {
829+
return "", fmt.Errorf("invalid soFileName %v", name)
830+
}
827831
var (
828832
v string
829833
soname string

internal/schema/registry.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,9 @@ func CreateOrUpdateSchema(info *Info) error {
177177
if strings.Contains(info.Name, "/") || strings.Contains(info.Name, "\\") || strings.Contains(info.Name, "..") {
178178
return fmt.Errorf("schema name %s is invalid", info.Name)
179179
}
180+
if strings.Contains(info.Version, "/") || strings.Contains(info.Version, "\\") || strings.Contains(info.Version, "..") {
181+
return fmt.Errorf("schema version %s is invalid", info.Version)
182+
}
180183
st, ok := modules.SchemaTypeDefs[info.Type]
181184
if !ok {
182185
return fmt.Errorf("schema type %s not found", info.Type)

internal/server/rest.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ import (
5353
"github.com/lf-edge/ekuiper/v2/pkg/infra"
5454
"github.com/lf-edge/ekuiper/v2/pkg/kv"
5555
"github.com/lf-edge/ekuiper/v2/pkg/memory"
56+
"github.com/lf-edge/ekuiper/v2/pkg/path"
5657
"github.com/lf-edge/ekuiper/v2/pkg/tracer"
5758
"github.com/lf-edge/ekuiper/v2/pkg/validate"
5859
)
@@ -291,6 +292,10 @@ func (f *fileContent) Validate() error {
291292
if f.Name == "" {
292293
return fmt.Errorf("invalid body: name is required")
293294
}
295+
// Disallow path traversal and path separators in name
296+
if err := path.VerifyFileName(f.Name); err != nil {
297+
return err
298+
}
294299
return nil
295300
}
296301

internal/server/rule_manager.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ import (
3636
"github.com/lf-edge/ekuiper/v2/pkg/ast"
3737
"github.com/lf-edge/ekuiper/v2/pkg/errorx"
3838
"github.com/lf-edge/ekuiper/v2/pkg/infra"
39+
"github.com/lf-edge/ekuiper/v2/pkg/path"
3940
"github.com/lf-edge/ekuiper/v2/pkg/replace"
4041
)
4142

@@ -558,6 +559,10 @@ func deleteRuleMetrics(name string) {
558559
}
559560

560561
func deleteRuleData(name string) {
562+
if !path.IsSafeFileComponent(name) {
563+
conf.Log.Errorf("delete rule data aborted: unsafe rule name '%s'", name)
564+
return
565+
}
561566
dataLoc, err := conf.GetDataLoc()
562567
if err != nil {
563568
conf.Log.Errorf("delete rule data error: %v", err)

internal/service/manager.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ import (
3535
"github.com/lf-edge/ekuiper/v2/internal/plugin"
3636
"github.com/lf-edge/ekuiper/v2/pkg/cast"
3737
"github.com/lf-edge/ekuiper/v2/pkg/kv"
38+
pathutil "github.com/lf-edge/ekuiper/v2/pkg/path"
3839
"github.com/lf-edge/ekuiper/v2/pkg/validate"
3940
)
4041

@@ -140,6 +141,13 @@ func (m *Manager) InitByFiles() error {
140141
}
141142

142143
func (m *Manager) initFile(baseName string) error {
144+
// Validate baseName to prevent directory traversal and absolute path
145+
if err := pathutil.VerifyFileName(baseName); err != nil {
146+
return err
147+
}
148+
if filepath.IsAbs(baseName) || strings.Contains(baseName, "/") || strings.Contains(baseName, "\\") || strings.Contains(baseName, "..") {
149+
return fmt.Errorf("invalid service file name: %q", baseName)
150+
}
143151
serviceConf := &conf{}
144152
err := filex.ReadJsonUnmarshal(filepath.Join(m.etcDir, baseName), serviceConf)
145153
if err != nil {

pkg/path/path.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,9 @@
1515
package path
1616

1717
import (
18+
"fmt"
1819
"path/filepath"
20+
"strings"
1921

2022
"github.com/lf-edge/ekuiper/contract/v2/api"
2123
)
@@ -26,3 +28,18 @@ func AbsPath(ctx api.StreamContext, path string) string {
2628
}
2729
return filepath.Join(ctx.GetRootPath(), path)
2830
}
31+
32+
func VerifyFileName(name string) error {
33+
if strings.Contains(name, "..") || filepath.IsAbs(name) {
34+
return fmt.Errorf("invalid file name: path traversal or absolute paths are not allowed: %q", name)
35+
}
36+
return nil
37+
}
38+
39+
func IsSafeFileComponent(name string) bool {
40+
// Disallow path separators and parent directory references.
41+
if strings.Contains(name, "/") || strings.Contains(name, "\\") || strings.Contains(name, "..") || name == "" {
42+
return false
43+
}
44+
return true
45+
}

0 commit comments

Comments
 (0)