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  }