Linux, unix.Capset, and runtime.LockOSThread

233 views
Skip to first unread message

Caleb Spare

unread,
Feb 13, 2020, 4:14:36 PM2/13/20
to golang-nuts
Hi! I have a Linux-specific question about capabilities, threads, and syscalls.

I have a Go program which runs other programs with specific
capabilities set. It basically does the following:

cmd := exec.Command(...)
runtime.LockOSThread()
unix.RawSyscall(unix.CAPSET, ...)
cmd.Start()

Empirically, it seems to work well, having run in production for several years.

I wrote it this way because, from my reading of capabilities
documentation, capset only affects the current thread, so it's
important that we use the same OS thread for running the capset
syscall as the fork. I also used RawSyscall (rather than Syscall) for
this reason.

I noticed that more recently the x/sys/unix package added Capget and
Capset which use Syscall rather than RawSyscall. Thinking about it
more now, ISTM that using Syscall is fine, and that LockOSThread is
all I need to ensure that the thread with the raised capabilities is
the one that runs the fork. Is that correct?

Relatedly, how does one definitively know whether a syscall is
nonblocking? AFAICT setcap and getcap shouldn't block. Why does unix
use Syscall for Capset/Capget but RawSyscall for calls like Getpgid?

Thanks!
Caleb

Ian Lance Taylor

unread,
Feb 14, 2020, 11:33:40 PM2/14/20
to Caleb Spare, golang-nuts
On Thu, Feb 13, 2020 at 1:14 PM Caleb Spare <ces...@gmail.com> wrote:
>
> Hi! I have a Linux-specific question about capabilities, threads, and syscalls.
>
> I have a Go program which runs other programs with specific
> capabilities set. It basically does the following:
>
> cmd := exec.Command(...)
> runtime.LockOSThread()
> unix.RawSyscall(unix.CAPSET, ...)
> cmd.Start()
>
> Empirically, it seems to work well, having run in production for several years.
>
> I wrote it this way because, from my reading of capabilities
> documentation, capset only affects the current thread, so it's
> important that we use the same OS thread for running the capset
> syscall as the fork. I also used RawSyscall (rather than Syscall) for
> this reason.
>
> I noticed that more recently the x/sys/unix package added Capget and
> Capset which use Syscall rather than RawSyscall. Thinking about it
> more now, ISTM that using Syscall is fine, and that LockOSThread is
> all I need to ensure that the thread with the raised capabilities is
> the one that runs the fork. Is that correct?

Yes.

The difference between Syscall and RawSyscall is that the latter does
not inform the scheduler that it is entering the kernel, and therefore
using RawSyscall will break your program if the system call blocks.
There is no difference between Syscall and RawSyscall with regard to
the behavior of LockOSThread.


> Relatedly, how does one definitively know whether a syscall is
> nonblocking? AFAICT setcap and getcap shouldn't block. Why does unix
> use Syscall for Capset/Capget but RawSyscall for calls like Getpgid?

It's possible that this is a performance bug. I don't know of any
reason why Capset/Capget might block.

Ian

Caleb Spare

unread,
Feb 18, 2020, 4:01:27 PM2/18/20
to Ian Lance Taylor, golang-nuts
Thanks for the reply.
Okay, I can send a CL for that.

>
> Ian
Reply all
Reply to author
Forward
0 new messages