mirror of
https://gitclone.com/github.com/MetaCubeX/Clash.Meta
synced 2025-05-24 02:48:02 +08:00
chore: the updateConfigs api also adds a check for SAFE_PATHS
This commit is contained in:
parent
a4fcd3af07
commit
2116640886
@ -138,7 +138,7 @@ func NewSsh(option SshOption) (*Ssh, error) {
|
||||
} else {
|
||||
path := C.Path.Resolve(option.PrivateKey)
|
||||
if !C.Path.IsSafePath(path) {
|
||||
return nil, fmt.Errorf("path is not subpath of home directory: %s", path)
|
||||
return nil, C.Path.ErrNotSafePath(path)
|
||||
}
|
||||
b, err = os.ReadFile(path)
|
||||
if err != nil {
|
||||
|
@ -17,7 +17,6 @@ import (
|
||||
|
||||
var (
|
||||
errVehicleType = errors.New("unsupport vehicle type")
|
||||
errSubPath = errors.New("path is not subpath of home directory")
|
||||
)
|
||||
|
||||
type healthCheckSchema struct {
|
||||
@ -115,7 +114,7 @@ func ParseProxyProvider(name string, mapping map[string]any) (types.ProxyProvide
|
||||
if schema.Path != "" {
|
||||
path = C.Path.Resolve(schema.Path)
|
||||
if !C.Path.IsSafePath(path) {
|
||||
return nil, fmt.Errorf("%w: %s", errSubPath, path)
|
||||
return nil, C.Path.ErrNotSafePath(path)
|
||||
}
|
||||
}
|
||||
vehicle = resource.NewHTTPVehicle(schema.URL, path, schema.Proxy, schema.Header, resource.DefaultHttpTimeout, schema.SizeLimit)
|
||||
|
@ -83,7 +83,7 @@ func GetCertPool(customCA string, customCAString string) (*x509.CertPool, error)
|
||||
if len(customCA) > 0 {
|
||||
path := C.Path.Resolve(customCA)
|
||||
if !C.Path.IsSafePath(path) {
|
||||
return nil, fmt.Errorf("path is not subpath of home directory: %s", path)
|
||||
return nil, C.Path.ErrNotSafePath(path)
|
||||
}
|
||||
certificate, err = os.ReadFile(path)
|
||||
if err != nil {
|
||||
|
@ -17,6 +17,7 @@ import (
|
||||
type Path interface {
|
||||
Resolve(path string) string
|
||||
IsSafePath(path string) bool
|
||||
ErrNotSafePath(path string) error
|
||||
}
|
||||
|
||||
// LoadTLSKeyPair loads a TLS key pair from the provided certificate and private key data or file paths, supporting fallback resolution.
|
||||
@ -42,10 +43,12 @@ func LoadTLSKeyPair(certificate, privateKey string, path Path) (tls.Certificate,
|
||||
certificate = path.Resolve(certificate)
|
||||
privateKey = path.Resolve(privateKey)
|
||||
var loadErr error
|
||||
if path.IsSafePath(certificate) && path.IsSafePath(privateKey) {
|
||||
cert, loadErr = tls.LoadX509KeyPair(certificate, privateKey)
|
||||
if !path.IsSafePath(certificate) {
|
||||
loadErr = path.ErrNotSafePath(certificate)
|
||||
} else if !path.IsSafePath(privateKey) {
|
||||
loadErr = path.ErrNotSafePath(privateKey)
|
||||
} else {
|
||||
loadErr = fmt.Errorf("path is not subpath of home directory")
|
||||
cert, loadErr = tls.LoadX509KeyPair(certificate, privateKey)
|
||||
}
|
||||
if loadErr != nil {
|
||||
return tls.Certificate{}, fmt.Errorf("parse certificate failed, maybe format error:%s, or path error: %s", painTextErr.Error(), loadErr.Error())
|
||||
|
@ -755,7 +755,7 @@ func parseGeneral(cfg *RawConfig) (*General, error) {
|
||||
|
||||
func parseController(cfg *RawConfig) (*Controller, error) {
|
||||
if path := cfg.ExternalUI; path != "" && !C.Path.IsSafePath(path) {
|
||||
return nil, fmt.Errorf("path is not subpath of home directory: %s", path)
|
||||
return nil, C.Path.ErrNotSafePath(path)
|
||||
}
|
||||
return &Controller{
|
||||
ExternalController: cfg.ExternalController,
|
||||
|
@ -1,6 +1,7 @@
|
||||
package constant
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
P "path"
|
||||
"path/filepath"
|
||||
@ -87,10 +88,8 @@ func (p *path) IsSafePath(path string) bool {
|
||||
if p.allowUnsafePath || features.CMFA {
|
||||
return true
|
||||
}
|
||||
homedir := p.HomeDir()
|
||||
path = p.Resolve(path)
|
||||
safePaths := append([]string{homedir}, p.safePaths...) // add homedir to safePaths
|
||||
for _, safePath := range safePaths {
|
||||
for _, safePath := range p.SafePaths() {
|
||||
if rel, err := filepath.Rel(safePath, path); err == nil {
|
||||
if filepath.IsLocal(rel) {
|
||||
return true
|
||||
@ -100,6 +99,23 @@ func (p *path) IsSafePath(path string) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (p *path) SafePaths() []string {
|
||||
return append([]string{p.homeDir}, p.safePaths...) // add homedir to safePaths
|
||||
}
|
||||
|
||||
func (p *path) ErrNotSafePath(path string) error {
|
||||
return ErrNotSafePath{Path: path, SafePaths: p.SafePaths()}
|
||||
}
|
||||
|
||||
type ErrNotSafePath struct {
|
||||
Path string
|
||||
SafePaths []string
|
||||
}
|
||||
|
||||
func (e ErrNotSafePath) Error() string {
|
||||
return fmt.Sprintf("path is not subpath of home directory or SAFE_PATHS: %s \n allowed paths: %s", e.Path, e.SafePaths)
|
||||
}
|
||||
|
||||
func (p *path) GetPathByHash(prefix, name string) string {
|
||||
hash := utils.MakeHash([]byte(name))
|
||||
filename := hash.String()
|
||||
|
@ -371,12 +371,20 @@ func updateConfigs(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
} else {
|
||||
if req.Path == "" {
|
||||
if req.Path == "" { // default path unneeded any safe check
|
||||
req.Path = C.Path.Config()
|
||||
} else if !filepath.IsAbs(req.Path) {
|
||||
render.Status(r, http.StatusBadRequest)
|
||||
render.JSON(w, r, newError("path is not a absolute path"))
|
||||
return
|
||||
} else {
|
||||
if !filepath.IsAbs(req.Path) {
|
||||
render.Status(r, http.StatusBadRequest)
|
||||
render.JSON(w, r, newError("path is not a absolute path"))
|
||||
return
|
||||
}
|
||||
|
||||
if !C.Path.IsSafePath(req.Path) {
|
||||
render.Status(r, http.StatusBadRequest)
|
||||
render.JSON(w, r, newError(C.Path.ErrNotSafePath(req.Path).Error()))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
cfg, err = executor.ParseWithPath(req.Path)
|
||||
|
@ -1,7 +1,6 @@
|
||||
package provider
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
@ -12,10 +11,6 @@ import (
|
||||
"github.com/metacubex/mihomo/rules/common"
|
||||
)
|
||||
|
||||
var (
|
||||
errSubPath = errors.New("path is not subpath of home directory")
|
||||
)
|
||||
|
||||
type ruleProviderSchema struct {
|
||||
Type string `provider:"type"`
|
||||
Behavior string `provider:"behavior"`
|
||||
@ -53,7 +48,7 @@ func ParseRuleProvider(name string, mapping map[string]any, parse common.ParseRu
|
||||
if schema.Path != "" {
|
||||
path = C.Path.Resolve(schema.Path)
|
||||
if !C.Path.IsSafePath(path) {
|
||||
return nil, fmt.Errorf("%w: %s", errSubPath, path)
|
||||
return nil, C.Path.ErrNotSafePath(path)
|
||||
}
|
||||
}
|
||||
vehicle = resource.NewHTTPVehicle(schema.URL, path, schema.Proxy, nil, resource.DefaultHttpTimeout, schema.SizeLimit)
|
||||
|
Loading…
Reference in New Issue
Block a user