Skip to content

Commit

Permalink
Handle multiple processes holding file
Browse files Browse the repository at this point in the history
  • Loading branch information
RebeccaMahany committed Dec 18, 2024
1 parent 511dbb0 commit e65370a
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 29 deletions.
48 changes: 27 additions & 21 deletions pkg/osquery/runtime/osqueryinstance.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import (
"github.com/osquery/osquery-go/plugin/config"
"github.com/osquery/osquery-go/plugin/distributed"
osquerylogger "github.com/osquery/osquery-go/plugin/logger"
"github.com/shirou/gopsutil/v3/process"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/trace"

Expand Down Expand Up @@ -731,7 +732,7 @@ func (i *OsqueryInstance) detectStaleDatabaseLock(ctx context.Context, paths *os

infoToLog := []any{
"lockfile_path", lockFilePath,
"lockfile_modtime", lockFileInfo.ModTime().String(),
"lockfile_modtime", lockFileInfo.ModTime().UTC().String(),
}

defer func() {
Expand All @@ -742,37 +743,42 @@ func (i *OsqueryInstance) detectStaleDatabaseLock(ctx context.Context, paths *os
}()

// Check to see whether the process holding the file still exists
p, err := getProcessHoldingFile(ctx, lockFilePath)
processes, err := getProcessesHoldingFile(ctx, lockFilePath)
if err != nil {
infoToLog = append(infoToLog, "err", err)
return false, fmt.Errorf("getting process holding file: %w", err)
}

// Grab more info to log from the process using the lockfile
infoToLog = append(infoToLog, "pid", p.Pid)
if name, err := p.NameWithContext(ctx); err == nil {
infoToLog = append(infoToLog, "process_name", name)
// Grab more info to log from the processes using the lockfile
processStrs := make([]string, len(processes))
for i, p := range processes {
processStrs[i] = processStr(ctx, p)
}
if cmdline, err := p.CmdlineWithContext(ctx); err == nil {
infoToLog = append(infoToLog, "process_cmdline", cmdline)
infoToLog = append(infoToLog, "processes", processStrs)

return true, nil
}

func processStr(ctx context.Context, p *process.Process) string {
name := "unknown"
uids := "unknown"
status := "unknown"
cmdline := "unknown"

if gotName, err := p.NameWithContext(ctx); err == nil {
name = gotName
}
if status, err := p.StatusWithContext(ctx); err == nil {
infoToLog = append(infoToLog, "process_status", status)
if gotUids, err := p.UidsWithContext(ctx); err == nil {
uids = fmt.Sprintf("%v", gotUids)
}
if isRunning, err := p.IsRunningWithContext(ctx); err == nil {
infoToLog = append(infoToLog, "process_is_running", isRunning)
if gotStatus, err := p.StatusWithContext(ctx); err == nil {
status = strings.Join(gotStatus, " ")
}
if parent, err := p.ParentWithContext(ctx); err == nil {
infoToLog = append(infoToLog, "process_parent_pid", parent.Pid)
if parentCmdline, err := parent.CmdlineWithContext(ctx); err == nil {
infoToLog = append(infoToLog, "process_parent_cmdline", parentCmdline)
}
if parentStatus, err := p.StatusWithContext(ctx); err == nil {
infoToLog = append(infoToLog, "process_parent_status", parentStatus)
}
if gotCmdline, err := p.CmdlineWithContext(ctx); err == nil {
cmdline = gotCmdline
}

return true, nil
return fmt.Sprintf("process with name `%s` and PID %d belonging to UIDs %s has current status `%s` (%s)", name, p.Pid, uids, status, cmdline)
}

// createOsquerydCommand uses osqueryOptions to return an *exec.Cmd
Expand Down
24 changes: 19 additions & 5 deletions pkg/osquery/runtime/runtime_helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ func isExitOk(_ error) bool {
return false
}

func getProcessHoldingFile(ctx context.Context, pathToFile string) (*process.Process, error) {
func getProcessesHoldingFile(ctx context.Context, pathToFile string) ([]*process.Process, error) {
cmd, err := allowedcmd.Lsof(ctx, "-t", pathToFile)
if err != nil {
return nil, fmt.Errorf("creating lsof command: %w", err)
Expand All @@ -57,10 +57,24 @@ func getProcessHoldingFile(ctx context.Context, pathToFile string) (*process.Pro
return nil, errors.New("no process found using file via lsof")
}

pid, err := strconv.ParseInt(pidStr, 10, 32)
if err != nil {
return nil, fmt.Errorf("invalid pid %s: %w", pidStr, err)
pidStrs := strings.Split(strings.TrimSpace(string(out)), "\n")
if len(pidStrs) == 0 {
return nil, errors.New("no processes found using file via lsof")
}

processes := make([]*process.Process, 0)
for _, pidStr := range pidStrs {
pid, err := strconv.ParseInt(pidStr, 10, 32)
if err != nil {
return nil, fmt.Errorf("invalid pid %s: %w", pidStr, err)
}

p, err := process.NewProcess(int32(pid))
if err != nil {
return nil, fmt.Errorf("getting process for %d: %w", pid, err)
}
processes = append(processes, p)
}

return process.NewProcess(int32(pid))
return processes, nil
}
12 changes: 9 additions & 3 deletions pkg/osquery/runtime/runtime_helpers_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,12 +82,13 @@ func isExitOk(err error) bool {
return false
}

func getProcessHoldingFile(ctx context.Context, pathToFile string) (*process.Process, error) {
func getProcessesHoldingFile(ctx context.Context, pathToFile string) ([]*process.Process, error) {
allProcesses, err := process.ProcessesWithContext(ctx)
if err != nil {
return nil, fmt.Errorf("getting process list: %w", err)
}

processes := make([]*process.Process, 0)
for _, p := range allProcesses {
openFiles, err := p.OpenFilesWithContext(ctx)
if err != nil {
Expand All @@ -100,9 +101,14 @@ func getProcessHoldingFile(ctx context.Context, pathToFile string) (*process.Pro
continue
}

return p, nil
processes = append(processes, p)
break
}
}

return nil, errors.New("no process found using file")
if len(processes) == 0 {
return nil, errors.New("no processes found using file")
}

return processes, nil
}

0 comments on commit e65370a

Please sign in to comment.