mirror of
https://gitcode.com/JianFeeeee/ModelRouter.git
synced 2026-11-12 20:27:23 +00:00
feat(lua): 适配器导入路径冲突校验(R6)——防静默覆盖与路径逃逸
用户要求:导入适配器时必须检查路径冲突,避免静默错误。 之前 UploadAdapter(name, code) 直接拼 adapter_dir/<name>.lua: - name 含 "../" 或绝对路径会写到目录外 - name 与内置同名会静默覆盖,加载失败只报 "adapter X missing", 现场与病因分离 实现(internal/lua/adapter_validate.go): - ValidateAdapterName:字符集 ^[a-zA-Z0-9_-]+$,拒绝 /、\、..、绝对路径、空白 - ValidateAdapterPath:文件必须在 adapter_dir 内 - VM.InstallPluginAdapter:插件装内置名 → ErrAdapterNameReserved 拒 - Core.UploadAdapter:在 WriteFile 之前校验(防路径逃逸) - Core.RemoveAdapter:也校验名字(防 os.Remove 越界) 设计取舍:保留名禁止只对插件生效,不对运维生效。 - operator 放 openai.lua 覆盖内置 = 文档化的热覆盖机制,放行 - 第三方插件静默换掉内核自带的协议翻译 = 篡改发行物,拒绝 - 先误做成了全拒,Start() 加载内置适配器直接崩,测试抓住后改对 (TestLoadBundledAdapters 等锁住回归) 测试 12 个:路径穿越/绝对路径/保留段/空白/内置覆盖(允许 vs 插件拒绝)/ 目录外加载/错误点名/热重载不回归。 验证:go test -tags luajit ./... 全绿。
This commit is contained in:
@ -8,10 +8,10 @@ import (
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/url"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"net/url"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
@ -874,6 +874,14 @@ func (c *Core) UploadAdapter(name, code string) error {
|
||||
if name == "" {
|
||||
return fmt.Errorf("adapter name required")
|
||||
}
|
||||
// Validate name SAFETY before touching the filesystem (R6). A path-traversal
|
||||
// name ("../openai") must be rejected BEFORE WriteFile, or it would already
|
||||
// have escaped the adapter dir by the time LoadAdapter re-checks. Built-in
|
||||
// names are allowed here: an admin uploading openai.lua is the documented
|
||||
// override, same as placing the file in adapter_dir by hand.
|
||||
if err := lua.ValidateAdapterName(name, nil); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := os.MkdirAll(c.cfg.AdapterDir, 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
@ -885,6 +893,13 @@ func (c *Core) UploadAdapter(name, code string) error {
|
||||
}
|
||||
|
||||
func (c *Core) RemoveAdapter(name string) error {
|
||||
// Validate the name so a traversal name cannot os.Remove a file outside the
|
||||
// adapter dir. A reserved (built-in) name is a legitimate delete target in
|
||||
// the running VM, so reserved-name rejection is NOT applied here — only the
|
||||
// path-safety character set is.
|
||||
if err := lua.ValidateAdapterName(name, nil); err != nil {
|
||||
return err
|
||||
}
|
||||
path := filepath.Join(c.cfg.AdapterDir, name+".lua")
|
||||
_ = os.Remove(path)
|
||||
c.vm.RemoveAdapter(name)
|
||||
|
||||
Reference in New Issue
Block a user