-
Notifications
You must be signed in to change notification settings - Fork 18.8k
Description
I have a go program that is using unix.Capget/Capset and was randomly crashing.
Thanks to @ianlancetaylor this code was identified as a culprit:
hdr := unix.CapUserHeader{Version: unix.LINUX_CAPABILITY_VERSION_3}
var data unix.CapUserData
unix.Capget(&hdr, &data) // this might write past &data.Turns out that version 2 and version 3 linux capabilities are wider than version 1 capabilities.
Version 1 uses 32bit fields and fit perfectly into a single unix.CapUserData:
type CapUserData struct {
Effective uint32
Permitted uint32
Inheritable uint32
}However version 2 and version 3 capabilities are 64 bit and do not fit into a single unix.CapUserData.
Instead of using a struct with wider fields however linux capget syscall uses the same struct but writes into 2 instances of the struct. It writes lower bits of the capabilities into the first struct and the higher bits into the second one.
So, confusingly the correct way of writing the code above would be:
hdr := unix.CapUserHeader{Version: unix.LINUX_CAPABILITY_VERSION_3}
var data [2]unix.CapUserData
unix.Capget(&hdr, &data[0])Which is normal practice in C, but doesn't look like a typical go to me.
This code would write lower bits into data[0] and higher bits into data[1]. Then the client would have to be careful when setting capabilities, choosing data[0] vs data[1] depending on the capability, for example:
data[0].Effective |= 1<<unix.CAP_SYS_ADMIN
data[1].Effective |= 1<<(unix.CAP_CHECKPOINT_RESTORE - 32)Same applies to unix.Capset, except it would read past the first struct.
I'm wondering if the signature of unix.Capget/Capset should be changed into something like:
func Capget(hdr *CapUserHeader, data *[2]CapUserData) (err error)to prevent issues like this. Such a signature would clearly indicate the amount of memory affected by the syscall.
Or maybe make the fields wider and repack during the call to account for a weird memory layout? That wouldn't work very well though if linux keeps expanding capabilities and would go even wider.
Thoughts?
Metadata
Metadata
Assignees
Labels
Type
Projects
Status