Skip to content

x/sys/unix: Capget/Capset writes past struct's memory #44312

@ghost

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

No one assigned

    Labels

    NeedsInvestigationSomeone must examine and confirm this is a valid issue and not a duplicate of an existing one.compiler/runtimeIssues related to the Go compiler and/or runtime.

    Type

    No type

    Projects

    Status

    Triage Backlog

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions