<p dir="auto">In issue <a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="51277802" data-permission-text="Title is private" data-url="https://github.com/golang/go/issues/1435" data-hovercard-type="issue" data-hovercard-url="/golang/go/issues/1435/hovercard" href="https://github.com/golang/go/issues/1435">#1435</a> it has been suggested to use capabilities as a workaround to achieve security. To make this workaround viable, internal threads created by the Go runtime before main() even starts need to drop all capabilities, because the user thread running main() is not permitted to do that.</p>
<p dir="auto">In addition there should probably be a mask in the runtime package that determines which capabilities are preserved when the Go runtime creates new threads. And for convenience there should be a function to drop capabilities in the current thread (although this can be done with cgo and is therefore secondary)<br>
The idea is to make the following work</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="func main() {
    runtime.LockOSThread() // stay on this thread to make sure we don't lose capabilities
    runtime.SetInheritedCapabilities(0) // all threads created from now on will drop ALL capabilities

   // Do privileged stuff such as chroot or bind to privileged port
   // This may start new Goroutines and thereby new threads, but due to
   // runtime.SetInheritedCapabilities(0) these threads will drop all capabilities immediately,
   // so no privileged threads will be created

  runtime.DropAllCapabilities()  // convenience function. Could be done with C.capset(...)

  // At this point no privileged threads exist anymore
  runtime.UnlockOSThread() // now it doesn't matter on which thread we execute
 }"><pre class="notranslate"><code class="notranslate">func main() {
    runtime.LockOSThread() // stay on this thread to make sure we don't lose capabilities
    runtime.SetInheritedCapabilities(0) // all threads created from now on will drop ALL capabilities

   // Do privileged stuff such as chroot or bind to privileged port
   // This may start new Goroutines and thereby new threads, but due to
   // runtime.SetInheritedCapabilities(0) these threads will drop all capabilities immediately,
   // so no privileged threads will be created

  runtime.DropAllCapabilities()  // convenience function. Could be done with C.capset(...)

  // At this point no privileged threads exist anymore
  runtime.UnlockOSThread() // now it doesn't matter on which thread we execute
 }
</code></pre></div>
<p dir="auto">by <strong><a href="mailto:ziutek@Lnet.pl">ziutek@Lnet.pl</a></strong>:</p>
<pre class="notranslate">What steps will reproduce the problem?

Compile attached test code. Run it as root like this:

# GOMAXPROCS=4 ./test 65534 65534

and note output:

gorutine 1: uid=0 euid=0 gid=0 egid=0
gorutine 2: uid=0 euid=0 gid=0 egid=0
gorutine 3: uid=0 euid=0 gid=0 egid=0
gorutine 4: uid=0 euid=0 gid=0 egid=0
gorutine 5: uid=0 euid=0 gid=0 egid=0
gorutine 6: uid=0 euid=0 gid=0 egid=0
gorutine 7: uid=0 euid=0 gid=0 egid=0
gorutine 8: uid=0 euid=0 gid=0 egid=0
gorutine 9: uid=0 euid=0 gid=0 egid=0
gorutine 0: uid=65534 euid=65534 gid=65534 egid=65534
gorutine 1: uid=0 euid=0 gid=0 egid=0
gorutine 2: uid=0 euid=0 gid=0 egid=0
gorutine 3: uid=0 euid=0 gid=0 egid=0
gorutine 4: uid=0 euid=0 gid=0 egid=0
gorutine 5: uid=0 euid=0 gid=0 egid=0
gorutine 6: uid=0 euid=0 gid=0 egid=0
gorutine 7: uid=0 euid=0 gid=0 egid=0
gorutine 8: uid=0 euid=0 gid=0 egid=0
gorutine 9: uid=0 euid=0 gid=0 egid=0
gorutine 0: uid=65534 euid=65534 gid=65534 egid=65534

Use ps -efL during test execution and note output:

UID        PID  PPID   LWP  C NLWP STIME TTY          TIME CMD
nobody   26088 25928 26088  0   10 11:56 pts/1    00:00:00 ./test 65534 65534
root     26088 25928 26089  0   10 11:56 pts/1    00:00:00 ./test 65534 65534
root     26088 25928 26090  0   10 11:56 pts/1    00:00:00 ./test 65534 65534
root     26088 25928 26091  0   10 11:56 pts/1    00:00:00 ./test 65534 65534
root     26088 25928 26092  0   10 11:56 pts/1    00:00:00 ./test 65534 65534
root     26088 25928 26093  0   10 11:56 pts/1    00:00:00 ./test 65534 65534
root     26088 25928 26094  0   10 11:56 pts/1    00:00:00 ./test 65534 65534
root     26088 25928 26095  0   10 11:56 pts/1    00:00:00 ./test 65534 65534
root     26088 25928 26096  0   10 11:56 pts/1    00:00:00 ./test 65534 65534
root     26088 25928 26097  0   10 11:56 pts/1    00:00:00 ./test 65534 65534

What is the expected output?

All threads must have the same UID/GID: (65534, nobody user in my system).

Which compiler are you using (5g, 6g, 8g, gccgo)?

I tested this with 6g and 8g.

Which operating system are you using?

Linux (Debian 6.0 SID on i386, Ubuntu 10.10 on amd64)

Which revision are you using?  (hg identify)

d8ba80011a98 release/release.2011-01-20

Please provide any additional information below.

<a href="http://groups.google.com/group/golang-nuts/browse_thread/thread/59597aafdd84a0e" rel="nofollow">http://groups.google.com/group/golang-nuts/browse_thread/thread/59597aafdd84a0e</a></pre>
<p dir="auto">Attachments:</p>
<ol dir="auto">
<li><a href="https://storage.googleapis.com/go-attachment/1435/0/test.go" rel="nofollow">test.go</a> (1067 bytes)</li>
</ol>