Skip to main content

Go 1.4, setuid and linux's capabilities feature

·2 mins

This first came to me when I realized my newly compiled socks5dns spew error failing at dropping user privilege, since I run it on an arm machine I thought it was specific error for arm-based linux only. But then I checked this on an x86 and it still behave the same, after looking into some source codes apparently Go’s syscall.Setuid is not supported in linux. But hey, it was worked before, what the fuss?? Searching through the issues tracker finally revealed that linux’s setuid actually just change uid only for the current calling thread. Long story short, the previous implementation was purged for good until the new implementation live at os.Setuid. The discussion itself apparently arose at early 2011 and syscall.Setuid still intact until go 1.3. Shame from my side for missed the announcement when reading the changelog.

Furthermore, that discussion actually shed some light regarding linux privilege systems. I learned about linux capabilities which actually dated from linux 2.2[1] (/me laaaate). It’s an extended attribute which allow a file (or a process for this matter) to do some operations which normally require some extra privilege. I can relate that with SELinux, but this one supposed to be much older, or something.

So I guess I’ll just remove the setuid related code from socks5dns, and go like this: (from within runit)

# this run script will run as root by default

# set capabilities
setcap cap_net_bind_service+ep $GOPATH/bin/socks5dns

# run as unprivileged random user named socksuser
# and can still open port 53 swiftly, neat!
exec chpst -u socksuser $GOPATH/bin/socks5dns -s= -b= -c -m=256

For security measure, I think I can set the permission so it can only be executed by its respected owner.

[1] man capabilities