Skip to content

Commit

Permalink
🐛 Fix handling of socketMap
Browse files Browse the repository at this point in the history
Fixes #1434

Signed-off-by: Christian Zunker <[email protected]>
  • Loading branch information
czunker committed Oct 5, 2023
1 parent 406c336 commit ce289d7
Show file tree
Hide file tree
Showing 10 changed files with 166 additions and 112 deletions.
70 changes: 2 additions & 68 deletions providers/os/resources/port.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,20 +84,6 @@ var reLinuxProcNet = regexp.MustCompile(
"", // lots of other stuff if we want it...
)

// "lrwx------ 1 0 0 64 Dec 6 13:56 /proc/1/fd/12 -> socket:[37364]"
var reFindSockets = regexp.MustCompile(
"^[lrwx-]+\\s+" +
"\\d+\\s+" +
"\\d+\\s+" + // uid
"\\d+\\s+" + // gid
"\\d+\\s+" +
"[^ ]+\\s+" + // month, e.g. Dec
"\\d+\\s+" + // day
"\\d+:\\d+\\s+" + // time
"/proc/(\\d+)/fd/\\d+\\s+" + // path
"->\\s+" +
".*socket:\\[(\\d+)\\].*\\s*") // target

var TCP_STATES = map[int64]string{
1: "established",
2: "syn sent",
Expand Down Expand Up @@ -249,63 +235,11 @@ func (p *mqlPorts) processesBySocket() (map[int64]*mqlProcess, error) {
return nil, err
}

conn := p.MqlRuntime.Connection.(shared.Connection)
res := map[int64]*mqlProcess{}
if len(res) == 0 {
c, err := conn.RunCommand("find /proc -maxdepth 4 -path '/proc/*/fd/*' -exec ls -n {} \\;")
if err != nil {
p.processes2ports = plugin.TValue[map[int64]*mqlProcess]{
State: plugin.StateIsSet,
Error: errors.New("processes> could not run command: " + err.Error()),
}
return nil, p.processes2ports.Error
}

processesBySocket := map[int64]*mqlProcess{}
scanner := bufio.NewScanner(c.Stdout)
for scanner.Scan() {
line := scanner.Text()
pid, inode, err := parseLinuxFindLine(line)
if err != nil || (pid == 0 && inode == 0) {
continue
}

processesBySocket[inode] = processes.ByPID[pid]
}
processes.BySocketID = processesBySocket
res = processesBySocket
}

p.processes2ports = plugin.TValue[map[int64]*mqlProcess]{
Data: res,
Data: processes.BySocketID,
State: plugin.StateIsSet,
}
return res, err
}

func parseLinuxFindLine(line string) (int64, int64, error) {
if strings.HasSuffix(line, "Permission denied") || strings.HasSuffix(line, "No such file or directory") {
return 0, 0, nil
}

m := reFindSockets.FindStringSubmatch(line)
if len(m) == 0 {
return 0, 0, nil
}

pid, err := strconv.ParseInt(m[1], 10, 64)
if err != nil {
log.Error().Err(err).Msg("cannot parse unix pid " + m[1])
return 0, 0, err
}

inode, err := strconv.ParseInt(m[2], 10, 64)
if err != nil {
log.Error().Err(err).Msg("cannot parse socket inode " + m[2])
return 0, 0, err
}

return pid, inode, nil
return processes.BySocketID, err
}

// See:
Expand Down
42 changes: 0 additions & 42 deletions providers/os/resources/port_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,45 +85,3 @@ func TestParseLinuxProcNetIPv6(t *testing.T) {
assert.Equal(t, int64(0), port.RemotePort)
assert.Equal(t, "[::]", port.RemoteAddress)
}

func TestParseLinuxFind(t *testing.T) {
fi, err := os.Open("./ports/testdata/find_nginx_container.txt")
require.NoError(t, err)
defer fi.Close()

scanner := bufio.NewScanner(fi)
scanner.Scan()
line := scanner.Text()
pid, inode, err := parseLinuxFindLine(line)
require.NoError(t, err)
require.Equal(t, int64(0), pid)
require.Equal(t, int64(0), inode)

scanner.Scan()
line = scanner.Text()
pid, inode, err = parseLinuxFindLine(line)
require.NoError(t, err)
require.Equal(t, int64(0), pid)
require.Equal(t, int64(0), inode)

scanner.Scan()
line = scanner.Text()
pid, inode, err = parseLinuxFindLine(line)
require.NoError(t, err)
require.Equal(t, int64(1), pid)
require.Equal(t, int64(41866685), inode)

scanner.Scan()
line = scanner.Text()
pid, inode, err = parseLinuxFindLine(line)
require.NoError(t, err)
require.Equal(t, int64(0), pid)
require.Equal(t, int64(0), inode)

scanner.Scan()
line = scanner.Text()
pid, inode, err = parseLinuxFindLine(line)
require.NoError(t, err)
require.Equal(t, int64(0), pid)
require.Equal(t, int64(0), inode)
}
21 changes: 19 additions & 2 deletions providers/os/resources/processes.go
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,12 @@ func (p *mqlProcesses) list() ([]interface{}, error) {
}
log.Debug().Int("processes", len(processes)).Msg("mql[processes]> running processes")

