Cherry-pick MM-66789: Restrict log downloads to a root path for support packets (#35164)
Automatic Merge
Этот коммит содержится в:
@@ -5,6 +5,8 @@ package config
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
@@ -50,3 +52,169 @@ func TestMloggerConfigFromAuditConfig(t *testing.T) {
|
||||
assert.Equal(t, optionsExpected, optionsReceived)
|
||||
})
|
||||
}
|
||||
|
||||
func TestGetLogRootPath(t *testing.T) {
|
||||
t.Run("returns MM_LOG_PATH when set", func(t *testing.T) {
|
||||
// Create a temp directory to use as MM_LOG_PATH
|
||||
dir, err := os.MkdirTemp("", "logroot")
|
||||
require.NoError(t, err)
|
||||
t.Cleanup(func() {
|
||||
os.RemoveAll(dir)
|
||||
})
|
||||
|
||||
t.Setenv("MM_LOG_PATH", dir)
|
||||
|
||||
result := GetLogRootPath()
|
||||
absDir, _ := filepath.Abs(dir)
|
||||
assert.Equal(t, absDir, result)
|
||||
})
|
||||
|
||||
t.Run("finds logs directory relative to binary when MM_LOG_PATH not set", func(t *testing.T) {
|
||||
// When MM_LOG_PATH is not set, GetLogRootPath falls back to FindDir("logs"),
|
||||
// which searches for a "logs" directory relative to the working directory
|
||||
// and the binary location. Create a logs directory relative to the test
|
||||
// binary to verify this behavior.
|
||||
t.Setenv("MM_LOG_PATH", "")
|
||||
|
||||
// Get the test binary location
|
||||
exe, err := os.Executable()
|
||||
require.NoError(t, err)
|
||||
exe, err = filepath.EvalSymlinks(exe)
|
||||
require.NoError(t, err)
|
||||
binaryDir := filepath.Dir(exe)
|
||||
|
||||
// Create a "logs" directory next to the binary
|
||||
logsDir := filepath.Join(binaryDir, "logs")
|
||||
err = os.MkdirAll(logsDir, 0755)
|
||||
require.NoError(t, err)
|
||||
t.Cleanup(func() {
|
||||
os.RemoveAll(logsDir)
|
||||
})
|
||||
|
||||
result := GetLogRootPath()
|
||||
|
||||
// Result should be an absolute path
|
||||
assert.True(t, filepath.IsAbs(result), "GetLogRootPath should return an absolute path, got: %s", result)
|
||||
|
||||
// FindDir searches working directory first, then binary directory.
|
||||
// The result should be either the logs directory we created or another
|
||||
// logs directory found earlier in the search path. Either way, it should
|
||||
// be a valid directory path ending in "logs".
|
||||
assert.True(t, filepath.Base(result) == "logs" || result == "./",
|
||||
"GetLogRootPath should return a logs directory path, got: %s", result)
|
||||
})
|
||||
}
|
||||
|
||||
func TestValidateLogFilePath(t *testing.T) {
|
||||
t.Run("valid path within root", func(t *testing.T) {
|
||||
root, err := os.MkdirTemp("", "logroot")
|
||||
require.NoError(t, err)
|
||||
t.Cleanup(func() {
|
||||
os.RemoveAll(root)
|
||||
})
|
||||
|
||||
validFile := filepath.Join(root, "app.log")
|
||||
err = os.WriteFile(validFile, []byte("test"), 0644)
|
||||
require.NoError(t, err)
|
||||
|
||||
err = ValidateLogFilePath(validFile, root)
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
|
||||
t.Run("valid path in subdirectory", func(t *testing.T) {
|
||||
root, err := os.MkdirTemp("", "logroot")
|
||||
require.NoError(t, err)
|
||||
t.Cleanup(func() {
|
||||
os.RemoveAll(root)
|
||||
})
|
||||
|
||||
subdir := filepath.Join(root, "subdir")
|
||||
err = os.MkdirAll(subdir, 0755)
|
||||
require.NoError(t, err)
|
||||
|
||||
validFile := filepath.Join(subdir, "app.log")
|
||||
err = os.WriteFile(validFile, []byte("test"), 0644)
|
||||
require.NoError(t, err)
|
||||
|
||||
err = ValidateLogFilePath(validFile, root)
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
|
||||
t.Run("rejects absolute path outside root", func(t *testing.T) {
|
||||
root, err := os.MkdirTemp("", "logroot")
|
||||
require.NoError(t, err)
|
||||
t.Cleanup(func() {
|
||||
os.RemoveAll(root)
|
||||
})
|
||||
|
||||
outsideDir, err := os.MkdirTemp("", "outside")
|
||||
require.NoError(t, err)
|
||||
t.Cleanup(func() {
|
||||
os.RemoveAll(outsideDir)
|
||||
})
|
||||
|
||||
outsideFile := filepath.Join(outsideDir, "secret.txt")
|
||||
err = os.WriteFile(outsideFile, []byte("secret"), 0644)
|
||||
require.NoError(t, err)
|
||||
|
||||
err = ValidateLogFilePath(outsideFile, root)
|
||||
assert.Error(t, err)
|
||||
assert.Contains(t, err.Error(), "outside logging root")
|
||||
})
|
||||
|
||||
t.Run("rejects path traversal attack", func(t *testing.T) {
|
||||
root, err := os.MkdirTemp("", "logroot")
|
||||
require.NoError(t, err)
|
||||
t.Cleanup(func() {
|
||||
os.RemoveAll(root)
|
||||
})
|
||||
|
||||
traversalPath := filepath.Join(root, "..", "..", "etc", "passwd")
|
||||
|
||||
err = ValidateLogFilePath(traversalPath, root)
|
||||
assert.Error(t, err)
|
||||
assert.Contains(t, err.Error(), "outside logging root")
|
||||
})
|
||||
|
||||
t.Run("rejects symlink pointing outside root", func(t *testing.T) {
|
||||
root, err := os.MkdirTemp("", "logroot")
|
||||
require.NoError(t, err)
|
||||
t.Cleanup(func() {
|
||||
os.RemoveAll(root)
|
||||
})
|
||||
|
||||
outsideDir, err := os.MkdirTemp("", "outside")
|
||||
require.NoError(t, err)
|
||||
t.Cleanup(func() {
|
||||
os.RemoveAll(outsideDir)
|
||||
})
|
||||
|
||||
// Create a file outside the root
|
||||
outsideFile := filepath.Join(outsideDir, "secret.txt")
|
||||
err = os.WriteFile(outsideFile, []byte("secret"), 0644)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Create a symlink inside root pointing to the outside file
|
||||
symlinkPath := filepath.Join(root, "sneaky.log")
|
||||
err = os.Symlink(outsideFile, symlinkPath)
|
||||
require.NoError(t, err)
|
||||
|
||||
err = ValidateLogFilePath(symlinkPath, root)
|
||||
assert.Error(t, err)
|
||||
assert.Contains(t, err.Error(), "outside logging root")
|
||||
})
|
||||
|
||||
t.Run("allows non-existent file path within root", func(t *testing.T) {
|
||||
root, err := os.MkdirTemp("", "logroot")
|
||||
require.NoError(t, err)
|
||||
t.Cleanup(func() {
|
||||
os.RemoveAll(root)
|
||||
})
|
||||
|
||||
// File doesn't exist but path is within root
|
||||
nonExistentFile := filepath.Join(root, "future.log")
|
||||
|
||||
err = ValidateLogFilePath(nonExistentFile, root)
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
}
|
||||
|
||||
Ссылка в новой задаче
Block a user