github.com/pyroscope-io/pyroscope@v0.37.3-0.20230725203016-5f6947968bd0/pkg/exec/cli_unix.go (about)

     1  //go:build !windows
     2  // +build !windows
     3  
     4  package exec
     5  
     6  import (
     7  	"os"
     8  	goexec "os/exec"
     9  	"os/user"
    10  	"regexp"
    11  	"strconv"
    12  	"syscall"
    13  
    14  	"github.com/sirupsen/logrus"
    15  )
    16  
    17  func adjustCmd(cmd *goexec.Cmd, noRootDrop bool, userName, groupName string) error {
    18  	cmd.SysProcAttr = &syscall.SysProcAttr{}
    19  	// permissions drop
    20  	if isRoot() && !noRootDrop && os.Getenv("SUDO_UID") != "" && os.Getenv("SUDO_GID") != "" {
    21  		creds, err := generateCredentialsDrop()
    22  		if err != nil {
    23  			logrus.Errorf("failed to drop permissions, %q", err)
    24  		} else {
    25  			cmd.SysProcAttr.Credential = creds
    26  		}
    27  	}
    28  
    29  	if userName != "" || groupName != "" {
    30  		creds, err := generateCredentials(userName, groupName)
    31  		if err != nil {
    32  			logrus.Errorf("failed to generate credentials: %q", err)
    33  		} else {
    34  			cmd.SysProcAttr.Credential = creds
    35  		}
    36  	}
    37  	cmd.SysProcAttr.Setpgid = true
    38  	return nil
    39  }
    40  
    41  func isRoot() bool {
    42  	u, err := user.Current()
    43  	return err == nil && u.Username == "root"
    44  }
    45  
    46  func generateCredentialsDrop() (*syscall.Credential, error) {
    47  	sudoUser := os.Getenv("SUDO_USER")
    48  	sudoUID := os.Getenv("SUDO_UID")
    49  	sudoGid := os.Getenv("SUDO_GID")
    50  
    51  	logrus.Infof("dropping permissions, running command as %q (%s/%s)", sudoUser, sudoUID, sudoGid)
    52  
    53  	uid, err := strconv.Atoi(sudoUID)
    54  	if err != nil {
    55  		return nil, err
    56  	}
    57  	gid, err := strconv.Atoi(sudoGid)
    58  	if err != nil {
    59  		return nil, err
    60  	}
    61  
    62  	return &syscall.Credential{Uid: uint32(uid), Gid: uint32(gid)}, nil
    63  }
    64  
    65  var digitCheck = regexp.MustCompile(`^[0-9]+$`)
    66  
    67  func generateCredentials(userName, groupName string) (*syscall.Credential, error) {
    68  	c := syscall.Credential{}
    69  
    70  	var u *user.User
    71  	var g *user.Group
    72  	var err error
    73  
    74  	if userName != "" {
    75  		if digitCheck.MatchString(userName) {
    76  			u, err = user.LookupId(userName)
    77  		} else {
    78  			u, err = user.Lookup(userName)
    79  		}
    80  		if err != nil {
    81  			return nil, err
    82  		}
    83  
    84  		uid, _ := strconv.Atoi(u.Uid)
    85  		c.Uid = uint32(uid)
    86  	}
    87  
    88  	if groupName != "" {
    89  		if digitCheck.MatchString(groupName) {
    90  			g, err = user.LookupGroupId(groupName)
    91  		} else {
    92  			g, err = user.LookupGroup(groupName)
    93  		}
    94  		if err != nil {
    95  			return nil, err
    96  		}
    97  
    98  		gid, _ := strconv.Atoi(g.Gid)
    99  		c.Gid = uint32(gid)
   100  	}
   101  
   102  	return &c, nil
   103  }