fix: service binary overwrite privilege escalation vuln

This commit is contained in:
go-compile 2024-02-18 16:24:20 +00:00
parent bd99e3e09d
commit c0a5e389d9
No known key found for this signature in database
GPG key ID: 53F4922E9D5497B8
2 changed files with 51 additions and 0 deletions
internal/home

View file

@ -748,6 +748,7 @@ func writePIDFile(fn string) bool {
// initConfigFilename sets up context config file path. This file path can be
// overridden by command-line arguments, or is set to default.
func initConfigFilename(opts options) {
// TODO: if running as service the config location should be /etc/AdGuardHome/AdGuardHome.yaml
Context.configFilename = stringutil.Coalesce(opts.confFilename, "AdGuardHome.yaml")
}
@ -760,6 +761,8 @@ func initWorkingDir(opts options) (err error) {
return err
}
// TODO: if running as a service use /var/lib/AdGuardHome
if opts.workDir != "" {
// If there is a custom config file, use it's directory as our working dir
Context.workDir = opts.workDir

View file

@ -304,6 +304,11 @@ func handleServiceStatusCommand(s service.Service) {
// handleServiceStatusCommand handles service "install" command
func handleServiceInstallCommand(s service.Service) {
// Set the binary's permissions and move to /usr/bin (if on linux)
if err := secureBinary(); err != nil {
log.Fatal(err)
}
err := svcAction(s, "install")
if err != nil {
log.Fatalf("service: executing action %q: %s", "install", err)
@ -681,3 +686,46 @@ rc_bg=YES
rc_cmd $1
`
// secureBinary is used before service.Install(). This function protects AdGuardHome from
// privilege escalation vulnerabilities caused by writable files
func secureBinary() error {
switch runtime.GOOS {
case "windows":
// TODO: support windows service support securely
// Set file owner to admin/system and public permissions read-only
return errors.Error("you currently cannot install adguardhome as a service on window")
default:
return secureBinaryUnix()
}
}
func secureBinaryUnix() error {
// Installalation can only be completed with root privileges, so check and handle if not
if os.Getuid() != 0 {
return errors.Error("permission denied. Root privileges required")
}
// Get current file path
binary := os.Args[0]
// Change owner to root:root
err := os.Chown(binary, 0, 0)
if err != nil {
return err
}
// Set permissions to root(read,write,exec), group(read,exec), public(read)
// This combined with changing the owner make the file undeletable without root privlages
// UNLESS THE PARENT FOLDER IS WRITABLE!
if err := os.Chmod(binary, 0755); err != nil {
return err
}
// Move binary to the PATH in a folder which is read-only to non root users
if err := os.Rename(binary, "/usr/bin/AdGuardHome"); err != nil {
return err
}
return nil
}