Compare commits
68 Commits
Author | SHA1 | Date |
---|---|---|
|
7c6167725b | |
|
b63cf81bb5 | |
|
e86b33e7c5 | |
|
71fa86684d | |
|
9d8d33bd67 | |
|
bfdd693beb | |
|
2fe6ea2d9f | |
|
4590fdba26 | |
|
a028edf9cb | |
|
22a4f30f48 | |
|
34b21b6dc3 | |
|
63fefe0f20 | |
|
591153cb8f | |
|
8a24390d18 | |
|
97f2983630 | |
|
e2a50af30e | |
|
1a717caef7 | |
|
d363e25d2a | |
|
bdb2268d7b | |
|
c5e4904edc | |
|
630a09f34e | |
|
51eaa377ce | |
|
b8a02cc18f | |
|
6c8ecb124e | |
|
6a2d670f51 | |
|
e9fdef4dbf | |
|
76a55c7ad9 | |
|
e6400f5b96 | |
|
bad4003415 | |
|
a26fed5314 | |
|
1a9b6396ef | |
|
b03cedfb33 | |
|
1326c0606a | |
|
898f7b190e | |
|
3b4191616c | |
|
ff7d010baf | |
|
7af78de4f7 | |
|
00e2d7245d | |
|
f72ed843c0 | |
|
0bc7da7ab1 | |
|
51015d1966 | |
|
f9b9e536f8 | |
|
2f5237395e | |
|
b897a7d464 | |
|
7a6c9d3a3d | |
|
86b2c1c2cc | |
|
266bdfe05f | |
|
1ec8ce61a5 | |
|
ba91441159 | |
|
5553f90b1c | |
|
681179f1bd | |
|
b486e8181e | |
|
cd907412d5 | |
|
969537eb7a | |
|
ec31ff1e86 | |
|
fe7a74ceed | |
|
01ca720a78 | |
|
57e5d60a3f | |
|
062cbb9697 | |
|
12a6b5a7ef | |
|
d7918b036c | |
|
8b59acfd3d | |
|
3082eed8f1 | |
|
a4c0f838cd | |
|
fff84e808d | |
|
5ed5002d6c | |
|
ad9b137be0 | |
|
1c78fe1b15 |
|
@ -11,9 +11,8 @@ env:
|
||||||
GOCACHE: "${HOME}/.cache/go-build"
|
GOCACHE: "${HOME}/.cache/go-build"
|
||||||
|
|
||||||
# VM Image built in containers/automation_images
|
# VM Image built in containers/automation_images
|
||||||
IMAGE_SUFFIX: "c20230816t191118z-f38f37d13"
|
IMAGE_SUFFIX: "c20250324t111922z-f41f40d13"
|
||||||
FEDORA_CACHE_IMAGE_NAME: "fedora-${IMAGE_SUFFIX}"
|
FEDORA_CACHE_IMAGE_NAME: "fedora-${IMAGE_SUFFIX}"
|
||||||
RAWHIDE_CACHE_IMAGE_NAME: "rawhide-${IMAGE_SUFFIX}"
|
|
||||||
|
|
||||||
# Must be defined true when testing w/in containers
|
# Must be defined true when testing w/in containers
|
||||||
CONTAINER: "false"
|
CONTAINER: "false"
|
||||||
|
@ -35,7 +34,6 @@ meta_task:
|
||||||
# Space-separated list of images used by this repository state
|
# Space-separated list of images used by this repository state
|
||||||
IMGNAMES: |-
|
IMGNAMES: |-
|
||||||
${FEDORA_CACHE_IMAGE_NAME}
|
${FEDORA_CACHE_IMAGE_NAME}
|
||||||
${RAWHIDE_CACHE_IMAGE_NAME}
|
|
||||||
BUILDID: "${CIRRUS_BUILD_ID}"
|
BUILDID: "${CIRRUS_BUILD_ID}"
|
||||||
REPOREF: "${CIRRUS_CHANGE_IN_REPO}"
|
REPOREF: "${CIRRUS_CHANGE_IN_REPO}"
|
||||||
GCPJSON: ENCRYPTED[ef070c453a5ce68efca096a940835fdca530ed0ec2272ddb52bb02bf7d70dcc3ac9697b85b1d8dcce851931e008f63c0]
|
GCPJSON: ENCRYPTED[ef070c453a5ce68efca096a940835fdca530ed0ec2272ddb52bb02bf7d70dcc3ac9697b85b1d8dcce851931e008f63c0]
|
||||||
|
@ -50,7 +48,7 @@ meta_task:
|
||||||
vendor_task:
|
vendor_task:
|
||||||
|
|
||||||
container:
|
container:
|
||||||
image: golang:1.19
|
image: golang:1.23
|
||||||
|
|
||||||
script:
|
script:
|
||||||
- make vendor
|
- make vendor
|
||||||
|
@ -71,9 +69,6 @@ build_and_test_task:
|
||||||
- name: "Test on Fedora"
|
- name: "Test on Fedora"
|
||||||
gce_instance:
|
gce_instance:
|
||||||
image_name: "${FEDORA_CACHE_IMAGE_NAME}"
|
image_name: "${FEDORA_CACHE_IMAGE_NAME}"
|
||||||
- name: "Test on Rawhide"
|
|
||||||
gce_instance:
|
|
||||||
image_name: "${RAWHIDE_CACHE_IMAGE_NAME}"
|
|
||||||
|
|
||||||
# Avoid downloading this stuff every time
|
# Avoid downloading this stuff every time
|
||||||
gocache_cache:
|
gocache_cache:
|
||||||
|
|
7
Makefile
7
Makefile
|
@ -6,6 +6,7 @@ GO_BUILD=$(GO) build
|
||||||
ifeq ($(shell go help mod >/dev/null 2>&1 && echo true), true)
|
ifeq ($(shell go help mod >/dev/null 2>&1 && echo true), true)
|
||||||
GO_BUILD=GO111MODULE=on $(GO) build -mod=vendor
|
GO_BUILD=GO111MODULE=on $(GO) build -mod=vendor
|
||||||
endif
|
endif
|
||||||
|
BUILDDIR ?= .
|
||||||
DESTDIR ?=
|
DESTDIR ?=
|
||||||
PREFIX ?= /usr/local
|
PREFIX ?= /usr/local
|
||||||
SELINUXOPT ?= $(shell test -x /usr/sbin/selinuxenabled && selinuxenabled && echo -Z)
|
SELINUXOPT ?= $(shell test -x /usr/sbin/selinuxenabled && selinuxenabled && echo -Z)
|
||||||
|
@ -46,7 +47,7 @@ docs:
|
||||||
|
|
||||||
.PHONY: binary
|
.PHONY: binary
|
||||||
binary:
|
binary:
|
||||||
$(GO_BUILD) -mod=vendor -o bin/oci-seccomp-bpf-hook -ldflags "-X main.version=$(OSBH_VERSION)" $(PROJECT)
|
$(GO_BUILD) -mod=vendor -o $(BUILDDIR)/bin/oci-seccomp-bpf-hook -ldflags "-X main.version=$(OSBH_VERSION)" $(PROJECT)
|
||||||
|
|
||||||
.PHONY: validate
|
.PHONY: validate
|
||||||
validate:
|
validate:
|
||||||
|
@ -73,7 +74,7 @@ test-unit:
|
||||||
.PHONY: install.tools
|
.PHONY: install.tools
|
||||||
install.tools: .install.golangci-lint .install.md2man
|
install.tools: .install.golangci-lint .install.md2man
|
||||||
|
|
||||||
.install.golangci-lint: VERSION=v1.51.2
|
.install.golangci-lint: VERSION=v1.60.3
|
||||||
.install.golangci-lint:
|
.install.golangci-lint:
|
||||||
curl -fsSL https://raw.githubusercontent.com/golangci/golangci-lint/$(VERSION)/install.sh | sh -s -- -b ./build $(VERSION)
|
curl -fsSL https://raw.githubusercontent.com/golangci/golangci-lint/$(VERSION)/install.sh | sh -s -- -b ./build $(VERSION)
|
||||||
|
|
||||||
|
@ -94,7 +95,7 @@ install.docs:
|
||||||
install-nobuild: install.docs-nobuild
|
install-nobuild: install.docs-nobuild
|
||||||
install $(SELINUXOPT) -d -m 755 $(DESTDIR)$(HOOK_BIN_DIR)
|
install $(SELINUXOPT) -d -m 755 $(DESTDIR)$(HOOK_BIN_DIR)
|
||||||
install $(SELINUXOPT) -d -m 755 $(DESTDIR)$(HOOK_DIR)
|
install $(SELINUXOPT) -d -m 755 $(DESTDIR)$(HOOK_DIR)
|
||||||
install $(SELINUXOPT) -m 755 bin/oci-seccomp-bpf-hook $(DESTDIR)$(HOOK_BIN_DIR)
|
install $(SELINUXOPT) -m 755 $(BUILDDIR)/bin/oci-seccomp-bpf-hook $(DESTDIR)$(HOOK_BIN_DIR)
|
||||||
install $(SELINUXOPT) -m 644 oci-seccomp-bpf-hook.json $(DESTDIR)$(HOOK_DIR)
|
install $(SELINUXOPT) -m 644 oci-seccomp-bpf-hook.json $(DESTDIR)$(HOOK_DIR)
|
||||||
sed -i 's|HOOK_BIN_DIR|$(HOOK_BIN_DIR)|g' $(DESTDIR)$(HOOK_DIR)/oci-seccomp-bpf-hook.json
|
sed -i 's|HOOK_BIN_DIR|$(HOOK_BIN_DIR)|g' $(DESTDIR)$(HOOK_DIR)/oci-seccomp-bpf-hook.json
|
||||||
|
|
||||||
|
|
7
ebpf.go
7
ebpf.go
|
@ -111,6 +111,13 @@ int enter_trace(struct tracepoint__raw_syscalls__sys_enter* args)
|
||||||
// The syscall was already notified.
|
// The syscall was already notified.
|
||||||
if (seen > 0)
|
if (seen > 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
// if prctl was not seen, ignore the current syscall.
|
||||||
|
u64 prctl = __NR_prctl;
|
||||||
|
u64 *prctl_seen = seen_syscalls.lookup(&prctl);
|
||||||
|
if (prctl_seen == NULL) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
data.stopTracing = false;
|
data.stopTracing = false;
|
||||||
|
|
24
go.mod
24
go.mod
|
@ -1,26 +1,28 @@
|
||||||
module github.com/containers/oci-seccomp-bpf-hook
|
module github.com/containers/oci-seccomp-bpf-hook
|
||||||
|
|
||||||
go 1.19
|
go 1.23.0
|
||||||
|
|
||||||
|
toolchain go1.23.8
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/containers/common v0.56.0
|
github.com/containers/common v0.62.3
|
||||||
github.com/containers/storage v1.50.2
|
github.com/containers/storage v1.58.0
|
||||||
github.com/iovisor/gobpf v0.2.1-0.20221005153822-16120a1bf4d4
|
github.com/iovisor/gobpf v0.2.1-0.20221005153822-16120a1bf4d4
|
||||||
github.com/opencontainers/runtime-spec v1.1.0
|
github.com/opencontainers/runtime-spec v1.2.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/stretchr/testify v1.8.4
|
github.com/stretchr/testify v1.10.0
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
||||||
github.com/docker/go-units v0.5.0 // indirect
|
github.com/docker/go-units v0.5.0 // indirect
|
||||||
github.com/kr/pretty v0.3.1 // indirect
|
github.com/kr/pretty v0.3.1 // indirect
|
||||||
github.com/moby/sys/mountinfo v0.6.2 // indirect
|
github.com/moby/sys/capability v0.4.0 // indirect
|
||||||
github.com/opencontainers/runc v1.1.9 // indirect
|
github.com/moby/sys/mountinfo v0.7.2 // indirect
|
||||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
github.com/moby/sys/user v0.4.0 // indirect
|
||||||
github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635 // indirect
|
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
|
||||||
golang.org/x/sys v0.12.0 // indirect
|
golang.org/x/sys v0.32.0 // indirect
|
||||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
|
||||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
)
|
)
|
||||||
|
|
40
go.sum
40
go.sum
|
@ -1,11 +1,12 @@
|
||||||
github.com/containers/common v0.56.0 h1:hysHUsEai1EkMXanU26UV55wMXns/a6AYmaFqJ4fEMY=
|
github.com/containers/common v0.62.3 h1:aOGryqXfW6aKBbHbqOveH7zB+ihavUN03X/2pUSvWFI=
|
||||||
github.com/containers/common v0.56.0/go.mod h1:IjaDdfUtcs2CfCcJMZxuut4XlvkTkY9Nlqkso9xCOq4=
|
github.com/containers/common v0.62.3/go.mod h1:3R8kDox2prC9uj/a2hmXj/YjZz5sBEUNrcDiw51S0Lo=
|
||||||
github.com/containers/storage v1.50.2 h1:Fys4BjFUVNRBEXlO70hFI48VW4EXsgnGisTpk9tTMsE=
|
github.com/containers/storage v1.58.0 h1:Q7SyyCCjqgT3wYNgRNIL8o/wUS92heIj2/cc8Sewvcc=
|
||||||
github.com/containers/storage v1.50.2/go.mod h1:dpspZsUrcKD8SpTofvKWhwPDHD0MkO4Q7VE+oYdWkiA=
|
github.com/containers/storage v1.58.0/go.mod h1:w7Jl6oG+OpeLGLzlLyOZPkmUso40kjpzgrHUk5tyBlo=
|
||||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
|
||||||
|
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
|
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
|
||||||
github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
|
github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
|
||||||
github.com/iovisor/gobpf v0.2.1-0.20221005153822-16120a1bf4d4 h1:WpizD4VUT5V+VcaQSvW5BlvFpQYrd2974H9KbiGa5/0=
|
github.com/iovisor/gobpf v0.2.1-0.20221005153822-16120a1bf4d4 h1:WpizD4VUT5V+VcaQSvW5BlvFpQYrd2974H9KbiGa5/0=
|
||||||
|
@ -17,16 +18,20 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||||
github.com/moby/sys/mountinfo v0.6.2 h1:BzJjoreD5BMFNmD9Rus6gdd1pLuecOFPt8wC+Vygl78=
|
github.com/moby/sys/capability v0.4.0 h1:4D4mI6KlNtWMCM1Z/K0i7RV1FkX+DBDHKVJpCndZoHk=
|
||||||
github.com/moby/sys/mountinfo v0.6.2/go.mod h1:IJb6JQeOklcdMU9F5xQ8ZALD+CUr5VlGpwtX+VE0rpI=
|
github.com/moby/sys/capability v0.4.0/go.mod h1:4g9IK291rVkms3LKCDOoYlnV8xKwoDTpIrNEE35Wq0I=
|
||||||
github.com/opencontainers/runc v1.1.9 h1:XR0VIHTGce5eWPkaPesqTBrhW2yAcaraWfsEalNwQLM=
|
github.com/moby/sys/mountinfo v0.7.2 h1:1shs6aH5s4o5H2zQLn796ADW1wMrIwHsyJ2v9KouLrg=
|
||||||
github.com/opencontainers/runc v1.1.9/go.mod h1:CbUumNnWCuTGFukNXahoo/RFBZvDAgRh/smNYNOhA50=
|
github.com/moby/sys/mountinfo v0.7.2/go.mod h1:1YOa8w8Ih7uW0wALDUgT1dTTSBrZ+HiBLGws92L2RU4=
|
||||||
github.com/opencontainers/runtime-spec v1.1.0 h1:HHUyrt9mwHUjtasSbXSMvs4cyFxh+Bll4AjJ9odEGpg=
|
github.com/moby/sys/user v0.4.0 h1:jhcMKit7SA80hivmFJcbB1vqmw//wU61Zdui2eQXuMs=
|
||||||
github.com/opencontainers/runtime-spec v1.1.0/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
|
github.com/moby/sys/user v0.4.0/go.mod h1:bG+tYYYJgaMtRKgEmuueC0hJEAZWwtIbZTB+85uoHjs=
|
||||||
github.com/opencontainers/runtime-tools v0.9.1-0.20230317050512-e931285f4b69 h1:NL4xDvl68WWqQ+8WPMM3l5PsZTxaT7Z4K3VSKDRuAGs=
|
github.com/opencontainers/runtime-spec v1.2.1 h1:S4k4ryNgEpxW1dzyqffOmhI1BHYcjzU8lpJfSlR0xww=
|
||||||
|
github.com/opencontainers/runtime-spec v1.2.1/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
|
||||||
|
github.com/opencontainers/runtime-tools v0.9.1-0.20241108202711-f7e3563b0271 h1:TPj0pMLCTy1CKwmrat3hqTxoZfqOuTy0asG0ccpGk8Q=
|
||||||
|
github.com/opencontainers/runtime-tools v0.9.1-0.20241108202711-f7e3563b0271/go.mod h1:oIH6VwKkaDOO+SIYZpdwrC/0wKYqrfO6E1sG1j3UVws=
|
||||||
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
|
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
|
||||||
|
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
|
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
|
||||||
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
|
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
|
||||||
github.com/seccomp/libseccomp-golang v0.10.0 h1:aA4bp+/Zzi0BnWZ2F1wgNBs5gTpm+na2rWM6M9YjLpY=
|
github.com/seccomp/libseccomp-golang v0.10.0 h1:aA4bp+/Zzi0BnWZ2F1wgNBs5gTpm+na2rWM6M9YjLpY=
|
||||||
|
@ -35,14 +40,13 @@ github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ
|
||||||
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
||||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
github.com/stretchr/testify v1.10.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 h1:kdXcSzyDtseVEc4yCz2qF8ZrQvIDBJLl4S1c3GCXmoI=
|
||||||
github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
|
github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
|
||||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o=
|
golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20=
|
||||||
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||||
|
|
|
@ -228,6 +228,13 @@ func runBPFSource(pid int, profilePath string, inputFile string) (finalErr error
|
||||||
m := bcc.NewModule(src, []string{})
|
m := bcc.NewModule(src, []string{})
|
||||||
defer m.Close()
|
defer m.Close()
|
||||||
|
|
||||||
|
table := bcc.NewTable(m.TableId("events"), m)
|
||||||
|
channel := make(chan []byte)
|
||||||
|
perfMap, err := bcc.InitPerfMap(table, channel, nil)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error initializing perf map: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
logrus.Info("Loading enter tracepoint")
|
logrus.Info("Loading enter tracepoint")
|
||||||
enterTrace, err := m.LoadTracepoint("enter_trace")
|
enterTrace, err := m.LoadTracepoint("enter_trace")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -247,13 +254,6 @@ func runBPFSource(pid int, profilePath string, inputFile string) (finalErr error
|
||||||
return fmt.Errorf("error attaching to tracepoint: %v", err)
|
return fmt.Errorf("error attaching to tracepoint: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
table := bcc.NewTable(m.TableId("events"), m)
|
|
||||||
channel := make(chan []byte)
|
|
||||||
perfMap, err := bcc.InitPerfMap(table, channel, nil)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("error initializing perf map: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initialize the wait group used to wait for the tracing to be finished.
|
// Initialize the wait group used to wait for the tracing to be finished.
|
||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
var events []event
|
var events []event
|
||||||
|
|
|
@ -51,9 +51,16 @@ func DefaultProfile() *Seccomp {
|
||||||
{
|
{
|
||||||
Names: []string{
|
Names: []string{
|
||||||
"bdflush",
|
"bdflush",
|
||||||
|
"cachestat",
|
||||||
|
"futex_requeue",
|
||||||
|
"futex_wait",
|
||||||
|
"futex_waitv",
|
||||||
|
"futex_wake",
|
||||||
"io_pgetevents",
|
"io_pgetevents",
|
||||||
|
"io_pgetevents_time64",
|
||||||
"kexec_file_load",
|
"kexec_file_load",
|
||||||
"kexec_load",
|
"kexec_load",
|
||||||
|
"map_shadow_stack",
|
||||||
"migrate_pages",
|
"migrate_pages",
|
||||||
"move_pages",
|
"move_pages",
|
||||||
"nfsservctl",
|
"nfsservctl",
|
||||||
|
@ -68,9 +75,9 @@ func DefaultProfile() *Seccomp {
|
||||||
"pciconfig_write",
|
"pciconfig_write",
|
||||||
"sgetmask",
|
"sgetmask",
|
||||||
"ssetmask",
|
"ssetmask",
|
||||||
"swapcontext",
|
|
||||||
"swapoff",
|
"swapoff",
|
||||||
"swapon",
|
"swapon",
|
||||||
|
"syscall",
|
||||||
"sysfs",
|
"sysfs",
|
||||||
"uselib",
|
"uselib",
|
||||||
"userfaultfd",
|
"userfaultfd",
|
||||||
|
@ -142,6 +149,7 @@ func DefaultProfile() *Seccomp {
|
||||||
"fchdir",
|
"fchdir",
|
||||||
"fchmod",
|
"fchmod",
|
||||||
"fchmodat",
|
"fchmodat",
|
||||||
|
"fchmodat2",
|
||||||
"fchown",
|
"fchown",
|
||||||
"fchown32",
|
"fchown32",
|
||||||
"fchownat",
|
"fchownat",
|
||||||
|
@ -309,7 +317,6 @@ func DefaultProfile() *Seccomp {
|
||||||
"pwritev2",
|
"pwritev2",
|
||||||
"read",
|
"read",
|
||||||
"readahead",
|
"readahead",
|
||||||
"readdir",
|
|
||||||
"readlink",
|
"readlink",
|
||||||
"readlinkat",
|
"readlinkat",
|
||||||
"readv",
|
"readv",
|
||||||
|
@ -397,15 +404,12 @@ func DefaultProfile() *Seccomp {
|
||||||
"shmdt",
|
"shmdt",
|
||||||
"shmget",
|
"shmget",
|
||||||
"shutdown",
|
"shutdown",
|
||||||
"sigaction",
|
|
||||||
"sigaltstack",
|
"sigaltstack",
|
||||||
"signal",
|
"signal",
|
||||||
"signalfd",
|
"signalfd",
|
||||||
"signalfd4",
|
"signalfd4",
|
||||||
"sigpending",
|
|
||||||
"sigprocmask",
|
"sigprocmask",
|
||||||
"sigreturn",
|
"sigreturn",
|
||||||
"sigsuspend",
|
|
||||||
"socketcall",
|
"socketcall",
|
||||||
"socketpair",
|
"socketpair",
|
||||||
"splice",
|
"splice",
|
||||||
|
@ -419,7 +423,6 @@ func DefaultProfile() *Seccomp {
|
||||||
"sync",
|
"sync",
|
||||||
"sync_file_range",
|
"sync_file_range",
|
||||||
"syncfs",
|
"syncfs",
|
||||||
"syscall",
|
|
||||||
"sysinfo",
|
"sysinfo",
|
||||||
"syslog",
|
"syslog",
|
||||||
"tee",
|
"tee",
|
||||||
|
@ -432,7 +435,6 @@ func DefaultProfile() *Seccomp {
|
||||||
"timer_gettime64",
|
"timer_gettime64",
|
||||||
"timer_settime",
|
"timer_settime",
|
||||||
"timer_settime64",
|
"timer_settime64",
|
||||||
"timerfd",
|
|
||||||
"timerfd_create",
|
"timerfd_create",
|
||||||
"timerfd_gettime",
|
"timerfd_gettime",
|
||||||
"timerfd_gettime64",
|
"timerfd_gettime64",
|
||||||
|
@ -522,6 +524,7 @@ func DefaultProfile() *Seccomp {
|
||||||
{
|
{
|
||||||
Names: []string{
|
Names: []string{
|
||||||
"sync_file_range2",
|
"sync_file_range2",
|
||||||
|
"swapcontext",
|
||||||
},
|
},
|
||||||
Action: ActAllow,
|
Action: ActAllow,
|
||||||
Args: []*Arg{},
|
Args: []*Arg{},
|
||||||
|
@ -576,6 +579,16 @@ func DefaultProfile() *Seccomp {
|
||||||
Arches: []string{"s390", "s390x"},
|
Arches: []string{"s390", "s390x"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
Names: []string{
|
||||||
|
"riscv_flush_icache",
|
||||||
|
},
|
||||||
|
Action: ActAllow,
|
||||||
|
Args: []*Arg{},
|
||||||
|
Includes: Filter{
|
||||||
|
Arches: []string{"riscv64"},
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
Names: []string{
|
Names: []string{
|
||||||
"open_by_handle_at",
|
"open_by_handle_at",
|
||||||
|
@ -603,8 +616,8 @@ func DefaultProfile() *Seccomp {
|
||||||
"bpf",
|
"bpf",
|
||||||
"fanotify_init",
|
"fanotify_init",
|
||||||
"lookup_dcookie",
|
"lookup_dcookie",
|
||||||
"perf_event_open",
|
|
||||||
"quotactl",
|
"quotactl",
|
||||||
|
"quotactl_fd",
|
||||||
"setdomainname",
|
"setdomainname",
|
||||||
"sethostname",
|
"sethostname",
|
||||||
"setns",
|
"setns",
|
||||||
|
@ -617,11 +630,11 @@ func DefaultProfile() *Seccomp {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Names: []string{
|
Names: []string{
|
||||||
"bpf",
|
|
||||||
"fanotify_init",
|
"fanotify_init",
|
||||||
"lookup_dcookie",
|
"lookup_dcookie",
|
||||||
"perf_event_open",
|
"perf_event_open",
|
||||||
"quotactl",
|
"quotactl",
|
||||||
|
"quotactl_fd",
|
||||||
"setdomainname",
|
"setdomainname",
|
||||||
"sethostname",
|
"sethostname",
|
||||||
"setns",
|
"setns",
|
||||||
|
@ -884,6 +897,50 @@ func DefaultProfile() *Seccomp {
|
||||||
Caps: []string{"CAP_AUDIT_WRITE"},
|
Caps: []string{"CAP_AUDIT_WRITE"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
Names: []string{
|
||||||
|
"bpf",
|
||||||
|
},
|
||||||
|
Action: ActErrno,
|
||||||
|
Errno: "EPERM",
|
||||||
|
ErrnoRet: &eperm,
|
||||||
|
Args: []*Arg{},
|
||||||
|
Excludes: Filter{
|
||||||
|
Caps: []string{"CAP_SYS_ADMIN", "CAP_BPF"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Names: []string{
|
||||||
|
"bpf",
|
||||||
|
},
|
||||||
|
Action: ActAllow,
|
||||||
|
Args: []*Arg{},
|
||||||
|
Includes: Filter{
|
||||||
|
Caps: []string{"CAP_BPF"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Names: []string{
|
||||||
|
"perf_event_open",
|
||||||
|
},
|
||||||
|
Action: ActErrno,
|
||||||
|
Errno: "EPERM",
|
||||||
|
ErrnoRet: &eperm,
|
||||||
|
Args: []*Arg{},
|
||||||
|
Excludes: Filter{
|
||||||
|
Caps: []string{"CAP_SYS_ADMIN", "CAP_BPF"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Names: []string{
|
||||||
|
"perf_event_open",
|
||||||
|
},
|
||||||
|
Action: ActAllow,
|
||||||
|
Args: []*Arg{},
|
||||||
|
Includes: Filter{
|
||||||
|
Caps: []string{"CAP_PERFMON"},
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
return &Seccomp{
|
return &Seccomp{
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
//go:build linux && seccomp
|
//go:build linux && seccomp
|
||||||
// +build linux,seccomp
|
|
||||||
|
|
||||||
package seccomp
|
package seccomp
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
//go:build seccomp
|
//go:build seccomp
|
||||||
// +build seccomp
|
|
||||||
|
|
||||||
// NOTE: this package has originally been copied from
|
// NOTE: this package has originally been copied from
|
||||||
// github.com/opencontainers/runc and modified to work for other use cases
|
// github.com/opencontainers/runc and modified to work for other use cases
|
||||||
|
|
|
@ -55,9 +55,16 @@
|
||||||
{
|
{
|
||||||
"names": [
|
"names": [
|
||||||
"bdflush",
|
"bdflush",
|
||||||
|
"cachestat",
|
||||||
|
"futex_requeue",
|
||||||
|
"futex_wait",
|
||||||
|
"futex_waitv",
|
||||||
|
"futex_wake",
|
||||||
"io_pgetevents",
|
"io_pgetevents",
|
||||||
|
"io_pgetevents_time64",
|
||||||
"kexec_file_load",
|
"kexec_file_load",
|
||||||
"kexec_load",
|
"kexec_load",
|
||||||
|
"map_shadow_stack",
|
||||||
"migrate_pages",
|
"migrate_pages",
|
||||||
"move_pages",
|
"move_pages",
|
||||||
"nfsservctl",
|
"nfsservctl",
|
||||||
|
@ -72,9 +79,9 @@
|
||||||
"pciconfig_write",
|
"pciconfig_write",
|
||||||
"sgetmask",
|
"sgetmask",
|
||||||
"ssetmask",
|
"ssetmask",
|
||||||
"swapcontext",
|
|
||||||
"swapoff",
|
"swapoff",
|
||||||
"swapon",
|
"swapon",
|
||||||
|
"syscall",
|
||||||
"sysfs",
|
"sysfs",
|
||||||
"uselib",
|
"uselib",
|
||||||
"userfaultfd",
|
"userfaultfd",
|
||||||
|
@ -149,6 +156,7 @@
|
||||||
"fchdir",
|
"fchdir",
|
||||||
"fchmod",
|
"fchmod",
|
||||||
"fchmodat",
|
"fchmodat",
|
||||||
|
"fchmodat2",
|
||||||
"fchown",
|
"fchown",
|
||||||
"fchown32",
|
"fchown32",
|
||||||
"fchownat",
|
"fchownat",
|
||||||
|
@ -316,7 +324,6 @@
|
||||||
"pwritev2",
|
"pwritev2",
|
||||||
"read",
|
"read",
|
||||||
"readahead",
|
"readahead",
|
||||||
"readdir",
|
|
||||||
"readlink",
|
"readlink",
|
||||||
"readlinkat",
|
"readlinkat",
|
||||||
"readv",
|
"readv",
|
||||||
|
@ -404,15 +411,12 @@
|
||||||
"shmdt",
|
"shmdt",
|
||||||
"shmget",
|
"shmget",
|
||||||
"shutdown",
|
"shutdown",
|
||||||
"sigaction",
|
|
||||||
"sigaltstack",
|
"sigaltstack",
|
||||||
"signal",
|
"signal",
|
||||||
"signalfd",
|
"signalfd",
|
||||||
"signalfd4",
|
"signalfd4",
|
||||||
"sigpending",
|
|
||||||
"sigprocmask",
|
"sigprocmask",
|
||||||
"sigreturn",
|
"sigreturn",
|
||||||
"sigsuspend",
|
|
||||||
"socketcall",
|
"socketcall",
|
||||||
"socketpair",
|
"socketpair",
|
||||||
"splice",
|
"splice",
|
||||||
|
@ -426,7 +430,6 @@
|
||||||
"sync",
|
"sync",
|
||||||
"sync_file_range",
|
"sync_file_range",
|
||||||
"syncfs",
|
"syncfs",
|
||||||
"syscall",
|
|
||||||
"sysinfo",
|
"sysinfo",
|
||||||
"syslog",
|
"syslog",
|
||||||
"tee",
|
"tee",
|
||||||
|
@ -439,7 +442,6 @@
|
||||||
"timer_gettime64",
|
"timer_gettime64",
|
||||||
"timer_settime",
|
"timer_settime",
|
||||||
"timer_settime64",
|
"timer_settime64",
|
||||||
"timerfd",
|
|
||||||
"timerfd_create",
|
"timerfd_create",
|
||||||
"timerfd_gettime",
|
"timerfd_gettime",
|
||||||
"timerfd_gettime64",
|
"timerfd_gettime64",
|
||||||
|
@ -561,7 +563,8 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"names": [
|
"names": [
|
||||||
"sync_file_range2"
|
"sync_file_range2",
|
||||||
|
"swapcontext"
|
||||||
],
|
],
|
||||||
"action": "SCMP_ACT_ALLOW",
|
"action": "SCMP_ACT_ALLOW",
|
||||||
"args": [],
|
"args": [],
|
||||||
|
@ -641,6 +644,20 @@
|
||||||
},
|
},
|
||||||
"excludes": {}
|
"excludes": {}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"names": [
|
||||||
|
"riscv_flush_icache"
|
||||||
|
],
|
||||||
|
"action": "SCMP_ACT_ALLOW",
|
||||||
|
"args": [],
|
||||||
|
"comment": "",
|
||||||
|
"includes": {
|
||||||
|
"arches": [
|
||||||
|
"riscv64"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"excludes": {}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"names": [
|
"names": [
|
||||||
"open_by_handle_at"
|
"open_by_handle_at"
|
||||||
|
@ -676,8 +693,8 @@
|
||||||
"bpf",
|
"bpf",
|
||||||
"fanotify_init",
|
"fanotify_init",
|
||||||
"lookup_dcookie",
|
"lookup_dcookie",
|
||||||
"perf_event_open",
|
|
||||||
"quotactl",
|
"quotactl",
|
||||||
|
"quotactl_fd",
|
||||||
"setdomainname",
|
"setdomainname",
|
||||||
"sethostname",
|
"sethostname",
|
||||||
"setns"
|
"setns"
|
||||||
|
@ -694,11 +711,11 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"names": [
|
"names": [
|
||||||
"bpf",
|
|
||||||
"fanotify_init",
|
"fanotify_init",
|
||||||
"lookup_dcookie",
|
"lookup_dcookie",
|
||||||
"perf_event_open",
|
"perf_event_open",
|
||||||
"quotactl",
|
"quotactl",
|
||||||
|
"quotactl_fd",
|
||||||
"setdomainname",
|
"setdomainname",
|
||||||
"sethostname",
|
"sethostname",
|
||||||
"setns"
|
"setns"
|
||||||
|
@ -1046,6 +1063,68 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"excludes": {}
|
"excludes": {}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"names": [
|
||||||
|
"bpf"
|
||||||
|
],
|
||||||
|
"action": "SCMP_ACT_ERRNO",
|
||||||
|
"args": [],
|
||||||
|
"comment": "",
|
||||||
|
"includes": {},
|
||||||
|
"excludes": {
|
||||||
|
"caps": [
|
||||||
|
"CAP_SYS_ADMIN",
|
||||||
|
"CAP_BPF"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"errnoRet": 1,
|
||||||
|
"errno": "EPERM"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"names": [
|
||||||
|
"bpf"
|
||||||
|
],
|
||||||
|
"action": "SCMP_ACT_ALLOW",
|
||||||
|
"args": [],
|
||||||
|
"comment": "",
|
||||||
|
"includes": {
|
||||||
|
"caps": [
|
||||||
|
"CAP_BPF"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"excludes": {}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"names": [
|
||||||
|
"perf_event_open"
|
||||||
|
],
|
||||||
|
"action": "SCMP_ACT_ERRNO",
|
||||||
|
"args": [],
|
||||||
|
"comment": "",
|
||||||
|
"includes": {},
|
||||||
|
"excludes": {
|
||||||
|
"caps": [
|
||||||
|
"CAP_SYS_ADMIN",
|
||||||
|
"CAP_BPF"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"errnoRet": 1,
|
||||||
|
"errno": "EPERM"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"names": [
|
||||||
|
"perf_event_open"
|
||||||
|
],
|
||||||
|
"action": "SCMP_ACT_ALLOW",
|
||||||
|
"args": [],
|
||||||
|
"comment": "",
|
||||||
|
"includes": {
|
||||||
|
"caps": [
|
||||||
|
"CAP_PERFMON"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"excludes": {}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
|
@ -1,5 +1,4 @@
|
||||||
//go:build seccomp
|
//go:build seccomp
|
||||||
// +build seccomp
|
|
||||||
|
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
//go:build !linux || !seccomp
|
//go:build !linux || !seccomp
|
||||||
// +build !linux !seccomp
|
|
||||||
|
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
@ -15,12 +14,12 @@ import (
|
||||||
|
|
||||||
var errNotSupported = errors.New("seccomp not enabled in this build")
|
var errNotSupported = errors.New("seccomp not enabled in this build")
|
||||||
|
|
||||||
// LoadProfile returns an error on unsuppored systems
|
// LoadProfile returns an error on unsupported systems
|
||||||
func LoadProfile(body string, rs *specs.Spec) (*specs.LinuxSeccomp, error) {
|
func LoadProfile(body string, rs *specs.Spec) (*specs.LinuxSeccomp, error) {
|
||||||
return nil, errNotSupported
|
return nil, errNotSupported
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetDefaultProfile returns an error on unsuppored systems
|
// GetDefaultProfile returns an error on unsupported systems
|
||||||
func GetDefaultProfile(rs *specs.Spec) (*specs.LinuxSeccomp, error) {
|
func GetDefaultProfile(rs *specs.Spec) (*specs.LinuxSeccomp, error) {
|
||||||
return nil, errNotSupported
|
return nil, errNotSupported
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
//go:build linux && seccomp
|
//go:build linux && seccomp
|
||||||
// +build linux,seccomp
|
|
||||||
|
|
||||||
package seccomp
|
package seccomp
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
//go:build seccomp
|
//go:build seccomp
|
||||||
// +build seccomp
|
|
||||||
|
|
||||||
package seccomp
|
package seccomp
|
||||||
|
|
||||||
|
|
38
vendor/github.com/containers/storage/pkg/fileutils/exists_freebsd.go
generated
vendored
Normal file
38
vendor/github.com/containers/storage/pkg/fileutils/exists_freebsd.go
generated
vendored
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
package fileutils
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"os"
|
||||||
|
"syscall"
|
||||||
|
|
||||||
|
"golang.org/x/sys/unix"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Exists checks whether a file or directory exists at the given path.
|
||||||
|
// If the path is a symlink, the symlink is followed.
|
||||||
|
func Exists(path string) error {
|
||||||
|
// It uses unix.Faccessat which is a faster operation compared to os.Stat for
|
||||||
|
// simply checking the existence of a file.
|
||||||
|
err := unix.Faccessat(unix.AT_FDCWD, path, unix.F_OK, 0)
|
||||||
|
if err != nil {
|
||||||
|
return &os.PathError{Op: "faccessat", Path: path, Err: err}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lexists checks whether a file or directory exists at the given path.
|
||||||
|
// If the path is a symlink, the symlink itself is checked.
|
||||||
|
func Lexists(path string) error {
|
||||||
|
// FreeBSD before 15.0 does not support the AT_SYMLINK_NOFOLLOW flag for
|
||||||
|
// faccessat. In this case, the call to faccessat will return EINVAL and
|
||||||
|
// we fall back to using Lstat.
|
||||||
|
err := unix.Faccessat(unix.AT_FDCWD, path, unix.F_OK, unix.AT_SYMLINK_NOFOLLOW)
|
||||||
|
if err != nil {
|
||||||
|
if errors.Is(err, syscall.EINVAL) {
|
||||||
|
_, err = os.Lstat(path)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return &os.PathError{Op: "faccessat", Path: path, Err: err}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -0,0 +1,33 @@
|
||||||
|
//go:build !windows && !freebsd
|
||||||
|
|
||||||
|
package fileutils
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"golang.org/x/sys/unix"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Exists checks whether a file or directory exists at the given path.
|
||||||
|
// If the path is a symlink, the symlink is followed.
|
||||||
|
func Exists(path string) error {
|
||||||
|
// It uses unix.Faccessat which is a faster operation compared to os.Stat for
|
||||||
|
// simply checking the existence of a file.
|
||||||
|
err := unix.Faccessat(unix.AT_FDCWD, path, unix.F_OK, unix.AT_EACCESS)
|
||||||
|
if err != nil {
|
||||||
|
return &os.PathError{Op: "faccessat", Path: path, Err: err}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lexists checks whether a file or directory exists at the given path.
|
||||||
|
// If the path is a symlink, the symlink itself is checked.
|
||||||
|
func Lexists(path string) error {
|
||||||
|
// It uses unix.Faccessat which is a faster operation compared to os.Stat for
|
||||||
|
// simply checking the existence of a file.
|
||||||
|
err := unix.Faccessat(unix.AT_FDCWD, path, unix.F_OK, unix.AT_SYMLINK_NOFOLLOW|unix.AT_EACCESS)
|
||||||
|
if err != nil {
|
||||||
|
return &os.PathError{Op: "faccessat", Path: path, Err: err}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
18
vendor/github.com/containers/storage/pkg/fileutils/exists_windows.go
generated
vendored
Normal file
18
vendor/github.com/containers/storage/pkg/fileutils/exists_windows.go
generated
vendored
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
package fileutils
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Exists checks whether a file or directory exists at the given path.
|
||||||
|
func Exists(path string) error {
|
||||||
|
_, err := os.Stat(path)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lexists checks whether a file or directory exists at the given path, without
|
||||||
|
// resolving symlinks
|
||||||
|
func Lexists(path string) error {
|
||||||
|
_, err := os.Lstat(path)
|
||||||
|
return err
|
||||||
|
}
|
|
@ -0,0 +1,371 @@
|
||||||
|
package fileutils
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
"text/scanner"
|
||||||
|
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
// PatternMatcher allows checking paths against a list of patterns
|
||||||
|
type PatternMatcher struct {
|
||||||
|
patterns []*Pattern
|
||||||
|
exclusions bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewPatternMatcher creates a new matcher object for specific patterns that can
|
||||||
|
// be used later to match against patterns against paths
|
||||||
|
func NewPatternMatcher(patterns []string) (*PatternMatcher, error) {
|
||||||
|
pm := &PatternMatcher{
|
||||||
|
patterns: make([]*Pattern, 0, len(patterns)),
|
||||||
|
}
|
||||||
|
for _, p := range patterns {
|
||||||
|
// Eliminate leading and trailing whitespace.
|
||||||
|
p = strings.TrimSpace(p)
|
||||||
|
if p == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
p = filepath.Clean(p)
|
||||||
|
newp := &Pattern{}
|
||||||
|
if p[0] == '!' {
|
||||||
|
if len(p) == 1 {
|
||||||
|
return nil, errors.New("illegal exclusion pattern: \"!\"")
|
||||||
|
}
|
||||||
|
newp.exclusion = true
|
||||||
|
p = strings.TrimPrefix(filepath.Clean(p[1:]), "/")
|
||||||
|
pm.exclusions = true
|
||||||
|
}
|
||||||
|
// Do some syntax checking on the pattern.
|
||||||
|
// filepath's Match() has some really weird rules that are inconsistent
|
||||||
|
// so instead of trying to dup their logic, just call Match() for its
|
||||||
|
// error state and if there is an error in the pattern return it.
|
||||||
|
// If this becomes an issue we can remove this since its really only
|
||||||
|
// needed in the error (syntax) case - which isn't really critical.
|
||||||
|
if _, err := filepath.Match(p, "."); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
newp.cleanedPattern = p
|
||||||
|
newp.dirs = strings.Split(p, string(os.PathSeparator))
|
||||||
|
pm.patterns = append(pm.patterns, newp)
|
||||||
|
}
|
||||||
|
return pm, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Please use the `MatchesResult` method instead.
|
||||||
|
// Matches matches path against all the patterns. Matches is not safe to be
|
||||||
|
// called concurrently
|
||||||
|
func (pm *PatternMatcher) Matches(file string) (bool, error) {
|
||||||
|
matched := false
|
||||||
|
file = filepath.FromSlash(file)
|
||||||
|
|
||||||
|
for _, pattern := range pm.patterns {
|
||||||
|
negative := false
|
||||||
|
|
||||||
|
if pattern.exclusion {
|
||||||
|
negative = true
|
||||||
|
}
|
||||||
|
|
||||||
|
match, err := pattern.match(file)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if match {
|
||||||
|
matched = !negative
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if matched {
|
||||||
|
logrus.Debugf("Skipping excluded path: %s", file)
|
||||||
|
}
|
||||||
|
|
||||||
|
return matched, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type MatchResult struct {
|
||||||
|
isMatched bool
|
||||||
|
matches, excludes uint
|
||||||
|
}
|
||||||
|
|
||||||
|
// Excludes returns true if the overall result is matched
|
||||||
|
func (m *MatchResult) IsMatched() bool {
|
||||||
|
return m.isMatched
|
||||||
|
}
|
||||||
|
|
||||||
|
// Excludes returns the amount of matches of an MatchResult
|
||||||
|
func (m *MatchResult) Matches() uint {
|
||||||
|
return m.matches
|
||||||
|
}
|
||||||
|
|
||||||
|
// Excludes returns the amount of excludes of an MatchResult
|
||||||
|
func (m *MatchResult) Excludes() uint {
|
||||||
|
return m.excludes
|
||||||
|
}
|
||||||
|
|
||||||
|
// MatchesResult verifies the provided filepath against all patterns.
|
||||||
|
// It returns the `*MatchResult` result for the patterns on success, otherwise
|
||||||
|
// an error. This method is not safe to be called concurrently.
|
||||||
|
func (pm *PatternMatcher) MatchesResult(file string) (res *MatchResult, err error) {
|
||||||
|
file = filepath.FromSlash(file)
|
||||||
|
res = &MatchResult{false, 0, 0}
|
||||||
|
|
||||||
|
for _, pattern := range pm.patterns {
|
||||||
|
negative := false
|
||||||
|
|
||||||
|
if pattern.exclusion {
|
||||||
|
negative = true
|
||||||
|
}
|
||||||
|
|
||||||
|
match, err := pattern.match(file)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if match {
|
||||||
|
res.isMatched = !negative
|
||||||
|
if negative {
|
||||||
|
res.excludes++
|
||||||
|
} else {
|
||||||
|
res.matches++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if res.matches > 0 {
|
||||||
|
logrus.Debugf("Skipping excluded path: %s", file)
|
||||||
|
}
|
||||||
|
|
||||||
|
return res, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsMatch verifies the provided filepath against all patterns and returns true
|
||||||
|
// if it matches. A match is valid if the last match is a positive one.
|
||||||
|
// It returns an error on failure and is not safe to be called concurrently.
|
||||||
|
func (pm *PatternMatcher) IsMatch(file string) (matched bool, err error) {
|
||||||
|
res, err := pm.MatchesResult(file)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
return res.isMatched, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exclusions returns true if any of the patterns define exclusions
|
||||||
|
func (pm *PatternMatcher) Exclusions() bool {
|
||||||
|
return pm.exclusions
|
||||||
|
}
|
||||||
|
|
||||||
|
// Patterns returns array of active patterns
|
||||||
|
func (pm *PatternMatcher) Patterns() []*Pattern {
|
||||||
|
return pm.patterns
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pattern defines a single regexp used to filter file paths.
|
||||||
|
type Pattern struct {
|
||||||
|
cleanedPattern string
|
||||||
|
dirs []string
|
||||||
|
regexp *regexp.Regexp
|
||||||
|
exclusion bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Pattern) String() string {
|
||||||
|
return p.cleanedPattern
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exclusion returns true if this pattern defines exclusion
|
||||||
|
func (p *Pattern) Exclusion() bool {
|
||||||
|
return p.exclusion
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Pattern) match(path string) (bool, error) {
|
||||||
|
if p.regexp == nil {
|
||||||
|
if err := p.compile(); err != nil {
|
||||||
|
return false, filepath.ErrBadPattern
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
b := p.regexp.MatchString(path)
|
||||||
|
|
||||||
|
return b, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Pattern) compile() error {
|
||||||
|
regStr := "^"
|
||||||
|
pattern := p.cleanedPattern
|
||||||
|
// Go through the pattern and convert it to a regexp.
|
||||||
|
// We use a scanner so we can support utf-8 chars.
|
||||||
|
var scan scanner.Scanner
|
||||||
|
scan.Init(strings.NewReader(pattern))
|
||||||
|
|
||||||
|
sl := string(os.PathSeparator)
|
||||||
|
escSL := sl
|
||||||
|
const bs = `\`
|
||||||
|
if sl == bs {
|
||||||
|
escSL += bs
|
||||||
|
}
|
||||||
|
|
||||||
|
for scan.Peek() != scanner.EOF {
|
||||||
|
ch := scan.Next()
|
||||||
|
|
||||||
|
if ch == '*' {
|
||||||
|
if scan.Peek() == '*' {
|
||||||
|
// is some flavor of "**"
|
||||||
|
scan.Next()
|
||||||
|
|
||||||
|
// Treat **/ as ** so eat the "/"
|
||||||
|
if string(scan.Peek()) == sl {
|
||||||
|
scan.Next()
|
||||||
|
}
|
||||||
|
|
||||||
|
if scan.Peek() == scanner.EOF {
|
||||||
|
// is "**EOF" - to align with .gitignore just accept all
|
||||||
|
regStr += ".*"
|
||||||
|
} else {
|
||||||
|
// is "**"
|
||||||
|
// Note that this allows for any # of /'s (even 0) because
|
||||||
|
// the .* will eat everything, even /'s
|
||||||
|
regStr += "(.*" + escSL + ")?"
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// is "*" so map it to anything but "/"
|
||||||
|
regStr += "[^" + escSL + "]*"
|
||||||
|
}
|
||||||
|
} else if ch == '?' {
|
||||||
|
// "?" is any char except "/"
|
||||||
|
regStr += "[^" + escSL + "]"
|
||||||
|
} else if ch == '.' || ch == '$' {
|
||||||
|
// Escape some regexp special chars that have no meaning
|
||||||
|
// in golang's filepath.Match
|
||||||
|
regStr += bs + string(ch)
|
||||||
|
} else if ch == '\\' {
|
||||||
|
// escape next char.
|
||||||
|
if sl == bs {
|
||||||
|
// On windows map "\" to "\\", meaning an escaped backslash,
|
||||||
|
// and then just continue because filepath.Match on
|
||||||
|
// Windows doesn't allow escaping at all
|
||||||
|
regStr += escSL
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if scan.Peek() != scanner.EOF {
|
||||||
|
regStr += bs + string(scan.Next())
|
||||||
|
} else {
|
||||||
|
return filepath.ErrBadPattern
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
regStr += string(ch)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
regStr += "(" + escSL + ".*)?$"
|
||||||
|
|
||||||
|
re, err := regexp.Compile(regStr)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
p.regexp = re
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Matches returns true if file matches any of the patterns
|
||||||
|
// and isn't excluded by any of the subsequent patterns.
|
||||||
|
func Matches(file string, patterns []string) (bool, error) {
|
||||||
|
pm, err := NewPatternMatcher(patterns)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
file = filepath.Clean(file)
|
||||||
|
|
||||||
|
if file == "." {
|
||||||
|
// Don't let them exclude everything, kind of silly.
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return pm.IsMatch(file)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CopyFile copies from src to dst until either EOF is reached
|
||||||
|
// on src or an error occurs. It verifies src exists and removes
|
||||||
|
// the dst if it exists.
|
||||||
|
func CopyFile(src, dst string) (int64, error) {
|
||||||
|
cleanSrc := filepath.Clean(src)
|
||||||
|
cleanDst := filepath.Clean(dst)
|
||||||
|
if cleanSrc == cleanDst {
|
||||||
|
return 0, nil
|
||||||
|
}
|
||||||
|
sf, err := os.Open(cleanSrc)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
defer sf.Close()
|
||||||
|
if err := os.Remove(cleanDst); err != nil && !os.IsNotExist(err) {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
df, err := os.Create(cleanDst)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
defer df.Close()
|
||||||
|
return io.Copy(df, sf)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReadSymlinkedDirectory returns the target directory of a symlink.
|
||||||
|
// The target of the symbolic link may not be a file.
|
||||||
|
func ReadSymlinkedDirectory(path string) (string, error) {
|
||||||
|
var realPath string
|
||||||
|
var err error
|
||||||
|
if realPath, err = filepath.Abs(path); err != nil {
|
||||||
|
return "", fmt.Errorf("unable to get absolute path for %s: %w", path, err)
|
||||||
|
}
|
||||||
|
if realPath, err = filepath.EvalSymlinks(realPath); err != nil {
|
||||||
|
return "", fmt.Errorf("failed to canonicalise path for %s: %w", path, err)
|
||||||
|
}
|
||||||
|
realPathInfo, err := os.Stat(realPath)
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("failed to stat target '%s' of '%s': %w", realPath, path, err)
|
||||||
|
}
|
||||||
|
if !realPathInfo.Mode().IsDir() {
|
||||||
|
return "", fmt.Errorf("canonical path points to a file '%s'", realPath)
|
||||||
|
}
|
||||||
|
return realPath, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReadSymlinkedPath returns the target directory of a symlink.
|
||||||
|
// The target of the symbolic link can be a file and a directory.
|
||||||
|
func ReadSymlinkedPath(path string) (realPath string, err error) {
|
||||||
|
if realPath, err = filepath.Abs(path); err != nil {
|
||||||
|
return "", fmt.Errorf("unable to get absolute path for %q: %w", path, err)
|
||||||
|
}
|
||||||
|
if realPath, err = filepath.EvalSymlinks(realPath); err != nil {
|
||||||
|
return "", fmt.Errorf("failed to canonicalise path for %q: %w", path, err)
|
||||||
|
}
|
||||||
|
if err := Exists(realPath); err != nil {
|
||||||
|
return "", fmt.Errorf("failed to stat target %q of %q: %w", realPath, path, err)
|
||||||
|
}
|
||||||
|
return realPath, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateIfNotExists creates a file or a directory only if it does not already exist.
|
||||||
|
func CreateIfNotExists(path string, isDir bool) error {
|
||||||
|
if err := Exists(path); err != nil {
|
||||||
|
if os.IsNotExist(err) {
|
||||||
|
if isDir {
|
||||||
|
return os.MkdirAll(path, 0o755)
|
||||||
|
}
|
||||||
|
if err := os.MkdirAll(filepath.Dir(path), 0o755); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
f, err := os.OpenFile(path, os.O_CREATE, 0o755)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
f.Close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
27
vendor/github.com/containers/storage/pkg/fileutils/fileutils_darwin.go
generated
vendored
Normal file
27
vendor/github.com/containers/storage/pkg/fileutils/fileutils_darwin.go
generated
vendored
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
package fileutils
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// GetTotalUsedFds returns the number of used File Descriptors by
|
||||||
|
// executing `lsof -p PID`
|
||||||
|
func GetTotalUsedFds() int {
|
||||||
|
pid := os.Getpid()
|
||||||
|
|
||||||
|
cmd := exec.Command("lsof", "-p", strconv.Itoa(pid))
|
||||||
|
|
||||||
|
output, err := cmd.CombinedOutput()
|
||||||
|
if err != nil {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
outputStr := strings.TrimSpace(string(output))
|
||||||
|
|
||||||
|
fds := strings.Split(outputStr, "\n")
|
||||||
|
|
||||||
|
return len(fds) - 1
|
||||||
|
}
|
7
vendor/github.com/containers/storage/pkg/fileutils/fileutils_solaris.go
generated
vendored
Normal file
7
vendor/github.com/containers/storage/pkg/fileutils/fileutils_solaris.go
generated
vendored
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
package fileutils
|
||||||
|
|
||||||
|
// GetTotalUsedFds Returns the number of used File Descriptors.
|
||||||
|
// On Solaris these limits are per process and not systemwide
|
||||||
|
func GetTotalUsedFds() int {
|
||||||
|
return -1
|
||||||
|
}
|
21
vendor/github.com/containers/storage/pkg/fileutils/fileutils_unix.go
generated
vendored
Normal file
21
vendor/github.com/containers/storage/pkg/fileutils/fileutils_unix.go
generated
vendored
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
//go:build linux || freebsd
|
||||||
|
|
||||||
|
package fileutils
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
// GetTotalUsedFds Returns the number of used File Descriptors by
|
||||||
|
// reading it via /proc filesystem.
|
||||||
|
func GetTotalUsedFds() int {
|
||||||
|
if fds, err := os.ReadDir(fmt.Sprintf("/proc/%d/fd", os.Getpid())); err != nil {
|
||||||
|
logrus.Errorf("%v", err)
|
||||||
|
} else {
|
||||||
|
return len(fds)
|
||||||
|
}
|
||||||
|
return -1
|
||||||
|
}
|
7
vendor/github.com/containers/storage/pkg/fileutils/fileutils_windows.go
generated
vendored
Normal file
7
vendor/github.com/containers/storage/pkg/fileutils/fileutils_windows.go
generated
vendored
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
package fileutils
|
||||||
|
|
||||||
|
// GetTotalUsedFds Returns the number of used File Descriptors. Not supported
|
||||||
|
// on Windows.
|
||||||
|
func GetTotalUsedFds() int {
|
||||||
|
return -1
|
||||||
|
}
|
20
vendor/github.com/containers/storage/pkg/fileutils/reflink_linux.go
generated
vendored
Normal file
20
vendor/github.com/containers/storage/pkg/fileutils/reflink_linux.go
generated
vendored
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
package fileutils
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"golang.org/x/sys/unix"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ReflinkOrCopy attempts to reflink the source to the destination fd.
|
||||||
|
// If reflinking fails or is unsupported, it falls back to io.Copy().
|
||||||
|
func ReflinkOrCopy(src, dst *os.File) error {
|
||||||
|
err := unix.IoctlFileClone(int(dst.Fd()), int(src.Fd()))
|
||||||
|
if err == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = io.Copy(dst, src)
|
||||||
|
return err
|
||||||
|
}
|
15
vendor/github.com/containers/storage/pkg/fileutils/reflink_unsupported.go
generated
vendored
Normal file
15
vendor/github.com/containers/storage/pkg/fileutils/reflink_unsupported.go
generated
vendored
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
//go:build !linux
|
||||||
|
|
||||||
|
package fileutils
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ReflinkOrCopy attempts to reflink the source to the destination fd.
|
||||||
|
// If reflinking fails or is unsupported, it falls back to io.Copy().
|
||||||
|
func ReflinkOrCopy(src, dst *os.File) error {
|
||||||
|
_, err := io.Copy(dst, src)
|
||||||
|
return err
|
||||||
|
}
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"bufio"
|
"bufio"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io/fs"
|
||||||
"os"
|
"os"
|
||||||
"os/user"
|
"os/user"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
@ -228,7 +229,7 @@ func getOverflowUID() int {
|
||||||
return overflowUID
|
return overflowUID
|
||||||
}
|
}
|
||||||
|
|
||||||
// getOverflowUID returns the GID mapped to the overflow user
|
// getOverflowGID returns the GID mapped to the overflow user
|
||||||
func getOverflowGID() int {
|
func getOverflowGID() int {
|
||||||
overflowGIDOnce.Do(func() {
|
overflowGIDOnce.Do(func() {
|
||||||
// 65534 is the value on older kernels where /proc/sys/kernel/overflowgid is not present
|
// 65534 is the value on older kernels where /proc/sys/kernel/overflowgid is not present
|
||||||
|
@ -367,21 +368,174 @@ func checkChownErr(err error, name string, uid, gid int) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Stat contains file states that can be overridden with ContainersOverrideXattr.
|
||||||
|
type Stat struct {
|
||||||
|
IDs IDPair
|
||||||
|
Mode os.FileMode
|
||||||
|
Major int
|
||||||
|
Minor int
|
||||||
|
}
|
||||||
|
|
||||||
|
// FormatContainersOverrideXattr will format the given uid, gid, and mode into a string
|
||||||
|
// that can be used as the value for the ContainersOverrideXattr xattr.
|
||||||
|
func FormatContainersOverrideXattr(uid, gid, mode int) string {
|
||||||
|
return FormatContainersOverrideXattrDevice(uid, gid, fs.FileMode(mode), 0, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
// FormatContainersOverrideXattrDevice will format the given uid, gid, and mode into a string
|
||||||
|
// that can be used as the value for the ContainersOverrideXattr xattr. For devices, it also
|
||||||
|
// needs the major and minor numbers.
|
||||||
|
func FormatContainersOverrideXattrDevice(uid, gid int, mode fs.FileMode, major, minor int) string {
|
||||||
|
typ := ""
|
||||||
|
switch mode & os.ModeType {
|
||||||
|
case os.ModeDir:
|
||||||
|
typ = "dir"
|
||||||
|
case os.ModeSymlink:
|
||||||
|
typ = "symlink"
|
||||||
|
case os.ModeNamedPipe:
|
||||||
|
typ = "pipe"
|
||||||
|
case os.ModeSocket:
|
||||||
|
typ = "socket"
|
||||||
|
case os.ModeDevice:
|
||||||
|
typ = fmt.Sprintf("block-%d-%d", major, minor)
|
||||||
|
case os.ModeDevice | os.ModeCharDevice:
|
||||||
|
typ = fmt.Sprintf("char-%d-%d", major, minor)
|
||||||
|
default:
|
||||||
|
typ = "file"
|
||||||
|
}
|
||||||
|
unixMode := mode & os.ModePerm
|
||||||
|
if mode&os.ModeSetuid != 0 {
|
||||||
|
unixMode |= 0o4000
|
||||||
|
}
|
||||||
|
if mode&os.ModeSetgid != 0 {
|
||||||
|
unixMode |= 0o2000
|
||||||
|
}
|
||||||
|
if mode&os.ModeSticky != 0 {
|
||||||
|
unixMode |= 0o1000
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("%d:%d:%04o:%s", uid, gid, unixMode, typ)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetContainersOverrideXattr will get and decode ContainersOverrideXattr.
|
||||||
|
func GetContainersOverrideXattr(path string) (Stat, error) {
|
||||||
|
xstat, err := system.Lgetxattr(path, ContainersOverrideXattr)
|
||||||
|
if err != nil {
|
||||||
|
return Stat{}, err
|
||||||
|
}
|
||||||
|
return parseOverrideXattr(xstat) // This will fail if (xstat, err) == (nil, nil), i.e. the xattr does not exist.
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseOverrideXattr(xstat []byte) (Stat, error) {
|
||||||
|
var stat Stat
|
||||||
|
attrs := strings.Split(string(xstat), ":")
|
||||||
|
if len(attrs) < 3 {
|
||||||
|
return stat, fmt.Errorf("the number of parts in %s is less than 3",
|
||||||
|
ContainersOverrideXattr)
|
||||||
|
}
|
||||||
|
|
||||||
|
value, err := strconv.ParseUint(attrs[0], 10, 32)
|
||||||
|
if err != nil {
|
||||||
|
return stat, fmt.Errorf("failed to parse UID: %w", err)
|
||||||
|
}
|
||||||
|
stat.IDs.UID = int(value)
|
||||||
|
|
||||||
|
value, err = strconv.ParseUint(attrs[1], 10, 32)
|
||||||
|
if err != nil {
|
||||||
|
return stat, fmt.Errorf("failed to parse GID: %w", err)
|
||||||
|
}
|
||||||
|
stat.IDs.GID = int(value)
|
||||||
|
|
||||||
|
value, err = strconv.ParseUint(attrs[2], 8, 32)
|
||||||
|
if err != nil {
|
||||||
|
return stat, fmt.Errorf("failed to parse mode: %w", err)
|
||||||
|
}
|
||||||
|
stat.Mode = os.FileMode(value) & os.ModePerm
|
||||||
|
if value&0o1000 != 0 {
|
||||||
|
stat.Mode |= os.ModeSticky
|
||||||
|
}
|
||||||
|
if value&0o2000 != 0 {
|
||||||
|
stat.Mode |= os.ModeSetgid
|
||||||
|
}
|
||||||
|
if value&0o4000 != 0 {
|
||||||
|
stat.Mode |= os.ModeSetuid
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(attrs) > 3 {
|
||||||
|
typ := attrs[3]
|
||||||
|
if strings.HasPrefix(typ, "file") {
|
||||||
|
} else if strings.HasPrefix(typ, "dir") {
|
||||||
|
stat.Mode |= os.ModeDir
|
||||||
|
} else if strings.HasPrefix(typ, "symlink") {
|
||||||
|
stat.Mode |= os.ModeSymlink
|
||||||
|
} else if strings.HasPrefix(typ, "pipe") {
|
||||||
|
stat.Mode |= os.ModeNamedPipe
|
||||||
|
} else if strings.HasPrefix(typ, "socket") {
|
||||||
|
stat.Mode |= os.ModeSocket
|
||||||
|
} else if strings.HasPrefix(typ, "block") {
|
||||||
|
stat.Mode |= os.ModeDevice
|
||||||
|
stat.Major, stat.Minor, err = parseDevice(typ)
|
||||||
|
if err != nil {
|
||||||
|
return stat, err
|
||||||
|
}
|
||||||
|
} else if strings.HasPrefix(typ, "char") {
|
||||||
|
stat.Mode |= os.ModeDevice | os.ModeCharDevice
|
||||||
|
stat.Major, stat.Minor, err = parseDevice(typ)
|
||||||
|
if err != nil {
|
||||||
|
return stat, err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return stat, fmt.Errorf("invalid file type %s", typ)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return stat, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseDevice(typ string) (int, int, error) {
|
||||||
|
parts := strings.Split(typ, "-")
|
||||||
|
// If there are more than 3 parts, just ignore them to be forward compatible
|
||||||
|
if len(parts) < 3 {
|
||||||
|
return 0, 0, fmt.Errorf("invalid device type %s", typ)
|
||||||
|
}
|
||||||
|
if parts[0] != "block" && parts[0] != "char" {
|
||||||
|
return 0, 0, fmt.Errorf("invalid device type %s", typ)
|
||||||
|
}
|
||||||
|
major, err := strconv.Atoi(parts[1])
|
||||||
|
if err != nil {
|
||||||
|
return 0, 0, fmt.Errorf("failed to parse major number: %w", err)
|
||||||
|
}
|
||||||
|
minor, err := strconv.Atoi(parts[2])
|
||||||
|
if err != nil {
|
||||||
|
return 0, 0, fmt.Errorf("failed to parse minor number: %w", err)
|
||||||
|
}
|
||||||
|
return major, minor, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetContainersOverrideXattr will encode and set ContainersOverrideXattr.
|
||||||
|
func SetContainersOverrideXattr(path string, stat Stat) error {
|
||||||
|
value := FormatContainersOverrideXattrDevice(stat.IDs.UID, stat.IDs.GID, stat.Mode, stat.Major, stat.Minor)
|
||||||
|
return system.Lsetxattr(path, ContainersOverrideXattr, []byte(value), 0)
|
||||||
|
}
|
||||||
|
|
||||||
func SafeChown(name string, uid, gid int) error {
|
func SafeChown(name string, uid, gid int) error {
|
||||||
if runtime.GOOS == "darwin" {
|
if runtime.GOOS == "darwin" {
|
||||||
var mode uint64 = 0o0700
|
stat := Stat{
|
||||||
|
Mode: os.FileMode(0o0700),
|
||||||
|
}
|
||||||
xstat, err := system.Lgetxattr(name, ContainersOverrideXattr)
|
xstat, err := system.Lgetxattr(name, ContainersOverrideXattr)
|
||||||
if err == nil {
|
if err == nil && xstat != nil {
|
||||||
attrs := strings.Split(string(xstat), ":")
|
stat, err = parseOverrideXattr(xstat)
|
||||||
if len(attrs) == 3 {
|
if err != nil {
|
||||||
val, err := strconv.ParseUint(attrs[2], 8, 32)
|
return err
|
||||||
if err == nil {
|
|
||||||
mode = val
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
st, err := os.Stat(name) // Ideally we would share this with system.Stat below, but then we would need to convert Mode.
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
stat.Mode = st.Mode()
|
||||||
}
|
}
|
||||||
value := fmt.Sprintf("%d:%d:0%o", uid, gid, mode)
|
stat.IDs = IDPair{UID: uid, GID: gid}
|
||||||
if err = system.Lsetxattr(name, ContainersOverrideXattr, []byte(value), 0); err != nil {
|
if err = SetContainersOverrideXattr(name, stat); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
uid = os.Getuid()
|
uid = os.Getuid()
|
||||||
|
@ -397,19 +551,24 @@ func SafeChown(name string, uid, gid int) error {
|
||||||
|
|
||||||
func SafeLchown(name string, uid, gid int) error {
|
func SafeLchown(name string, uid, gid int) error {
|
||||||
if runtime.GOOS == "darwin" {
|
if runtime.GOOS == "darwin" {
|
||||||
var mode uint64 = 0o0700
|
stat := Stat{
|
||||||
|
Mode: os.FileMode(0o0700),
|
||||||
|
}
|
||||||
xstat, err := system.Lgetxattr(name, ContainersOverrideXattr)
|
xstat, err := system.Lgetxattr(name, ContainersOverrideXattr)
|
||||||
if err == nil {
|
if err == nil && xstat != nil {
|
||||||
attrs := strings.Split(string(xstat), ":")
|
stat, err = parseOverrideXattr(xstat)
|
||||||
if len(attrs) == 3 {
|
if err != nil {
|
||||||
val, err := strconv.ParseUint(attrs[2], 8, 32)
|
return err
|
||||||
if err == nil {
|
|
||||||
mode = val
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
st, err := os.Lstat(name) // Ideally we would share this with system.Stat below, but then we would need to convert Mode.
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
stat.Mode = st.Mode()
|
||||||
}
|
}
|
||||||
value := fmt.Sprintf("%d:%d:0%o", uid, gid, mode)
|
stat.IDs = IDPair{UID: uid, GID: gid}
|
||||||
if err = system.Lsetxattr(name, ContainersOverrideXattr, []byte(value), 0); err != nil {
|
if err = SetContainersOverrideXattr(name, stat); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
uid = os.Getuid()
|
uid = os.Getuid()
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
//go:build linux && cgo && libsubid
|
//go:build linux && cgo && libsubid
|
||||||
// +build linux,cgo,libsubid
|
|
||||||
|
|
||||||
package idtools
|
package idtools
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"os/user"
|
"os/user"
|
||||||
|
"sync"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -14,16 +14,14 @@ import (
|
||||||
#include <shadow/subid.h>
|
#include <shadow/subid.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
const char *Prog = "storage";
|
|
||||||
FILE *shadow_logfd = NULL;
|
|
||||||
|
|
||||||
struct subid_range get_range(struct subid_range *ranges, int i)
|
struct subid_range get_range(struct subid_range *ranges, int i)
|
||||||
{
|
{
|
||||||
shadow_logfd = stderr;
|
|
||||||
return ranges[i];
|
return ranges[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
#if !defined(SUBID_ABI_MAJOR) || (SUBID_ABI_MAJOR < 4)
|
#if !defined(SUBID_ABI_MAJOR) || (SUBID_ABI_MAJOR < 4)
|
||||||
|
# define subid_init libsubid_init
|
||||||
# define subid_get_uid_ranges get_subuid_ranges
|
# define subid_get_uid_ranges get_subuid_ranges
|
||||||
# define subid_get_gid_ranges get_subgid_ranges
|
# define subid_get_gid_ranges get_subgid_ranges
|
||||||
#endif
|
#endif
|
||||||
|
@ -31,6 +29,8 @@ struct subid_range get_range(struct subid_range *ranges, int i)
|
||||||
*/
|
*/
|
||||||
import "C"
|
import "C"
|
||||||
|
|
||||||
|
var onceInit sync.Once
|
||||||
|
|
||||||
func readSubid(username string, isUser bool) (ranges, error) {
|
func readSubid(username string, isUser bool) (ranges, error) {
|
||||||
var ret ranges
|
var ret ranges
|
||||||
uidstr := ""
|
uidstr := ""
|
||||||
|
@ -43,6 +43,10 @@ func readSubid(username string, isUser bool) (ranges, error) {
|
||||||
uidstr = u.Uid
|
uidstr = u.Uid
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onceInit.Do(func() {
|
||||||
|
C.subid_init(C.CString("storage"), C.stderr)
|
||||||
|
})
|
||||||
|
|
||||||
cUsername := C.CString(username)
|
cUsername := C.CString(username)
|
||||||
defer C.free(unsafe.Pointer(cUsername))
|
defer C.free(unsafe.Pointer(cUsername))
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
//go:build !windows
|
//go:build !windows
|
||||||
// +build !windows
|
|
||||||
|
|
||||||
package idtools
|
package idtools
|
||||||
|
|
||||||
|
@ -13,8 +12,9 @@ import (
|
||||||
"sync"
|
"sync"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
|
"github.com/containers/storage/pkg/fileutils"
|
||||||
"github.com/containers/storage/pkg/system"
|
"github.com/containers/storage/pkg/system"
|
||||||
"github.com/opencontainers/runc/libcontainer/user"
|
"github.com/moby/sys/user"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -55,7 +55,7 @@ func mkdirAs(path string, mode os.FileMode, ownerUID, ownerGID int, mkAll, chown
|
||||||
if dirPath == "/" {
|
if dirPath == "/" {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if _, err := os.Stat(dirPath); err != nil && os.IsNotExist(err) {
|
if err := fileutils.Exists(dirPath); err != nil && os.IsNotExist(err) {
|
||||||
paths = append(paths, dirPath)
|
paths = append(paths, dirPath)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
//go:build !linux || !libsubid || !cgo
|
//go:build !linux || !libsubid || !cgo
|
||||||
// +build !linux !libsubid !cgo
|
|
||||||
|
|
||||||
package idtools
|
package idtools
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
//go:build windows
|
//go:build windows
|
||||||
// +build windows
|
|
||||||
|
|
||||||
package idtools
|
package idtools
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
//go:build !linux
|
//go:build !linux
|
||||||
// +build !linux
|
|
||||||
|
|
||||||
package idtools
|
package idtools
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
//go:build !windows
|
//go:build !windows
|
||||||
// +build !windows
|
|
||||||
|
|
||||||
package idtools
|
package idtools
|
||||||
|
|
||||||
|
|
|
@ -97,14 +97,14 @@ func MergeTmpfsOptions(options []string) ([]string, error) {
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
opt := strings.SplitN(option, "=", 2)
|
opt, _, ok := strings.Cut(option, "=")
|
||||||
if len(opt) != 2 || !validFlags[opt[0]] {
|
if !ok || !validFlags[opt] {
|
||||||
return nil, fmt.Errorf("invalid tmpfs option %q", opt)
|
return nil, fmt.Errorf("invalid tmpfs option %q", opt)
|
||||||
}
|
}
|
||||||
if !dataCollisions[opt[0]] {
|
if !dataCollisions[opt] {
|
||||||
// We prepend the option and add to collision map
|
// We prepend the option and add to collision map
|
||||||
newOptions = append([]string{option}, newOptions...)
|
newOptions = append([]string{option}, newOptions...)
|
||||||
dataCollisions[opt[0]] = true
|
dataCollisions[opt] = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -140,8 +140,8 @@ func ParseOptions(options string) (int, string) {
|
||||||
func ParseTmpfsOptions(options string) (int, string, error) {
|
func ParseTmpfsOptions(options string) (int, string, error) {
|
||||||
flags, data := ParseOptions(options)
|
flags, data := ParseOptions(options)
|
||||||
for _, o := range strings.Split(data, ",") {
|
for _, o := range strings.Split(data, ",") {
|
||||||
opt := strings.SplitN(o, "=", 2)
|
opt, _, _ := strings.Cut(o, "=")
|
||||||
if !validFlags[opt[0]] {
|
if !validFlags[opt] {
|
||||||
return 0, "", fmt.Errorf("invalid tmpfs option %q", opt)
|
return 0, "", fmt.Errorf("invalid tmpfs option %q", opt)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
//go:build !linux && !freebsd
|
//go:build !linux && !freebsd
|
||||||
// +build !linux,!freebsd
|
|
||||||
|
|
||||||
package mount
|
package mount
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
//go:build freebsd && cgo
|
//go:build freebsd && cgo
|
||||||
// +build freebsd,cgo
|
|
||||||
|
|
||||||
package mount
|
package mount
|
||||||
|
|
||||||
|
@ -40,13 +39,9 @@ func mount(device, target, mType string, flag uintptr, data string) error {
|
||||||
isNullFS = true
|
isNullFS = true
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
opt := strings.SplitN(x, "=", 2)
|
name, val, _ := strings.Cut(x, "=")
|
||||||
options = append(options, opt[0])
|
options = append(options, name)
|
||||||
if len(opt) == 2 {
|
options = append(options, val)
|
||||||
options = append(options, opt[1])
|
|
||||||
} else {
|
|
||||||
options = append(options, "")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
//go:build !linux && !(freebsd && cgo)
|
//go:build !linux && !(freebsd && cgo)
|
||||||
// +build !linux
|
|
||||||
// +build !freebsd !cgo
|
|
||||||
|
|
||||||
package mount
|
package mount
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,18 @@
|
||||||
package mount
|
package mount
|
||||||
|
|
||||||
import "github.com/moby/sys/mountinfo"
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
|
||||||
var PidMountInfo = mountinfo.PidMountInfo
|
"github.com/moby/sys/mountinfo"
|
||||||
|
)
|
||||||
|
|
||||||
|
func PidMountInfo(pid int) ([]*Info, error) {
|
||||||
|
f, err := os.Open(fmt.Sprintf("/proc/%d/mountinfo", pid))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
return mountinfo.GetMountsFromReader(f, nil)
|
||||||
|
}
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
//go:build !windows
|
//go:build !windows
|
||||||
// +build !windows
|
|
||||||
|
|
||||||
package mount
|
package mount
|
||||||
|
|
||||||
|
@ -11,7 +10,7 @@ import (
|
||||||
|
|
||||||
func unmount(target string, flags int) error {
|
func unmount(target string, flags int) error {
|
||||||
var err error
|
var err error
|
||||||
for i := 0; i < 50; i++ {
|
for range 50 {
|
||||||
err = unix.Unmount(target, flags)
|
err = unix.Unmount(target, flags)
|
||||||
switch err {
|
switch err {
|
||||||
case unix.EBUSY:
|
case unix.EBUSY:
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
//go:build windows
|
//go:build windows
|
||||||
// +build windows
|
|
||||||
|
|
||||||
package mount
|
package mount
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
//go:build freebsd
|
//go:build freebsd
|
||||||
// +build freebsd
|
|
||||||
|
|
||||||
package reexec
|
package reexec
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
//go:build linux
|
//go:build linux
|
||||||
// +build linux
|
|
||||||
|
|
||||||
package reexec
|
package reexec
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
//go:build solaris || darwin
|
//go:build solaris || darwin
|
||||||
// +build solaris darwin
|
|
||||||
|
|
||||||
package reexec
|
package reexec
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
//go:build !linux && !windows && !freebsd && !solaris && !darwin
|
//go:build !linux && !windows && !freebsd && !solaris && !darwin
|
||||||
// +build !linux,!windows,!freebsd,!solaris,!darwin
|
|
||||||
|
|
||||||
package reexec
|
package reexec
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
//go:build windows
|
//go:build windows
|
||||||
// +build windows
|
|
||||||
|
|
||||||
package reexec
|
package reexec
|
||||||
|
|
||||||
|
|
|
@ -49,7 +49,7 @@ func panicIfNotInitialized() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func naiveSelf() string { //nolint: unused
|
func naiveSelf() string {
|
||||||
name := os.Args[0]
|
name := os.Args[0]
|
||||||
if filepath.Base(name) == name {
|
if filepath.Base(name) == name {
|
||||||
if lp, err := exec.LookPath(name); err == nil {
|
if lp, err := exec.LookPath(name); err == nil {
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
//go:build !regexp_precompile
|
//go:build !regexp_precompile
|
||||||
// +build !regexp_precompile
|
|
||||||
|
|
||||||
package regexp
|
package regexp
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
//go:build regexp_precompile
|
//go:build regexp_precompile
|
||||||
// +build regexp_precompile
|
|
||||||
|
|
||||||
package regexp
|
package regexp
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
//go:build !windows
|
//go:build !windows
|
||||||
// +build !windows
|
|
||||||
|
|
||||||
package system
|
package system
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
//go:build windows
|
//go:build windows
|
||||||
// +build windows
|
|
||||||
|
|
||||||
package system
|
package system
|
||||||
|
|
||||||
|
|
93
vendor/github.com/containers/storage/pkg/system/extattr_freebsd.go
generated
vendored
Normal file
93
vendor/github.com/containers/storage/pkg/system/extattr_freebsd.go
generated
vendored
Normal file
|
@ -0,0 +1,93 @@
|
||||||
|
//go:build freebsd
|
||||||
|
|
||||||
|
package system
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
"golang.org/x/sys/unix"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
EXTATTR_NAMESPACE_EMPTY = unix.EXTATTR_NAMESPACE_EMPTY
|
||||||
|
EXTATTR_NAMESPACE_USER = unix.EXTATTR_NAMESPACE_USER
|
||||||
|
EXTATTR_NAMESPACE_SYSTEM = unix.EXTATTR_NAMESPACE_SYSTEM
|
||||||
|
)
|
||||||
|
|
||||||
|
// ExtattrGetLink retrieves the value of the extended attribute identified by attrname
|
||||||
|
// in the given namespace and associated with the given path in the file system.
|
||||||
|
// If the path is a symbolic link, the extended attribute is retrieved from the link itself.
|
||||||
|
// Returns a []byte slice if the extattr is set and nil otherwise.
|
||||||
|
func ExtattrGetLink(path string, attrnamespace int, attrname string) ([]byte, error) {
|
||||||
|
size, errno := unix.ExtattrGetLink(path, attrnamespace, attrname,
|
||||||
|
uintptr(unsafe.Pointer(nil)), 0)
|
||||||
|
if errno != nil {
|
||||||
|
if errno == unix.ENOATTR {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
return nil, &os.PathError{Op: "extattr_get_link", Path: path, Err: errno}
|
||||||
|
}
|
||||||
|
if size == 0 {
|
||||||
|
return []byte{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
dest := make([]byte, size)
|
||||||
|
size, errno = unix.ExtattrGetLink(path, attrnamespace, attrname,
|
||||||
|
uintptr(unsafe.Pointer(&dest[0])), size)
|
||||||
|
if errno != nil {
|
||||||
|
return nil, &os.PathError{Op: "extattr_get_link", Path: path, Err: errno}
|
||||||
|
}
|
||||||
|
|
||||||
|
return dest[:size], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExtattrSetLink sets the value of extended attribute identified by attrname
|
||||||
|
// in the given namespace and associated with the given path in the file system.
|
||||||
|
// If the path is a symbolic link, the extended attribute is set on the link itself.
|
||||||
|
func ExtattrSetLink(path string, attrnamespace int, attrname string, data []byte) error {
|
||||||
|
if len(data) == 0 {
|
||||||
|
data = []byte{} // ensure non-nil for empty data
|
||||||
|
}
|
||||||
|
if _, errno := unix.ExtattrSetLink(path, attrnamespace, attrname,
|
||||||
|
uintptr(unsafe.Pointer(&data[0])), len(data)); errno != nil {
|
||||||
|
return &os.PathError{Op: "extattr_set_link", Path: path, Err: errno}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExtattrListLink lists extended attributes associated with the given path
|
||||||
|
// in the specified namespace. If the path is a symbolic link, the attributes
|
||||||
|
// are listed from the link itself.
|
||||||
|
func ExtattrListLink(path string, attrnamespace int) ([]string, error) {
|
||||||
|
size, errno := unix.ExtattrListLink(path, attrnamespace,
|
||||||
|
uintptr(unsafe.Pointer(nil)), 0)
|
||||||
|
if errno != nil {
|
||||||
|
return nil, &os.PathError{Op: "extattr_list_link", Path: path, Err: errno}
|
||||||
|
}
|
||||||
|
if size == 0 {
|
||||||
|
return []string{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
dest := make([]byte, size)
|
||||||
|
size, errno = unix.ExtattrListLink(path, attrnamespace,
|
||||||
|
uintptr(unsafe.Pointer(&dest[0])), size)
|
||||||
|
if errno != nil {
|
||||||
|
return nil, &os.PathError{Op: "extattr_list_link", Path: path, Err: errno}
|
||||||
|
}
|
||||||
|
|
||||||
|
var attrs []string
|
||||||
|
for i := 0; i < size; {
|
||||||
|
// Each attribute is preceded by a single byte length
|
||||||
|
length := int(dest[i])
|
||||||
|
i++
|
||||||
|
if i+length > size {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
attrs = append(attrs, string(dest[i:i+length]))
|
||||||
|
i += length
|
||||||
|
}
|
||||||
|
|
||||||
|
return attrs, nil
|
||||||
|
}
|
24
vendor/github.com/containers/storage/pkg/system/extattr_unsupported.go
generated
vendored
Normal file
24
vendor/github.com/containers/storage/pkg/system/extattr_unsupported.go
generated
vendored
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
//go:build !freebsd
|
||||||
|
|
||||||
|
package system
|
||||||
|
|
||||||
|
const (
|
||||||
|
EXTATTR_NAMESPACE_EMPTY = 0
|
||||||
|
EXTATTR_NAMESPACE_USER = 0
|
||||||
|
EXTATTR_NAMESPACE_SYSTEM = 0
|
||||||
|
)
|
||||||
|
|
||||||
|
// ExtattrGetLink is not supported on platforms other than FreeBSD.
|
||||||
|
func ExtattrGetLink(path string, attrnamespace int, attrname string) ([]byte, error) {
|
||||||
|
return nil, ErrNotSupportedPlatform
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExtattrSetLink is not supported on platforms other than FreeBSD.
|
||||||
|
func ExtattrSetLink(path string, attrnamespace int, attrname string, data []byte) error {
|
||||||
|
return ErrNotSupportedPlatform
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExtattrListLink is not supported on platforms other than FreeBSD.
|
||||||
|
func ExtattrListLink(path string, attrnamespace int) ([]string, error) {
|
||||||
|
return nil, ErrNotSupportedPlatform
|
||||||
|
}
|
|
@ -1,5 +1,4 @@
|
||||||
//go:build freebsd
|
//go:build freebsd
|
||||||
// +build freebsd
|
|
||||||
|
|
||||||
package system
|
package system
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
//go:build !windows
|
//go:build !windows
|
||||||
// +build !windows
|
|
||||||
|
|
||||||
package system
|
package system
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
//go:build !windows
|
//go:build !windows
|
||||||
// +build !windows
|
|
||||||
|
|
||||||
package system
|
package system
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
//go:build freebsd && cgo
|
//go:build freebsd && cgo
|
||||||
// +build freebsd,cgo
|
|
||||||
|
|
||||||
package system
|
package system
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
//go:build solaris && cgo
|
//go:build solaris && cgo
|
||||||
// +build solaris,cgo
|
|
||||||
|
|
||||||
package system
|
package system
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,4 @@
|
||||||
//go:build !linux && !windows && !solaris && !(freebsd && cgo)
|
//go:build !linux && !windows && !solaris && !(freebsd && cgo)
|
||||||
// +build !linux
|
|
||||||
// +build !windows
|
|
||||||
// +build !solaris
|
|
||||||
// +build !freebsd !cgo
|
|
||||||
|
|
||||||
package system
|
package system
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
//go:build !windows && !freebsd
|
//go:build !windows && !freebsd
|
||||||
// +build !windows,!freebsd
|
|
||||||
|
|
||||||
package system
|
package system
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
//go:build freebsd
|
//go:build freebsd
|
||||||
// +build freebsd
|
|
||||||
|
|
||||||
package system
|
package system
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
//go:build windows
|
//go:build windows
|
||||||
// +build windows
|
|
||||||
|
|
||||||
package system
|
package system
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
//go:build !windows
|
//go:build !windows
|
||||||
// +build !windows
|
|
||||||
|
|
||||||
package system
|
package system
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
//go:build windows
|
//go:build windows
|
||||||
// +build windows
|
|
||||||
|
|
||||||
package system
|
package system
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
//go:build linux || freebsd || solaris || darwin
|
//go:build linux || freebsd || solaris || darwin
|
||||||
// +build linux freebsd solaris darwin
|
|
||||||
|
|
||||||
package system
|
package system
|
||||||
|
|
||||||
|
|
|
@ -28,7 +28,7 @@ func EnsureRemoveAll(dir string) error {
|
||||||
|
|
||||||
// track retries
|
// track retries
|
||||||
exitOnErr := make(map[string]int)
|
exitOnErr := make(map[string]int)
|
||||||
maxRetry := 100
|
maxRetry := 1000
|
||||||
|
|
||||||
// Attempt a simple remove all first, this avoids the more expensive
|
// Attempt a simple remove all first, this avoids the more expensive
|
||||||
// RecursiveUnmount call if not needed.
|
// RecursiveUnmount call if not needed.
|
||||||
|
@ -38,7 +38,7 @@ func EnsureRemoveAll(dir string) error {
|
||||||
|
|
||||||
// Attempt to unmount anything beneath this dir first
|
// Attempt to unmount anything beneath this dir first
|
||||||
if err := mount.RecursiveUnmount(dir); err != nil {
|
if err := mount.RecursiveUnmount(dir); err != nil {
|
||||||
logrus.Debugf("RecusiveUnmount on %s failed: %v", dir, err)
|
logrus.Debugf("RecursiveUnmount on %s failed: %v", dir, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
for {
|
for {
|
||||||
|
@ -94,6 +94,6 @@ func EnsureRemoveAll(dir string) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
exitOnErr[pe.Path]++
|
exitOnErr[pe.Path]++
|
||||||
time.Sleep(100 * time.Millisecond)
|
time.Sleep(10 * time.Millisecond)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
//go:build !freebsd
|
//go:build !freebsd
|
||||||
// +build !freebsd
|
|
||||||
|
|
||||||
package system
|
package system
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
//go:build !freebsd
|
//go:build !freebsd
|
||||||
// +build !freebsd
|
|
||||||
|
|
||||||
package system
|
package system
|
||||||
|
|
||||||
|
|
|
@ -9,9 +9,9 @@ func fromStatT(s *syscall.Stat_t) (*StatT, error) {
|
||||||
mode: s.Mode,
|
mode: s.Mode,
|
||||||
uid: s.Uid,
|
uid: s.Uid,
|
||||||
gid: s.Gid,
|
gid: s.Gid,
|
||||||
rdev: uint64(s.Rdev),
|
rdev: uint64(s.Rdev), //nolint:unconvert
|
||||||
mtim: s.Mtim,
|
mtim: s.Mtim,
|
||||||
dev: uint64(s.Dev),
|
dev: uint64(s.Dev), //nolint:unconvert
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
package system
|
||||||
|
|
||||||
|
import "syscall"
|
||||||
|
|
||||||
|
// fromStatT converts a syscall.Stat_t type to a system.Stat_t type
|
||||||
|
func fromStatT(s *syscall.Stat_t) (*StatT, error) {
|
||||||
|
return &StatT{size: s.Size,
|
||||||
|
mode: uint32(s.Mode),
|
||||||
|
uid: s.Uid,
|
||||||
|
gid: s.Gid,
|
||||||
|
rdev: uint64(s.Rdev),
|
||||||
|
mtim: s.Mtimespec}, nil
|
||||||
|
}
|
|
@ -1,5 +1,4 @@
|
||||||
//go:build !windows
|
//go:build !windows
|
||||||
// +build !windows
|
|
||||||
|
|
||||||
package system
|
package system
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
//go:build linux || freebsd || darwin
|
//go:build !windows
|
||||||
// +build linux freebsd darwin
|
|
||||||
|
|
||||||
package system
|
package system
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
//go:build !windows
|
//go:build !windows
|
||||||
// +build !windows
|
|
||||||
|
|
||||||
package system
|
package system
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
//go:build windows
|
//go:build windows
|
||||||
// +build windows
|
|
||||||
|
|
||||||
package system
|
package system
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
//go:build !linux && !freebsd
|
//go:build !linux && !freebsd
|
||||||
// +build !linux,!freebsd
|
|
||||||
|
|
||||||
package system
|
package system
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,7 @@ const (
|
||||||
E2BIG unix.Errno = unix.E2BIG
|
E2BIG unix.Errno = unix.E2BIG
|
||||||
|
|
||||||
// Operation not supported
|
// Operation not supported
|
||||||
EOPNOTSUPP unix.Errno = unix.EOPNOTSUPP
|
ENOTSUP unix.Errno = unix.ENOTSUP
|
||||||
)
|
)
|
||||||
|
|
||||||
// Lgetxattr retrieves the value of the extended attribute identified by attr
|
// Lgetxattr retrieves the value of the extended attribute identified by attr
|
||||||
|
|
|
@ -0,0 +1,85 @@
|
||||||
|
package system
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"golang.org/x/sys/unix"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// Value is larger than the maximum size allowed
|
||||||
|
E2BIG unix.Errno = unix.E2BIG
|
||||||
|
|
||||||
|
// Operation not supported
|
||||||
|
ENOTSUP unix.Errno = unix.ENOTSUP
|
||||||
|
|
||||||
|
// Value is too small or too large for maximum size allowed
|
||||||
|
EOVERFLOW unix.Errno = unix.EOVERFLOW
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
namespaceMap = map[string]int{
|
||||||
|
"user": EXTATTR_NAMESPACE_USER,
|
||||||
|
"system": EXTATTR_NAMESPACE_SYSTEM,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func xattrToExtattr(xattr string) (namespace int, extattr string, err error) {
|
||||||
|
namespaceName, extattr, found := strings.Cut(xattr, ".")
|
||||||
|
if !found {
|
||||||
|
return -1, "", ENOTSUP
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace, ok := namespaceMap[namespaceName]
|
||||||
|
if !ok {
|
||||||
|
return -1, "", ENOTSUP
|
||||||
|
}
|
||||||
|
return namespace, extattr, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lgetxattr retrieves the value of the extended attribute identified by attr
|
||||||
|
// and associated with the given path in the file system.
|
||||||
|
// Returns a []byte slice if the xattr is set and nil otherwise.
|
||||||
|
func Lgetxattr(path string, attr string) ([]byte, error) {
|
||||||
|
namespace, extattr, err := xattrToExtattr(attr)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return ExtattrGetLink(path, namespace, extattr)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lsetxattr sets the value of the extended attribute identified by attr
|
||||||
|
// and associated with the given path in the file system.
|
||||||
|
func Lsetxattr(path string, attr string, value []byte, flags int) error {
|
||||||
|
if flags != 0 {
|
||||||
|
// FIXME: Flags are not supported on FreeBSD, but we can implement
|
||||||
|
// them mimicking the behavior of the Linux implementation.
|
||||||
|
// See lsetxattr(2) on Linux for more information.
|
||||||
|
return ENOTSUP
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace, extattr, err := xattrToExtattr(attr)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return ExtattrSetLink(path, namespace, extattr, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Llistxattr lists extended attributes associated with the given path
|
||||||
|
// in the file system.
|
||||||
|
func Llistxattr(path string) ([]string, error) {
|
||||||
|
attrs := []string{}
|
||||||
|
|
||||||
|
for namespaceName, namespace := range namespaceMap {
|
||||||
|
namespaceAttrs, err := ExtattrListLink(path, namespace)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, attr := range namespaceAttrs {
|
||||||
|
attrs = append(attrs, namespaceName+"."+attr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return attrs, nil
|
||||||
|
}
|
|
@ -12,7 +12,7 @@ const (
|
||||||
E2BIG unix.Errno = unix.E2BIG
|
E2BIG unix.Errno = unix.E2BIG
|
||||||
|
|
||||||
// Operation not supported
|
// Operation not supported
|
||||||
EOPNOTSUPP unix.Errno = unix.EOPNOTSUPP
|
ENOTSUP unix.Errno = unix.ENOTSUP
|
||||||
|
|
||||||
// Value is too small or too large for maximum size allowed
|
// Value is too small or too large for maximum size allowed
|
||||||
EOVERFLOW unix.Errno = unix.EOVERFLOW
|
EOVERFLOW unix.Errno = unix.EOVERFLOW
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
//go:build !linux && !darwin
|
//go:build !linux && !darwin && !freebsd
|
||||||
// +build !linux,!darwin
|
|
||||||
|
|
||||||
package system
|
package system
|
||||||
|
|
||||||
|
@ -10,7 +9,7 @@ const (
|
||||||
E2BIG syscall.Errno = syscall.Errno(0)
|
E2BIG syscall.Errno = syscall.Errno(0)
|
||||||
|
|
||||||
// Operation not supported
|
// Operation not supported
|
||||||
EOPNOTSUPP syscall.Errno = syscall.Errno(0)
|
ENOTSUP syscall.Errno = syscall.Errno(0)
|
||||||
|
|
||||||
// Value is too small or too large for maximum size allowed
|
// Value is too small or too large for maximum size allowed
|
||||||
EOVERFLOW syscall.Errno = syscall.Errno(0)
|
EOVERFLOW syscall.Errno = syscall.Errno(0)
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
//go:build linux && cgo
|
//go:build linux && cgo
|
||||||
// +build linux,cgo
|
|
||||||
|
|
||||||
package unshare
|
package unshare
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
//go:build linux && !cgo
|
//go:build linux && !cgo
|
||||||
// +build linux,!cgo
|
|
||||||
|
|
||||||
package unshare
|
package unshare
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
#include <termios.h>
|
#include <termios.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <libgen.h>
|
||||||
#include <sys/vfs.h>
|
#include <sys/vfs.h>
|
||||||
#include <sys/mount.h>
|
#include <sys/mount.h>
|
||||||
#include <linux/limits.h>
|
#include <linux/limits.h>
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
//go:build (linux && cgo && !gccgo) || (freebsd && cgo)
|
//go:build (linux && cgo && !gccgo) || (freebsd && cgo)
|
||||||
// +build linux,cgo,!gccgo freebsd,cgo
|
|
||||||
|
|
||||||
package unshare
|
package unshare
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
//go:build darwin
|
//go:build darwin
|
||||||
// +build darwin
|
|
||||||
|
|
||||||
package unshare
|
package unshare
|
||||||
|
|
||||||
|
@ -25,6 +24,11 @@ func GetRootlessUID() int {
|
||||||
return os.Getuid()
|
return os.Getuid()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetRootlessGID returns the GID of the user in the parent userNS
|
||||||
|
func GetRootlessGID() int {
|
||||||
|
return os.Getgid()
|
||||||
|
}
|
||||||
|
|
||||||
// RootlessEnv returns the environment settings for the rootless containers
|
// RootlessEnv returns the environment settings for the rootless containers
|
||||||
func RootlessEnv() []string {
|
func RootlessEnv() []string {
|
||||||
return append(os.Environ(), UsernsEnvName+"=")
|
return append(os.Environ(), UsernsEnvName+"=")
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
//go:build freebsd
|
//go:build freebsd
|
||||||
// +build freebsd
|
|
||||||
|
|
||||||
package unshare
|
package unshare
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
//go:build linux && cgo && gccgo
|
//go:build linux && cgo && gccgo
|
||||||
// +build linux,cgo,gccgo
|
|
||||||
|
|
||||||
package unshare
|
package unshare
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
//go:build linux
|
//go:build linux
|
||||||
// +build linux
|
|
||||||
|
|
||||||
package unshare
|
package unshare
|
||||||
|
|
||||||
|
@ -21,9 +20,9 @@ import (
|
||||||
|
|
||||||
"github.com/containers/storage/pkg/idtools"
|
"github.com/containers/storage/pkg/idtools"
|
||||||
"github.com/containers/storage/pkg/reexec"
|
"github.com/containers/storage/pkg/reexec"
|
||||||
|
"github.com/moby/sys/capability"
|
||||||
"github.com/opencontainers/runtime-spec/specs-go"
|
"github.com/opencontainers/runtime-spec/specs-go"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
"github.com/syndtr/gocapability/capability"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Cmd wraps an exec.Cmd created by the reexec package in unshare(), and
|
// Cmd wraps an exec.Cmd created by the reexec package in unshare(), and
|
||||||
|
@ -33,9 +32,9 @@ type Cmd struct {
|
||||||
*exec.Cmd
|
*exec.Cmd
|
||||||
UnshareFlags int
|
UnshareFlags int
|
||||||
UseNewuidmap bool
|
UseNewuidmap bool
|
||||||
UidMappings []specs.LinuxIDMapping // nolint: revive,golint
|
UidMappings []specs.LinuxIDMapping //nolint: revive
|
||||||
UseNewgidmap bool
|
UseNewgidmap bool
|
||||||
GidMappings []specs.LinuxIDMapping // nolint: revive,golint
|
GidMappings []specs.LinuxIDMapping //nolint: revive
|
||||||
GidMappingsEnableSetgroups bool
|
GidMappingsEnableSetgroups bool
|
||||||
Setsid bool
|
Setsid bool
|
||||||
Setpgrp bool
|
Setpgrp bool
|
||||||
|
@ -99,7 +98,7 @@ func IsSetID(path string, modeid os.FileMode, capid capability.Cap) (bool, error
|
||||||
return cap.Get(capability.EFFECTIVE, capid), nil
|
return cap.Get(capability.EFFECTIVE, capid), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Cmd) Start() error {
|
func (c *Cmd) Start() (retErr error) {
|
||||||
runtime.LockOSThread()
|
runtime.LockOSThread()
|
||||||
defer runtime.UnlockOSThread()
|
defer runtime.UnlockOSThread()
|
||||||
|
|
||||||
|
@ -168,6 +167,15 @@ func (c *Cmd) Start() error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If the function fails from here, we need to make sure the
|
||||||
|
// child process is killed and properly cleaned up.
|
||||||
|
defer func() {
|
||||||
|
if retErr != nil {
|
||||||
|
_ = c.Cmd.Process.Kill()
|
||||||
|
_ = c.Cmd.Wait()
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
// Close the ends of the pipes that the parent doesn't need.
|
// Close the ends of the pipes that the parent doesn't need.
|
||||||
continueRead.Close()
|
continueRead.Close()
|
||||||
continueRead = nil
|
continueRead = nil
|
||||||
|
@ -241,7 +249,7 @@ func (c *Cmd) Start() error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("finding newgidmap: %w", err)
|
return fmt.Errorf("finding newgidmap: %w", err)
|
||||||
}
|
}
|
||||||
cmd := exec.Command(path, append([]string{pidString}, strings.Fields(strings.Replace(g.String(), "\n", " ", -1))...)...)
|
cmd := exec.Command(path, append([]string{pidString}, strings.Fields(g.String())...)...)
|
||||||
g.Reset()
|
g.Reset()
|
||||||
cmd.Stdout = g
|
cmd.Stdout = g
|
||||||
cmd.Stderr = g
|
cmd.Stderr = g
|
||||||
|
@ -259,7 +267,7 @@ func (c *Cmd) Start() error {
|
||||||
}
|
}
|
||||||
logrus.Warnf("Falling back to single mapping")
|
logrus.Warnf("Falling back to single mapping")
|
||||||
g.Reset()
|
g.Reset()
|
||||||
g.Write([]byte(fmt.Sprintf("0 %d 1\n", os.Getegid())))
|
fmt.Fprintf(g, "0 %d 1\n", os.Getegid())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !gidmapSet {
|
if !gidmapSet {
|
||||||
|
@ -301,7 +309,7 @@ func (c *Cmd) Start() error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("finding newuidmap: %w", err)
|
return fmt.Errorf("finding newuidmap: %w", err)
|
||||||
}
|
}
|
||||||
cmd := exec.Command(path, append([]string{pidString}, strings.Fields(strings.Replace(u.String(), "\n", " ", -1))...)...)
|
cmd := exec.Command(path, append([]string{pidString}, strings.Fields(u.String())...)...)
|
||||||
u.Reset()
|
u.Reset()
|
||||||
cmd.Stdout = u
|
cmd.Stdout = u
|
||||||
cmd.Stderr = u
|
cmd.Stderr = u
|
||||||
|
@ -320,7 +328,7 @@ func (c *Cmd) Start() error {
|
||||||
|
|
||||||
logrus.Warnf("Falling back to single mapping")
|
logrus.Warnf("Falling back to single mapping")
|
||||||
u.Reset()
|
u.Reset()
|
||||||
u.Write([]byte(fmt.Sprintf("0 %d 1\n", os.Geteuid())))
|
fmt.Fprintf(u, "0 %d 1\n", os.Geteuid())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !uidmapSet {
|
if !uidmapSet {
|
||||||
|
@ -441,6 +449,16 @@ func GetRootlessUID() int {
|
||||||
return os.Getuid()
|
return os.Getuid()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetRootlessGID returns the GID of the user in the parent userNS
|
||||||
|
func GetRootlessGID() int {
|
||||||
|
gidEnv := getenv("_CONTAINERS_ROOTLESS_GID")
|
||||||
|
if gidEnv != "" {
|
||||||
|
u, _ := strconv.Atoi(gidEnv)
|
||||||
|
return u
|
||||||
|
}
|
||||||
|
return os.Getgid()
|
||||||
|
}
|
||||||
|
|
||||||
// RootlessEnv returns the environment settings for the rootless containers
|
// RootlessEnv returns the environment settings for the rootless containers
|
||||||
func RootlessEnv() []string {
|
func RootlessEnv() []string {
|
||||||
return append(os.Environ(), UsernsEnvName+"=done")
|
return append(os.Environ(), UsernsEnvName+"=done")
|
||||||
|
@ -450,7 +468,7 @@ type Runnable interface {
|
||||||
Run() error
|
Run() error
|
||||||
}
|
}
|
||||||
|
|
||||||
func bailOnError(err error, format string, a ...interface{}) { // nolint: revive,goprintffuncname
|
func bailOnError(err error, format string, a ...any) { //nolint:revive,goprintffuncname
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if format != "" {
|
if format != "" {
|
||||||
logrus.Errorf("%s: %v", fmt.Sprintf(format, a...), err)
|
logrus.Errorf("%s: %v", fmt.Sprintf(format, a...), err)
|
||||||
|
@ -516,8 +534,11 @@ func MaybeReexecUsingUserNamespace(evenForRoot bool) {
|
||||||
} else {
|
} else {
|
||||||
// If we have CAP_SYS_ADMIN, then we don't need to create a new namespace in order to be able
|
// If we have CAP_SYS_ADMIN, then we don't need to create a new namespace in order to be able
|
||||||
// to use unshare(), so don't bother creating a new user namespace at this point.
|
// to use unshare(), so don't bother creating a new user namespace at this point.
|
||||||
capabilities, err := capability.NewPid(0)
|
capabilities, err := capability.NewPid2(0)
|
||||||
|
bailOnError(err, "Initializing a new Capabilities object of pid 0")
|
||||||
|
err = capabilities.Load()
|
||||||
bailOnError(err, "Reading the current capabilities sets")
|
bailOnError(err, "Reading the current capabilities sets")
|
||||||
|
|
||||||
if capabilities.Get(capability.EFFECTIVE, capability.CAP_SYS_ADMIN) {
|
if capabilities.Get(capability.EFFECTIVE, capability.CAP_SYS_ADMIN) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -577,7 +598,12 @@ func MaybeReexecUsingUserNamespace(evenForRoot bool) {
|
||||||
cmd.Hook = func(int) error {
|
cmd.Hook = func(int) error {
|
||||||
go func() {
|
go func() {
|
||||||
for receivedSignal := range interrupted {
|
for receivedSignal := range interrupted {
|
||||||
cmd.Cmd.Process.Signal(receivedSignal)
|
if err := cmd.Cmd.Process.Signal(receivedSignal); err != nil {
|
||||||
|
logrus.Warnf(
|
||||||
|
"Failed to send a signal '%d' to the Process (PID: %d): %v",
|
||||||
|
receivedSignal, cmd.Cmd.Process.Pid, err,
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
//go:build !linux && !darwin
|
//go:build !linux && !darwin
|
||||||
// +build !linux,!darwin
|
|
||||||
|
|
||||||
package unshare
|
package unshare
|
||||||
|
|
||||||
|
@ -17,7 +16,7 @@ const (
|
||||||
|
|
||||||
// IsRootless tells us if we are running in rootless mode
|
// IsRootless tells us if we are running in rootless mode
|
||||||
func IsRootless() bool {
|
func IsRootless() bool {
|
||||||
return false
|
return os.Getuid() != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetRootlessUID returns the UID of the user in the parent userNS
|
// GetRootlessUID returns the UID of the user in the parent userNS
|
||||||
|
@ -25,6 +24,11 @@ func GetRootlessUID() int {
|
||||||
return os.Getuid()
|
return os.Getuid()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetRootlessGID returns the GID of the user in the parent userNS
|
||||||
|
func GetRootlessGID() int {
|
||||||
|
return os.Getgid()
|
||||||
|
}
|
||||||
|
|
||||||
// RootlessEnv returns the environment settings for the rootless containers
|
// RootlessEnv returns the environment settings for the rootless containers
|
||||||
func RootlessEnv() []string {
|
func RootlessEnv() []string {
|
||||||
return append(os.Environ(), UsernsEnvName+"=")
|
return append(os.Environ(), UsernsEnvName+"=")
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
//go:build cgo && !(linux || freebsd)
|
//go:build cgo && !(linux || freebsd)
|
||||||
// +build cgo,!linux,!freebsd
|
|
||||||
|
|
||||||
package unshare
|
package unshare
|
||||||
|
|
||||||
|
|
|
@ -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
|
|
@ -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.
|
||||||
|
|
|
@ -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
|
|
@ -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...)
|
||||||
|
}
|
|
@ -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)
|
return
|
||||||
c = p
|
}
|
||||||
|
switch ver {
|
||||||
|
case linuxCapVer1, linuxCapVer2:
|
||||||
|
retErr = errors.New("old/unsupported capability version (kernel older than 2.6.26?)")
|
||||||
default:
|
default:
|
||||||
err = errUnknownVers
|
// Either linuxCapVer3, or an unknown/future version (such as v4).
|
||||||
return
|
// 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)
|
||||||
|
p.hdr.version = linuxCapVer3
|
||||||
|
p.hdr.pid = int32(pid)
|
||||||
|
c = p
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
type capsV1 struct {
|
func ignoreEINVAL(err error) error {
|
||||||
hdr capHeader
|
if errors.Is(err, syscall.EINVAL) {
|
||||||
data capData
|
err = nil
|
||||||
}
|
}
|
||||||
|
return err
|
||||||
func (c *capsV1) Get(which CapType, what Cap) bool {
|
|
||||||
if what > 32 {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *capsV1) Empty(which CapType) bool {
|
|
||||||
return c.getData(which) == 0
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
|
||||||
if err != nil {
|
|
||||||
// Ignore EINVAL since the capability may not be supported in this system.
|
// Ignore EINVAL since the capability may not be supported in this system.
|
||||||
if errno, ok := err.(syscall.Errno); ok && errno == syscall.EINVAL {
|
err = ignoreEINVAL(dropBound(i))
|
||||||
err = nil
|
if err != nil {
|
||||||
continue
|
return err
|
||||||
}
|
|
||||||
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++ {
|
|
||||||
action := pr_CAP_AMBIENT_LOWER
|
|
||||||
if c.Get(AMBIENT, i) {
|
|
||||||
action = pr_CAP_AMBIENT_RAISE
|
|
||||||
}
|
|
||||||
err := prctl(pr_CAP_AMBIENT, action, uintptr(i), 0, 0)
|
|
||||||
// Ignore EINVAL as not supported on kernels before 4.3
|
// Ignore EINVAL as not supported on kernels before 4.3
|
||||||
if errno, ok := err.(syscall.Errno); ok && errno == syscall.EINVAL {
|
err = ignoreEINVAL(resetAmbient())
|
||||||
err = nil
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for i := Cap(0); i <= last; i++ {
|
||||||
|
if !c.Get(AMBIENT, i) {
|
||||||
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) {
|
|
@ -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
|
||||||
|
}
|
|
@ -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
|
||||||
|
}
|
|
@ -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,
|
|
@ -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
|
||||||
}
|
}
|
|
@ -51,7 +51,7 @@ func mountedByOpenat2(path string) (bool, error) {
|
||||||
Resolve: unix.RESOLVE_NO_XDEV,
|
Resolve: unix.RESOLVE_NO_XDEV,
|
||||||
})
|
})
|
||||||
_ = unix.Close(dirfd)
|
_ = unix.Close(dirfd)
|
||||||
switch err { //nolint:errorlint // unix errors are bare
|
switch err {
|
||||||
case nil: // definitely not a mount
|
case nil: // definitely not a mount
|
||||||
_ = unix.Close(fd)
|
_ = unix.Close(fd)
|
||||||
return false, nil
|
return false, nil
|
||||||
|
|
|
@ -5,15 +5,19 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
|
"runtime"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"golang.org/x/sys/unix"
|
||||||
)
|
)
|
||||||
|
|
||||||
// GetMountsFromReader retrieves a list of mounts from the
|
// GetMountsFromReader retrieves a list of mounts from the
|
||||||
// reader provided, with an optional filter applied (use nil
|
// reader provided, with an optional filter applied (use nil
|
||||||
// for no filter). This can be useful in tests or benchmarks
|
// for no filter). This can be useful in tests or benchmarks
|
||||||
// that provide fake mountinfo data, or when a source other
|
// that provide fake mountinfo data, or when a source other
|
||||||
// than /proc/self/mountinfo needs to be read from.
|
// than /proc/thread-self/mountinfo needs to be read from.
|
||||||
//
|
//
|
||||||
// This function is Linux-specific.
|
// This function is Linux-specific.
|
||||||
func GetMountsFromReader(r io.Reader, filter FilterFunc) ([]*Info, error) {
|
func GetMountsFromReader(r io.Reader, filter FilterFunc) ([]*Info, error) {
|
||||||
|
@ -127,8 +131,40 @@ func GetMountsFromReader(r io.Reader, filter FilterFunc) ([]*Info, error) {
|
||||||
return out, nil
|
return out, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseMountTable(filter FilterFunc) ([]*Info, error) {
|
var (
|
||||||
f, err := os.Open("/proc/self/mountinfo")
|
haveProcThreadSelf bool
|
||||||
|
haveProcThreadSelfOnce sync.Once
|
||||||
|
)
|
||||||
|
|
||||||
|
func parseMountTable(filter FilterFunc) (_ []*Info, err error) {
|
||||||
|
haveProcThreadSelfOnce.Do(func() {
|
||||||
|
_, err := os.Stat("/proc/thread-self/mountinfo")
|
||||||
|
haveProcThreadSelf = err == nil
|
||||||
|
})
|
||||||
|
|
||||||
|
// We need to lock ourselves to the current OS thread in order to make sure
|
||||||
|
// that the thread referenced by /proc/thread-self stays alive until we
|
||||||
|
// finish parsing the file.
|
||||||
|
runtime.LockOSThread()
|
||||||
|
defer runtime.UnlockOSThread()
|
||||||
|
|
||||||
|
var f *os.File
|
||||||
|
if haveProcThreadSelf {
|
||||||
|
f, err = os.Open("/proc/thread-self/mountinfo")
|
||||||
|
} else {
|
||||||
|
// On pre-3.17 kernels (such as CentOS 7), we don't have
|
||||||
|
// /proc/thread-self/ so we need to manually construct
|
||||||
|
// /proc/self/task/<tid>/ as a fallback.
|
||||||
|
f, err = os.Open("/proc/self/task/" + strconv.Itoa(unix.Gettid()) + "/mountinfo")
|
||||||
|
if os.IsNotExist(err) {
|
||||||
|
// If /proc/self/task/... failed, it means that our active pid
|
||||||
|
// namespace doesn't match the pid namespace of the /proc mount. In
|
||||||
|
// this case we just have to make do with /proc/self, since there
|
||||||
|
// is no other way of figuring out our tid in a parent pid
|
||||||
|
// namespace on pre-3.17 kernels.
|
||||||
|
f, err = os.Open("/proc/self/mountinfo")
|
||||||
|
}
|
||||||
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
13
vendor/github.com/opencontainers/runc/LICENSE → vendor/github.com/moby/sys/user/LICENSE
generated
vendored
13
vendor/github.com/opencontainers/runc/LICENSE → vendor/github.com/moby/sys/user/LICENSE
generated
vendored
|
@ -176,7 +176,18 @@
|
||||||
|
|
||||||
END OF TERMS AND CONDITIONS
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
Copyright 2014 Docker, Inc.
|
APPENDIX: How to apply the Apache License to your work.
|
||||||
|
|
||||||
|
To apply the Apache License to your work, attach the following
|
||||||
|
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||||
|
replaced with your own identifying information. (Don't include
|
||||||
|
the brackets!) The text should be enclosed in the appropriate
|
||||||
|
comment syntax for the file format. We also recommend that a
|
||||||
|
file or class name and description of purpose be included on the
|
||||||
|
same "printed page" as the copyright notice for easier
|
||||||
|
identification within third-party archives.
|
||||||
|
|
||||||
|
Copyright [yyyy] [name of copyright owner]
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
|
@ -0,0 +1,141 @@
|
||||||
|
package user
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
// MkdirOpt is a type for options to pass to Mkdir calls
|
||||||
|
type MkdirOpt func(*mkdirOptions)
|
||||||
|
|
||||||
|
type mkdirOptions struct {
|
||||||
|
onlyNew bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithOnlyNew is an option for MkdirAllAndChown that will only change ownership and permissions
|
||||||
|
// on newly created directories. If the directory already exists, it will not be modified
|
||||||
|
func WithOnlyNew(o *mkdirOptions) {
|
||||||
|
o.onlyNew = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// MkdirAllAndChown creates a directory (include any along the path) and then modifies
|
||||||
|
// ownership to the requested uid/gid. By default, if the directory already exists, this
|
||||||
|
// function will still change ownership and permissions. If WithOnlyNew is passed as an
|
||||||
|
// option, then only the newly created directories will have ownership and permissions changed.
|
||||||
|
func MkdirAllAndChown(path string, mode os.FileMode, uid, gid int, opts ...MkdirOpt) error {
|
||||||
|
var options mkdirOptions
|
||||||
|
for _, opt := range opts {
|
||||||
|
opt(&options)
|
||||||
|
}
|
||||||
|
|
||||||
|
return mkdirAs(path, mode, uid, gid, true, options.onlyNew)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MkdirAndChown creates a directory and then modifies ownership to the requested uid/gid.
|
||||||
|
// By default, if the directory already exists, this function still changes ownership and permissions.
|
||||||
|
// If WithOnlyNew is passed as an option, then only the newly created directory will have ownership
|
||||||
|
// and permissions changed.
|
||||||
|
// Note that unlike os.Mkdir(), this function does not return IsExist error
|
||||||
|
// in case path already exists.
|
||||||
|
func MkdirAndChown(path string, mode os.FileMode, uid, gid int, opts ...MkdirOpt) error {
|
||||||
|
var options mkdirOptions
|
||||||
|
for _, opt := range opts {
|
||||||
|
opt(&options)
|
||||||
|
}
|
||||||
|
return mkdirAs(path, mode, uid, gid, false, options.onlyNew)
|
||||||
|
}
|
||||||
|
|
||||||
|
// getRootUIDGID retrieves the remapped root uid/gid pair from the set of maps.
|
||||||
|
// If the maps are empty, then the root uid/gid will default to "real" 0/0
|
||||||
|
func getRootUIDGID(uidMap, gidMap []IDMap) (int, int, error) {
|
||||||
|
uid, err := toHost(0, uidMap)
|
||||||
|
if err != nil {
|
||||||
|
return -1, -1, err
|
||||||
|
}
|
||||||
|
gid, err := toHost(0, gidMap)
|
||||||
|
if err != nil {
|
||||||
|
return -1, -1, err
|
||||||
|
}
|
||||||
|
return uid, gid, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// toContainer takes an id mapping, and uses it to translate a
|
||||||
|
// host ID to the remapped ID. If no map is provided, then the translation
|
||||||
|
// assumes a 1-to-1 mapping and returns the passed in id
|
||||||
|
func toContainer(hostID int, idMap []IDMap) (int, error) {
|
||||||
|
if idMap == nil {
|
||||||
|
return hostID, nil
|
||||||
|
}
|
||||||
|
for _, m := range idMap {
|
||||||
|
if (int64(hostID) >= m.ParentID) && (int64(hostID) <= (m.ParentID + m.Count - 1)) {
|
||||||
|
contID := int(m.ID + (int64(hostID) - m.ParentID))
|
||||||
|
return contID, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1, fmt.Errorf("host ID %d cannot be mapped to a container ID", hostID)
|
||||||
|
}
|
||||||
|
|
||||||
|
// toHost takes an id mapping and a remapped ID, and translates the
|
||||||
|
// ID to the mapped host ID. If no map is provided, then the translation
|
||||||
|
// assumes a 1-to-1 mapping and returns the passed in id #
|
||||||
|
func toHost(contID int, idMap []IDMap) (int, error) {
|
||||||
|
if idMap == nil {
|
||||||
|
return contID, nil
|
||||||
|
}
|
||||||
|
for _, m := range idMap {
|
||||||
|
if (int64(contID) >= m.ID) && (int64(contID) <= (m.ID + m.Count - 1)) {
|
||||||
|
hostID := int(m.ParentID + (int64(contID) - m.ID))
|
||||||
|
return hostID, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1, fmt.Errorf("container ID %d cannot be mapped to a host ID", contID)
|
||||||
|
}
|
||||||
|
|
||||||
|
// IdentityMapping contains a mappings of UIDs and GIDs.
|
||||||
|
// The zero value represents an empty mapping.
|
||||||
|
type IdentityMapping struct {
|
||||||
|
UIDMaps []IDMap `json:"UIDMaps"`
|
||||||
|
GIDMaps []IDMap `json:"GIDMaps"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// RootPair returns a uid and gid pair for the root user. The error is ignored
|
||||||
|
// because a root user always exists, and the defaults are correct when the uid
|
||||||
|
// and gid maps are empty.
|
||||||
|
func (i IdentityMapping) RootPair() (int, int) {
|
||||||
|
uid, gid, _ := getRootUIDGID(i.UIDMaps, i.GIDMaps)
|
||||||
|
return uid, gid
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToHost returns the host UID and GID for the container uid, gid.
|
||||||
|
// Remapping is only performed if the ids aren't already the remapped root ids
|
||||||
|
func (i IdentityMapping) ToHost(uid, gid int) (int, int, error) {
|
||||||
|
var err error
|
||||||
|
ruid, rgid := i.RootPair()
|
||||||
|
|
||||||
|
if uid != ruid {
|
||||||
|
ruid, err = toHost(uid, i.UIDMaps)
|
||||||
|
if err != nil {
|
||||||
|
return ruid, rgid, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if gid != rgid {
|
||||||
|
rgid, err = toHost(gid, i.GIDMaps)
|
||||||
|
}
|
||||||
|
return ruid, rgid, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToContainer returns the container UID and GID for the host uid and gid
|
||||||
|
func (i IdentityMapping) ToContainer(uid, gid int) (int, int, error) {
|
||||||
|
ruid, err := toContainer(uid, i.UIDMaps)
|
||||||
|
if err != nil {
|
||||||
|
return -1, -1, err
|
||||||
|
}
|
||||||
|
rgid, err := toContainer(gid, i.GIDMaps)
|
||||||
|
return ruid, rgid, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Empty returns true if there are no id mappings
|
||||||
|
func (i IdentityMapping) Empty() bool {
|
||||||
|
return len(i.UIDMaps) == 0 && len(i.GIDMaps) == 0
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue