go.mondoo.com/cnquery@v0.0.0-20231005093811-59568235f6ea/providers/os/resources/processes/linuxproc_unix.go (about) 1 // Copyright (c) Mondoo, Inc. 2 // SPDX-License-Identifier: BUSL-1.1 3 4 //go:build !windows 5 6 package processes 7 8 import ( 9 "bytes" 10 "errors" 11 "fmt" 12 "io" 13 "io/fs" 14 "os" 15 "path/filepath" 16 "regexp" 17 "strconv" 18 "strings" 19 20 "github.com/rs/zerolog/log" 21 ) 22 23 var UNIX_INODE_REGEX = regexp.MustCompile(`^socket:\[(\d+)\]$`) 24 25 // Read out all connected sockets 26 // we will ignore all FD errors here since we may not have access to everything 27 func (lpm *LinuxProcManager) procSocketInods(pid int64, procPidPath string) ([]int64, error) { 28 fdDirPath := filepath.Join(procPidPath, "fd") 29 30 fdDir, err := lpm.conn.FileSystem().Open(fdDirPath) 31 if err != nil { 32 if errors.Is(err, os.ErrPermission) { 33 return nil, fs.ErrPermission 34 } 35 return nil, err 36 } 37 38 fds, err := fdDir.Readdirnames(-1) 39 if err != nil { 40 if errors.Is(err, os.ErrPermission) { 41 return nil, fs.ErrPermission 42 } 43 return nil, err 44 } 45 46 var res []int64 47 for i := range fds { 48 fdPath := filepath.Join(fdDirPath, fds[i]) 49 fdInfo, err := lpm.conn.FileSystem().Stat(fdPath) 50 if err != nil { 51 continue 52 } 53 54 if fdInfo.Mode()&fs.ModeSocket == 0 { 55 continue 56 } 57 58 inode, err := lpm.getInodeFromFd(fdPath) 59 if err != nil { 60 log.Error().Err(err).Msg("cannot get inode for fd") 61 continue 62 } 63 64 res = append(res, inode) 65 } 66 67 return res, nil 68 } 69 70 func (lpm *LinuxProcManager) getInodeFromFd(fdPath string) (int64, error) { 71 var inode int64 72 command := fmt.Sprintf("readlink %s", fdPath) 73 c, err := lpm.conn.RunCommand(command) 74 if err != nil { 75 return inode, fmt.Errorf("processes> could not run command: %v", err) 76 } 77 return readInodeFromOutput(c.Stdout) 78 } 79 80 func readInodeFromOutput(reader io.Reader) (int64, error) { 81 var inode int64 82 buf := &bytes.Buffer{} 83 _, err := buf.ReadFrom(reader) 84 if err != nil { 85 return inode, fmt.Errorf("processes> could not read command output: %v", err) 86 } 87 line := strings.TrimSuffix(buf.String(), "\n") 88 if line == "" { 89 return inode, fmt.Errorf("processes> could not get inode from fd") 90 } 91 m := UNIX_INODE_REGEX.FindStringSubmatch(line) 92 inode, err = strconv.ParseInt(m[1], 10, 64) 93 if err != nil { 94 return inode, fmt.Errorf("processes> could not parse inode: %v", err) 95 } 96 return inode, nil 97 }