Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Spawn processes with the correct GID. #2791

Merged
merged 1 commit into from
Jun 24, 2019
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 44 additions & 20 deletions lib/srv/exec.go
Original file line number Diff line number Diff line change
Expand Up @@ -309,36 +309,60 @@ func prepareCommand(ctx *ServerContext) (*exec.Cmd, error) {
teleport.SSHTeleportClusterName + "=" + clusterName.GetClusterName(),
}
c.Dir = osUser.HomeDir
c.SysProcAttr = &syscall.SysProcAttr{}

// execute the command under requested user's UID:GID
me, err := user.Current()
// Lookup all groups the user is a member of.
userGroups, err := osUser.GroupIds()
if err != nil {
return nil, trace.Wrap(err)
}
if me.Uid != osUser.Uid || me.Gid != osUser.Gid {
userGroups, err := osUser.GroupIds()
groups := make([]uint32, 0)
for _, sgid := range userGroups {
igid, err := strconv.Atoi(sgid)
if err != nil {
return nil, trace.Wrap(err)
}
groups := make([]uint32, 0)
for _, sgid := range userGroups {
igid, err := strconv.Atoi(sgid)
if err != nil {
log.Warnf("Cannot interpret user group: '%v'", sgid)
} else {
groups = append(groups, uint32(igid))
}
}
if len(groups) == 0 {
groups = append(groups, uint32(gid))
log.Warnf("Cannot interpret user group: '%v'", sgid)
} else {
groups = append(groups, uint32(igid))
}
c.SysProcAttr.Credential = &syscall.Credential{
}
if len(groups) == 0 {
groups = append(groups, uint32(gid))
}

// Only set process credentials if the UID/GID of the requesting user are
// different than the process (Teleport).
//
// Note, the above is important because setting the credentials struct
// triggers calling of the SETUID and SETGID syscalls during process start.
// If the caller does not have permission to call those two syscalls (for
// example, if Teleport is started from a shell), this will prevent the
// process from spawning shells with the error: "operation not permitted". To
// workaround this, the credentials struct is only set if the credentials
// are different from the process itself. If the credentials are not, simply
// pick up the ambient credentials of the process.
var credentials *syscall.Credential
if strconv.Itoa(os.Getuid()) != osUser.Uid || strconv.Itoa(os.Getgid()) != osUser.Gid {
credentials = &syscall.Credential{
Uid: uint32(uid),
Gid: uint32(gid),
Groups: groups,
}
c.SysProcAttr.Setsid = true
log.Debugf("Creating process with UID %v, GID: %v, and Groups: %v.",
uid, gid, groups)
} else {
log.Debugf("Credential process with ambient credentials UID %v, GID: %v, Groups: %v.",
uid, gid, groups)
}

// Filling out syscall.SysProcAttr will trigger calling of certain syscalls
// during process start.
c.SysProcAttr = &syscall.SysProcAttr{
// Call SETUID and SETGID syscalls if credentials is not nil to set the
// process UID and GID. See "man 7 credentials" for more details.
Credential: credentials,

// Call the SETSID syscall which will "create a new session if the calling
// process is not a process group leader". See "man 2 setsid" for more details.
Setsid: true,
}

// apply environment variables passed from the client
Expand Down