[medium] prevent agentdestroy module from removing executable in use

This commit is contained in:
Julien Vehent 2014-12-19 12:48:14 -05:00
Родитель 4665b20349
Коммит ddbf9745ee
1 изменённых файлов: 36 добавлений и 21 удалений

Просмотреть файл

@ -5,12 +5,12 @@
// Contributor: Julien Vehent jvehent@mozilla.com [:ulfr] // Contributor: Julien Vehent jvehent@mozilla.com [:ulfr]
// agentdestroy is a module used in the upgrade protocol to kill an agent // agentdestroy is a module used in the upgrade protocol to kill an agent
// that has been upgraded, and remove its binary from the file system. // that has been upgraded. This module will refuse to suicide, meaning that
// The only sanity check it does, aside from validating the parameters, is // an agent will not run this module against itself
// refusing to suicide. Meaning an agent will not run this module against itself.
package agentdestroy package agentdestroy
import ( import (
"bitbucket.org/kardianos/osext"
"encoding/json" "encoding/json"
"fmt" "fmt"
"mig" "mig"
@ -77,35 +77,50 @@ func (r Runner) Run(Args []byte) string {
} }
// get the path of the agent's executable // get the path of the agent's executable
var binary string var targetExecutable string
switch runtime.GOOS { switch runtime.GOOS {
case "linux", "darwin", "freebsd", "openbsd", "netbsd": case "linux", "darwin", "freebsd", "openbsd", "netbsd":
binary, err = os.Readlink(fmt.Sprintf("/proc/%d/exe", r.Parameters.PID)) targetExecutable, err = os.Readlink(fmt.Sprintf("/proc/%d/exe", r.Parameters.PID))
if err != nil { if err != nil {
r.Results.Errors = append(r.Results.Errors, fmt.Sprintf("Binary path of PID '%d' not found: '%v'", r.Parameters.PID, err)) r.Results.Errors = append(r.Results.Errors, fmt.Sprintf("Executable path of PID '%d' not found: '%v'", r.Parameters.PID, err))
return r.buildResults() return r.buildResults()
} }
case "windows": case "windows":
binary = fmt.Sprintf("C:/Windows/mig-agent-%s.exe", r.Parameters.Version) targetExecutable = fmt.Sprintf("C:/Windows/mig-agent-%s.exe", r.Parameters.Version)
default: default:
r.Results.Errors = append(r.Results.Errors, fmt.Sprintf("'%s' isn't a supported OS", runtime.GOOS)) r.Results.Errors = append(r.Results.Errors, fmt.Sprintf("'%s' isn't a supported OS", runtime.GOOS))
return r.buildResults() return r.buildResults()
} }
// verify that the executable we're removing isn't in use by the current agent
// this can happen when two agents are running of the same executable
// in which case, do not remove the executable, and only kill the process
myExecutable, err := osext.Executable()
if err != nil {
r.Results.Errors = append(r.Results.Errors, fmt.Sprintf("Failed to retrieve my executable location: '%v'", err))
return r.buildResults()
}
removeExecutable := true
if myExecutable == targetExecutable {
r.Results.Errors = append(r.Results.Errors, "Executable not removed because current agent uses it as well")
removeExecutable = false
}
// check that the binary we're removing has the right version if removeExecutable {
version, err := getAgentVersion(binary) // check that the binary we're removing has the right version
if err != nil { version, err := getAgentVersion(targetExecutable)
r.Results.Errors = append(r.Results.Errors, fmt.Sprintf("Failed to check agent version: '%v'", err)) if err != nil {
return r.buildResults() r.Results.Errors = append(r.Results.Errors, fmt.Sprintf("Failed to check agent version: '%v'", err))
} return r.buildResults()
if version != r.Parameters.Version { }
r.Results.Errors = append(r.Results.Errors, fmt.Sprintf("Version mismatch. Expected '%s', found '%s'", r.Parameters.Version, version)) if version != r.Parameters.Version {
return r.buildResults() r.Results.Errors = append(r.Results.Errors, fmt.Sprintf("Version mismatch. Expected '%s', found '%s'", r.Parameters.Version, version))
} return r.buildResults()
err = os.Remove(binary) }
if err != nil { err = os.Remove(targetExecutable)
r.Results.Errors = append(r.Results.Errors, fmt.Sprintf("Failed to remove binary '%s': '%v'", binary, err)) if err != nil {
return r.buildResults() r.Results.Errors = append(r.Results.Errors, fmt.Sprintf("Failed to remove executable '%s': '%v'", targetExecutable, err))
return r.buildResults()
}
} }
// Then kill the PID // Then kill the PID