收紧运行目录与管理员本地文件读取边界
This commit is contained in:
parent
f732a255ce
commit
2dd5156018
@ -16,7 +16,15 @@ func MigrateLegacySSLStorage(root string) error {
|
||||
if !runtimepath.DeploymentLayout(root) {
|
||||
return nil
|
||||
}
|
||||
data, err := os.ReadFile(filepath.Join(root, "config", "config.json"))
|
||||
configRoot, err := os.OpenRoot(filepath.Join(root, "config"))
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
data, err := configRoot.ReadFile("config.json")
|
||||
_ = configRoot.Close()
|
||||
if os.IsNotExist(err) {
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -148,7 +148,15 @@ func pruneManagedSSLLocked(root string, protected []SSLConfig) error {
|
||||
}
|
||||
}
|
||||
// 磁盘引用也必须保留,避免其他管理器实例或已提交未发布的候选被删除。
|
||||
data, err := os.ReadFile(filepath.Join(root, "config", "ssl.json"))
|
||||
configRoot, err := os.OpenRoot(filepath.Join(root, "config"))
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
data, err := configRoot.ReadFile("ssl.json")
|
||||
_ = configRoot.Close()
|
||||
if err == nil {
|
||||
var section SSLSectionConfig
|
||||
if err := ParseStrict(data, §ion); err != nil {
|
||||
|
||||
@ -120,7 +120,12 @@ func findStartCaller() (callerIdentity, error) {
|
||||
if err != nil || (executable != "/usr/bin/systemctl" && executable != "/bin/systemctl") {
|
||||
continue
|
||||
}
|
||||
data, err := os.ReadFile(filepath.Join(base, "cmdline"))
|
||||
procRoot, err := os.OpenRoot(base)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
data, err := procRoot.ReadFile("cmdline")
|
||||
_ = procRoot.Close()
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
@ -132,7 +137,12 @@ func findStartCaller() (callerIdentity, error) {
|
||||
if !allowed {
|
||||
return callerIdentity{}, ErrUnauthorizedPeer
|
||||
}
|
||||
status, err := os.ReadFile(filepath.Join(base, "status"))
|
||||
procRoot, err = os.OpenRoot(base)
|
||||
if err != nil {
|
||||
return callerIdentity{}, ErrUnauthorizedPeer
|
||||
}
|
||||
status, err := procRoot.ReadFile("status")
|
||||
_ = procRoot.Close()
|
||||
if err != nil || !rootProcessStatus(string(status)) {
|
||||
return callerIdentity{}, ErrUnauthorizedPeer
|
||||
}
|
||||
|
||||
@ -36,6 +36,59 @@ func ReadRegularFile(path string, maxSize int64) ([]byte, error) {
|
||||
return data, nil
|
||||
}
|
||||
|
||||
func OpenRegularFile(path string, flags int, perm os.FileMode) (*os.File, error) {
|
||||
if strings.TrimSpace(path) == "" {
|
||||
return nil, ErrUnsafeRegularFile
|
||||
}
|
||||
absolute, err := filepath.Abs(filepath.Clean(path))
|
||||
if err != nil {
|
||||
return nil, ErrUnsafeRegularFile
|
||||
}
|
||||
root, err := os.OpenRoot(filepath.Dir(absolute))
|
||||
if err != nil {
|
||||
return nil, ErrUnsafeRegularFile
|
||||
}
|
||||
defer root.Close()
|
||||
|
||||
name := filepath.Base(absolute)
|
||||
info, err := root.Lstat(name)
|
||||
if err != nil && !os.IsNotExist(err) {
|
||||
return nil, ErrUnsafeRegularFile
|
||||
}
|
||||
if err == nil && (info.Mode()&os.ModeSymlink != 0 || !info.Mode().IsRegular()) {
|
||||
return nil, ErrUnsafeRegularFile
|
||||
}
|
||||
file, err := root.OpenFile(name, flags, perm)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
opened, err := file.Stat()
|
||||
if err != nil || !opened.Mode().IsRegular() {
|
||||
_ = file.Close()
|
||||
return nil, ErrUnsafeRegularFile
|
||||
}
|
||||
return file, nil
|
||||
}
|
||||
|
||||
func CreateExclusiveFile(path string, perm os.FileMode) (*os.File, error) {
|
||||
return OpenRegularFile(path, os.O_CREATE|os.O_EXCL|os.O_WRONLY, perm)
|
||||
}
|
||||
|
||||
func WriteRegularFile(path string, data []byte, perm os.FileMode) error {
|
||||
if strings.TrimSpace(path) == "" {
|
||||
return ErrUnsafeRegularFile
|
||||
}
|
||||
absolute, err := filepath.Abs(filepath.Clean(path))
|
||||
if err != nil {
|
||||
return ErrUnsafeRegularFile
|
||||
}
|
||||
root, err := os.OpenRoot(filepath.Dir(absolute))
|
||||
if err != nil {
|
||||
return ErrUnsafeRegularFile
|
||||
}
|
||||
defer root.Close()
|
||||
return root.WriteFile(filepath.Base(absolute), data, perm)
|
||||
}
|
||||
func ControlledRelativePath(base, value string) (string, error) {
|
||||
if strings.TrimSpace(value) == "" {
|
||||
return "", errors.New("path is required")
|
||||
|
||||
@ -180,7 +180,15 @@ func CheckReady(root string) error {
|
||||
return ErrMigrationRequired
|
||||
}
|
||||
// 已初始化部署缺失账号库或加密密钥时必须报错,不能按首次安装处理。
|
||||
raw, err := os.ReadFile(filepath.Join(root, "config", "config.json"))
|
||||
configRoot, err := os.OpenRoot(filepath.Join(root, "config"))
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
raw, err := configRoot.ReadFile("config.json")
|
||||
_ = configRoot.Close()
|
||||
if os.IsNotExist(err) {
|
||||
return nil
|
||||
}
|
||||
@ -279,7 +287,12 @@ func migrate(root string, rename func(string, string) error) ([]Move, error) {
|
||||
return nil, err
|
||||
}
|
||||
lockPath := filepath.Join(directory, migrationLock)
|
||||
lock, err := os.OpenFile(lockPath, os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0600)
|
||||
lockRoot, err := os.OpenRoot(directory)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
lock, err := lockRoot.OpenFile(migrationLock, os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0600)
|
||||
_ = lockRoot.Close()
|
||||
if err != nil {
|
||||
return nil, errors.New("无法取得迁移锁;请确认没有其他迁移进程,并人工核对中断现场")
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user