mirror of
https://github.com/opencontainers/runc.git
synced 2026-07-11 06:03:57 +08:00
Switch to github.com/moby/sys/capability v0.4.0
This removes the last unversioned package in runc's direct dependencies. Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
This commit is contained in:
@@ -15,6 +15,7 @@ require (
|
|||||||
github.com/cyphar/filepath-securejoin v0.3.4
|
github.com/cyphar/filepath-securejoin v0.3.4
|
||||||
github.com/docker/go-units v0.5.0
|
github.com/docker/go-units v0.5.0
|
||||||
github.com/godbus/dbus/v5 v5.1.0
|
github.com/godbus/dbus/v5 v5.1.0
|
||||||
|
github.com/moby/sys/capability v0.4.0
|
||||||
github.com/moby/sys/mountinfo v0.7.2
|
github.com/moby/sys/mountinfo v0.7.2
|
||||||
github.com/moby/sys/user v0.3.0
|
github.com/moby/sys/user v0.3.0
|
||||||
github.com/moby/sys/userns v0.1.0
|
github.com/moby/sys/userns v0.1.0
|
||||||
@@ -23,7 +24,6 @@ require (
|
|||||||
github.com/opencontainers/selinux v1.11.1
|
github.com/opencontainers/selinux v1.11.1
|
||||||
github.com/seccomp/libseccomp-golang v0.10.0
|
github.com/seccomp/libseccomp-golang v0.10.0
|
||||||
github.com/sirupsen/logrus v1.9.3
|
github.com/sirupsen/logrus v1.9.3
|
||||||
github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635
|
|
||||||
github.com/urfave/cli v1.22.16
|
github.com/urfave/cli v1.22.16
|
||||||
github.com/vishvananda/netlink v1.3.0
|
github.com/vishvananda/netlink v1.3.0
|
||||||
golang.org/x/net v0.31.0
|
golang.org/x/net v0.31.0
|
||||||
|
|||||||
@@ -39,6 +39,8 @@ github.com/mdlayher/netlink v1.7.2 h1:/UtM3ofJap7Vl4QWCPDGXY8d3GIY2UGSDbK+QWmY8/
|
|||||||
github.com/mdlayher/netlink v1.7.2/go.mod h1:xraEF7uJbxLhc5fpHL4cPe221LI2bdttWlU+ZGLfQSw=
|
github.com/mdlayher/netlink v1.7.2/go.mod h1:xraEF7uJbxLhc5fpHL4cPe221LI2bdttWlU+ZGLfQSw=
|
||||||
github.com/mdlayher/socket v0.4.1 h1:eM9y2/jlbs1M615oshPQOHZzj6R6wMT7bX5NPiQvn2U=
|
github.com/mdlayher/socket v0.4.1 h1:eM9y2/jlbs1M615oshPQOHZzj6R6wMT7bX5NPiQvn2U=
|
||||||
github.com/mdlayher/socket v0.4.1/go.mod h1:cAqeGjoufqdxWkD7DkpyS+wcefOtmu5OQ8KuoJGIReA=
|
github.com/mdlayher/socket v0.4.1/go.mod h1:cAqeGjoufqdxWkD7DkpyS+wcefOtmu5OQ8KuoJGIReA=
|
||||||
|
github.com/moby/sys/capability v0.4.0 h1:4D4mI6KlNtWMCM1Z/K0i7RV1FkX+DBDHKVJpCndZoHk=
|
||||||
|
github.com/moby/sys/capability v0.4.0/go.mod h1:4g9IK291rVkms3LKCDOoYlnV8xKwoDTpIrNEE35Wq0I=
|
||||||
github.com/moby/sys/mountinfo v0.7.2 h1:1shs6aH5s4o5H2zQLn796ADW1wMrIwHsyJ2v9KouLrg=
|
github.com/moby/sys/mountinfo v0.7.2 h1:1shs6aH5s4o5H2zQLn796ADW1wMrIwHsyJ2v9KouLrg=
|
||||||
github.com/moby/sys/mountinfo v0.7.2/go.mod h1:1YOa8w8Ih7uW0wALDUgT1dTTSBrZ+HiBLGws92L2RU4=
|
github.com/moby/sys/mountinfo v0.7.2/go.mod h1:1YOa8w8Ih7uW0wALDUgT1dTTSBrZ+HiBLGws92L2RU4=
|
||||||
github.com/moby/sys/user v0.3.0 h1:9ni5DlcW5an3SvRSx4MouotOygvzaXbaSrc/wGDFWPo=
|
github.com/moby/sys/user v0.3.0 h1:9ni5DlcW5an3SvRSx4MouotOygvzaXbaSrc/wGDFWPo=
|
||||||
@@ -73,8 +75,6 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO
|
|||||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||||
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||||
github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635 h1:kdXcSzyDtseVEc4yCz2qF8ZrQvIDBJLl4S1c3GCXmoI=
|
|
||||||
github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
|
|
||||||
github.com/urfave/cli v1.22.16 h1:MH0k6uJxdwdeWQTwhSO42Pwr4YLrNLwBtg1MRgTqPdQ=
|
github.com/urfave/cli v1.22.16 h1:MH0k6uJxdwdeWQTwhSO42Pwr4YLrNLwBtg1MRgTqPdQ=
|
||||||
github.com/urfave/cli v1.22.16/go.mod h1:EeJR6BKodywf4zciqrdw6hpCPk68JO9z5LazXZMn5Po=
|
github.com/urfave/cli v1.22.16/go.mod h1:EeJR6BKodywf4zciqrdw6hpCPk68JO9z5LazXZMn5Po=
|
||||||
github.com/vishvananda/netlink v1.3.0 h1:X7l42GfcV4S6E4vHTsw48qbrV+9PVojNfIhZcwQdrZk=
|
github.com/vishvananda/netlink v1.3.0 h1:X7l42GfcV4S6E4vHTsw48qbrV+9PVojNfIhZcwQdrZk=
|
||||||
|
|||||||
@@ -3,42 +3,36 @@
|
|||||||
package capabilities
|
package capabilities
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
|
"github.com/moby/sys/capability"
|
||||||
"github.com/opencontainers/runc/libcontainer/configs"
|
"github.com/opencontainers/runc/libcontainer/configs"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
"github.com/syndtr/gocapability/capability"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const allCapabilityTypes = capability.CAPS | capability.BOUNDING | capability.AMBIENT
|
func capToStr(c capability.Cap) string {
|
||||||
|
return "CAP_" + strings.ToUpper(c.String())
|
||||||
|
}
|
||||||
|
|
||||||
var (
|
var capMap = sync.OnceValues(func() (map[string]capability.Cap, error) {
|
||||||
capTypes = []capability.CapType{
|
list, err := capability.ListSupported()
|
||||||
capability.BOUNDING,
|
if err != nil {
|
||||||
capability.PERMITTED,
|
return nil, err
|
||||||
capability.INHERITABLE,
|
|
||||||
capability.EFFECTIVE,
|
|
||||||
capability.AMBIENT,
|
|
||||||
}
|
}
|
||||||
|
cm := make(map[string]capability.Cap, len(list))
|
||||||
capMap = sync.OnceValue(func() map[string]capability.Cap {
|
for _, c := range list {
|
||||||
cm := make(map[string]capability.Cap, capability.CAP_LAST_CAP+1)
|
cm[capToStr(c)] = c
|
||||||
for _, c := range capability.List() {
|
}
|
||||||
if c > capability.CAP_LAST_CAP {
|
return cm, nil
|
||||||
continue
|
})
|
||||||
}
|
|
||||||
cm["CAP_"+strings.ToUpper(c.String())] = c
|
|
||||||
}
|
|
||||||
return cm
|
|
||||||
})
|
|
||||||
)
|
|
||||||
|
|
||||||
// KnownCapabilities returns the list of the known capabilities.
|
// KnownCapabilities returns the list of the known capabilities.
|
||||||
// Used by `runc features`.
|
// Used by `runc features`.
|
||||||
func KnownCapabilities() []string {
|
func KnownCapabilities() []string {
|
||||||
list := capability.List()
|
list := capability.ListKnown()
|
||||||
res := make([]string, len(list))
|
res := make([]string, len(list))
|
||||||
for i, c := range list {
|
for i, c := range list {
|
||||||
res[i] = "CAP_" + strings.ToUpper(c.String())
|
res[i] = "CAP_" + strings.ToUpper(c.String())
|
||||||
@@ -50,11 +44,12 @@ func KnownCapabilities() []string {
|
|||||||
// or Capabilities that are unavailable in the current environment are ignored,
|
// or Capabilities that are unavailable in the current environment are ignored,
|
||||||
// printing a warning instead.
|
// printing a warning instead.
|
||||||
func New(capConfig *configs.Capabilities) (*Caps, error) {
|
func New(capConfig *configs.Capabilities) (*Caps, error) {
|
||||||
var (
|
var c Caps
|
||||||
err error
|
|
||||||
c Caps
|
|
||||||
)
|
|
||||||
|
|
||||||
|
_, err := capMap()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
unknownCaps := make(map[string]struct{})
|
unknownCaps := make(map[string]struct{})
|
||||||
c.caps = map[capability.CapType][]capability.Cap{
|
c.caps = map[capability.CapType][]capability.Cap{
|
||||||
capability.BOUNDING: capSlice(capConfig.Bounding, unknownCaps),
|
capability.BOUNDING: capSlice(capConfig.Bounding, unknownCaps),
|
||||||
@@ -76,7 +71,7 @@ func New(capConfig *configs.Capabilities) (*Caps, error) {
|
|||||||
// equivalent, and returns them as a slice. Unknown or unavailable capabilities
|
// equivalent, and returns them as a slice. Unknown or unavailable capabilities
|
||||||
// are not returned, but appended to unknownCaps.
|
// are not returned, but appended to unknownCaps.
|
||||||
func capSlice(caps []string, unknownCaps map[string]struct{}) []capability.Cap {
|
func capSlice(caps []string, unknownCaps map[string]struct{}) []capability.Cap {
|
||||||
cm := capMap()
|
cm, _ := capMap()
|
||||||
out := make([]capability.Cap, 0, len(caps))
|
out := make([]capability.Cap, 0, len(caps))
|
||||||
for _, c := range caps {
|
for _, c := range caps {
|
||||||
if v, ok := cm[c]; !ok {
|
if v, ok := cm[c]; !ok {
|
||||||
@@ -113,9 +108,36 @@ func (c *Caps) ApplyBoundingSet() error {
|
|||||||
|
|
||||||
// Apply sets all the capabilities for the current process in the config.
|
// Apply sets all the capabilities for the current process in the config.
|
||||||
func (c *Caps) ApplyCaps() error {
|
func (c *Caps) ApplyCaps() error {
|
||||||
c.pid.Clear(allCapabilityTypes)
|
c.pid.Clear(capability.CAPS | capability.BOUNDS)
|
||||||
for _, g := range capTypes {
|
for _, g := range []capability.CapType{
|
||||||
|
capability.EFFECTIVE,
|
||||||
|
capability.PERMITTED,
|
||||||
|
capability.INHERITABLE,
|
||||||
|
capability.BOUNDING,
|
||||||
|
} {
|
||||||
c.pid.Set(g, c.caps[g]...)
|
c.pid.Set(g, c.caps[g]...)
|
||||||
}
|
}
|
||||||
return c.pid.Apply(allCapabilityTypes)
|
if err := c.pid.Apply(capability.CAPS | capability.BOUNDS); err != nil {
|
||||||
|
return fmt.Errorf("can't apply capabilities: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Old version of capability package used to ignore errors from setting
|
||||||
|
// ambient capabilities, which is now fixed (see
|
||||||
|
// https://github.com/kolyshkin/capability/pull/3).
|
||||||
|
//
|
||||||
|
// To maintain backward compatibility, set ambient caps one by one and
|
||||||
|
// don't return any errors, only warn.
|
||||||
|
ambs := c.caps[capability.AMBIENT]
|
||||||
|
err := capability.ResetAmbient()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("can't reset ambient capabilities: %w", err)
|
||||||
|
}
|
||||||
|
for _, a := range ambs {
|
||||||
|
err := capability.SetAmbient(true, a)
|
||||||
|
if err != nil {
|
||||||
|
logrus.Warnf("can't raise ambient capability %s: %v", capToStr(a), err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,12 +5,20 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/moby/sys/capability"
|
||||||
"github.com/opencontainers/runc/libcontainer/configs"
|
"github.com/opencontainers/runc/libcontainer/configs"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
"github.com/sirupsen/logrus/hooks/test"
|
"github.com/sirupsen/logrus/hooks/test"
|
||||||
"github.com/syndtr/gocapability/capability"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var capTypes = []capability.CapType{
|
||||||
|
capability.BOUNDING,
|
||||||
|
capability.PERMITTED,
|
||||||
|
capability.INHERITABLE,
|
||||||
|
capability.EFFECTIVE,
|
||||||
|
capability.AMBIENT,
|
||||||
|
}
|
||||||
|
|
||||||
func TestNew(t *testing.T) {
|
func TestNew(t *testing.T) {
|
||||||
cs := []string{"CAP_CHOWN", "CAP_UNKNOWN", "CAP_UNKNOWN2"}
|
cs := []string{"CAP_CHOWN", "CAP_UNKNOWN", "CAP_UNKNOWN2"}
|
||||||
conf := configs.Capabilities{
|
conf := configs.Capabilities{
|
||||||
|
|||||||
@@ -116,3 +116,17 @@ function teardown() {
|
|||||||
[[ "${output}" == *"CapBnd: 0000000400000021"* ]]
|
[[ "${output}" == *"CapBnd: 0000000400000021"* ]]
|
||||||
[[ "${output}" == *"CapAmb: 0000000400000001"* ]]
|
[[ "${output}" == *"CapAmb: 0000000400000001"* ]]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@test "runc run [ambient caps not set in inheritable result in a warning]" {
|
||||||
|
update_config ' .process.capabilities.inheritable = ["CAP_KILL"]
|
||||||
|
| .process.capabilities.ambient = ["CAP_KILL", "CAP_CHOWN"]'
|
||||||
|
runc run test_amb
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
# This should result in CAP_KILL set in ambient,
|
||||||
|
# and a warning about inability to set CAP_CHOWN.
|
||||||
|
#
|
||||||
|
# CAP_CHOWN is 0, the bit mask is 0x1 (1 << 0)
|
||||||
|
# CAP_KILL is 5, the bit mask is 0x20 (1 << 5).
|
||||||
|
[[ "$output" == *"can't raise ambient capability CAP_CHOWN: "* ]]
|
||||||
|
[[ "${output}" == *"CapAmb: 0000000000000020"* ]]
|
||||||
|
}
|
||||||
|
|||||||
+124
@@ -0,0 +1,124 @@
|
|||||||
|
# Changelog
|
||||||
|
This file documents all notable changes made to this project since the initial fork
|
||||||
|
from https://github.com/syndtr/gocapability/commit/42c35b4376354fd5.
|
||||||
|
|
||||||
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||||
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
|
## [0.4.0] - 2024-11-11
|
||||||
|
|
||||||
|
### Added
|
||||||
|
* New separate API for ambient ([GetAmbient], [SetAmbient], [ResetAmbient])
|
||||||
|
and bound ([GetBound], [DropBound]) capabilities, modelled after libcap. (#176)
|
||||||
|
|
||||||
|
### 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`. (#168, #174)
|
||||||
|
* Fixed tests that change capabilities to be run in a separate process. (#173)
|
||||||
|
* Other improvements in tests. (#169, #170)
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
* Use raw syscalls (which are slightly faster). (#176)
|
||||||
|
* Most tests are now limited to testing the public API of the package. (#162)
|
||||||
|
* Simplify parsing /proc/*pid*/status, add a test case. (#162)
|
||||||
|
* Optimize the number of syscall to set ambient capabilities in Apply
|
||||||
|
by clearing them first; add a test case. (#163, #164)
|
||||||
|
* Better documentation for [Apply], [NewFile], [NewFile2], [NewPid], [NewPid2]. (#175)
|
||||||
|
|
||||||
|
### Removed
|
||||||
|
* `.golangci.yml` and `.codespellrc` are no longer part of the package. (#158)
|
||||||
|
|
||||||
|
## [0.3.0] - 2024-09-25
|
||||||
|
|
||||||
|
### Added
|
||||||
|
* Added [ListKnown] and [ListSupported] functions. (#153)
|
||||||
|
* [LastCap] is now available on non-Linux platforms (where it returns an error). (#152)
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
* [List] is now deprecated in favor of [ListKnown] and [ListSupported]. (#153)
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
* Various documentation improvements. (#151)
|
||||||
|
* Fix "generated code" comment. (#153)
|
||||||
|
|
||||||
|
## [0.2.0] - 2024-09-16
|
||||||
|
|
||||||
|
This is the first release after the move to a new home in
|
||||||
|
github.com/moby/sys/capability.
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
* Fixed URLs in documentation to reflect the new home.
|
||||||
|
|
||||||
|
## [0.1.1] - 2024-08-01
|
||||||
|
|
||||||
|
This is a maintenance release, fixing a few minor issues.
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
* Fixed future kernel compatibility, for real this time. [#11]
|
||||||
|
* Fixed [LastCap] to be a function. [#12]
|
||||||
|
|
||||||
|
## [0.1.0] - 2024-07-31
|
||||||
|
|
||||||
|
This is an initial release since the fork.
|
||||||
|
|
||||||
|
### Breaking changes
|
||||||
|
|
||||||
|
* The `CAP_LAST_CAP` variable is removed; users need to modify the code to
|
||||||
|
use [LastCap] to get the value. [#6]
|
||||||
|
* The code now requires Go >= 1.21.
|
||||||
|
|
||||||
|
### Added
|
||||||
|
* `go.mod` and `go.sum` files. [#2]
|
||||||
|
* New [LastCap] function. [#6]
|
||||||
|
* Basic CI using GHA infra. [#8], [#9]
|
||||||
|
* README and CHANGELOG. [#10]
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
* Fixed ambient capabilities error handling in [Apply]. [#3]
|
||||||
|
* Fixed future kernel compatibility. [#1]
|
||||||
|
* Fixed various linter warnings. [#4], [#7]
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
* Go build tags changed from old-style (`+build`) to new Go 1.17+ style (`go:build`). [#2]
|
||||||
|
|
||||||
|
### Removed
|
||||||
|
* Removed support for capabilities v1 and v2. [#1]
|
||||||
|
* Removed init function so programs that use this package start faster. [#6]
|
||||||
|
* Removed `CAP_LAST_CAP` (use [LastCap] instead). [#6]
|
||||||
|
|
||||||
|
<!-- 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
|
||||||
|
|
||||||
|
<!-- Minor releases. -->
|
||||||
|
[0.4.0]: https://github.com/moby/sys/releases/tag/capability%2Fv0.4.0
|
||||||
|
[0.3.0]: https://github.com/moby/sys/releases/tag/capability%2Fv0.3.0
|
||||||
|
[0.2.0]: https://github.com/moby/sys/releases/tag/capability%2Fv0.2.0
|
||||||
|
[0.1.1]: https://github.com/kolyshkin/capability/compare/v0.1.0...v0.1.1
|
||||||
|
[0.1.0]: https://github.com/kolyshkin/capability/compare/42c35b4376354fd5...v0.1.0
|
||||||
|
|
||||||
|
<!-- PRs in 0.1.x releases. -->
|
||||||
|
[#1]: https://github.com/kolyshkin/capability/pull/1
|
||||||
|
[#2]: https://github.com/kolyshkin/capability/pull/2
|
||||||
|
[#3]: https://github.com/kolyshkin/capability/pull/3
|
||||||
|
[#4]: https://github.com/kolyshkin/capability/pull/4
|
||||||
|
[#6]: https://github.com/kolyshkin/capability/pull/6
|
||||||
|
[#7]: https://github.com/kolyshkin/capability/pull/7
|
||||||
|
[#8]: https://github.com/kolyshkin/capability/pull/8
|
||||||
|
[#9]: https://github.com/kolyshkin/capability/pull/9
|
||||||
|
[#10]: https://github.com/kolyshkin/capability/pull/10
|
||||||
|
[#11]: https://github.com/kolyshkin/capability/pull/11
|
||||||
|
[#12]: https://github.com/kolyshkin/capability/pull/12
|
||||||
Generated
Vendored
+1
@@ -1,3 +1,4 @@
|
|||||||
|
Copyright 2023 The Capability Authors.
|
||||||
Copyright 2013 Suryandaru Triandana <syndtr@gmail.com>
|
Copyright 2013 Suryandaru Triandana <syndtr@gmail.com>
|
||||||
All rights reserved.
|
All rights reserved.
|
||||||
|
|
||||||
+13
@@ -0,0 +1,13 @@
|
|||||||
|
This is a fork of (apparently no longer maintained)
|
||||||
|
https://github.com/syndtr/gocapability package. It provides basic primitives to
|
||||||
|
work with [Linux capabilities][capabilities(7)].
|
||||||
|
|
||||||
|
For changes, see [CHANGELOG.md](./CHANGELOG.md).
|
||||||
|
|
||||||
|
[](https://pkg.go.dev/github.com/moby/sys/capability)
|
||||||
|
|
||||||
|
## Alternatives
|
||||||
|
|
||||||
|
* https://pkg.go.dev/kernel.org/pub/linux/libs/security/libcap/cap
|
||||||
|
|
||||||
|
[capabilities(7)]: https://man7.org/linux/man-pages/man7/capabilities.7.html
|
||||||
+176
@@ -0,0 +1,176 @@
|
|||||||
|
// Copyright 2023 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 provides utilities for manipulating POSIX capabilities.
|
||||||
|
package capability
|
||||||
|
|
||||||
|
type Capabilities interface {
|
||||||
|
// Get check whether a capability present in the given
|
||||||
|
// capabilities set. The 'which' value should be one of EFFECTIVE,
|
||||||
|
// PERMITTED, INHERITABLE, BOUNDING or AMBIENT.
|
||||||
|
Get(which CapType, what Cap) bool
|
||||||
|
|
||||||
|
// Empty check whether all capability bits of the given capabilities
|
||||||
|
// set are zero. The 'which' value should be one of EFFECTIVE,
|
||||||
|
// PERMITTED, INHERITABLE, BOUNDING or AMBIENT.
|
||||||
|
Empty(which CapType) bool
|
||||||
|
|
||||||
|
// Full check whether all capability bits of the given capabilities
|
||||||
|
// set are one. The 'which' value should be one of EFFECTIVE,
|
||||||
|
// PERMITTED, INHERITABLE, BOUNDING or AMBIENT.
|
||||||
|
Full(which CapType) bool
|
||||||
|
|
||||||
|
// Set sets capabilities of the given capabilities sets. The
|
||||||
|
// 'which' value should be one or combination (OR'ed) of EFFECTIVE,
|
||||||
|
// PERMITTED, INHERITABLE, BOUNDING or AMBIENT.
|
||||||
|
Set(which CapType, caps ...Cap)
|
||||||
|
|
||||||
|
// Unset unsets capabilities of the given capabilities sets. The
|
||||||
|
// 'which' value should be one or combination (OR'ed) of EFFECTIVE,
|
||||||
|
// PERMITTED, INHERITABLE, BOUNDING or AMBIENT.
|
||||||
|
Unset(which CapType, caps ...Cap)
|
||||||
|
|
||||||
|
// Fill sets all bits of the given capabilities kind to one. The
|
||||||
|
// 'kind' value should be one or combination (OR'ed) of CAPS,
|
||||||
|
// BOUNDS or AMBS.
|
||||||
|
Fill(kind CapType)
|
||||||
|
|
||||||
|
// Clear sets all bits of the given capabilities kind to zero. The
|
||||||
|
// 'kind' value should be one or combination (OR'ed) of CAPS,
|
||||||
|
// BOUNDS or AMBS.
|
||||||
|
Clear(kind CapType)
|
||||||
|
|
||||||
|
// String return current capabilities state of the given capabilities
|
||||||
|
// set as string. The 'which' value should be one of EFFECTIVE,
|
||||||
|
// PERMITTED, INHERITABLE BOUNDING or AMBIENT
|
||||||
|
StringCap(which CapType) string
|
||||||
|
|
||||||
|
// String return current capabilities state as string.
|
||||||
|
String() string
|
||||||
|
|
||||||
|
// Load load actual capabilities value. This will overwrite all
|
||||||
|
// outstanding changes.
|
||||||
|
Load() error
|
||||||
|
|
||||||
|
// Apply apply the capabilities settings, so all changes made by
|
||||||
|
// [Set], [Unset], [Fill], or [Clear] will take effect.
|
||||||
|
Apply(kind CapType) error
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewPid initializes a new [Capabilities] object for given pid when
|
||||||
|
// it is nonzero, or for the current process if pid is 0.
|
||||||
|
//
|
||||||
|
// Deprecated: replace with [NewPid2] followed by optional [Capabilities.Load]
|
||||||
|
// (only if needed). For example, replace:
|
||||||
|
//
|
||||||
|
// c, err := NewPid(0)
|
||||||
|
// if err != nil {
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// with:
|
||||||
|
//
|
||||||
|
// c, err := NewPid2(0)
|
||||||
|
// if err != nil {
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
|
// err = c.Load()
|
||||||
|
// if err != nil {
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
|
func NewPid(pid int) (Capabilities, error) {
|
||||||
|
c, err := newPid(pid)
|
||||||
|
if err != nil {
|
||||||
|
return c, err
|
||||||
|
}
|
||||||
|
err = c.Load()
|
||||||
|
return c, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewPid2 initializes a new [Capabilities] object for given pid when
|
||||||
|
// it is nonzero, or for the current process if pid is 0. This
|
||||||
|
// does not load the process's current capabilities; if needed,
|
||||||
|
// call [Capabilities.Load].
|
||||||
|
func NewPid2(pid int) (Capabilities, error) {
|
||||||
|
return newPid(pid)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewFile initializes a new Capabilities object for given file path.
|
||||||
|
//
|
||||||
|
// Deprecated: replace with [NewFile2] followed by optional [Capabilities.Load]
|
||||||
|
// (only if needed). For example, replace:
|
||||||
|
//
|
||||||
|
// c, err := NewFile(path)
|
||||||
|
// if err != nil {
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// with:
|
||||||
|
//
|
||||||
|
// c, err := NewFile2(path)
|
||||||
|
// if err != nil {
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
|
// err = c.Load()
|
||||||
|
// if err != nil {
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
|
func NewFile(path string) (Capabilities, error) {
|
||||||
|
c, err := newFile(path)
|
||||||
|
if err != nil {
|
||||||
|
return c, err
|
||||||
|
}
|
||||||
|
err = c.Load()
|
||||||
|
return c, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewFile2 creates a new initialized [Capabilities] object for given
|
||||||
|
// file path. This does not load the process's current capabilities;
|
||||||
|
// if needed, call [Capabilities.Load].
|
||||||
|
func NewFile2(path string) (Capabilities, error) {
|
||||||
|
return newFile(path)
|
||||||
|
}
|
||||||
|
|
||||||
|
// LastCap returns highest valid capability of the running kernel,
|
||||||
|
// or an error if it can not be obtained.
|
||||||
|
//
|
||||||
|
// See also: [ListSupported].
|
||||||
|
func LastCap() (Cap, error) {
|
||||||
|
return lastCap()
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetAmbient determines if a specific ambient capability is raised in the
|
||||||
|
// calling thread.
|
||||||
|
func GetAmbient(c Cap) (bool, error) {
|
||||||
|
return getAmbient(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetAmbient raises or lowers specified ambient capabilities for the calling
|
||||||
|
// thread. To complete successfully, the prevailing effective capability set
|
||||||
|
// must have a raised CAP_SETPCAP. Further, to raise a specific ambient
|
||||||
|
// capability the inheritable and permitted sets of the calling thread must
|
||||||
|
// already contain the specified capability.
|
||||||
|
func SetAmbient(raise bool, caps ...Cap) error {
|
||||||
|
return setAmbient(raise, caps...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ResetAmbient resets all of the ambient capabilities for the calling thread
|
||||||
|
// to their lowered value.
|
||||||
|
func ResetAmbient() error {
|
||||||
|
return resetAmbient()
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetBound determines if a specific bounding capability is raised in the
|
||||||
|
// calling thread.
|
||||||
|
func GetBound(c Cap) (bool, error) {
|
||||||
|
return getBound(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DropBound lowers the specified bounding set capability.
|
||||||
|
func DropBound(caps ...Cap) error {
|
||||||
|
return dropBound(caps...)
|
||||||
|
}
|
||||||
Generated
Vendored
+146
-197
@@ -1,8 +1,9 @@
|
|||||||
// Copyright (c) 2013, Suryandaru Triandana <syndtr@gmail.com>
|
// Copyright 2023 The Capability Authors.
|
||||||
|
// Copyright 2013 Suryandaru Triandana <syndtr@gmail.com>
|
||||||
// All rights reserved.
|
// All rights reserved.
|
||||||
//
|
//
|
||||||
// Use of this source code is governed by a BSD-style license that can be
|
// Use of this source code is governed by a BSD-style
|
||||||
// found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package capability
|
package capability
|
||||||
|
|
||||||
@@ -12,62 +13,53 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
"syscall"
|
"syscall"
|
||||||
)
|
)
|
||||||
|
|
||||||
var errUnknownVers = errors.New("unknown capability version")
|
|
||||||
|
|
||||||
const (
|
const (
|
||||||
linuxCapVer1 = 0x19980330
|
linuxCapVer1 = 0x19980330 // No longer supported.
|
||||||
linuxCapVer2 = 0x20071026
|
linuxCapVer2 = 0x20071026 // No longer supported.
|
||||||
linuxCapVer3 = 0x20080522
|
linuxCapVer3 = 0x20080522
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var lastCap = sync.OnceValues(func() (Cap, error) {
|
||||||
capVers uint32
|
|
||||||
capLastCap Cap
|
|
||||||
)
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
var hdr capHeader
|
|
||||||
capget(&hdr, nil)
|
|
||||||
capVers = hdr.version
|
|
||||||
|
|
||||||
if initLastCap() == nil {
|
|
||||||
CAP_LAST_CAP = capLastCap
|
|
||||||
if capLastCap > 31 {
|
|
||||||
capUpperMask = (uint32(1) << (uint(capLastCap) - 31)) - 1
|
|
||||||
} else {
|
|
||||||
capUpperMask = 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func initLastCap() error {
|
|
||||||
if capLastCap != 0 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
f, err := os.Open("/proc/sys/kernel/cap_last_cap")
|
f, err := os.Open("/proc/sys/kernel/cap_last_cap")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return 0, err
|
||||||
}
|
}
|
||||||
defer f.Close()
|
|
||||||
|
|
||||||
var b []byte = make([]byte, 11)
|
buf := make([]byte, 11)
|
||||||
_, err = f.Read(b)
|
l, err := f.Read(buf)
|
||||||
|
f.Close()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
buf = buf[:l]
|
||||||
|
|
||||||
fmt.Sscanf(string(b), "%d", &capLastCap)
|
last, err := strconv.Atoi(strings.TrimSpace(string(buf)))
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return Cap(last), nil
|
||||||
|
})
|
||||||
|
|
||||||
return nil
|
func capUpperMask() uint32 {
|
||||||
|
last, err := lastCap()
|
||||||
|
if err != nil || last < 32 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return (uint32(1) << (uint(last) - 31)) - 1
|
||||||
}
|
}
|
||||||
|
|
||||||
func mkStringCap(c Capabilities, which CapType) (ret string) {
|
func mkStringCap(c Capabilities, which CapType) (ret string) {
|
||||||
for i, first := Cap(0), true; i <= CAP_LAST_CAP; i++ {
|
last, err := lastCap()
|
||||||
|
if err != nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
for i, first := Cap(0), true; i <= last; i++ {
|
||||||
if !c.Get(which, i) {
|
if !c.Get(which, i) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@@ -98,136 +90,38 @@ func mkString(c Capabilities, max CapType) (ret string) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func newPid(pid int) (c Capabilities, err error) {
|
var capVersion = sync.OnceValues(func() (uint32, error) {
|
||||||
switch capVers {
|
var hdr capHeader
|
||||||
case linuxCapVer1:
|
err := capget(&hdr, nil)
|
||||||
p := new(capsV1)
|
return hdr.version, err
|
||||||
p.hdr.version = capVers
|
})
|
||||||
p.hdr.pid = int32(pid)
|
|
||||||
c = p
|
func newPid(pid int) (c Capabilities, retErr error) {
|
||||||
case linuxCapVer2, linuxCapVer3:
|
ver, err := capVersion()
|
||||||
p := new(capsV3)
|
if err != nil {
|
||||||
p.hdr.version = capVers
|
retErr = fmt.Errorf("unable to get capability version from the kernel: %w", err)
|
||||||
p.hdr.pid = int32(pid)
|
|
||||||
c = p
|
|
||||||
default:
|
|
||||||
err = errUnknownVers
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
return
|
switch ver {
|
||||||
}
|
case linuxCapVer1, linuxCapVer2:
|
||||||
|
retErr = errors.New("old/unsupported capability version (kernel older than 2.6.26?)")
|
||||||
type capsV1 struct {
|
default:
|
||||||
hdr capHeader
|
// Either linuxCapVer3, or an unknown/future version (such as v4).
|
||||||
data capData
|
// In the latter case, we fall back to v3 as the latest version known
|
||||||
}
|
// to this package, as kernel should be backward-compatible to v3.
|
||||||
|
p := new(capsV3)
|
||||||
func (c *capsV1) Get(which CapType, what Cap) bool {
|
p.hdr.version = linuxCapVer3
|
||||||
if what > 32 {
|
p.hdr.pid = int32(pid)
|
||||||
return false
|
c = p
|
||||||
}
|
|
||||||
|
|
||||||
switch which {
|
|
||||||
case EFFECTIVE:
|
|
||||||
return (1<<uint(what))&c.data.effective != 0
|
|
||||||
case PERMITTED:
|
|
||||||
return (1<<uint(what))&c.data.permitted != 0
|
|
||||||
case INHERITABLE:
|
|
||||||
return (1<<uint(what))&c.data.inheritable != 0
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *capsV1) getData(which CapType) (ret uint32) {
|
|
||||||
switch which {
|
|
||||||
case EFFECTIVE:
|
|
||||||
ret = c.data.effective
|
|
||||||
case PERMITTED:
|
|
||||||
ret = c.data.permitted
|
|
||||||
case INHERITABLE:
|
|
||||||
ret = c.data.inheritable
|
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *capsV1) Empty(which CapType) bool {
|
func ignoreEINVAL(err error) error {
|
||||||
return c.getData(which) == 0
|
if errors.Is(err, syscall.EINVAL) {
|
||||||
}
|
err = nil
|
||||||
|
|
||||||
func (c *capsV1) Full(which CapType) bool {
|
|
||||||
return (c.getData(which) & 0x7fffffff) == 0x7fffffff
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *capsV1) Set(which CapType, caps ...Cap) {
|
|
||||||
for _, what := range caps {
|
|
||||||
if what > 32 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if which&EFFECTIVE != 0 {
|
|
||||||
c.data.effective |= 1 << uint(what)
|
|
||||||
}
|
|
||||||
if which&PERMITTED != 0 {
|
|
||||||
c.data.permitted |= 1 << uint(what)
|
|
||||||
}
|
|
||||||
if which&INHERITABLE != 0 {
|
|
||||||
c.data.inheritable |= 1 << uint(what)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
return err
|
||||||
|
|
||||||
func (c *capsV1) Unset(which CapType, caps ...Cap) {
|
|
||||||
for _, what := range caps {
|
|
||||||
if what > 32 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if which&EFFECTIVE != 0 {
|
|
||||||
c.data.effective &= ^(1 << uint(what))
|
|
||||||
}
|
|
||||||
if which&PERMITTED != 0 {
|
|
||||||
c.data.permitted &= ^(1 << uint(what))
|
|
||||||
}
|
|
||||||
if which&INHERITABLE != 0 {
|
|
||||||
c.data.inheritable &= ^(1 << uint(what))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *capsV1) Fill(kind CapType) {
|
|
||||||
if kind&CAPS == CAPS {
|
|
||||||
c.data.effective = 0x7fffffff
|
|
||||||
c.data.permitted = 0x7fffffff
|
|
||||||
c.data.inheritable = 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *capsV1) Clear(kind CapType) {
|
|
||||||
if kind&CAPS == CAPS {
|
|
||||||
c.data.effective = 0
|
|
||||||
c.data.permitted = 0
|
|
||||||
c.data.inheritable = 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *capsV1) StringCap(which CapType) (ret string) {
|
|
||||||
return mkStringCap(c, which)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *capsV1) String() (ret string) {
|
|
||||||
return mkString(c, BOUNDING)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *capsV1) Load() (err error) {
|
|
||||||
return capget(&c.hdr, &c.data)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *capsV1) Apply(kind CapType) error {
|
|
||||||
if kind&CAPS == CAPS {
|
|
||||||
return capset(&c.hdr, &c.data)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type capsV3 struct {
|
type capsV3 struct {
|
||||||
@@ -292,7 +186,8 @@ func (c *capsV3) Full(which CapType) bool {
|
|||||||
if (data[0] & 0xffffffff) != 0xffffffff {
|
if (data[0] & 0xffffffff) != 0xffffffff {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return (data[1] & capUpperMask) == capUpperMask
|
mask := capUpperMask()
|
||||||
|
return (data[1] & mask) == mask
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *capsV3) Set(which CapType, caps ...Cap) {
|
func (c *capsV3) Set(which CapType, caps ...Cap) {
|
||||||
@@ -401,15 +296,12 @@ func (c *capsV3) Load() (err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var status_path string
|
path := "/proc/self/status"
|
||||||
|
if c.hdr.pid != 0 {
|
||||||
if c.hdr.pid == 0 {
|
path = fmt.Sprintf("/proc/%d/status", c.hdr.pid)
|
||||||
status_path = fmt.Sprintf("/proc/self/status")
|
|
||||||
} else {
|
|
||||||
status_path = fmt.Sprintf("/proc/%d/status", c.hdr.pid)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
f, err := os.Open(status_path)
|
f, err := os.Open(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -422,12 +314,18 @@ func (c *capsV3) Load() (err error) {
|
|||||||
}
|
}
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if strings.HasPrefix(line, "CapB") {
|
if val, ok := strings.CutPrefix(line, "CapBnd:\t"); ok {
|
||||||
fmt.Sscanf(line[4:], "nd: %08x%08x", &c.bounds[1], &c.bounds[0])
|
_, err = fmt.Sscanf(val, "%08x%08x", &c.bounds[1], &c.bounds[0])
|
||||||
|
if err != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if strings.HasPrefix(line, "CapA") {
|
if val, ok := strings.CutPrefix(line, "CapAmb:\t"); ok {
|
||||||
fmt.Sscanf(line[4:], "mb: %08x%08x", &c.ambient[1], &c.ambient[0])
|
_, err = fmt.Sscanf(val, "%08x%08x", &c.ambient[1], &c.ambient[0])
|
||||||
|
if err != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -436,26 +334,29 @@ func (c *capsV3) Load() (err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *capsV3) Apply(kind CapType) (err error) {
|
func (c *capsV3) Apply(kind CapType) error {
|
||||||
|
if c.hdr.pid != 0 {
|
||||||
|
return errors.New("unable to modify capabilities of another process")
|
||||||
|
}
|
||||||
|
last, err := LastCap()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
if kind&BOUNDS == BOUNDS {
|
if kind&BOUNDS == BOUNDS {
|
||||||
var data [2]capData
|
var data [2]capData
|
||||||
err = capget(&c.hdr, &data[0])
|
err = capget(&c.hdr, &data[0])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return err
|
||||||
}
|
}
|
||||||
if (1<<uint(CAP_SETPCAP))&data[0].effective != 0 {
|
if (1<<uint(CAP_SETPCAP))&data[0].effective != 0 {
|
||||||
for i := Cap(0); i <= CAP_LAST_CAP; i++ {
|
for i := Cap(0); i <= last; i++ {
|
||||||
if c.Get(BOUNDING, i) {
|
if c.Get(BOUNDING, i) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
err = prctl(syscall.PR_CAPBSET_DROP, uintptr(i), 0, 0, 0)
|
// Ignore EINVAL since the capability may not be supported in this system.
|
||||||
|
err = ignoreEINVAL(dropBound(i))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// Ignore EINVAL since the capability may not be supported in this system.
|
return err
|
||||||
if errno, ok := err.(syscall.Errno); ok && errno == syscall.EINVAL {
|
|
||||||
err = nil
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -464,26 +365,73 @@ func (c *capsV3) Apply(kind CapType) (err error) {
|
|||||||
if kind&CAPS == CAPS {
|
if kind&CAPS == CAPS {
|
||||||
err = capset(&c.hdr, &c.data[0])
|
err = capset(&c.hdr, &c.data[0])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if kind&AMBS == AMBS {
|
if kind&AMBS == AMBS {
|
||||||
for i := Cap(0); i <= CAP_LAST_CAP; i++ {
|
// Ignore EINVAL as not supported on kernels before 4.3
|
||||||
action := pr_CAP_AMBIENT_LOWER
|
err = ignoreEINVAL(resetAmbient())
|
||||||
if c.Get(AMBIENT, i) {
|
if err != nil {
|
||||||
action = pr_CAP_AMBIENT_RAISE
|
return err
|
||||||
}
|
}
|
||||||
err := prctl(pr_CAP_AMBIENT, action, uintptr(i), 0, 0)
|
for i := Cap(0); i <= last; i++ {
|
||||||
// Ignore EINVAL as not supported on kernels before 4.3
|
if !c.Get(AMBIENT, i) {
|
||||||
if errno, ok := err.(syscall.Errno); ok && errno == syscall.EINVAL {
|
|
||||||
err = nil
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
// Ignore EINVAL as not supported on kernels before 4.3
|
||||||
|
err = ignoreEINVAL(setAmbient(true, i))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getAmbient(c Cap) (bool, error) {
|
||||||
|
res, err := prctlRetInt(pr_CAP_AMBIENT, pr_CAP_AMBIENT_IS_SET, uintptr(c))
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
return res > 0, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func setAmbient(raise bool, caps ...Cap) error {
|
||||||
|
op := pr_CAP_AMBIENT_RAISE
|
||||||
|
if !raise {
|
||||||
|
op = pr_CAP_AMBIENT_LOWER
|
||||||
|
}
|
||||||
|
for _, val := range caps {
|
||||||
|
err := prctl(pr_CAP_AMBIENT, op, uintptr(val))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resetAmbient() error {
|
||||||
|
return prctl(pr_CAP_AMBIENT, pr_CAP_AMBIENT_CLEAR_ALL, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getBound(c Cap) (bool, error) {
|
||||||
|
res, err := prctlRetInt(syscall.PR_CAPBSET_READ, uintptr(c), 0)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
return res > 0, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func dropBound(caps ...Cap) error {
|
||||||
|
for _, val := range caps {
|
||||||
|
err := prctl(syscall.PR_CAPBSET_DROP, uintptr(val), 0)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func newFile(path string) (c Capabilities, err error) {
|
func newFile(path string) (c Capabilities, err error) {
|
||||||
@@ -547,7 +495,8 @@ func (c *capsFile) Full(which CapType) bool {
|
|||||||
if (data[0] & 0xffffffff) != 0xffffffff {
|
if (data[0] & 0xffffffff) != 0xffffffff {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return (data[1] & capUpperMask) == capUpperMask
|
mask := capUpperMask()
|
||||||
|
return (data[1] & mask) == mask
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *capsFile) Set(which CapType, caps ...Cap) {
|
func (c *capsFile) Set(which CapType, caps ...Cap) {
|
||||||
+46
@@ -0,0 +1,46 @@
|
|||||||
|
// Copyright 2023 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.
|
||||||
|
|
||||||
|
//go:build !linux
|
||||||
|
|
||||||
|
package capability
|
||||||
|
|
||||||
|
import "errors"
|
||||||
|
|
||||||
|
var errNotSup = errors.New("not supported")
|
||||||
|
|
||||||
|
func newPid(_ int) (Capabilities, error) {
|
||||||
|
return nil, errNotSup
|
||||||
|
}
|
||||||
|
|
||||||
|
func newFile(_ string) (Capabilities, error) {
|
||||||
|
return nil, errNotSup
|
||||||
|
}
|
||||||
|
|
||||||
|
func lastCap() (Cap, error) {
|
||||||
|
return -1, errNotSup
|
||||||
|
}
|
||||||
|
|
||||||
|
func getAmbient(_ Cap) (bool, error) {
|
||||||
|
return false, errNotSup
|
||||||
|
}
|
||||||
|
|
||||||
|
func setAmbient(_ bool, _ ...Cap) error {
|
||||||
|
return errNotSup
|
||||||
|
}
|
||||||
|
|
||||||
|
func resetAmbient() error {
|
||||||
|
return errNotSup
|
||||||
|
}
|
||||||
|
|
||||||
|
func getBound(_ Cap) (bool, error) {
|
||||||
|
return false, errNotSup
|
||||||
|
}
|
||||||
|
|
||||||
|
func dropBound(_ ...Cap) error {
|
||||||
|
return errNotSup
|
||||||
|
}
|
||||||
Generated
Vendored
+29
-8
@@ -1,11 +1,14 @@
|
|||||||
// Copyright (c) 2013, Suryandaru Triandana <syndtr@gmail.com>
|
// Copyright 2024 The Capability Authors.
|
||||||
|
// Copyright 2013 Suryandaru Triandana <syndtr@gmail.com>
|
||||||
// All rights reserved.
|
// All rights reserved.
|
||||||
//
|
//
|
||||||
// Use of this source code is governed by a BSD-style license that can be
|
// Use of this source code is governed by a BSD-style
|
||||||
// found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package capability
|
package capability
|
||||||
|
|
||||||
|
import "slices"
|
||||||
|
|
||||||
type CapType uint
|
type CapType uint
|
||||||
|
|
||||||
func (c CapType) String() string {
|
func (c CapType) String() string {
|
||||||
@@ -301,9 +304,27 @@ const (
|
|||||||
CAP_CHECKPOINT_RESTORE = Cap(40)
|
CAP_CHECKPOINT_RESTORE = Cap(40)
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
// List returns the list of all capabilities known to the package.
|
||||||
// Highest valid capability of the running kernel.
|
//
|
||||||
CAP_LAST_CAP = Cap(63)
|
// Deprecated: use [ListKnown] or [ListSupported] instead.
|
||||||
|
func List() []Cap {
|
||||||
|
return ListKnown()
|
||||||
|
}
|
||||||
|
|
||||||
capUpperMask = ^uint32(0)
|
// ListKnown returns the list of all capabilities known to the package.
|
||||||
)
|
func ListKnown() []Cap {
|
||||||
|
return list()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListSupported returns the list of all capabilities known to the package,
|
||||||
|
// except those that are not supported by the currently running Linux kernel.
|
||||||
|
func ListSupported() ([]Cap, error) {
|
||||||
|
last, err := LastCap()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return slices.DeleteFunc(list(), func(c Cap) bool {
|
||||||
|
// Remove caps not supported by the kernel.
|
||||||
|
return c > last
|
||||||
|
}), nil
|
||||||
|
}
|
||||||
Generated
Vendored
+2
-3
@@ -1,4 +1,4 @@
|
|||||||
// generated file; DO NOT EDIT - use go generate in directory with source
|
// Code generated by go generate; DO NOT EDIT.
|
||||||
|
|
||||||
package capability
|
package capability
|
||||||
|
|
||||||
@@ -90,8 +90,7 @@ func (c Cap) String() string {
|
|||||||
return "unknown"
|
return "unknown"
|
||||||
}
|
}
|
||||||
|
|
||||||
// List returns list of all supported capabilities
|
func list() []Cap {
|
||||||
func List() []Cap {
|
|
||||||
return []Cap{
|
return []Cap{
|
||||||
CAP_CHOWN,
|
CAP_CHOWN,
|
||||||
CAP_DAC_OVERRIDE,
|
CAP_DAC_OVERRIDE,
|
||||||
Generated
Vendored
+19
-12
@@ -1,8 +1,9 @@
|
|||||||
// Copyright (c) 2013, Suryandaru Triandana <syndtr@gmail.com>
|
// Copyright 2024 The Capability Authors.
|
||||||
|
// Copyright 2013 Suryandaru Triandana <syndtr@gmail.com>
|
||||||
// All rights reserved.
|
// All rights reserved.
|
||||||
//
|
//
|
||||||
// Use of this source code is governed by a BSD-style license that can be
|
// Use of this source code is governed by a BSD-style
|
||||||
// found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package capability
|
package capability
|
||||||
|
|
||||||
@@ -23,7 +24,7 @@ type capData struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func capget(hdr *capHeader, data *capData) (err error) {
|
func capget(hdr *capHeader, data *capData) (err error) {
|
||||||
_, _, e1 := syscall.Syscall(syscall.SYS_CAPGET, uintptr(unsafe.Pointer(hdr)), uintptr(unsafe.Pointer(data)), 0)
|
_, _, e1 := syscall.RawSyscall(syscall.SYS_CAPGET, uintptr(unsafe.Pointer(hdr)), uintptr(unsafe.Pointer(data)), 0)
|
||||||
if e1 != 0 {
|
if e1 != 0 {
|
||||||
err = e1
|
err = e1
|
||||||
}
|
}
|
||||||
@@ -31,7 +32,7 @@ func capget(hdr *capHeader, data *capData) (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func capset(hdr *capHeader, data *capData) (err error) {
|
func capset(hdr *capHeader, data *capData) (err error) {
|
||||||
_, _, e1 := syscall.Syscall(syscall.SYS_CAPSET, uintptr(unsafe.Pointer(hdr)), uintptr(unsafe.Pointer(data)), 0)
|
_, _, e1 := syscall.RawSyscall(syscall.SYS_CAPSET, uintptr(unsafe.Pointer(hdr)), uintptr(unsafe.Pointer(data)), 0)
|
||||||
if e1 != 0 {
|
if e1 != 0 {
|
||||||
err = e1
|
err = e1
|
||||||
}
|
}
|
||||||
@@ -47,14 +48,22 @@ const (
|
|||||||
pr_CAP_AMBIENT_CLEAR_ALL = uintptr(4)
|
pr_CAP_AMBIENT_CLEAR_ALL = uintptr(4)
|
||||||
)
|
)
|
||||||
|
|
||||||
func prctl(option int, arg2, arg3, arg4, arg5 uintptr) (err error) {
|
func prctl(option int, arg2, arg3 uintptr) (err error) {
|
||||||
_, _, e1 := syscall.Syscall6(syscall.SYS_PRCTL, uintptr(option), arg2, arg3, arg4, arg5, 0)
|
_, _, e1 := syscall.RawSyscall(syscall.SYS_PRCTL, uintptr(option), arg2, arg3)
|
||||||
if e1 != 0 {
|
if e1 != 0 {
|
||||||
err = e1
|
err = e1
|
||||||
}
|
}
|
||||||
return
|
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 (
|
const (
|
||||||
vfsXattrName = "security.capability"
|
vfsXattrName = "security.capability"
|
||||||
|
|
||||||
@@ -79,9 +88,7 @@ type vfscapData struct {
|
|||||||
version int8
|
version int8
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var _vfsXattrName *byte
|
||||||
_vfsXattrName *byte
|
|
||||||
)
|
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
_vfsXattrName, _ = syscall.BytePtrFromString(vfsXattrName)
|
_vfsXattrName, _ = syscall.BytePtrFromString(vfsXattrName)
|
||||||
@@ -93,7 +100,7 @@ func getVfsCap(path string, dest *vfscapData) (err error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
r0, _, e1 := syscall.Syscall6(syscall.SYS_GETXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_vfsXattrName)), uintptr(unsafe.Pointer(dest)), vfscapDataSizeV2, 0, 0)
|
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 != 0 {
|
||||||
if e1 == syscall.ENODATA {
|
if e1 == syscall.ENODATA {
|
||||||
dest.version = 2
|
dest.version = 2
|
||||||
@@ -146,7 +153,7 @@ func setVfsCap(path string, data *vfscapData) (err error) {
|
|||||||
} else {
|
} else {
|
||||||
return syscall.EINVAL
|
return syscall.EINVAL
|
||||||
}
|
}
|
||||||
_, _, e1 := syscall.Syscall6(syscall.SYS_SETXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_vfsXattrName)), uintptr(unsafe.Pointer(data)), size, 0, 0)
|
_, _, e1 := syscall.RawSyscall6(syscall.SYS_SETXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_vfsXattrName)), uintptr(unsafe.Pointer(data)), size, 0, 0)
|
||||||
if e1 != 0 {
|
if e1 != 0 {
|
||||||
err = e1
|
err = e1
|
||||||
}
|
}
|
||||||
-133
@@ -1,133 +0,0 @@
|
|||||||
// Copyright (c) 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 provides utilities for manipulating POSIX capabilities.
|
|
||||||
package capability
|
|
||||||
|
|
||||||
type Capabilities interface {
|
|
||||||
// Get check whether a capability present in the given
|
|
||||||
// capabilities set. The 'which' value should be one of EFFECTIVE,
|
|
||||||
// PERMITTED, INHERITABLE, BOUNDING or AMBIENT.
|
|
||||||
Get(which CapType, what Cap) bool
|
|
||||||
|
|
||||||
// Empty check whether all capability bits of the given capabilities
|
|
||||||
// set are zero. The 'which' value should be one of EFFECTIVE,
|
|
||||||
// PERMITTED, INHERITABLE, BOUNDING or AMBIENT.
|
|
||||||
Empty(which CapType) bool
|
|
||||||
|
|
||||||
// Full check whether all capability bits of the given capabilities
|
|
||||||
// set are one. The 'which' value should be one of EFFECTIVE,
|
|
||||||
// PERMITTED, INHERITABLE, BOUNDING or AMBIENT.
|
|
||||||
Full(which CapType) bool
|
|
||||||
|
|
||||||
// Set sets capabilities of the given capabilities sets. The
|
|
||||||
// 'which' value should be one or combination (OR'ed) of EFFECTIVE,
|
|
||||||
// PERMITTED, INHERITABLE, BOUNDING or AMBIENT.
|
|
||||||
Set(which CapType, caps ...Cap)
|
|
||||||
|
|
||||||
// Unset unsets capabilities of the given capabilities sets. The
|
|
||||||
// 'which' value should be one or combination (OR'ed) of EFFECTIVE,
|
|
||||||
// PERMITTED, INHERITABLE, BOUNDING or AMBIENT.
|
|
||||||
Unset(which CapType, caps ...Cap)
|
|
||||||
|
|
||||||
// Fill sets all bits of the given capabilities kind to one. The
|
|
||||||
// 'kind' value should be one or combination (OR'ed) of CAPS,
|
|
||||||
// BOUNDS or AMBS.
|
|
||||||
Fill(kind CapType)
|
|
||||||
|
|
||||||
// Clear sets all bits of the given capabilities kind to zero. The
|
|
||||||
// 'kind' value should be one or combination (OR'ed) of CAPS,
|
|
||||||
// BOUNDS or AMBS.
|
|
||||||
Clear(kind CapType)
|
|
||||||
|
|
||||||
// String return current capabilities state of the given capabilities
|
|
||||||
// set as string. The 'which' value should be one of EFFECTIVE,
|
|
||||||
// PERMITTED, INHERITABLE BOUNDING or AMBIENT
|
|
||||||
StringCap(which CapType) string
|
|
||||||
|
|
||||||
// String return current capabilities state as string.
|
|
||||||
String() string
|
|
||||||
|
|
||||||
// Load load actual capabilities value. This will overwrite all
|
|
||||||
// outstanding changes.
|
|
||||||
Load() error
|
|
||||||
|
|
||||||
// Apply apply the capabilities settings, so all changes will take
|
|
||||||
// effect.
|
|
||||||
Apply(kind CapType) error
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewPid initializes a new Capabilities object for given pid when
|
|
||||||
// it is nonzero, or for the current process if pid is 0.
|
|
||||||
//
|
|
||||||
// Deprecated: Replace with NewPid2. For example, replace:
|
|
||||||
//
|
|
||||||
// c, err := NewPid(0)
|
|
||||||
// if err != nil {
|
|
||||||
// return err
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// with:
|
|
||||||
//
|
|
||||||
// c, err := NewPid2(0)
|
|
||||||
// if err != nil {
|
|
||||||
// return err
|
|
||||||
// }
|
|
||||||
// err = c.Load()
|
|
||||||
// if err != nil {
|
|
||||||
// return err
|
|
||||||
// }
|
|
||||||
func NewPid(pid int) (Capabilities, error) {
|
|
||||||
c, err := newPid(pid)
|
|
||||||
if err != nil {
|
|
||||||
return c, err
|
|
||||||
}
|
|
||||||
err = c.Load()
|
|
||||||
return c, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewPid2 initializes a new Capabilities object for given pid when
|
|
||||||
// it is nonzero, or for the current process if pid is 0. This
|
|
||||||
// does not load the process's current capabilities; to do that you
|
|
||||||
// must call Load explicitly.
|
|
||||||
func NewPid2(pid int) (Capabilities, error) {
|
|
||||||
return newPid(pid)
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewFile initializes a new Capabilities object for given file path.
|
|
||||||
//
|
|
||||||
// Deprecated: Replace with NewFile2. For example, replace:
|
|
||||||
//
|
|
||||||
// c, err := NewFile(path)
|
|
||||||
// if err != nil {
|
|
||||||
// return err
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// with:
|
|
||||||
//
|
|
||||||
// c, err := NewFile2(path)
|
|
||||||
// if err != nil {
|
|
||||||
// return err
|
|
||||||
// }
|
|
||||||
// err = c.Load()
|
|
||||||
// if err != nil {
|
|
||||||
// return err
|
|
||||||
// }
|
|
||||||
func NewFile(path string) (Capabilities, error) {
|
|
||||||
c, err := newFile(path)
|
|
||||||
if err != nil {
|
|
||||||
return c, err
|
|
||||||
}
|
|
||||||
err = c.Load()
|
|
||||||
return c, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewFile2 creates a new initialized Capabilities object for given
|
|
||||||
// file path. This does not load the process's current capabilities;
|
|
||||||
// to do that you must call Load explicitly.
|
|
||||||
func NewFile2(path string) (Capabilities, error) {
|
|
||||||
return newFile(path)
|
|
||||||
}
|
|
||||||
-19
@@ -1,19 +0,0 @@
|
|||||||
// Copyright (c) 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.
|
|
||||||
|
|
||||||
// +build !linux
|
|
||||||
|
|
||||||
package capability
|
|
||||||
|
|
||||||
import "errors"
|
|
||||||
|
|
||||||
func newPid(pid int) (Capabilities, error) {
|
|
||||||
return nil, errors.New("not supported")
|
|
||||||
}
|
|
||||||
|
|
||||||
func newFile(path string) (Capabilities, error) {
|
|
||||||
return nil, errors.New("not supported")
|
|
||||||
}
|
|
||||||
Vendored
+3
-3
@@ -34,6 +34,9 @@ github.com/docker/go-units
|
|||||||
# github.com/godbus/dbus/v5 v5.1.0
|
# github.com/godbus/dbus/v5 v5.1.0
|
||||||
## explicit; go 1.12
|
## explicit; go 1.12
|
||||||
github.com/godbus/dbus/v5
|
github.com/godbus/dbus/v5
|
||||||
|
# github.com/moby/sys/capability v0.4.0
|
||||||
|
## explicit; go 1.21
|
||||||
|
github.com/moby/sys/capability
|
||||||
# github.com/moby/sys/mountinfo v0.7.2
|
# github.com/moby/sys/mountinfo v0.7.2
|
||||||
## explicit; go 1.17
|
## explicit; go 1.17
|
||||||
github.com/moby/sys/mountinfo
|
github.com/moby/sys/mountinfo
|
||||||
@@ -65,9 +68,6 @@ github.com/seccomp/libseccomp-golang
|
|||||||
## explicit; go 1.13
|
## explicit; go 1.13
|
||||||
github.com/sirupsen/logrus
|
github.com/sirupsen/logrus
|
||||||
github.com/sirupsen/logrus/hooks/test
|
github.com/sirupsen/logrus/hooks/test
|
||||||
# github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635
|
|
||||||
## explicit
|
|
||||||
github.com/syndtr/gocapability/capability
|
|
||||||
# github.com/urfave/cli v1.22.16
|
# github.com/urfave/cli v1.22.16
|
||||||
## explicit; go 1.11
|
## explicit; go 1.11
|
||||||
github.com/urfave/cli
|
github.com/urfave/cli
|
||||||
|
|||||||
Reference in New Issue
Block a user