mirror of
https://github.com/moby/buildkit.git
synced 2026-08-09 01:01:08 +00:00
fileop: contain rm parent traversal
Anchor rm paths before splitting them so parent traversal is normalized
relative to the fileop root before the final path component is appended.
Add regression coverage for parent traversal attempts and preserve removal of
terminal symlinks without following them.
Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
(cherry picked from commit cc8b70d02fb890880e79abd44b9a0ad8b7e15d5b)
(cherry picked from commit 3916124aa4)
This commit is contained in:
@@ -162,12 +162,12 @@ func rm(d string, action *pb.FileActionRm) (err error) {
|
||||
}
|
||||
|
||||
func rmPath(root, src string, allowNotFound bool) error {
|
||||
src = filepath.Clean(src)
|
||||
src = filepath.Join("/", src)
|
||||
dir, base := filepath.Split(src)
|
||||
if base == "" {
|
||||
return errors.New("rmPath: invalid empty path")
|
||||
}
|
||||
dir, err := fs.RootPath(root, filepath.Join("/", dir))
|
||||
dir, err := fs.RootPath(root, dir)
|
||||
if err != nil {
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/moby/buildkit/solver/pb"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
@@ -35,3 +36,45 @@ func TestRmPathFileExists(t *testing.T) {
|
||||
|
||||
require.True(t, os.IsNotExist(err))
|
||||
}
|
||||
|
||||
func TestRmParentTraversalDoesNotEscapeRoot(t *testing.T) {
|
||||
// Backslash variants are separators on Windows (real traversal there) and
|
||||
// ordinary filename characters on Linux (inert, but still must not escape).
|
||||
for _, p := range []string{
|
||||
"..", "../..", "a/../..", "../victim",
|
||||
"..\\..", "a\\..\\..", "..\\victim",
|
||||
} {
|
||||
t.Run(p, func(t *testing.T) {
|
||||
parent := t.TempDir()
|
||||
root := filepath.Join(parent, "root")
|
||||
victim := filepath.Join(parent, "victim")
|
||||
|
||||
require.NoError(t, os.Mkdir(root, 0o755))
|
||||
require.NoError(t, os.Mkdir(victim, 0o755))
|
||||
require.NoError(t, os.WriteFile(filepath.Join(victim, "data"), []byte("data"), 0o644))
|
||||
|
||||
require.Error(t, rm(root, &pb.FileActionRm{Path: p}))
|
||||
|
||||
_, err := os.Stat(victim)
|
||||
require.NoError(t, err, "rm escaped root and deleted sibling %q", victim)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestRmPathRemovesSymlinkItself(t *testing.T) {
|
||||
root := t.TempDir()
|
||||
|
||||
target := filepath.Join(root, "target")
|
||||
link := filepath.Join(root, "link")
|
||||
|
||||
require.NoError(t, os.WriteFile(target, []byte("target"), 0o644))
|
||||
require.NoError(t, os.Symlink("target", link))
|
||||
|
||||
require.NoError(t, rmPath(root, "link", false))
|
||||
|
||||
_, err := os.Lstat(link)
|
||||
require.True(t, os.IsNotExist(err))
|
||||
|
||||
_, err = os.Stat(target)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user