Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

syscall: Pdeathsig ignored when using setuid/setgid (Linux) #9686

Closed
williamsandrew opened this issue Jan 25, 2015 · 2 comments
Closed

syscall: Pdeathsig ignored when using setuid/setgid (Linux) #9686

williamsandrew opened this issue Jan 25, 2015 · 2 comments
Milestone

Comments

@williamsandrew
Copy link
Contributor

@williamsandrew williamsandrew commented Jan 25, 2015

When attempting to use the Pdeathsig functionality on Linux, along with using setuid/setgid, the death signal appears to be ignored. However when setuid/setgid is not used, the death signal works as expected. This behavior was observed on Go version 1.4.1 with the following test code:

package main

import (
    "log"
    "os"
    "os/exec"
    "strconv"
    "syscall"
    "time"
)

func main() {
    attrs := syscall.SysProcAttr{
        Pdeathsig: syscall.SIGTERM,
    }

    if len(os.Args) > 1 {
        id, _ := strconv.ParseUint(os.Args[1], 0, 32)
        attrs.Credential = &syscall.Credential{Uid: uint32(id), Gid: uint32(id)}
    }

    cmd := exec.Command("/bin/sleep", "300")
    cmd.SysProcAttr = &attrs

    err := cmd.Start()
    if err != nil {
        log.Fatal(err)
    }
    log.Printf("Started child %d\n", cmd.Process.Pid)

    // Wait a bit and then die
    time.Sleep(2 * time.Second)
    log.Printf("Dying... Check child status with `ps -p %d -f`\n", cmd.Process.Pid)
}

Steps to reproduce

Without setting a uid/gid to switch to, the death signal works as expected

[andrew@localhost ~]$ sudo ./deathsig_example 
2015/01/25 14:56:15 Started child 2022
2015/01/25 14:56:17 Dying... Check child status with `ps -p 2022 -f`
[andrew@localhost ~]$ ps -p 2022 -f
UID        PID  PPID  C STIME TTY          TIME CMD

When switching to another uid/gid (user and group "nobody" in this case) we see that the child is not sent a sigterm.

[andrew@localhost ~]$ sudo ./deathsig_example 99
2015/01/25 14:56:26 Started child 2029
2015/01/25 14:56:28 Dying... Check child status with `ps -p 2029 -f`
[andrew@localhost ~]$ ps -p 2029 -f
UID        PID  PPID  C STIME TTY          TIME CMD
nobody    2029     1  0 14:56 pts/2    00:00:00 /bin/sleep 300

I reproduced this bug on Fedora 20 (kernel version: 3.16.4-200.fc20.x86_64) as well as on Centos 6.6 (kernel version: 2.6.32-431.11.2.el6.x86_64).

The fix

From what I can tell by looking at the kernel source, it appears Linux resets the death signal attribute on a task when the effective uid/gid changes.

https://github.com/torvalds/linux/blob/d82012695ef29e4e1c8153ccf43098ec8e50369e/kernel/sys.c#L561
https://github.com/torvalds/linux/blob/9a3c4145af32125c5ee39c0272662b47307a8323/kernel/cred.c#L441

In src/syscall/exec_linux.go we set the death signal before we make any setuid/setgid system calls which means it will always be cleared in those cases. Moving the Pdeathsig code farther down in the function seems to fix the problem.

I'll be submitting a CL shortly.

williamsandrew added a commit to williamsandrew/go that referenced this issue Jan 25, 2015
Fix a bug on Linux where using the `Pdeathsig` along with SETUID/SETGID
would cause the death signal to be ignored. This is because the
Linux kernel will clear the `deathsignal` field on a task when
performing a SETUID/SETGID system call.

To avoid this we simply move the `Pdeathsig` logic farther down in
the funcion after we have switched to our new uid/gid.

Fixes golang#9686

Change-Id: Id01896ad4e979b8c448e0061f00aa8762ca0ac94
@ianlancetaylor ianlancetaylor added this to the Go1.5 milestone Jan 26, 2015
@bradfitz
Copy link
Contributor

@bradfitz bradfitz commented Apr 8, 2015

williamsandrew added a commit to williamsandrew/go that referenced this issue Apr 18, 2015
Fix a bug on Linux where using the `Pdeathsig` along with SETUID/SETGID
would cause the death signal to be ignored. This is because the
Linux kernel will clear the `deathsignal` field on a task when
performing a SETUID/SETGID system call.

To avoid this we simply move the `Pdeathsig` logic farther down in
the function after we have switched to our new uid/gid.

Fixes golang#9686

Change-Id: Id01896ad4e979b8c448e0061f00aa8762ca0ac94
williamsandrew added a commit to williamsandrew/go that referenced this issue Apr 23, 2015
Fix a bug on Linux where using the `Pdeathsig` along with SETUID/SETGID
would cause the death signal to be ignored. This is because the
Linux kernel will clear the `deathsignal` field on a task when
performing a SETUID/SETGID system call.

To avoid this we simply move the `Pdeathsig` logic farther down in
the function after we have switched to our new uid/gid.

Fixes golang#9686

Change-Id: Id01896ad4e979b8c448e0061f00aa8762ca0ac94
@gopherbot
Copy link

@gopherbot gopherbot commented Apr 25, 2015

CL https://golang.org/cl/3290 mentions this issue.

@golang golang locked and limited conversation to collaborators Jun 25, 2016
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
4 participants
You can’t perform that action at this time.