boxx: Fix unsafe installation
This commit is contained in:
@@ -12,6 +12,17 @@ import (
|
||||
"golang.org/x/sys/windows/svc/eventlog"
|
||||
)
|
||||
|
||||
var commandRunFlagAllowUnsafeInstallation bool
|
||||
|
||||
func init() {
|
||||
commandRun.Flags().BoolVar(
|
||||
&commandRunFlagAllowUnsafeInstallation,
|
||||
"allow-unsafe-installation-directory-permissions",
|
||||
false,
|
||||
"allow unsafe daemon working directory ancestor permissions",
|
||||
)
|
||||
}
|
||||
|
||||
func runService() (bool, error) {
|
||||
isWindowsService, err := svc.IsWindowsService()
|
||||
if err != nil {
|
||||
@@ -27,7 +38,10 @@ func preparePlatformWorkingDirectory() error {
|
||||
if listenAddress != "" {
|
||||
return os.MkdirAll(workingDirectory, 0o700)
|
||||
}
|
||||
serviceWorkingDirectory, err := resolveWindowsServiceWorkingDirectory(workingDirectory)
|
||||
serviceWorkingDirectory, err := resolveWindowsServiceWorkingDirectory(
|
||||
workingDirectory,
|
||||
commandRunFlagAllowUnsafeInstallation,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -66,7 +66,7 @@ func addPlatformServiceCommands() {
|
||||
&commandServiceFlagAllowUnsafeInstallation,
|
||||
"allow-unsafe-installation-directory-permissions",
|
||||
false,
|
||||
"skip installation path security validation and permission hardening",
|
||||
"allow unsafe installation path security and daemon working directory ancestor permissions",
|
||||
)
|
||||
commandService.AddCommand(commandServiceInstall)
|
||||
commandService.AddCommand(commandServiceUninstall)
|
||||
@@ -128,7 +128,10 @@ func serviceInstall() error {
|
||||
if err != nil {
|
||||
return E.Cause(err, "get executable path")
|
||||
}
|
||||
serviceWorkingDirectory, err := resolveWindowsServiceWorkingDirectory(commandServiceFlagWorkingDirectory)
|
||||
serviceWorkingDirectory, err := resolveWindowsServiceWorkingDirectory(
|
||||
commandServiceFlagWorkingDirectory,
|
||||
commandServiceFlagAllowUnsafeInstallation,
|
||||
)
|
||||
if err != nil {
|
||||
return E.Cause(err, "validate working directory")
|
||||
}
|
||||
@@ -146,6 +149,9 @@ func serviceInstall() error {
|
||||
}
|
||||
defer manager.Disconnect()
|
||||
arguments := []string{"run", "--working-directory", serviceWorkingDirectory}
|
||||
if commandServiceFlagAllowUnsafeInstallation {
|
||||
arguments = append(arguments, "--allow-unsafe-installation-directory-permissions")
|
||||
}
|
||||
config := mgr.Config{
|
||||
DisplayName: serviceDisplayName,
|
||||
Description: serviceDescriptionText,
|
||||
|
||||
@@ -67,7 +67,7 @@ func secureWindowsInstallation(executablePath string, allowUnsafeInstallation bo
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
err = validateInstallationAncestors(filepath.Dir(installationDirectory), volumeRoot, true)
|
||||
err = validateInstallationAncestors(filepath.Dir(installationDirectory), volumeRoot, false)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
@@ -336,7 +336,7 @@ func validateFixedNTFSVolume(path string) (string, error) {
|
||||
return filepath.Clean(volumePath), nil
|
||||
}
|
||||
|
||||
func resolveWindowsServiceWorkingDirectory(path string) (string, error) {
|
||||
func resolveWindowsServiceWorkingDirectory(path string, allowUnsafePermissions bool) (string, error) {
|
||||
if path == "" {
|
||||
return "", E.New("missing daemon working directory")
|
||||
}
|
||||
@@ -363,18 +363,18 @@ func resolveWindowsServiceWorkingDirectory(path string) (string, error) {
|
||||
if strings.EqualFold(cleanPath, filepath.Clean(volumeRoot)) {
|
||||
return "", E.New("daemon working directory must not be a volume root")
|
||||
}
|
||||
err = validateInstallationAncestors(parentPath, volumeRoot, true)
|
||||
err = validateInstallationAncestors(parentPath, volumeRoot, allowUnsafePermissions)
|
||||
if err != nil {
|
||||
return "", E.Cause(err, "validate daemon working directory ancestors")
|
||||
}
|
||||
return cleanPath, nil
|
||||
}
|
||||
|
||||
func validateInstallationAncestors(path string, volumeRoot string, validatePermissions bool) error {
|
||||
func validateInstallationAncestors(path string, volumeRoot string, allowUnsafePermissions bool) error {
|
||||
currentPath := filepath.Clean(path)
|
||||
cleanVolumeRoot := filepath.Clean(volumeRoot)
|
||||
for {
|
||||
err := validateInstallationAncestor(currentPath, validatePermissions)
|
||||
err := validateInstallationAncestor(currentPath, allowUnsafePermissions)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -389,7 +389,7 @@ func validateInstallationAncestors(path string, volumeRoot string, validatePermi
|
||||
}
|
||||
}
|
||||
|
||||
func validateInstallationAncestor(path string, validatePermissions bool) error {
|
||||
func validateInstallationAncestor(path string, allowUnsafePermissions bool) error {
|
||||
attributes, err := windowsFileAttributes(path)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -400,9 +400,6 @@ func validateInstallationAncestor(path string, validatePermissions bool) error {
|
||||
if attributes&windows.FILE_ATTRIBUTE_REPARSE_POINT != 0 {
|
||||
return E.New("installation ancestor is a reparse point: ", path)
|
||||
}
|
||||
if !validatePermissions {
|
||||
return nil
|
||||
}
|
||||
descriptor, err := windows.GetNamedSecurityInfo(
|
||||
path,
|
||||
windows.SE_FILE_OBJECT,
|
||||
@@ -443,7 +440,7 @@ func validateInstallationAncestor(path string, validatePermissions bool) error {
|
||||
continue
|
||||
}
|
||||
principal := (*windows.SID)(unsafe.Pointer(&accessControlEntry.SidStart))
|
||||
if !trustedAdministrativeUser(principal) {
|
||||
if !trustedAdministrativeUser(principal) && !allowUnsafePermissions {
|
||||
return E.New("installation ancestor is replaceable by an unprivileged principal: ", path)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user