mirror of
https://github.com/XTLS/Xray-core.git
synced 2026-10-15 03:53:59 +00:00
lua: validate script extension after resolving symlinks
This commit is contained in:
@@ -40,11 +40,18 @@ func TestDownloadOneLuaGuard(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
data, err := os.ReadFile(staged.temp)
|
tx, err := swapAll([]stage{staged})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if err := tx.commit(); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
data, err := os.ReadFile(staged.target)
|
||||||
if err != nil || string(data) != luaGuardHeader+tc.body {
|
if err != nil || string(data) != luaGuardHeader+tc.body {
|
||||||
t.Fatalf("downloaded data = % x, %v", data, err)
|
t.Fatalf("downloaded data = % x, %v", data, err)
|
||||||
}
|
}
|
||||||
program, err := xlua.Compile(staged.temp)
|
program, err := xlua.Compile(staged.target)
|
||||||
var syntaxErr *parse.Error
|
var syntaxErr *parse.Error
|
||||||
if program != nil || !errors.As(err, &syntaxErr) || syntaxErr.Pos.Line != 1 || syntaxErr.Pos.Column != 1 {
|
if program != nil || !errors.As(err, &syntaxErr) || syntaxErr.Pos.Line != 1 || syntaxErr.Pos.Column != 1 {
|
||||||
t.Fatalf("want Lua rejection at the first byte, got %v, %v", program, err)
|
t.Fatalf("want Lua rejection at the first byte, got %v, %v", program, err)
|
||||||
@@ -57,7 +64,7 @@ func TestDownloadOneLuaGuard(t *testing.T) {
|
|||||||
if len(list.Entry) != 1 || list.Entry[0].Code != tc.code {
|
if len(list.Entry) != 1 || list.Entry[0].Code != tc.code {
|
||||||
t.Fatalf("header changed geodata: %v", &list)
|
t.Fatalf("header changed geodata: %v", &list)
|
||||||
}
|
}
|
||||||
if _, err := commongeodata.ParseDomainRules([]string{"ext:" + filepath.Base(staged.temp) + ":" + tc.code}, commongeodata.Domain_Full); err != nil {
|
if _, err := commongeodata.ParseDomainRules([]string{"ext:" + filepath.Base(staged.target) + ":" + tc.code}, commongeodata.Domain_Full); err != nil {
|
||||||
t.Fatalf("geodata loader rejected the header: %v", err)
|
t.Fatalf("geodata loader rejected the header: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,10 +21,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func TestProgramStatesAreIndependent(t *testing.T) {
|
func TestProgramStatesAreIndependent(t *testing.T) {
|
||||||
path := filepath.Join(t.TempDir(), "state.lua")
|
path := writeTestScript(t, "value = (value or 0) + 1")
|
||||||
if err := os.WriteFile(path, []byte("value = (value or 0) + 1"), 0o600); err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
program, err := Compile(path)
|
program, err := Compile(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
@@ -191,6 +188,22 @@ func TestCompileInlineDiagnostics(t *testing.T) {
|
|||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
func TestCompileFileExtension(t *testing.T) {
|
||||||
|
for _, name := range []string{"script", "script.dat", "script.lua.txt", "script.LUA"} {
|
||||||
|
path := filepath.Join(t.TempDir(), name)
|
||||||
|
if err := os.WriteFile(path, []byte("value = 42"), 0o600); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if program, err := Compile(path); program != nil || err == nil || !strings.Contains(err.Error(), "Lua file extension must be .lua") {
|
||||||
|
t.Fatalf("Compile(%q) = %v, %v; want nil program and .lua extension error", path, program, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
path := writeTestScript(t, "value = 42") + string(filepath.Separator) + "."
|
||||||
|
if program, err := Compile(path); program == nil || err != nil {
|
||||||
|
t.Fatalf("Compile(%q) = %v, %v; want acceptance of the resolved .lua path", path, program, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestCompileRejectsReadFailure(t *testing.T) {
|
func TestCompileRejectsReadFailure(t *testing.T) {
|
||||||
path := filepath.Join(t.TempDir(), "unreadable.lua")
|
path := filepath.Join(t.TempDir(), "unreadable.lua")
|
||||||
if err := os.WriteFile(path, []byte("value = 42"), 0o600); err != nil {
|
if err := os.WriteFile(path, []byte("value = 42"), 0o600); err != nil {
|
||||||
@@ -255,6 +268,10 @@ func writeTestScript(t *testing.T, code string) string {
|
|||||||
if err := os.WriteFile(path, []byte(code), 0o600); err != nil {
|
if err := os.WriteFile(path, []byte(code), 0o600); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
path, err := filepath.EvalSymlinks(path)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
return path
|
return path
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -93,7 +93,7 @@ func GetConfDirPath() string {
|
|||||||
return configPath
|
return configPath
|
||||||
}
|
}
|
||||||
|
|
||||||
// ResolveLuaFile finds a local Lua script and returns its absolute path.
|
// ResolveLuaFile finds a local .lua script and returns its resolved absolute path.
|
||||||
// Relative paths: XRAY_LOCATION_CONFDIR > XRAY_LOCATION_CONFIG > working dir > executable dir.
|
// Relative paths: XRAY_LOCATION_CONFDIR > XRAY_LOCATION_CONFIG > working dir > executable dir.
|
||||||
func ResolveLuaFile(path string) (string, error) {
|
func ResolveLuaFile(path string) (string, error) {
|
||||||
if path == "" {
|
if path == "" {
|
||||||
@@ -113,7 +113,22 @@ func ResolveLuaFile(path string) (string, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return resolveFile(paths)
|
path, err := resolveFile(paths)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return resolveLuaTarget(path)
|
||||||
|
}
|
||||||
|
|
||||||
|
func resolveLuaTarget(path string) (string, error) {
|
||||||
|
path, err := filepath.EvalSymlinks(path)
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("failed to resolve Lua file symlinks: %w", err)
|
||||||
|
}
|
||||||
|
if filepath.Ext(path) != ".lua" {
|
||||||
|
return "", errors.New("Lua file extension must be .lua")
|
||||||
|
}
|
||||||
|
return path, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func resolveFile(paths []string) (string, error) {
|
func resolveFile(paths []string) (string, error) {
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/xtls/xray-core/common"
|
"github.com/xtls/xray-core/common"
|
||||||
@@ -88,6 +89,10 @@ func TestResolveLuaFile(t *testing.T) {
|
|||||||
for _, path := range paths[:3] {
|
for _, path := range paths[:3] {
|
||||||
common.Must(os.WriteFile(path, nil, 0o600))
|
common.Must(os.WriteFile(path, nil, 0o600))
|
||||||
}
|
}
|
||||||
|
for i, path := range paths {
|
||||||
|
paths[i], err = filepath.EvalSymlinks(path)
|
||||||
|
common.Must(err)
|
||||||
|
}
|
||||||
if got, err := ResolveLuaFile(paths[2]); err != nil || got != paths[2] {
|
if got, err := ResolveLuaFile(paths[2]); err != nil || got != paths[2] {
|
||||||
t.Fatalf("absolute path = %q, %v; want %q", got, err, paths[2])
|
t.Fatalf("absolute path = %q, %v; want %q", got, err, paths[2])
|
||||||
}
|
}
|
||||||
@@ -115,3 +120,35 @@ func TestResolveLuaFile(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestResolveLuaFileSymlink(t *testing.T) {
|
||||||
|
for _, tc := range []struct {
|
||||||
|
link, target string
|
||||||
|
valid bool
|
||||||
|
}{
|
||||||
|
{"alias.lua", "data.dat", false},
|
||||||
|
{"alias.dat", "script.lua", true},
|
||||||
|
} {
|
||||||
|
t.Run(tc.link, func(t *testing.T) {
|
||||||
|
dir, err := filepath.EvalSymlinks(t.TempDir())
|
||||||
|
common.Must(err)
|
||||||
|
target := filepath.Join(dir, tc.target)
|
||||||
|
common.Must(os.WriteFile(target, nil, 0o600))
|
||||||
|
link := filepath.Join(dir, tc.link)
|
||||||
|
if err := os.Symlink(tc.target, link); err != nil {
|
||||||
|
if runtime.GOOS == "windows" {
|
||||||
|
t.Skipf("cannot create symlinks: %v", err)
|
||||||
|
}
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
got, err := ResolveLuaFile(link)
|
||||||
|
if tc.valid {
|
||||||
|
if err != nil || got != target {
|
||||||
|
t.Fatalf("ResolveLuaFile(%q) = %q, %v; want %q", link, got, err, target)
|
||||||
|
}
|
||||||
|
} else if err == nil || got != "" || !strings.Contains(err.Error(), "Lua file extension must be .lua") {
|
||||||
|
t.Fatalf("ResolveLuaFile(%q) = %q, %v; want .lua extension error", link, got, err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user