full diff: https://github.com/moby/sys/compare/capability/v0.3.0...capability/v0.4.0 Added * New separate API for ambient ([GetAmbient], [SetAmbient], [ResetAmbient]) and bound ([GetBound], [DropBound]) capabilities, modelled after libcap. Fixed * [Apply] now returns an error if called for non-zero `pid`. Before this change, it could silently change some capabilities of the current process, instead of the one identified by the `pid`. * Fixed tests that change capabilities to be run in a separate process. * Other improvements in tests. Changed * Use raw syscalls (which are slightly faster). * Most tests are now limited to testing the public API of the package. * Simplify parsing /proc/*pid*/status, add a test case. * Optimize the number of syscall to set ambient capabilities in Apply by clearing them first; add a test case. * Better documentation for [Apply], [NewFile], [NewFile2], [NewPid], [NewPid2]. Removed * `.golangci.yml` and `.codespellrc` are no longer part of the package. <!-- Doc links (please keep sorted). --> [Apply]: https://pkg.go.dev/github.com/moby/sys/capability#Capabilities.Apply [DropBound]: https://pkg.go.dev/github.com/moby/sys/capability#DropBound [GetAmbient]: https://pkg.go.dev/github.com/moby/sys/capability#GetAmbient [GetBound]: https://pkg.go.dev/github.com/moby/sys/capability#GetBound [LastCap]: https://pkg.go.dev/github.com/moby/sys/capability#LastCap [ListKnown]: https://pkg.go.dev/github.com/moby/sys/capability#ListKnown [ListSupported]: https://pkg.go.dev/github.com/moby/sys/capability#ListSupported [List]: https://pkg.go.dev/github.com/moby/sys/capability#List [NewFile2]: https://pkg.go.dev/github.com/moby/sys/capability#NewFile2 [NewFile]: https://pkg.go.dev/github.com/moby/sys/capability#NewFile [NewPid2]: https://pkg.go.dev/github.com/moby/sys/capability#NewPid2 [NewPid]: https://pkg.go.dev/github.com/moby/sys/capability#NewPid [ResetAmbient]: https://pkg.go.dev/github.com/moby/sys/capability#ResetAmbient [SetAmbient]: https://pkg.go.dev/github.com/moby/sys/capability#SetAmbient Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
162 lines
3.6 KiB
Go
162 lines
3.6 KiB
Go
// Copyright 2024 The Capability Authors.
|
|
// Copyright 2013 Suryandaru Triandana <syndtr@gmail.com>
|
|
// All rights reserved.
|
|
//
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package capability
|
|
|
|
import (
|
|
"syscall"
|
|
"unsafe"
|
|
)
|
|
|
|
type capHeader struct {
|
|
version uint32
|
|
pid int32
|
|
}
|
|
|
|
type capData struct {
|
|
effective uint32
|
|
permitted uint32
|
|
inheritable uint32
|
|
}
|
|
|
|
func capget(hdr *capHeader, data *capData) (err error) {
|
|
_, _, e1 := syscall.RawSyscall(syscall.SYS_CAPGET, uintptr(unsafe.Pointer(hdr)), uintptr(unsafe.Pointer(data)), 0)
|
|
if e1 != 0 {
|
|
err = e1
|
|
}
|
|
return
|
|
}
|
|
|
|
func capset(hdr *capHeader, data *capData) (err error) {
|
|
_, _, e1 := syscall.RawSyscall(syscall.SYS_CAPSET, uintptr(unsafe.Pointer(hdr)), uintptr(unsafe.Pointer(data)), 0)
|
|
if e1 != 0 {
|
|
err = e1
|
|
}
|
|
return
|
|
}
|
|
|
|
// not yet in syscall
|
|
const (
|
|
pr_CAP_AMBIENT = 47
|
|
pr_CAP_AMBIENT_IS_SET = uintptr(1)
|
|
pr_CAP_AMBIENT_RAISE = uintptr(2)
|
|
pr_CAP_AMBIENT_LOWER = uintptr(3)
|
|
pr_CAP_AMBIENT_CLEAR_ALL = uintptr(4)
|
|
)
|
|
|
|
func prctl(option int, arg2, arg3 uintptr) (err error) {
|
|
_, _, e1 := syscall.RawSyscall(syscall.SYS_PRCTL, uintptr(option), arg2, arg3)
|
|
if e1 != 0 {
|
|
err = e1
|
|
}
|
|
return
|
|
}
|
|
|
|
func prctlRetInt(option int, arg2, arg3 uintptr) (int, error) {
|
|
ret, _, err := syscall.RawSyscall(syscall.SYS_PRCTL, uintptr(option), arg2, arg3)
|
|
if err != 0 {
|
|
return 0, err
|
|
}
|
|
return int(ret), nil
|
|
}
|
|
|
|
const (
|
|
vfsXattrName = "security.capability"
|
|
|
|
vfsCapVerMask = 0xff000000
|
|
vfsCapVer1 = 0x01000000
|
|
vfsCapVer2 = 0x02000000
|
|
|
|
vfsCapFlagMask = ^vfsCapVerMask
|
|
vfsCapFlageffective = 0x000001
|
|
|
|
vfscapDataSizeV1 = 4 * (1 + 2*1)
|
|
vfscapDataSizeV2 = 4 * (1 + 2*2)
|
|
)
|
|
|
|
type vfscapData struct {
|
|
magic uint32
|
|
data [2]struct {
|
|
permitted uint32
|
|
inheritable uint32
|
|
}
|
|
effective [2]uint32
|
|
version int8
|
|
}
|
|
|
|
var _vfsXattrName *byte
|
|
|
|
func init() {
|
|
_vfsXattrName, _ = syscall.BytePtrFromString(vfsXattrName)
|
|
}
|
|
|
|
func getVfsCap(path string, dest *vfscapData) (err error) {
|
|
var _p0 *byte
|
|
_p0, err = syscall.BytePtrFromString(path)
|
|
if err != nil {
|
|
return
|
|
}
|
|
r0, _, e1 := syscall.RawSyscall6(syscall.SYS_GETXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_vfsXattrName)), uintptr(unsafe.Pointer(dest)), vfscapDataSizeV2, 0, 0)
|
|
if e1 != 0 {
|
|
if e1 == syscall.ENODATA {
|
|
dest.version = 2
|
|
return
|
|
}
|
|
err = e1
|
|
}
|
|
switch dest.magic & vfsCapVerMask {
|
|
case vfsCapVer1:
|
|
dest.version = 1
|
|
if r0 != vfscapDataSizeV1 {
|
|
return syscall.EINVAL
|
|
}
|
|
dest.data[1].permitted = 0
|
|
dest.data[1].inheritable = 0
|
|
case vfsCapVer2:
|
|
dest.version = 2
|
|
if r0 != vfscapDataSizeV2 {
|
|
return syscall.EINVAL
|
|
}
|
|
default:
|
|
return syscall.EINVAL
|
|
}
|
|
if dest.magic&vfsCapFlageffective != 0 {
|
|
dest.effective[0] = dest.data[0].permitted | dest.data[0].inheritable
|
|
dest.effective[1] = dest.data[1].permitted | dest.data[1].inheritable
|
|
} else {
|
|
dest.effective[0] = 0
|
|
dest.effective[1] = 0
|
|
}
|
|
return
|
|
}
|
|
|
|
func setVfsCap(path string, data *vfscapData) (err error) {
|
|
var _p0 *byte
|
|
_p0, err = syscall.BytePtrFromString(path)
|
|
if err != nil {
|
|
return
|
|
}
|
|
var size uintptr
|
|
if data.version == 1 {
|
|
data.magic = vfsCapVer1
|
|
size = vfscapDataSizeV1
|
|
} else if data.version == 2 {
|
|
data.magic = vfsCapVer2
|
|
if data.effective[0] != 0 || data.effective[1] != 0 {
|
|
data.magic |= vfsCapFlageffective
|
|
}
|
|
size = vfscapDataSizeV2
|
|
} else {
|
|
return syscall.EINVAL
|
|
}
|
|
_, _, e1 := syscall.RawSyscall6(syscall.SYS_SETXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_vfsXattrName)), uintptr(unsafe.Pointer(data)), size, 0, 0)
|
|
if e1 != 0 {
|
|
err = e1
|
|
}
|
|
return
|
|
}
|