processesInodesByPid, err := opm.ListSocketInodesByProcess()
if err != nil {
log.Warn().Err(err).Msg("mql[processes]> could not retrieve processes socket inodes")
return nil, fmt.Errorf("could not retrieve processes socket inodes")
}

procs := make([]interface{}, len(processes))

for i := range processes {
Expand All @@ -149,10 +155,21 @@ func (p *mqlProcesses) list() ([]interface{}, error) {
return nil, err
}

socketInodes := []int64{}
var socketInodesErr error
if _, ok := processesInodesByPid[proc.Pid]; ok {
socketInodes = processesInodesByPid[proc.Pid].Data
socketInodesErr = processesInodesByPid[proc.Pid].Error
} else {
if len(proc.SocketInodes) > 0 {
socketInodes = proc.SocketInodes
socketInodesErr = proc.SocketInodesError
}
}
process := o.(*mqlProcess)
process.SocketInodes = plugin.TValue[[]int64]{
Data: proc.SocketInodes,
Error: proc.SocketInodesError,
Data: socketInodes,
Error: socketInodesErr,
State: plugin.StateIsSet,
}

Expand Down
5 changes: 5 additions & 0 deletions providers/os/resources/processes/dockertop.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"fmt"
"strconv"

"go.mondoo.com/cnquery/providers-sdk/v1/plugin"
"go.mondoo.com/cnquery/providers/os/connection"
"go.mondoo.com/cnquery/providers/os/connection/shared"
)
Expand Down Expand Up @@ -90,3 +91,7 @@ func (lpm *DockerTopManager) Process(pid int64) (*OSProcess, error) {
}
return nil, fmt.Errorf("process with PID %d does not exist", pid)
}

func (lpm *DockerTopManager) ListSocketInodesByProcess() (map[int64]plugin.TValue[[]int64], error) {
return nil, nil
}
5 changes: 5 additions & 0 deletions providers/os/resources/processes/linuxproc.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"github.com/cockroachdb/errors"
"github.com/rs/zerolog/log"
"github.com/spf13/afero"
"go.mondoo.com/cnquery/providers-sdk/v1/plugin"
"go.mondoo.com/cnquery/providers/os/connection/shared"
"go.mondoo.com/cnquery/providers/os/resources/procfs"
)
Expand Down Expand Up @@ -108,3 +109,7 @@ func (lpm *LinuxProcManager) Process(pid int64) (*OSProcess, error) {

return process, nil
}

func (lpm *LinuxProcManager) ListSocketInodesByProcess() (map[int64]plugin.TValue[[]int64], error) {
return nil, nil
}
2 changes: 2 additions & 0 deletions providers/os/resources/processes/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ package processes
import (
"errors"

"go.mondoo.com/cnquery/providers-sdk/v1/plugin"
"go.mondoo.com/cnquery/providers/os/connection"
"go.mondoo.com/cnquery/providers/os/connection/mock"
"go.mondoo.com/cnquery/providers/os/connection/shared"
Expand All @@ -26,6 +27,7 @@ type OSProcessManager interface {
Exists(pid int64) (bool, error)
Process(pid int64) (*OSProcess, error)
List() ([]*OSProcess, error)
ListSocketInodesByProcess() (map[int64]plugin.TValue[[]int64], error)
}

func ResolveManager(conn shared.Connection) (OSProcessManager, error) {
Expand Down
5 changes: 5 additions & 0 deletions providers/os/resources/processes/ps1getprocess.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"io"

"github.com/rs/zerolog/log"
"go.mondoo.com/cnquery/providers-sdk/v1/plugin"
"go.mondoo.com/cnquery/providers/os/connection/shared"
"go.mondoo.com/cnquery/providers/os/resources/powershell"
)
Expand Down Expand Up @@ -176,3 +177,7 @@ func (wpm *WindowsProcessManager) Exists(pid int64) (bool, error) {
func (wpm *WindowsProcessManager) Process(pid int64) (*OSProcess, error) {
return nil, errors.New("not implemented")
}

func (wpm *WindowsProcessManager) ListSocketInodesByProcess() (map[int64]plugin.TValue[[]int64], error) {
return nil, errors.New("not implemented")
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ l-wx------ 1 0 0 64 Dec 13 05:40 /proc/1/fd/1 -> 'pipe:[41866636]'
lrwx------ 1 0 0 64 Dec 13 05:40 /proc/1/fd/3 -> 'socket:[41866685]'
ls: cannot read symbolic link '/proc/29/fd/0': Permission denied
lrwx------ 1 101 101 64 Dec 13 05:41 /proc/29/fd/0
lrwx------. 1 0 0 64 Oct 4 14:00 /proc/1/fd/11 -> socket:[18472]
75 changes: 75 additions & 0 deletions providers/os/resources/processes/unixps.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,33 @@ import (
"io"
"regexp"
"strconv"
"strings"
"time"

"github.com/kballard/go-shellquote"
"github.com/rs/zerolog/log"
"go.mondoo.com/cnquery/providers-sdk/v1/inventory"
"go.mondoo.com/cnquery/providers-sdk/v1/plugin"
"go.mondoo.com/cnquery/providers/os/connection/shared"
)

var (
LINUX_PS_REGEX = regexp.MustCompile(`^\s*([^ ]+)\s+([^ ]+)\s+([^ ]+)\s+([^ ]+)\s+([^ ]+)\s+([^ ]+)\s+([^ ]+)\s+([^ ]+)\s+([^ ]+)\s+([^ ]+)\s+([^ ].*)?$`)
UNIX_PS_REGEX = regexp.MustCompile(`^\s*([^ ]+)\s+([^ ]+)\s+([^ ]+)\s+([^ ]+)\s+([^ ]+)\s+([^ ]+)\s+([^ ]+)\s+([^ ]+)\s+([^ ]+)\s+([^ ].*)$`)

// "lrwx------ 1 0 0 64 Dec 6 13:56 /proc/1/fd/12 -> socket:[37364]"
reFindSockets = regexp.MustCompile(
"^[lrwx-]+\\.?\\s+" +
"\\d+\\s+" +
"\\d+\\s+" + // uid
"\\d+\\s+" + // gid
"\\d+\\s+" +
"[^ ]+\\s+" + // month, e.g. Dec
"\\d+\\s+" + // day
"\\d+:\\d+\\s+" + // time
"/proc/(\\d+)/fd/\\d+\\s+" + // path
"->\\s+" +
".*socket:\\[(\\d+)\\].*\\s*") // target
)

type ProcessEntry struct {
Expand Down Expand Up @@ -197,6 +214,39 @@ func (upm *UnixProcessManager) List() ([]*OSProcess, error) {
return ps, nil
}

// ListSocketInodesByProcess returns a map with a pid as key and a list of socket inodes as value
func (upm *UnixProcessManager) ListSocketInodesByProcess() (map[int64]plugin.TValue[[]int64], error) {
startTime := time.Now()
c, err := upm.conn.RunCommand("find /proc -maxdepth 4 -path '/proc/*/fd/*' -exec ls -n {} \\;")
if err != nil {
return nil, fmt.Errorf("processes> could not run command: %v", err)
}

processesInodesByPid := map[int64]plugin.TValue[[]int64]{}
scanner := bufio.NewScanner(c.Stdout)
for scanner.Scan() {
line := scanner.Text()
pid, inode, err := ParseLinuxFindLine(line)
if err != nil || (pid == 0 && inode == 0) {
pluginValue := processesInodesByPid[pid]
pluginValue.Error = err
processesInodesByPid[pid] = pluginValue
continue
}
pluginValue := plugin.TValue[[]int64]{}
if _, ok := processesInodesByPid[pid]; ok {
pluginValue = processesInodesByPid[pid]
pluginValue.Data = append(pluginValue.Data, inode)
} else {
pluginValue.Data = []int64{inode}
}
processesInodesByPid[pid] = pluginValue
}
log.Debug().Int64("duration (ms)", time.Duration(time.Since(startTime)).Milliseconds()).Msg("parsing find for process socket inodes")

return processesInodesByPid, nil
}

func (upm *UnixProcessManager) Exists(pid int64) (bool, error) {
process, err := upm.Process(pid)
if err != nil {
Expand Down Expand Up @@ -224,3 +274,28 @@ func (upm *UnixProcessManager) Process(pid int64) (*OSProcess, error) {

return nil, nil
}

func ParseLinuxFindLine(line string) (int64, int64, error) {
if strings.HasSuffix(line, "Permission denied") || strings.HasSuffix(line, "No such file or directory") {
return 0, 0, nil
}

m := reFindSockets.FindStringSubmatch(line)
if len(m) == 0 {
return 0, 0, nil
}

pid, err := strconv.ParseInt(m[1], 10, 64)
if err != nil {
log.Error().Err(err).Msg("cannot parse unix pid " + m[1])
return 0, 0, err
}

inode, err := strconv.ParseInt(m[2], 10, 64)
if err != nil {
log.Error().Err(err).Msg("cannot parse socket inode " + m[2])
return 0, 0, err
}

return pid, inode, nil
}
Loading

0 comments on commit ce289d7

Please sign in to comment.