mirror of
https://github.com/optim-enterprises-bv/kubernetes.git
synced 2025-10-30 17:58:14 +00:00
Merge pull request #128346 from dims/update-to-latest-advisor-for-1.32
Update to latest cadvisor - `v0.51.0`
This commit is contained in:
205
LICENSES/vendor/github.com/checkpoint-restore/go-criu/v5/LICENSE
generated
vendored
205
LICENSES/vendor/github.com/checkpoint-restore/go-criu/v5/LICENSE
generated
vendored
@@ -1,205 +0,0 @@
|
||||
= vendor/github.com/checkpoint-restore/go-criu/v5 licensed under: =
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
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");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
= vendor/github.com/checkpoint-restore/go-criu/v5/LICENSE e3fc50a88d0a364313df4b21ef20c29e
|
||||
195
LICENSES/vendor/github.com/containerd/console/LICENSE
generated
vendored
195
LICENSES/vendor/github.com/containerd/console/LICENSE
generated
vendored
@@ -1,195 +0,0 @@
|
||||
= vendor/github.com/containerd/console licensed under: =
|
||||
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
https://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
Copyright The containerd Authors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
https://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
= vendor/github.com/containerd/console/LICENSE 1269f40c0d099c21a871163984590d89
|
||||
26
LICENSES/vendor/github.com/seccomp/libseccomp-golang/LICENSE
generated
vendored
26
LICENSES/vendor/github.com/seccomp/libseccomp-golang/LICENSE
generated
vendored
@@ -1,26 +0,0 @@
|
||||
= vendor/github.com/seccomp/libseccomp-golang licensed under: =
|
||||
|
||||
Copyright (c) 2015 Matthew Heon <mheon@redhat.com>
|
||||
Copyright (c) 2015 Paul Moore <pmoore@redhat.com>
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
- Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
- Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
= vendor/github.com/seccomp/libseccomp-golang/LICENSE 343b433e752e8b44a543cdf61f14b628
|
||||
28
LICENSES/vendor/github.com/syndtr/gocapability/LICENSE
generated
vendored
28
LICENSES/vendor/github.com/syndtr/gocapability/LICENSE
generated
vendored
@@ -1,28 +0,0 @@
|
||||
= vendor/github.com/syndtr/gocapability licensed under: =
|
||||
|
||||
Copyright 2013 Suryandaru Triandana <syndtr@gmail.com>
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
= vendor/github.com/syndtr/gocapability/LICENSE a7304f5073e7be4ba7bffabbf9f2bbca
|
||||
5
go.mod
5
go.mod
@@ -34,7 +34,7 @@ require (
|
||||
github.com/gogo/protobuf v1.3.2
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da
|
||||
github.com/golang/protobuf v1.5.4
|
||||
github.com/google/cadvisor v0.50.0
|
||||
github.com/google/cadvisor v0.51.0
|
||||
github.com/google/cel-go v0.21.0
|
||||
github.com/google/gnostic-models v0.6.8
|
||||
github.com/google/go-cmp v0.6.0
|
||||
@@ -134,9 +134,7 @@ require (
|
||||
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||
github.com/chai2010/gettext-go v1.0.2 // indirect
|
||||
github.com/checkpoint-restore/go-criu/v5 v5.3.0 // indirect
|
||||
github.com/cilium/ebpf v0.11.0 // indirect
|
||||
github.com/containerd/console v1.0.4 // indirect
|
||||
github.com/containerd/containerd/api v1.7.19 // indirect
|
||||
github.com/containerd/errdefs v0.1.0 // indirect
|
||||
github.com/containerd/log v0.1.0 // indirect
|
||||
@@ -196,7 +194,6 @@ require (
|
||||
github.com/soheilhy/cmux v0.1.5 // indirect
|
||||
github.com/stoewer/go-strcase v1.3.0 // indirect
|
||||
github.com/stretchr/objx v0.5.2 // indirect
|
||||
github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635 // indirect
|
||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20220101234140-673ab2c3ae75 // indirect
|
||||
github.com/x448/float16 v0.8.4 // indirect
|
||||
github.com/xiang90/probing v0.0.0-20221125231312-a49e3df8f510 // indirect
|
||||
|
||||
15
go.sum
15
go.sum
@@ -169,7 +169,6 @@ github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UF
|
||||
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/chai2010/gettext-go v1.0.2 h1:1Lwwip6Q2QGsAdl/ZKPCwTe9fe0CjlUbqj5bFNSjIRk=
|
||||
github.com/chai2010/gettext-go v1.0.2/go.mod h1:y+wnP2cHYaVj19NZhYKAwEMH2CI1gNHeQQ+5AjwawxA=
|
||||
github.com/checkpoint-restore/go-criu/v5 v5.3.0 h1:wpFFOoomK3389ue2lAb0Boag6XPht5QYpipxmSNL4d8=
|
||||
github.com/checkpoint-restore/go-criu/v5 v5.3.0/go.mod h1:E/eQpaFtUKGOOSEBZgmKAcn+zUUwWxqcaKZlF54wK8E=
|
||||
github.com/chzyer/readline v1.5.1/go.mod h1:Eh+b79XXUwfKfcPLepksvw2tcLE/Ct21YObkaSkeBlk=
|
||||
github.com/cilium/ebpf v0.11.0 h1:V8gS/bTCCjX9uUnkUFUpPsksM8n1lXBAvHcpiFk1X2Y=
|
||||
@@ -183,8 +182,7 @@ github.com/container-storage-interface/spec v1.9.0 h1:zKtX4STsq31Knz3gciCYCi1SXt
|
||||
github.com/container-storage-interface/spec v1.9.0/go.mod h1:ZfDu+3ZRyeVqxZM0Ds19MVLkN2d1XJ5MAfi1L3VjlT0=
|
||||
github.com/containerd/cgroups v1.1.0 h1:v8rEWFl6EoqHB+swVNjVoCJE8o3jX7e8nqBGPLaDFBM=
|
||||
github.com/containerd/cgroups v1.1.0/go.mod h1:6ppBcbh/NOOUU+dMKrykgaBnK9lCIBxHqJDGwsa1mIw=
|
||||
github.com/containerd/console v1.0.4 h1:F2g4+oChYvBTsASRTz8NP6iIAi97J3TtSAsLbIFn4ro=
|
||||
github.com/containerd/console v1.0.4/go.mod h1:YynlIjWYF8myEu6sdkwKIvGQq+cOckRm6So2avqoYAk=
|
||||
github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U=
|
||||
github.com/containerd/containerd/api v1.7.19 h1:VWbJL+8Ap4Ju2mx9c9qS1uFSB1OVYr5JJrW2yT5vFoA=
|
||||
github.com/containerd/containerd/api v1.7.19/go.mod h1:fwGavl3LNwAV5ilJ0sbrABL44AQxmNjDRcwheXDb6Ig=
|
||||
github.com/containerd/errdefs v0.1.0 h1:m0wCRBiu1WJT/Fr+iOoQHMQS/eP5myQ8lCv4Dz5ZURM=
|
||||
@@ -299,7 +297,6 @@ github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:W
|
||||
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
||||
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
|
||||
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
|
||||
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
|
||||
github.com/golangplus/bytes v0.0.0-20160111154220-45c989fe5450/go.mod h1:Bk6SMAONeMXrxql8uvOKuAZSu8aM5RUGv+1C6IJaEho=
|
||||
@@ -309,8 +306,8 @@ github.com/golangplus/testing v1.0.0 h1:+ZeeiKZENNOMkTTELoSySazi+XaEhVO0mb+eanrS
|
||||
github.com/golangplus/testing v1.0.0/go.mod h1:ZDreixUV3YzhoVraIDyOzHrr76p6NUh6k/pPg/Q3gYA=
|
||||
github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4=
|
||||
github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA=
|
||||
github.com/google/cadvisor v0.50.0 h1:7w/hKIbJKBWqQsRTy+Hpj2vj+fnxrLXcEXFy+LW0Bsg=
|
||||
github.com/google/cadvisor v0.50.0/go.mod h1:VxCDwZalpFyENvmfabFqaIGsqNKLtDzE62a19rfVTB8=
|
||||
github.com/google/cadvisor v0.51.0 h1:BspqSPdZoLKrnvuZNOvM/KiJ/A+RdixwagN20n+2H8k=
|
||||
github.com/google/cadvisor v0.51.0/go.mod h1:czGE/c/P/i0QFpVNKTFrIEzord9Y10YfpwuaSWXELc0=
|
||||
github.com/google/cel-go v0.21.0 h1:cl6uW/gxN+Hy50tNYvI691+sXxioCnstFzLp2WO4GCI=
|
||||
github.com/google/cel-go v0.21.0/go.mod h1:rHUlWCcBKgyEk+eV03RPdZUekPp6YcJwV0FxuUksYxc=
|
||||
github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I=
|
||||
@@ -321,7 +318,6 @@ github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw
|
||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
@@ -492,7 +488,6 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO
|
||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/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/tmc/grpc-websocket-proxy v0.0.0-20220101234140-673ab2c3ae75 h1:6fotK7otjonDflCTK0BCfls4SPy3NcCVb5dqqmbRknE=
|
||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20220101234140-673ab2c3ae75/go.mod h1:KO6IkyS8Y3j8OdNO85qEYBsRPuteD+YciPomcXdrMnk=
|
||||
@@ -614,12 +609,10 @@ golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo=
|
||||
@@ -681,8 +674,6 @@ google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2
|
||||
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
|
||||
google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
|
||||
@@ -134,10 +134,12 @@ github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.2 h1:ORnrOK0C4WmYV/uYt3koHEWB
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.30.1 h1:+woJ607dllHJQtsnJLi52ycuqHMwlW+Wqm2Ppsfp4nQ=
|
||||
github.com/aws/smithy-go v1.20.3 h1:ryHwveWzPV5BIof6fyDvor6V3iUL7nTfiTKXHiW05nE=
|
||||
github.com/census-instrumentation/opencensus-proto v0.4.1 h1:iKLQ0xPNFxR/2hzXZMrBo8f1j86j5WHzznCCQxV/b8g=
|
||||
github.com/checkpoint-restore/go-criu/v5 v5.3.0 h1:wpFFOoomK3389ue2lAb0Boag6XPht5QYpipxmSNL4d8=
|
||||
github.com/chzyer/readline v1.5.1 h1:upd/6fQk4src78LMRzh5vItIt361/o4uq553V8B5sGI=
|
||||
github.com/client9/misspell v0.3.4 h1:ta993UF76GwbvJcIo3Y68y/M3WxlpEHPWIGDkJYwzJI=
|
||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f h1:WBZRG4aNOuI15bLRrCgN8fCq8E5Xuty6jGbmSNEvSsU=
|
||||
github.com/cncf/xds/go v0.0.0-20240423153145-555b57ec207b h1:ga8SEFjZ60pxLcmhnThWgvH2wg8376yUJmPhEH4H3kw=
|
||||
github.com/containerd/console v1.0.3 h1:lIr7SlA5PxZyMV30bDW0MGbiOPXwc63yRuCP0ARubLw=
|
||||
github.com/envoyproxy/go-control-plane v0.12.0 h1:4X+VP1GHd1Mhj6IB5mMeGbLCleqxjletLK6K0rbxyZI=
|
||||
github.com/envoyproxy/protoc-gen-validate v1.0.4 h1:gVPz/FMfvh57HdSJQyvBtF00j8JU4zdyUgIUNhlgg0A=
|
||||
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568 h1:BHsljHzVlRcyQhjrss6TZTdY2VfCqZPbv5k3iBFa2ZQ=
|
||||
@@ -165,6 +167,7 @@ github.com/opentracing/opentracing-go v1.1.0 h1:pWlfV3Bxv7k65HYwkikxat0+s3pV4bsq
|
||||
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e h1:aoZm08cpOy4WuID//EZDgcC4zIxODThtZNPirFr42+A=
|
||||
github.com/rogpeppe/fastuuid v1.2.0 h1:Ppwyp6VYCF1nvBTXL3trRso7mXMlRrw9ooo375wvi2s=
|
||||
github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=
|
||||
github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635 h1:kdXcSzyDtseVEc4yCz2qF8ZrQvIDBJLl4S1c3GCXmoI=
|
||||
github.com/urfave/cli v1.22.1 h1:+mkCCcOFKPnCmVYVcURKps1Xe+3zP90gSYGNfRkjoIY=
|
||||
github.com/xhit/go-str2duration/v2 v2.1.0 h1:lxklc02Drh6ynqX+DdPyp5pCKLUQpRT8bp8Ydu2Bstc=
|
||||
github.com/yuin/goldmark v1.4.13 h1:fVcFKWvrslecOb/tg+Cc05dkeYx540o0FuFt3nUVDoE=
|
||||
|
||||
6
vendor/github.com/checkpoint-restore/go-criu/v5/.gitignore
generated
vendored
6
vendor/github.com/checkpoint-restore/go-criu/v5/.gitignore
generated
vendored
@@ -1,6 +0,0 @@
|
||||
test/test
|
||||
test/test.coverage
|
||||
test/piggie/piggie
|
||||
test/phaul/phaul
|
||||
test/phaul/phaul.coverage
|
||||
image
|
||||
12
vendor/github.com/checkpoint-restore/go-criu/v5/.golangci.yml
generated
vendored
12
vendor/github.com/checkpoint-restore/go-criu/v5/.golangci.yml
generated
vendored
@@ -1,12 +0,0 @@
|
||||
run:
|
||||
skip_dirs:
|
||||
- rpc
|
||||
- stats
|
||||
|
||||
linters:
|
||||
disable-all: false
|
||||
presets:
|
||||
- bugs
|
||||
- performance
|
||||
- unused
|
||||
- format
|
||||
201
vendor/github.com/checkpoint-restore/go-criu/v5/LICENSE
generated
vendored
201
vendor/github.com/checkpoint-restore/go-criu/v5/LICENSE
generated
vendored
@@ -1,201 +0,0 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
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");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
107
vendor/github.com/checkpoint-restore/go-criu/v5/Makefile
generated
vendored
107
vendor/github.com/checkpoint-restore/go-criu/v5/Makefile
generated
vendored
@@ -1,107 +0,0 @@
|
||||
SHELL = /bin/bash
|
||||
GO ?= go
|
||||
CC ?= gcc
|
||||
COVERAGE_PATH ?= $(shell pwd)/.coverage
|
||||
CRIU_FEATURE_MEM_TRACK = $(shell if criu check --feature mem_dirty_track > /dev/null; then echo 1; else echo 0; fi)
|
||||
CRIU_FEATURE_LAZY_PAGES = $(shell if criu check --feature uffd-noncoop > /dev/null; then echo 1; else echo 0; fi)
|
||||
CRIU_FEATURE_PIDFD_STORE = $(shell if criu check --feature pidfd_store > /dev/null; then echo 1; else echo 0; fi)
|
||||
|
||||
export CRIU_FEATURE_MEM_TRACK CRIU_FEATURE_LAZY_PAGES CRIU_FEATURE_PIDFD_STORE
|
||||
|
||||
all: build test phaul-test
|
||||
|
||||
lint:
|
||||
golangci-lint run ./...
|
||||
|
||||
build:
|
||||
$(GO) build -v ./...
|
||||
|
||||
TEST_PAYLOAD := test/piggie/piggie
|
||||
TEST_BINARIES := test/test $(TEST_PAYLOAD) test/phaul/phaul
|
||||
COVERAGE_BINARIES := test/test.coverage test/phaul/phaul.coverage
|
||||
test-bin: $(TEST_BINARIES)
|
||||
|
||||
test/piggie/piggie: test/piggie/piggie.c
|
||||
$(CC) $^ -o $@
|
||||
|
||||
test/test: test/main.go
|
||||
$(GO) build -v -o $@ $^
|
||||
|
||||
test: $(TEST_BINARIES)
|
||||
mkdir -p image
|
||||
PID=$$(test/piggie/piggie) && { \
|
||||
test/test dump $$PID image && \
|
||||
test/test restore image; \
|
||||
pkill -9 piggie; \
|
||||
}
|
||||
rm -rf image
|
||||
|
||||
test/phaul/phaul: test/phaul/main.go
|
||||
$(GO) build -v -o $@ $^
|
||||
|
||||
phaul-test: $(TEST_BINARIES)
|
||||
rm -rf image
|
||||
PID=$$(test/piggie/piggie) && { \
|
||||
test/phaul/phaul $$PID; \
|
||||
pkill -9 piggie; \
|
||||
}
|
||||
|
||||
test/test.coverage: test/*.go
|
||||
$(GO) test \
|
||||
-covermode=count \
|
||||
-coverpkg=./... \
|
||||
-mod=vendor \
|
||||
-tags coverage \
|
||||
-buildmode=pie -c -o $@ $^
|
||||
|
||||
test/phaul/phaul.coverage: test/phaul/*.go
|
||||
$(GO) test \
|
||||
-covermode=count \
|
||||
-coverpkg=./... \
|
||||
-mod=vendor \
|
||||
-tags coverage \
|
||||
-buildmode=pie -c -o $@ $^
|
||||
|
||||
coverage: $(COVERAGE_BINARIES) $(TEST_PAYLOAD)
|
||||
mkdir -p $(COVERAGE_PATH)
|
||||
mkdir -p image
|
||||
PID=$$(test/piggie/piggie) && { \
|
||||
test/test.coverage -test.coverprofile=coverprofile.integration.$$RANDOM -test.outputdir=${COVERAGE_PATH} COVERAGE dump $$PID image && \
|
||||
test/test.coverage -test.coverprofile=coverprofile.integration.$$RANDOM -test.outputdir=${COVERAGE_PATH} COVERAGE restore image; \
|
||||
pkill -9 piggie; \
|
||||
}
|
||||
rm -rf image
|
||||
PID=$$(test/piggie/piggie) && { \
|
||||
test/phaul/phaul.coverage -test.coverprofile=coverprofile.integration.$$RANDOM -test.outputdir=${COVERAGE_PATH} COVERAGE $$PID; \
|
||||
pkill -9 piggie; \
|
||||
}
|
||||
echo "mode: set" > .coverage/coverage.out && cat .coverage/coverprofile* | \
|
||||
grep -v mode: | sort -r | awk '{if($$1 != last) {print $$0;last=$$1}}' >> .coverage/coverage.out
|
||||
|
||||
clean:
|
||||
@rm -f $(TEST_BINARIES) $(COVERAGE_BINARIES) codecov
|
||||
@rm -rf image $(COVERAGE_PATH)
|
||||
|
||||
rpc/rpc.proto:
|
||||
curl -sSL https://raw.githubusercontent.com/checkpoint-restore/criu/master/images/rpc.proto -o $@
|
||||
|
||||
stats/stats.proto:
|
||||
curl -sSL https://raw.githubusercontent.com/checkpoint-restore/criu/master/images/stats.proto -o $@
|
||||
|
||||
rpc/rpc.pb.go: rpc/rpc.proto
|
||||
protoc --go_out=. --go_opt=M$^=rpc/ $^
|
||||
|
||||
stats/stats.pb.go: stats/stats.proto
|
||||
protoc --go_out=. --go_opt=M$^=stats/ $^
|
||||
|
||||
vendor:
|
||||
GO111MODULE=on $(GO) mod tidy
|
||||
GO111MODULE=on $(GO) mod vendor
|
||||
GO111MODULE=on $(GO) mod verify
|
||||
|
||||
codecov:
|
||||
curl -Os https://uploader.codecov.io/latest/linux/codecov
|
||||
chmod +x codecov
|
||||
./codecov -f '.coverage/coverage.out'
|
||||
|
||||
.PHONY: build test phaul-test test-bin clean lint vendor coverage codecov
|
||||
96
vendor/github.com/checkpoint-restore/go-criu/v5/README.md
generated
vendored
96
vendor/github.com/checkpoint-restore/go-criu/v5/README.md
generated
vendored
@@ -1,96 +0,0 @@
|
||||
[](https://github.com/checkpoint-restore/go-criu/actions?query=workflow%3Aci)
|
||||
[](https://github.com/checkpoint-restore/go-criu/actions?query=workflow%3Averify)
|
||||
[](https://pkg.go.dev/github.com/checkpoint-restore/go-criu)
|
||||
|
||||
## go-criu -- Go bindings for CRIU
|
||||
|
||||
This repository provides Go bindings for [CRIU](https://criu.org/). The code is based on the Go-based PHaul
|
||||
implementation from the CRIU repository. For easier inclusion into other Go projects the
|
||||
CRIU Go bindings have been moved to this repository.
|
||||
|
||||
The Go bindings provide an easy way to use the CRIU RPC calls from Go without the need
|
||||
to set up all the infrastructure to make the actual RPC connection to CRIU.
|
||||
|
||||
The following example would print the version of CRIU:
|
||||
```go
|
||||
import (
|
||||
"log"
|
||||
|
||||
"github.com/checkpoint-restore/go-criu/v5"
|
||||
)
|
||||
|
||||
func main() {
|
||||
c := criu.MakeCriu()
|
||||
version, err := c.GetCriuVersion()
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
log.Println(version)
|
||||
}
|
||||
```
|
||||
|
||||
or to just check if at least a certain CRIU version is installed:
|
||||
|
||||
```go
|
||||
c := criu.MakeCriu()
|
||||
result, err := c.IsCriuAtLeast(31100)
|
||||
```
|
||||
|
||||
## Releases
|
||||
|
||||
The first go-criu release was 3.11 based on CRIU 3.11. The initial plan
|
||||
was to follow CRIU so that go-criu would carry the same version number as
|
||||
CRIU.
|
||||
|
||||
As go-criu is imported in other projects and as Go modules are expected
|
||||
to follow Semantic Versioning go-criu will also follow Semantic Versioning
|
||||
starting with the 4.0.0 release.
|
||||
|
||||
The following table shows the relation between go-criu and criu versions:
|
||||
|
||||
| Major version | Latest release | CRIU version |
|
||||
| -------------- | -------------- | ------------ |
|
||||
| v5 | 5.2.0 | 3.16 |
|
||||
| v5 | 5.0.0 | 3.15 |
|
||||
| v4 | 4.1.0 | 3.14 |
|
||||
|
||||
## How to contribute
|
||||
|
||||
While bug fixes can first be identified via an "issue", that is not required.
|
||||
It's ok to just open up a PR with the fix, but make sure you include the same
|
||||
information you would have included in an issue - like how to reproduce it.
|
||||
|
||||
PRs for new features should include some background on what use cases the
|
||||
new code is trying to address. When possible and when it makes sense, try to
|
||||
break-up larger PRs into smaller ones - it's easier to review smaller
|
||||
code changes. But only if those smaller ones make sense as stand-alone PRs.
|
||||
|
||||
Regardless of the type of PR, all PRs should include:
|
||||
* well documented code changes
|
||||
* additional testcases. Ideally, they should fail w/o your code change applied
|
||||
* documentation changes
|
||||
|
||||
Squash your commits into logical pieces of work that might want to be reviewed
|
||||
separate from the rest of the PRs. Ideally, each commit should implement a
|
||||
single idea, and the PR branch should pass the tests at every commit. GitHub
|
||||
makes it easy to review the cumulative effect of many commits; so, when in
|
||||
doubt, use smaller commits.
|
||||
|
||||
PRs that fix issues should include a reference like `Closes #XXXX` in the
|
||||
commit message so that github will automatically close the referenced issue
|
||||
when the PR is merged.
|
||||
|
||||
Contributors must assert that they are in compliance with the [Developer
|
||||
Certificate of Origin 1.1](http://developercertificate.org/). This is achieved
|
||||
by adding a "Signed-off-by" line containing the contributor's name and e-mail
|
||||
to every commit message. Your signature certifies that you wrote the patch or
|
||||
otherwise have the right to pass it on as an open-source patch.
|
||||
|
||||
### License and copyright
|
||||
|
||||
Unless mentioned otherwise in a specific file's header, all code in
|
||||
this project is released under the Apache 2.0 license.
|
||||
|
||||
The author of a change remains the copyright holder of their code
|
||||
(no copyright assignment). The list of authors and contributors can be
|
||||
retrieved from the git commit history and in some cases, the file headers.
|
||||
45
vendor/github.com/checkpoint-restore/go-criu/v5/features.go
generated
vendored
45
vendor/github.com/checkpoint-restore/go-criu/v5/features.go
generated
vendored
@@ -1,45 +0,0 @@
|
||||
package criu
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/checkpoint-restore/go-criu/v5/rpc"
|
||||
)
|
||||
|
||||
// Feature checking in go-criu is based on the libcriu feature checking function.
|
||||
|
||||
// Feature checking allows the user to check if CRIU supports
|
||||
// certain features. There are CRIU features which do not depend
|
||||
// on the version of CRIU but on kernel features or architecture.
|
||||
//
|
||||
// One example is memory tracking. Memory tracking can be disabled
|
||||
// in the kernel or there are architectures which do not support
|
||||
// it (aarch64 for example). By using the feature check a libcriu
|
||||
// user can easily query CRIU if a certain feature is available.
|
||||
//
|
||||
// The features which should be checked can be marked in the
|
||||
// structure 'struct criu_feature_check'. Each structure member
|
||||
// that is set to true will result in CRIU checking for the
|
||||
// availability of that feature in the current combination of
|
||||
// CRIU/kernel/architecture.
|
||||
//
|
||||
// Available features will be set to true when the function
|
||||
// returns successfully. Missing features will be set to false.
|
||||
|
||||
func (c *Criu) FeatureCheck(features *rpc.CriuFeatures) (*rpc.CriuFeatures, error) {
|
||||
resp, err := c.doSwrkWithResp(
|
||||
rpc.CriuReqType_FEATURE_CHECK,
|
||||
nil,
|
||||
nil,
|
||||
features,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if resp.GetType() != rpc.CriuReqType_FEATURE_CHECK {
|
||||
return nil, fmt.Errorf("Unexpected CRIU RPC response")
|
||||
}
|
||||
|
||||
return features, nil
|
||||
}
|
||||
264
vendor/github.com/checkpoint-restore/go-criu/v5/main.go
generated
vendored
264
vendor/github.com/checkpoint-restore/go-criu/v5/main.go
generated
vendored
@@ -1,264 +0,0 @@
|
||||
package criu
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strconv"
|
||||
"syscall"
|
||||
|
||||
"github.com/checkpoint-restore/go-criu/v5/rpc"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
// Criu struct
|
||||
type Criu struct {
|
||||
swrkCmd *exec.Cmd
|
||||
swrkSk *os.File
|
||||
swrkPath string
|
||||
}
|
||||
|
||||
// MakeCriu returns the Criu object required for most operations
|
||||
func MakeCriu() *Criu {
|
||||
return &Criu{
|
||||
swrkPath: "criu",
|
||||
}
|
||||
}
|
||||
|
||||
// SetCriuPath allows setting the path to the CRIU binary
|
||||
// if it is in a non standard location
|
||||
func (c *Criu) SetCriuPath(path string) {
|
||||
c.swrkPath = path
|
||||
}
|
||||
|
||||
// Prepare sets up everything for the RPC communication to CRIU
|
||||
func (c *Criu) Prepare() error {
|
||||
fds, err := syscall.Socketpair(syscall.AF_LOCAL, syscall.SOCK_SEQPACKET, 0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cln := os.NewFile(uintptr(fds[0]), "criu-xprt-cln")
|
||||
syscall.CloseOnExec(fds[0])
|
||||
srv := os.NewFile(uintptr(fds[1]), "criu-xprt-srv")
|
||||
defer srv.Close()
|
||||
|
||||
args := []string{"swrk", strconv.Itoa(fds[1])}
|
||||
// #nosec G204
|
||||
cmd := exec.Command(c.swrkPath, args...)
|
||||
|
||||
err = cmd.Start()
|
||||
if err != nil {
|
||||
cln.Close()
|
||||
return err
|
||||
}
|
||||
|
||||
c.swrkCmd = cmd
|
||||
c.swrkSk = cln
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Cleanup cleans up
|
||||
func (c *Criu) Cleanup() {
|
||||
if c.swrkCmd != nil {
|
||||
c.swrkSk.Close()
|
||||
c.swrkSk = nil
|
||||
_ = c.swrkCmd.Wait()
|
||||
c.swrkCmd = nil
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Criu) sendAndRecv(reqB []byte) ([]byte, int, error) {
|
||||
cln := c.swrkSk
|
||||
_, err := cln.Write(reqB)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
respB := make([]byte, 2*4096)
|
||||
n, err := cln.Read(respB)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
return respB, n, nil
|
||||
}
|
||||
|
||||
func (c *Criu) doSwrk(reqType rpc.CriuReqType, opts *rpc.CriuOpts, nfy Notify) error {
|
||||
resp, err := c.doSwrkWithResp(reqType, opts, nfy, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
respType := resp.GetType()
|
||||
if respType != reqType {
|
||||
return errors.New("unexpected CRIU RPC response")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Criu) doSwrkWithResp(reqType rpc.CriuReqType, opts *rpc.CriuOpts, nfy Notify, features *rpc.CriuFeatures) (*rpc.CriuResp, error) {
|
||||
var resp *rpc.CriuResp
|
||||
|
||||
req := rpc.CriuReq{
|
||||
Type: &reqType,
|
||||
Opts: opts,
|
||||
}
|
||||
|
||||
if nfy != nil {
|
||||
opts.NotifyScripts = proto.Bool(true)
|
||||
}
|
||||
|
||||
if features != nil {
|
||||
req.Features = features
|
||||
}
|
||||
|
||||
if c.swrkCmd == nil {
|
||||
err := c.Prepare()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
defer c.Cleanup()
|
||||
}
|
||||
|
||||
for {
|
||||
reqB, err := proto.Marshal(&req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
respB, respS, err := c.sendAndRecv(reqB)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
resp = &rpc.CriuResp{}
|
||||
err = proto.Unmarshal(respB[:respS], resp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !resp.GetSuccess() {
|
||||
return resp, fmt.Errorf("operation failed (msg:%s err:%d)",
|
||||
resp.GetCrErrmsg(), resp.GetCrErrno())
|
||||
}
|
||||
|
||||
respType := resp.GetType()
|
||||
if respType != rpc.CriuReqType_NOTIFY {
|
||||
break
|
||||
}
|
||||
if nfy == nil {
|
||||
return resp, errors.New("unexpected notify")
|
||||
}
|
||||
|
||||
notify := resp.GetNotify()
|
||||
switch notify.GetScript() {
|
||||
case "pre-dump":
|
||||
err = nfy.PreDump()
|
||||
case "post-dump":
|
||||
err = nfy.PostDump()
|
||||
case "pre-restore":
|
||||
err = nfy.PreRestore()
|
||||
case "post-restore":
|
||||
err = nfy.PostRestore(notify.GetPid())
|
||||
case "network-lock":
|
||||
err = nfy.NetworkLock()
|
||||
case "network-unlock":
|
||||
err = nfy.NetworkUnlock()
|
||||
case "setup-namespaces":
|
||||
err = nfy.SetupNamespaces(notify.GetPid())
|
||||
case "post-setup-namespaces":
|
||||
err = nfy.PostSetupNamespaces()
|
||||
case "post-resume":
|
||||
err = nfy.PostResume()
|
||||
default:
|
||||
err = nil
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return resp, err
|
||||
}
|
||||
|
||||
req = rpc.CriuReq{
|
||||
Type: &respType,
|
||||
NotifySuccess: proto.Bool(true),
|
||||
}
|
||||
}
|
||||
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// Dump dumps a process
|
||||
func (c *Criu) Dump(opts *rpc.CriuOpts, nfy Notify) error {
|
||||
return c.doSwrk(rpc.CriuReqType_DUMP, opts, nfy)
|
||||
}
|
||||
|
||||
// Restore restores a process
|
||||
func (c *Criu) Restore(opts *rpc.CriuOpts, nfy Notify) error {
|
||||
return c.doSwrk(rpc.CriuReqType_RESTORE, opts, nfy)
|
||||
}
|
||||
|
||||
// PreDump does a pre-dump
|
||||
func (c *Criu) PreDump(opts *rpc.CriuOpts, nfy Notify) error {
|
||||
return c.doSwrk(rpc.CriuReqType_PRE_DUMP, opts, nfy)
|
||||
}
|
||||
|
||||
// StartPageServer starts the page server
|
||||
func (c *Criu) StartPageServer(opts *rpc.CriuOpts) error {
|
||||
return c.doSwrk(rpc.CriuReqType_PAGE_SERVER, opts, nil)
|
||||
}
|
||||
|
||||
// StartPageServerChld starts the page server and returns PID and port
|
||||
func (c *Criu) StartPageServerChld(opts *rpc.CriuOpts) (int, int, error) {
|
||||
resp, err := c.doSwrkWithResp(rpc.CriuReqType_PAGE_SERVER_CHLD, opts, nil, nil)
|
||||
if err != nil {
|
||||
return 0, 0, err
|
||||
}
|
||||
|
||||
return int(resp.Ps.GetPid()), int(resp.Ps.GetPort()), nil
|
||||
}
|
||||
|
||||
// GetCriuVersion executes the VERSION RPC call and returns the version
|
||||
// as an integer. Major * 10000 + Minor * 100 + SubLevel
|
||||
func (c *Criu) GetCriuVersion() (int, error) {
|
||||
resp, err := c.doSwrkWithResp(rpc.CriuReqType_VERSION, nil, nil, nil)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
if resp.GetType() != rpc.CriuReqType_VERSION {
|
||||
return 0, fmt.Errorf("Unexpected CRIU RPC response")
|
||||
}
|
||||
|
||||
version := int(*resp.GetVersion().MajorNumber) * 10000
|
||||
version += int(*resp.GetVersion().MinorNumber) * 100
|
||||
if resp.GetVersion().Sublevel != nil {
|
||||
version += int(*resp.GetVersion().Sublevel)
|
||||
}
|
||||
|
||||
if resp.GetVersion().Gitid != nil {
|
||||
// taken from runc: if it is a git release -> increase minor by 1
|
||||
version -= (version % 100)
|
||||
version += 100
|
||||
}
|
||||
|
||||
return version, nil
|
||||
}
|
||||
|
||||
// IsCriuAtLeast checks if the version is at least the same
|
||||
// as the parameter version
|
||||
func (c *Criu) IsCriuAtLeast(version int) (bool, error) {
|
||||
criuVersion, err := c.GetCriuVersion()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
if criuVersion >= version {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
return false, nil
|
||||
}
|
||||
62
vendor/github.com/checkpoint-restore/go-criu/v5/notify.go
generated
vendored
62
vendor/github.com/checkpoint-restore/go-criu/v5/notify.go
generated
vendored
@@ -1,62 +0,0 @@
|
||||
package criu
|
||||
|
||||
// Notify interface
|
||||
type Notify interface {
|
||||
PreDump() error
|
||||
PostDump() error
|
||||
PreRestore() error
|
||||
PostRestore(pid int32) error
|
||||
NetworkLock() error
|
||||
NetworkUnlock() error
|
||||
SetupNamespaces(pid int32) error
|
||||
PostSetupNamespaces() error
|
||||
PostResume() error
|
||||
}
|
||||
|
||||
// NoNotify struct
|
||||
type NoNotify struct{}
|
||||
|
||||
// PreDump NoNotify
|
||||
func (c NoNotify) PreDump() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// PostDump NoNotify
|
||||
func (c NoNotify) PostDump() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// PreRestore NoNotify
|
||||
func (c NoNotify) PreRestore() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// PostRestore NoNotify
|
||||
func (c NoNotify) PostRestore(pid int32) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// NetworkLock NoNotify
|
||||
func (c NoNotify) NetworkLock() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// NetworkUnlock NoNotify
|
||||
func (c NoNotify) NetworkUnlock() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetupNamespaces NoNotify
|
||||
func (c NoNotify) SetupNamespaces(pid int32) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// PostSetupNamespaces NoNotify
|
||||
func (c NoNotify) PostSetupNamespaces() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// PostResume NoNotify
|
||||
func (c NoNotify) PostResume() error {
|
||||
return nil
|
||||
}
|
||||
2237
vendor/github.com/checkpoint-restore/go-criu/v5/rpc/rpc.pb.go
generated
vendored
2237
vendor/github.com/checkpoint-restore/go-criu/v5/rpc/rpc.pb.go
generated
vendored
File diff suppressed because it is too large
Load Diff
239
vendor/github.com/checkpoint-restore/go-criu/v5/rpc/rpc.proto
generated
vendored
239
vendor/github.com/checkpoint-restore/go-criu/v5/rpc/rpc.proto
generated
vendored
@@ -1,239 +0,0 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
syntax = "proto2";
|
||||
|
||||
message criu_page_server_info {
|
||||
optional string address = 1;
|
||||
optional int32 port = 2;
|
||||
optional int32 pid = 3;
|
||||
optional int32 fd = 4;
|
||||
}
|
||||
|
||||
message criu_veth_pair {
|
||||
required string if_in = 1;
|
||||
required string if_out = 2;
|
||||
};
|
||||
|
||||
message ext_mount_map {
|
||||
required string key = 1;
|
||||
required string val = 2;
|
||||
};
|
||||
|
||||
message join_namespace {
|
||||
required string ns = 1;
|
||||
required string ns_file = 2;
|
||||
optional string extra_opt = 3;
|
||||
}
|
||||
|
||||
message inherit_fd {
|
||||
required string key = 1;
|
||||
required int32 fd = 2;
|
||||
};
|
||||
|
||||
message cgroup_root {
|
||||
optional string ctrl = 1;
|
||||
required string path = 2;
|
||||
};
|
||||
|
||||
message unix_sk {
|
||||
required uint32 inode = 1;
|
||||
};
|
||||
|
||||
enum criu_cg_mode {
|
||||
IGNORE = 0;
|
||||
CG_NONE = 1;
|
||||
PROPS = 2;
|
||||
SOFT = 3;
|
||||
FULL = 4;
|
||||
STRICT = 5;
|
||||
DEFAULT = 6;
|
||||
};
|
||||
|
||||
enum criu_pre_dump_mode {
|
||||
SPLICE = 1;
|
||||
VM_READ = 2;
|
||||
};
|
||||
|
||||
message criu_opts {
|
||||
required int32 images_dir_fd = 1;
|
||||
optional int32 pid = 2; /* if not set on dump, will dump requesting process */
|
||||
|
||||
optional bool leave_running = 3;
|
||||
optional bool ext_unix_sk = 4;
|
||||
optional bool tcp_established = 5;
|
||||
optional bool evasive_devices = 6;
|
||||
optional bool shell_job = 7;
|
||||
optional bool file_locks = 8;
|
||||
optional int32 log_level = 9 [default = 2];
|
||||
optional string log_file = 10; /* No subdirs are allowed. Consider using work-dir */
|
||||
|
||||
optional criu_page_server_info ps = 11;
|
||||
|
||||
optional bool notify_scripts = 12;
|
||||
|
||||
optional string root = 13;
|
||||
optional string parent_img = 14;
|
||||
optional bool track_mem = 15;
|
||||
optional bool auto_dedup = 16;
|
||||
|
||||
optional int32 work_dir_fd = 17;
|
||||
optional bool link_remap = 18;
|
||||
repeated criu_veth_pair veths = 19; /* DEPRECATED, use external instead */
|
||||
|
||||
optional uint32 cpu_cap = 20 [default = 0xffffffff];
|
||||
optional bool force_irmap = 21;
|
||||
repeated string exec_cmd = 22;
|
||||
|
||||
repeated ext_mount_map ext_mnt = 23; /* DEPRECATED, use external instead */
|
||||
optional bool manage_cgroups = 24; /* backward compatibility */
|
||||
repeated cgroup_root cg_root = 25;
|
||||
|
||||
optional bool rst_sibling = 26; /* swrk only */
|
||||
repeated inherit_fd inherit_fd = 27; /* swrk only */
|
||||
|
||||
optional bool auto_ext_mnt = 28;
|
||||
optional bool ext_sharing = 29;
|
||||
optional bool ext_masters = 30;
|
||||
|
||||
repeated string skip_mnt = 31;
|
||||
repeated string enable_fs = 32;
|
||||
|
||||
repeated unix_sk unix_sk_ino = 33; /* DEPRECATED, use external instead */
|
||||
|
||||
optional criu_cg_mode manage_cgroups_mode = 34;
|
||||
optional uint32 ghost_limit = 35 [default = 0x100000];
|
||||
repeated string irmap_scan_paths = 36;
|
||||
repeated string external = 37;
|
||||
optional uint32 empty_ns = 38;
|
||||
repeated join_namespace join_ns = 39;
|
||||
|
||||
optional string cgroup_props = 41;
|
||||
optional string cgroup_props_file = 42;
|
||||
repeated string cgroup_dump_controller = 43;
|
||||
|
||||
optional string freeze_cgroup = 44;
|
||||
optional uint32 timeout = 45;
|
||||
optional bool tcp_skip_in_flight = 46;
|
||||
optional bool weak_sysctls = 47;
|
||||
optional bool lazy_pages = 48;
|
||||
optional int32 status_fd = 49;
|
||||
optional bool orphan_pts_master = 50;
|
||||
optional string config_file = 51;
|
||||
optional bool tcp_close = 52;
|
||||
optional string lsm_profile = 53;
|
||||
optional string tls_cacert = 54;
|
||||
optional string tls_cacrl = 55;
|
||||
optional string tls_cert = 56;
|
||||
optional string tls_key = 57;
|
||||
optional bool tls = 58;
|
||||
optional bool tls_no_cn_verify = 59;
|
||||
optional string cgroup_yard = 60;
|
||||
optional criu_pre_dump_mode pre_dump_mode = 61 [default = SPLICE];
|
||||
optional int32 pidfd_store_sk = 62;
|
||||
optional string lsm_mount_context = 63;
|
||||
/* optional bool check_mounts = 128; */
|
||||
}
|
||||
|
||||
message criu_dump_resp {
|
||||
optional bool restored = 1;
|
||||
}
|
||||
|
||||
message criu_restore_resp {
|
||||
required int32 pid = 1;
|
||||
}
|
||||
|
||||
message criu_notify {
|
||||
optional string script = 1;
|
||||
optional int32 pid = 2;
|
||||
}
|
||||
|
||||
enum criu_req_type {
|
||||
EMPTY = 0;
|
||||
DUMP = 1;
|
||||
RESTORE = 2;
|
||||
CHECK = 3;
|
||||
PRE_DUMP = 4;
|
||||
PAGE_SERVER = 5;
|
||||
|
||||
NOTIFY = 6;
|
||||
|
||||
CPUINFO_DUMP = 7;
|
||||
CPUINFO_CHECK = 8;
|
||||
|
||||
FEATURE_CHECK = 9;
|
||||
|
||||
VERSION = 10;
|
||||
|
||||
WAIT_PID = 11;
|
||||
PAGE_SERVER_CHLD = 12;
|
||||
}
|
||||
|
||||
/*
|
||||
* List of features which can queried via
|
||||
* CRIU_REQ_TYPE__FEATURE_CHECK
|
||||
*/
|
||||
message criu_features {
|
||||
optional bool mem_track = 1;
|
||||
optional bool lazy_pages = 2;
|
||||
optional bool pidfd_store = 3;
|
||||
}
|
||||
|
||||
/*
|
||||
* Request -- each type corresponds to must-be-there
|
||||
* request arguments of respective type
|
||||
*/
|
||||
|
||||
message criu_req {
|
||||
required criu_req_type type = 1;
|
||||
|
||||
optional criu_opts opts = 2;
|
||||
optional bool notify_success = 3;
|
||||
|
||||
/*
|
||||
* When set service won't close the connection but
|
||||
* will wait for more req-s to appear. Works not
|
||||
* for all request types.
|
||||
*/
|
||||
optional bool keep_open = 4;
|
||||
/*
|
||||
* 'features' can be used to query which features
|
||||
* are supported by the installed criu/kernel
|
||||
* via RPC.
|
||||
*/
|
||||
optional criu_features features = 5;
|
||||
|
||||
/* 'pid' is used for WAIT_PID */
|
||||
optional uint32 pid = 6;
|
||||
}
|
||||
|
||||
/*
|
||||
* Response -- it states whether the request was served
|
||||
* and additional request-specific information
|
||||
*/
|
||||
|
||||
message criu_resp {
|
||||
required criu_req_type type = 1;
|
||||
required bool success = 2;
|
||||
|
||||
optional criu_dump_resp dump = 3;
|
||||
optional criu_restore_resp restore = 4;
|
||||
optional criu_notify notify = 5;
|
||||
optional criu_page_server_info ps = 6;
|
||||
|
||||
optional int32 cr_errno = 7;
|
||||
optional criu_features features = 8;
|
||||
optional string cr_errmsg = 9;
|
||||
optional criu_version version = 10;
|
||||
|
||||
optional int32 status = 11;
|
||||
}
|
||||
|
||||
/* Answer for criu_req_type.VERSION requests */
|
||||
message criu_version {
|
||||
required int32 major_number = 1;
|
||||
required int32 minor_number = 2;
|
||||
optional string gitid = 3;
|
||||
optional int32 sublevel = 4;
|
||||
optional int32 extra = 5;
|
||||
optional string name = 6;
|
||||
}
|
||||
20
vendor/github.com/containerd/console/.golangci.yml
generated
vendored
20
vendor/github.com/containerd/console/.golangci.yml
generated
vendored
@@ -1,20 +0,0 @@
|
||||
linters:
|
||||
enable:
|
||||
- gofmt
|
||||
- goimports
|
||||
- ineffassign
|
||||
- misspell
|
||||
- revive
|
||||
- staticcheck
|
||||
- structcheck
|
||||
- unconvert
|
||||
- unused
|
||||
- varcheck
|
||||
- vet
|
||||
disable:
|
||||
- errcheck
|
||||
|
||||
run:
|
||||
timeout: 3m
|
||||
skip-dirs:
|
||||
- vendor
|
||||
191
vendor/github.com/containerd/console/LICENSE
generated
vendored
191
vendor/github.com/containerd/console/LICENSE
generated
vendored
@@ -1,191 +0,0 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
https://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
Copyright The containerd Authors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
https://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
29
vendor/github.com/containerd/console/README.md
generated
vendored
29
vendor/github.com/containerd/console/README.md
generated
vendored
@@ -1,29 +0,0 @@
|
||||
# console
|
||||
|
||||
[](https://pkg.go.dev/github.com/containerd/console)
|
||||
[](https://github.com/containerd/console/actions?query=workflow%3ACI)
|
||||
[](https://goreportcard.com/report/github.com/containerd/console)
|
||||
|
||||
Golang package for dealing with consoles. Light on deps and a simple API.
|
||||
|
||||
## Modifying the current process
|
||||
|
||||
```go
|
||||
current := console.Current()
|
||||
defer current.Reset()
|
||||
|
||||
if err := current.SetRaw(); err != nil {
|
||||
}
|
||||
ws, err := current.Size()
|
||||
current.Resize(ws)
|
||||
```
|
||||
|
||||
## Project details
|
||||
|
||||
console is a containerd sub-project, licensed under the [Apache 2.0 license](./LICENSE).
|
||||
As a containerd sub-project, you will find the:
|
||||
* [Project governance](https://github.com/containerd/project/blob/main/GOVERNANCE.md),
|
||||
* [Maintainers](https://github.com/containerd/project/blob/main/MAINTAINERS),
|
||||
* and [Contributing guidelines](https://github.com/containerd/project/blob/main/CONTRIBUTING.md)
|
||||
|
||||
information in our [`containerd/project`](https://github.com/containerd/project) repository.
|
||||
90
vendor/github.com/containerd/console/console.go
generated
vendored
90
vendor/github.com/containerd/console/console.go
generated
vendored
@@ -1,90 +0,0 @@
|
||||
/*
|
||||
Copyright The containerd Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package console
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io"
|
||||
"os"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrNotAConsole = errors.New("provided file is not a console")
|
||||
ErrNotImplemented = errors.New("not implemented")
|
||||
)
|
||||
|
||||
type File interface {
|
||||
io.ReadWriteCloser
|
||||
|
||||
// Fd returns its file descriptor
|
||||
Fd() uintptr
|
||||
// Name returns its file name
|
||||
Name() string
|
||||
}
|
||||
|
||||
type Console interface {
|
||||
File
|
||||
|
||||
// Resize resizes the console to the provided window size
|
||||
Resize(WinSize) error
|
||||
// ResizeFrom resizes the calling console to the size of the
|
||||
// provided console
|
||||
ResizeFrom(Console) error
|
||||
// SetRaw sets the console in raw mode
|
||||
SetRaw() error
|
||||
// DisableEcho disables echo on the console
|
||||
DisableEcho() error
|
||||
// Reset restores the console to its original state
|
||||
Reset() error
|
||||
// Size returns the window size of the console
|
||||
Size() (WinSize, error)
|
||||
}
|
||||
|
||||
// WinSize specifies the window size of the console
|
||||
type WinSize struct {
|
||||
// Height of the console
|
||||
Height uint16
|
||||
// Width of the console
|
||||
Width uint16
|
||||
x uint16
|
||||
y uint16
|
||||
}
|
||||
|
||||
// Current returns the current process' console
|
||||
func Current() (c Console) {
|
||||
var err error
|
||||
// Usually all three streams (stdin, stdout, and stderr)
|
||||
// are open to the same console, but some might be redirected,
|
||||
// so try all three.
|
||||
for _, s := range []*os.File{os.Stderr, os.Stdout, os.Stdin} {
|
||||
if c, err = ConsoleFromFile(s); err == nil {
|
||||
return c
|
||||
}
|
||||
}
|
||||
// One of the std streams should always be a console
|
||||
// for the design of this function.
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// ConsoleFromFile returns a console using the provided file
|
||||
// nolint:revive
|
||||
func ConsoleFromFile(f File) (Console, error) {
|
||||
if err := checkConsole(f); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return newMaster(f)
|
||||
}
|
||||
281
vendor/github.com/containerd/console/console_linux.go
generated
vendored
281
vendor/github.com/containerd/console/console_linux.go
generated
vendored
@@ -1,281 +0,0 @@
|
||||
//go:build linux
|
||||
// +build linux
|
||||
|
||||
/*
|
||||
Copyright The containerd Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package console
|
||||
|
||||
import (
|
||||
"io"
|
||||
"os"
|
||||
"sync"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
const (
|
||||
maxEvents = 128
|
||||
)
|
||||
|
||||
// Epoller manages multiple epoll consoles using edge-triggered epoll api so we
|
||||
// dont have to deal with repeated wake-up of EPOLLER or EPOLLHUP.
|
||||
// For more details, see:
|
||||
// - https://github.com/systemd/systemd/pull/4262
|
||||
// - https://github.com/moby/moby/issues/27202
|
||||
//
|
||||
// Example usage of Epoller and EpollConsole can be as follow:
|
||||
//
|
||||
// epoller, _ := NewEpoller()
|
||||
// epollConsole, _ := epoller.Add(console)
|
||||
// go epoller.Wait()
|
||||
// var (
|
||||
// b bytes.Buffer
|
||||
// wg sync.WaitGroup
|
||||
// )
|
||||
// wg.Add(1)
|
||||
// go func() {
|
||||
// io.Copy(&b, epollConsole)
|
||||
// wg.Done()
|
||||
// }()
|
||||
// // perform I/O on the console
|
||||
// epollConsole.Shutdown(epoller.CloseConsole)
|
||||
// wg.Wait()
|
||||
// epollConsole.Close()
|
||||
type Epoller struct {
|
||||
efd int
|
||||
mu sync.Mutex
|
||||
fdMapping map[int]*EpollConsole
|
||||
closeOnce sync.Once
|
||||
}
|
||||
|
||||
// NewEpoller returns an instance of epoller with a valid epoll fd.
|
||||
func NewEpoller() (*Epoller, error) {
|
||||
efd, err := unix.EpollCreate1(unix.EPOLL_CLOEXEC)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Epoller{
|
||||
efd: efd,
|
||||
fdMapping: make(map[int]*EpollConsole),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Add creates an epoll console based on the provided console. The console will
|
||||
// be registered with EPOLLET (i.e. using edge-triggered notification) and its
|
||||
// file descriptor will be set to non-blocking mode. After this, user should use
|
||||
// the return console to perform I/O.
|
||||
func (e *Epoller) Add(console Console) (*EpollConsole, error) {
|
||||
sysfd := int(console.Fd())
|
||||
// Set sysfd to non-blocking mode
|
||||
if err := unix.SetNonblock(sysfd, true); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ev := unix.EpollEvent{
|
||||
Events: unix.EPOLLIN | unix.EPOLLOUT | unix.EPOLLRDHUP | unix.EPOLLET,
|
||||
Fd: int32(sysfd),
|
||||
}
|
||||
if err := unix.EpollCtl(e.efd, unix.EPOLL_CTL_ADD, sysfd, &ev); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ef := &EpollConsole{
|
||||
Console: console,
|
||||
sysfd: sysfd,
|
||||
readc: sync.NewCond(&sync.Mutex{}),
|
||||
writec: sync.NewCond(&sync.Mutex{}),
|
||||
}
|
||||
e.mu.Lock()
|
||||
e.fdMapping[sysfd] = ef
|
||||
e.mu.Unlock()
|
||||
return ef, nil
|
||||
}
|
||||
|
||||
// Wait starts the loop to wait for its consoles' notifications and signal
|
||||
// appropriate console that it can perform I/O.
|
||||
func (e *Epoller) Wait() error {
|
||||
events := make([]unix.EpollEvent, maxEvents)
|
||||
for {
|
||||
n, err := unix.EpollWait(e.efd, events, -1)
|
||||
if err != nil {
|
||||
// EINTR: The call was interrupted by a signal handler before either
|
||||
// any of the requested events occurred or the timeout expired
|
||||
if err == unix.EINTR {
|
||||
continue
|
||||
}
|
||||
return err
|
||||
}
|
||||
for i := 0; i < n; i++ {
|
||||
ev := &events[i]
|
||||
// the console is ready to be read from
|
||||
if ev.Events&(unix.EPOLLIN|unix.EPOLLHUP|unix.EPOLLERR) != 0 {
|
||||
if epfile := e.getConsole(int(ev.Fd)); epfile != nil {
|
||||
epfile.signalRead()
|
||||
}
|
||||
}
|
||||
// the console is ready to be written to
|
||||
if ev.Events&(unix.EPOLLOUT|unix.EPOLLHUP|unix.EPOLLERR) != 0 {
|
||||
if epfile := e.getConsole(int(ev.Fd)); epfile != nil {
|
||||
epfile.signalWrite()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// CloseConsole unregisters the console's file descriptor from epoll interface
|
||||
func (e *Epoller) CloseConsole(fd int) error {
|
||||
e.mu.Lock()
|
||||
defer e.mu.Unlock()
|
||||
delete(e.fdMapping, fd)
|
||||
return unix.EpollCtl(e.efd, unix.EPOLL_CTL_DEL, fd, &unix.EpollEvent{})
|
||||
}
|
||||
|
||||
func (e *Epoller) getConsole(sysfd int) *EpollConsole {
|
||||
e.mu.Lock()
|
||||
f := e.fdMapping[sysfd]
|
||||
e.mu.Unlock()
|
||||
return f
|
||||
}
|
||||
|
||||
// Close closes the epoll fd
|
||||
func (e *Epoller) Close() error {
|
||||
closeErr := os.ErrClosed // default to "file already closed"
|
||||
e.closeOnce.Do(func() {
|
||||
closeErr = unix.Close(e.efd)
|
||||
})
|
||||
return closeErr
|
||||
}
|
||||
|
||||
// EpollConsole acts like a console but registers its file descriptor with an
|
||||
// epoll fd and uses epoll API to perform I/O.
|
||||
type EpollConsole struct {
|
||||
Console
|
||||
readc *sync.Cond
|
||||
writec *sync.Cond
|
||||
sysfd int
|
||||
closed bool
|
||||
}
|
||||
|
||||
// Read reads up to len(p) bytes into p. It returns the number of bytes read
|
||||
// (0 <= n <= len(p)) and any error encountered.
|
||||
//
|
||||
// If the console's read returns EAGAIN or EIO, we assume that it's a
|
||||
// temporary error because the other side went away and wait for the signal
|
||||
// generated by epoll event to continue.
|
||||
func (ec *EpollConsole) Read(p []byte) (n int, err error) {
|
||||
var read int
|
||||
ec.readc.L.Lock()
|
||||
defer ec.readc.L.Unlock()
|
||||
for {
|
||||
read, err = ec.Console.Read(p[n:])
|
||||
n += read
|
||||
if err != nil {
|
||||
var hangup bool
|
||||
if perr, ok := err.(*os.PathError); ok {
|
||||
hangup = (perr.Err == unix.EAGAIN || perr.Err == unix.EIO)
|
||||
} else {
|
||||
hangup = (err == unix.EAGAIN || err == unix.EIO)
|
||||
}
|
||||
// if the other end disappear, assume this is temporary and wait for the
|
||||
// signal to continue again. Unless we didnt read anything and the
|
||||
// console is already marked as closed then we should exit
|
||||
if hangup && !(n == 0 && len(p) > 0 && ec.closed) {
|
||||
ec.readc.Wait()
|
||||
continue
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
// if we didnt read anything then return io.EOF to end gracefully
|
||||
if n == 0 && len(p) > 0 && err == nil {
|
||||
err = io.EOF
|
||||
}
|
||||
// signal for others that we finished the read
|
||||
ec.readc.Signal()
|
||||
return n, err
|
||||
}
|
||||
|
||||
// Writes len(p) bytes from p to the console. It returns the number of bytes
|
||||
// written from p (0 <= n <= len(p)) and any error encountered that caused
|
||||
// the write to stop early.
|
||||
//
|
||||
// If writes to the console returns EAGAIN or EIO, we assume that it's a
|
||||
// temporary error because the other side went away and wait for the signal
|
||||
// generated by epoll event to continue.
|
||||
func (ec *EpollConsole) Write(p []byte) (n int, err error) {
|
||||
var written int
|
||||
ec.writec.L.Lock()
|
||||
defer ec.writec.L.Unlock()
|
||||
for {
|
||||
written, err = ec.Console.Write(p[n:])
|
||||
n += written
|
||||
if err != nil {
|
||||
var hangup bool
|
||||
if perr, ok := err.(*os.PathError); ok {
|
||||
hangup = (perr.Err == unix.EAGAIN || perr.Err == unix.EIO)
|
||||
} else {
|
||||
hangup = (err == unix.EAGAIN || err == unix.EIO)
|
||||
}
|
||||
// if the other end disappears, assume this is temporary and wait for the
|
||||
// signal to continue again.
|
||||
if hangup {
|
||||
ec.writec.Wait()
|
||||
continue
|
||||
}
|
||||
}
|
||||
// unrecoverable error, break the loop and return the error
|
||||
break
|
||||
}
|
||||
if n < len(p) && err == nil {
|
||||
err = io.ErrShortWrite
|
||||
}
|
||||
// signal for others that we finished the write
|
||||
ec.writec.Signal()
|
||||
return n, err
|
||||
}
|
||||
|
||||
// Shutdown closes the file descriptor and signals call waiters for this fd.
|
||||
// It accepts a callback which will be called with the console's fd. The
|
||||
// callback typically will be used to do further cleanup such as unregister the
|
||||
// console's fd from the epoll interface.
|
||||
// User should call Shutdown and wait for all I/O operation to be finished
|
||||
// before closing the console.
|
||||
func (ec *EpollConsole) Shutdown(close func(int) error) error {
|
||||
ec.readc.L.Lock()
|
||||
defer ec.readc.L.Unlock()
|
||||
ec.writec.L.Lock()
|
||||
defer ec.writec.L.Unlock()
|
||||
|
||||
ec.readc.Broadcast()
|
||||
ec.writec.Broadcast()
|
||||
ec.closed = true
|
||||
return close(ec.sysfd)
|
||||
}
|
||||
|
||||
// signalRead signals that the console is readable.
|
||||
func (ec *EpollConsole) signalRead() {
|
||||
ec.readc.L.Lock()
|
||||
ec.readc.Signal()
|
||||
ec.readc.L.Unlock()
|
||||
}
|
||||
|
||||
// signalWrite signals that the console is writable.
|
||||
func (ec *EpollConsole) signalWrite() {
|
||||
ec.writec.L.Lock()
|
||||
ec.writec.Signal()
|
||||
ec.writec.L.Unlock()
|
||||
}
|
||||
36
vendor/github.com/containerd/console/console_other.go
generated
vendored
36
vendor/github.com/containerd/console/console_other.go
generated
vendored
@@ -1,36 +0,0 @@
|
||||
//go:build !darwin && !freebsd && !linux && !netbsd && !openbsd && !solaris && !windows && !zos
|
||||
// +build !darwin,!freebsd,!linux,!netbsd,!openbsd,!solaris,!windows,!zos
|
||||
|
||||
/*
|
||||
Copyright The containerd Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package console
|
||||
|
||||
// NewPty creates a new pty pair
|
||||
// The master is returned as the first console and a string
|
||||
// with the path to the pty slave is returned as the second
|
||||
func NewPty() (Console, string, error) {
|
||||
return nil, "", ErrNotImplemented
|
||||
}
|
||||
|
||||
// checkConsole checks if the provided file is a console
|
||||
func checkConsole(f File) error {
|
||||
return ErrNotAConsole
|
||||
}
|
||||
|
||||
func newMaster(f File) (Console, error) {
|
||||
return nil, ErrNotImplemented
|
||||
}
|
||||
157
vendor/github.com/containerd/console/console_unix.go
generated
vendored
157
vendor/github.com/containerd/console/console_unix.go
generated
vendored
@@ -1,157 +0,0 @@
|
||||
//go:build darwin || freebsd || linux || netbsd || openbsd || zos
|
||||
// +build darwin freebsd linux netbsd openbsd zos
|
||||
|
||||
/*
|
||||
Copyright The containerd Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package console
|
||||
|
||||
import (
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
// NewPty creates a new pty pair
|
||||
// The master is returned as the first console and a string
|
||||
// with the path to the pty slave is returned as the second
|
||||
func NewPty() (Console, string, error) {
|
||||
f, err := openpt()
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
slave, err := ptsname(f)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
if err := unlockpt(f); err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
m, err := newMaster(f)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
return m, slave, nil
|
||||
}
|
||||
|
||||
type master struct {
|
||||
f File
|
||||
original *unix.Termios
|
||||
}
|
||||
|
||||
func (m *master) Read(b []byte) (int, error) {
|
||||
return m.f.Read(b)
|
||||
}
|
||||
|
||||
func (m *master) Write(b []byte) (int, error) {
|
||||
return m.f.Write(b)
|
||||
}
|
||||
|
||||
func (m *master) Close() error {
|
||||
return m.f.Close()
|
||||
}
|
||||
|
||||
func (m *master) Resize(ws WinSize) error {
|
||||
return tcswinsz(m.f.Fd(), ws)
|
||||
}
|
||||
|
||||
func (m *master) ResizeFrom(c Console) error {
|
||||
ws, err := c.Size()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return m.Resize(ws)
|
||||
}
|
||||
|
||||
func (m *master) Reset() error {
|
||||
if m.original == nil {
|
||||
return nil
|
||||
}
|
||||
return tcset(m.f.Fd(), m.original)
|
||||
}
|
||||
|
||||
func (m *master) getCurrent() (unix.Termios, error) {
|
||||
var termios unix.Termios
|
||||
if err := tcget(m.f.Fd(), &termios); err != nil {
|
||||
return unix.Termios{}, err
|
||||
}
|
||||
return termios, nil
|
||||
}
|
||||
|
||||
func (m *master) SetRaw() error {
|
||||
rawState, err := m.getCurrent()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
rawState = cfmakeraw(rawState)
|
||||
rawState.Oflag = rawState.Oflag | unix.OPOST
|
||||
return tcset(m.f.Fd(), &rawState)
|
||||
}
|
||||
|
||||
func (m *master) DisableEcho() error {
|
||||
rawState, err := m.getCurrent()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
rawState.Lflag = rawState.Lflag &^ unix.ECHO
|
||||
return tcset(m.f.Fd(), &rawState)
|
||||
}
|
||||
|
||||
func (m *master) Size() (WinSize, error) {
|
||||
return tcgwinsz(m.f.Fd())
|
||||
}
|
||||
|
||||
func (m *master) Fd() uintptr {
|
||||
return m.f.Fd()
|
||||
}
|
||||
|
||||
func (m *master) Name() string {
|
||||
return m.f.Name()
|
||||
}
|
||||
|
||||
// checkConsole checks if the provided file is a console
|
||||
func checkConsole(f File) error {
|
||||
var termios unix.Termios
|
||||
if tcget(f.Fd(), &termios) != nil {
|
||||
return ErrNotAConsole
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func newMaster(f File) (Console, error) {
|
||||
m := &master{
|
||||
f: f,
|
||||
}
|
||||
t, err := m.getCurrent()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
m.original = &t
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// ClearONLCR sets the necessary tty_ioctl(4)s to ensure that a pty pair
|
||||
// created by us acts normally. In particular, a not-very-well-known default of
|
||||
// Linux unix98 ptys is that they have +onlcr by default. While this isn't a
|
||||
// problem for terminal emulators, because we relay data from the terminal we
|
||||
// also relay that funky line discipline.
|
||||
func ClearONLCR(fd uintptr) error {
|
||||
return setONLCR(fd, false)
|
||||
}
|
||||
|
||||
// SetONLCR sets the necessary tty_ioctl(4)s to ensure that a pty pair
|
||||
// created by us acts as intended for a terminal emulator.
|
||||
func SetONLCR(fd uintptr) error {
|
||||
return setONLCR(fd, true)
|
||||
}
|
||||
219
vendor/github.com/containerd/console/console_windows.go
generated
vendored
219
vendor/github.com/containerd/console/console_windows.go
generated
vendored
@@ -1,219 +0,0 @@
|
||||
/*
|
||||
Copyright The containerd Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package console
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
var vtInputSupported bool
|
||||
|
||||
func (m *master) initStdios() {
|
||||
// Note: We discard console mode warnings, because in/out can be redirected.
|
||||
//
|
||||
// TODO: Investigate opening CONOUT$/CONIN$ to handle this correctly
|
||||
|
||||
m.in = windows.Handle(os.Stdin.Fd())
|
||||
if err := windows.GetConsoleMode(m.in, &m.inMode); err == nil {
|
||||
// Validate that windows.ENABLE_VIRTUAL_TERMINAL_INPUT is supported, but do not set it.
|
||||
if err = windows.SetConsoleMode(m.in, m.inMode|windows.ENABLE_VIRTUAL_TERMINAL_INPUT); err == nil {
|
||||
vtInputSupported = true
|
||||
}
|
||||
// Unconditionally set the console mode back even on failure because SetConsoleMode
|
||||
// remembers invalid bits on input handles.
|
||||
windows.SetConsoleMode(m.in, m.inMode)
|
||||
}
|
||||
|
||||
m.out = windows.Handle(os.Stdout.Fd())
|
||||
if err := windows.GetConsoleMode(m.out, &m.outMode); err == nil {
|
||||
if err := windows.SetConsoleMode(m.out, m.outMode|windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING); err == nil {
|
||||
m.outMode |= windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING
|
||||
} else {
|
||||
windows.SetConsoleMode(m.out, m.outMode)
|
||||
}
|
||||
}
|
||||
|
||||
m.err = windows.Handle(os.Stderr.Fd())
|
||||
if err := windows.GetConsoleMode(m.err, &m.errMode); err == nil {
|
||||
if err := windows.SetConsoleMode(m.err, m.errMode|windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING); err == nil {
|
||||
m.errMode |= windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING
|
||||
} else {
|
||||
windows.SetConsoleMode(m.err, m.errMode)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type master struct {
|
||||
in windows.Handle
|
||||
inMode uint32
|
||||
|
||||
out windows.Handle
|
||||
outMode uint32
|
||||
|
||||
err windows.Handle
|
||||
errMode uint32
|
||||
}
|
||||
|
||||
func (m *master) SetRaw() error {
|
||||
if err := makeInputRaw(m.in, m.inMode); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Set StdOut and StdErr to raw mode, we ignore failures since
|
||||
// windows.DISABLE_NEWLINE_AUTO_RETURN might not be supported on this version of
|
||||
// Windows.
|
||||
|
||||
windows.SetConsoleMode(m.out, m.outMode|windows.DISABLE_NEWLINE_AUTO_RETURN)
|
||||
|
||||
windows.SetConsoleMode(m.err, m.errMode|windows.DISABLE_NEWLINE_AUTO_RETURN)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *master) Reset() error {
|
||||
var errs []error
|
||||
|
||||
for _, s := range []struct {
|
||||
fd windows.Handle
|
||||
mode uint32
|
||||
}{
|
||||
{m.in, m.inMode},
|
||||
{m.out, m.outMode},
|
||||
{m.err, m.errMode},
|
||||
} {
|
||||
if err := windows.SetConsoleMode(s.fd, s.mode); err != nil {
|
||||
// we can't just abort on the first error, otherwise we might leave
|
||||
// the console in an unexpected state.
|
||||
errs = append(errs, fmt.Errorf("unable to restore console mode: %w", err))
|
||||
}
|
||||
}
|
||||
|
||||
if len(errs) > 0 {
|
||||
return errs[0]
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *master) Size() (WinSize, error) {
|
||||
var info windows.ConsoleScreenBufferInfo
|
||||
err := windows.GetConsoleScreenBufferInfo(m.out, &info)
|
||||
if err != nil {
|
||||
return WinSize{}, fmt.Errorf("unable to get console info: %w", err)
|
||||
}
|
||||
|
||||
winsize := WinSize{
|
||||
Width: uint16(info.Window.Right - info.Window.Left + 1),
|
||||
Height: uint16(info.Window.Bottom - info.Window.Top + 1),
|
||||
}
|
||||
|
||||
return winsize, nil
|
||||
}
|
||||
|
||||
func (m *master) Resize(ws WinSize) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
func (m *master) ResizeFrom(c Console) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
func (m *master) DisableEcho() error {
|
||||
mode := m.inMode &^ windows.ENABLE_ECHO_INPUT
|
||||
mode |= windows.ENABLE_PROCESSED_INPUT
|
||||
mode |= windows.ENABLE_LINE_INPUT
|
||||
|
||||
if err := windows.SetConsoleMode(m.in, mode); err != nil {
|
||||
return fmt.Errorf("unable to set console to disable echo: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *master) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *master) Read(b []byte) (int, error) {
|
||||
return os.Stdin.Read(b)
|
||||
}
|
||||
|
||||
func (m *master) Write(b []byte) (int, error) {
|
||||
return os.Stdout.Write(b)
|
||||
}
|
||||
|
||||
func (m *master) Fd() uintptr {
|
||||
return uintptr(m.in)
|
||||
}
|
||||
|
||||
// on windows, console can only be made from os.Std{in,out,err}, hence there
|
||||
// isnt a single name here we can use. Return a dummy "console" value in this
|
||||
// case should be sufficient.
|
||||
func (m *master) Name() string {
|
||||
return "console"
|
||||
}
|
||||
|
||||
// makeInputRaw puts the terminal (Windows Console) connected to the given
|
||||
// file descriptor into raw mode
|
||||
func makeInputRaw(fd windows.Handle, mode uint32) error {
|
||||
// See
|
||||
// -- https://msdn.microsoft.com/en-us/library/windows/desktop/ms686033(v=vs.85).aspx
|
||||
// -- https://msdn.microsoft.com/en-us/library/windows/desktop/ms683462(v=vs.85).aspx
|
||||
|
||||
// Disable these modes
|
||||
mode &^= windows.ENABLE_ECHO_INPUT
|
||||
mode &^= windows.ENABLE_LINE_INPUT
|
||||
mode &^= windows.ENABLE_MOUSE_INPUT
|
||||
mode &^= windows.ENABLE_WINDOW_INPUT
|
||||
mode &^= windows.ENABLE_PROCESSED_INPUT
|
||||
|
||||
// Enable these modes
|
||||
mode |= windows.ENABLE_EXTENDED_FLAGS
|
||||
mode |= windows.ENABLE_INSERT_MODE
|
||||
mode |= windows.ENABLE_QUICK_EDIT_MODE
|
||||
|
||||
if vtInputSupported {
|
||||
mode |= windows.ENABLE_VIRTUAL_TERMINAL_INPUT
|
||||
}
|
||||
|
||||
if err := windows.SetConsoleMode(fd, mode); err != nil {
|
||||
return fmt.Errorf("unable to set console to raw mode: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func checkConsole(f File) error {
|
||||
var mode uint32
|
||||
if err := windows.GetConsoleMode(windows.Handle(f.Fd()), &mode); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func newMaster(f File) (Console, error) {
|
||||
if f != os.Stdin && f != os.Stdout && f != os.Stderr {
|
||||
return nil, errors.New("creating a console from a file is not supported on windows")
|
||||
}
|
||||
m := &master{}
|
||||
m.initStdios()
|
||||
return m, nil
|
||||
}
|
||||
46
vendor/github.com/containerd/console/pty_freebsd_cgo.go
generated
vendored
46
vendor/github.com/containerd/console/pty_freebsd_cgo.go
generated
vendored
@@ -1,46 +0,0 @@
|
||||
//go:build freebsd && cgo
|
||||
// +build freebsd,cgo
|
||||
|
||||
/*
|
||||
Copyright The containerd Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package console
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
)
|
||||
|
||||
/*
|
||||
#include <fcntl.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
*/
|
||||
import "C"
|
||||
|
||||
// openpt allocates a new pseudo-terminal and establishes a connection with its
|
||||
// control device.
|
||||
func openpt() (*os.File, error) {
|
||||
fd, err := C.posix_openpt(C.O_RDWR)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("posix_openpt: %w", err)
|
||||
}
|
||||
if _, err := C.grantpt(fd); err != nil {
|
||||
C.close(fd)
|
||||
return nil, fmt.Errorf("grantpt: %w", err)
|
||||
}
|
||||
return os.NewFile(uintptr(fd), ""), nil
|
||||
}
|
||||
37
vendor/github.com/containerd/console/pty_freebsd_nocgo.go
generated
vendored
37
vendor/github.com/containerd/console/pty_freebsd_nocgo.go
generated
vendored
@@ -1,37 +0,0 @@
|
||||
//go:build freebsd && !cgo
|
||||
// +build freebsd,!cgo
|
||||
|
||||
/*
|
||||
Copyright The containerd Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package console
|
||||
|
||||
import (
|
||||
"os"
|
||||
)
|
||||
|
||||
//
|
||||
// Implementing the functions below requires cgo support. Non-cgo stubs
|
||||
// versions are defined below to enable cross-compilation of source code
|
||||
// that depends on these functions, but the resultant cross-compiled
|
||||
// binaries cannot actually be used. If the stub function(s) below are
|
||||
// actually invoked they will display an error message and cause the
|
||||
// calling process to exit.
|
||||
//
|
||||
|
||||
func openpt() (*os.File, error) {
|
||||
panic("openpt() support requires cgo.")
|
||||
}
|
||||
31
vendor/github.com/containerd/console/pty_unix.go
generated
vendored
31
vendor/github.com/containerd/console/pty_unix.go
generated
vendored
@@ -1,31 +0,0 @@
|
||||
//go:build darwin || linux || netbsd || openbsd
|
||||
// +build darwin linux netbsd openbsd
|
||||
|
||||
/*
|
||||
Copyright The containerd Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package console
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
// openpt allocates a new pseudo-terminal by opening the /dev/ptmx device
|
||||
func openpt() (*os.File, error) {
|
||||
return os.OpenFile("/dev/ptmx", unix.O_RDWR|unix.O_NOCTTY|unix.O_CLOEXEC, 0)
|
||||
}
|
||||
43
vendor/github.com/containerd/console/pty_zos.go
generated
vendored
43
vendor/github.com/containerd/console/pty_zos.go
generated
vendored
@@ -1,43 +0,0 @@
|
||||
//go:build zos
|
||||
// +build zos
|
||||
|
||||
/*
|
||||
Copyright The containerd Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package console
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
)
|
||||
|
||||
// openpt allocates a new pseudo-terminal by opening the first available /dev/ptypXX device
|
||||
func openpt() (*os.File, error) {
|
||||
var f *os.File
|
||||
var err error
|
||||
for i := 0; ; i++ {
|
||||
ptyp := fmt.Sprintf("/dev/ptyp%04d", i)
|
||||
f, err = os.OpenFile(ptyp, os.O_RDWR, 0600)
|
||||
if err == nil {
|
||||
break
|
||||
}
|
||||
if os.IsNotExist(err) {
|
||||
return nil, err
|
||||
}
|
||||
// else probably Resource Busy
|
||||
}
|
||||
return f, nil
|
||||
}
|
||||
44
vendor/github.com/containerd/console/tc_darwin.go
generated
vendored
44
vendor/github.com/containerd/console/tc_darwin.go
generated
vendored
@@ -1,44 +0,0 @@
|
||||
/*
|
||||
Copyright The containerd Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package console
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
const (
|
||||
cmdTcGet = unix.TIOCGETA
|
||||
cmdTcSet = unix.TIOCSETA
|
||||
)
|
||||
|
||||
// unlockpt unlocks the slave pseudoterminal device corresponding to the master pseudoterminal referred to by f.
|
||||
// unlockpt should be called before opening the slave side of a pty.
|
||||
func unlockpt(f *os.File) error {
|
||||
return unix.IoctlSetPointerInt(int(f.Fd()), unix.TIOCPTYUNLK, 0)
|
||||
}
|
||||
|
||||
// ptsname retrieves the name of the first available pts for the given master.
|
||||
func ptsname(f *os.File) (string, error) {
|
||||
n, err := unix.IoctlGetInt(int(f.Fd()), unix.TIOCPTYGNAME)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return fmt.Sprintf("/dev/pts/%d", n), nil
|
||||
}
|
||||
58
vendor/github.com/containerd/console/tc_freebsd_cgo.go
generated
vendored
58
vendor/github.com/containerd/console/tc_freebsd_cgo.go
generated
vendored
@@ -1,58 +0,0 @@
|
||||
//go:build freebsd && cgo
|
||||
// +build freebsd,cgo
|
||||
|
||||
/*
|
||||
Copyright The containerd Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package console
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
/*
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
*/
|
||||
import "C"
|
||||
|
||||
const (
|
||||
cmdTcGet = unix.TIOCGETA
|
||||
cmdTcSet = unix.TIOCSETA
|
||||
)
|
||||
|
||||
// unlockpt unlocks the slave pseudoterminal device corresponding to the master pseudoterminal referred to by f.
|
||||
// unlockpt should be called before opening the slave side of a pty.
|
||||
func unlockpt(f *os.File) error {
|
||||
fd := C.int(f.Fd())
|
||||
if _, err := C.unlockpt(fd); err != nil {
|
||||
C.close(fd)
|
||||
return fmt.Errorf("unlockpt: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ptsname retrieves the name of the first available pts for the given master.
|
||||
func ptsname(f *os.File) (string, error) {
|
||||
n, err := unix.IoctlGetInt(int(f.Fd()), unix.TIOCGPTN)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return fmt.Sprintf("/dev/pts/%d", n), nil
|
||||
}
|
||||
56
vendor/github.com/containerd/console/tc_freebsd_nocgo.go
generated
vendored
56
vendor/github.com/containerd/console/tc_freebsd_nocgo.go
generated
vendored
@@ -1,56 +0,0 @@
|
||||
//go:build freebsd && !cgo
|
||||
// +build freebsd,!cgo
|
||||
|
||||
/*
|
||||
Copyright The containerd Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package console
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
const (
|
||||
cmdTcGet = unix.TIOCGETA
|
||||
cmdTcSet = unix.TIOCSETA
|
||||
)
|
||||
|
||||
//
|
||||
// Implementing the functions below requires cgo support. Non-cgo stubs
|
||||
// versions are defined below to enable cross-compilation of source code
|
||||
// that depends on these functions, but the resultant cross-compiled
|
||||
// binaries cannot actually be used. If the stub function(s) below are
|
||||
// actually invoked they will display an error message and cause the
|
||||
// calling process to exit.
|
||||
//
|
||||
|
||||
// unlockpt unlocks the slave pseudoterminal device corresponding to the master pseudoterminal referred to by f.
|
||||
// unlockpt should be called before opening the slave side of a pty.
|
||||
func unlockpt(f *os.File) error {
|
||||
panic("unlockpt() support requires cgo.")
|
||||
}
|
||||
|
||||
// ptsname retrieves the name of the first available pts for the given master.
|
||||
func ptsname(f *os.File) (string, error) {
|
||||
n, err := unix.IoctlGetInt(int(f.Fd()), unix.TIOCGPTN)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return fmt.Sprintf("/dev/pts/%d", n), nil
|
||||
}
|
||||
51
vendor/github.com/containerd/console/tc_linux.go
generated
vendored
51
vendor/github.com/containerd/console/tc_linux.go
generated
vendored
@@ -1,51 +0,0 @@
|
||||
/*
|
||||
Copyright The containerd Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package console
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
const (
|
||||
cmdTcGet = unix.TCGETS
|
||||
cmdTcSet = unix.TCSETS
|
||||
)
|
||||
|
||||
// unlockpt unlocks the slave pseudoterminal device corresponding to the master pseudoterminal referred to by f.
|
||||
// unlockpt should be called before opening the slave side of a pty.
|
||||
func unlockpt(f *os.File) error {
|
||||
var u int32
|
||||
// XXX do not use unix.IoctlSetPointerInt here, see commit dbd69c59b81.
|
||||
if _, _, err := unix.Syscall(unix.SYS_IOCTL, f.Fd(), unix.TIOCSPTLCK, uintptr(unsafe.Pointer(&u))); err != 0 {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ptsname retrieves the name of the first available pts for the given master.
|
||||
func ptsname(f *os.File) (string, error) {
|
||||
var u uint32
|
||||
// XXX do not use unix.IoctlGetInt here, see commit dbd69c59b81.
|
||||
if _, _, err := unix.Syscall(unix.SYS_IOCTL, f.Fd(), unix.TIOCGPTN, uintptr(unsafe.Pointer(&u))); err != 0 {
|
||||
return "", err
|
||||
}
|
||||
return fmt.Sprintf("/dev/pts/%d", u), nil
|
||||
}
|
||||
45
vendor/github.com/containerd/console/tc_netbsd.go
generated
vendored
45
vendor/github.com/containerd/console/tc_netbsd.go
generated
vendored
@@ -1,45 +0,0 @@
|
||||
/*
|
||||
Copyright The containerd Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package console
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"os"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
const (
|
||||
cmdTcGet = unix.TIOCGETA
|
||||
cmdTcSet = unix.TIOCSETA
|
||||
)
|
||||
|
||||
// unlockpt unlocks the slave pseudoterminal device corresponding to the master pseudoterminal referred to by f.
|
||||
// unlockpt should be called before opening the slave side of a pty.
|
||||
// This does not exist on NetBSD, it does not allocate controlling terminals on open
|
||||
func unlockpt(f *os.File) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ptsname retrieves the name of the first available pts for the given master.
|
||||
func ptsname(f *os.File) (string, error) {
|
||||
ptm, err := unix.IoctlGetPtmget(int(f.Fd()), unix.TIOCPTSNAME)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return string(ptm.Sn[:bytes.IndexByte(ptm.Sn[:], 0)]), nil
|
||||
}
|
||||
52
vendor/github.com/containerd/console/tc_openbsd_cgo.go
generated
vendored
52
vendor/github.com/containerd/console/tc_openbsd_cgo.go
generated
vendored
@@ -1,52 +0,0 @@
|
||||
//go:build openbsd && cgo
|
||||
// +build openbsd,cgo
|
||||
|
||||
/*
|
||||
Copyright The containerd Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package console
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
//#include <stdlib.h>
|
||||
import "C"
|
||||
|
||||
const (
|
||||
cmdTcGet = unix.TIOCGETA
|
||||
cmdTcSet = unix.TIOCSETA
|
||||
)
|
||||
|
||||
// ptsname retrieves the name of the first available pts for the given master.
|
||||
func ptsname(f *os.File) (string, error) {
|
||||
ptspath, err := C.ptsname(C.int(f.Fd()))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return C.GoString(ptspath), nil
|
||||
}
|
||||
|
||||
// unlockpt unlocks the slave pseudoterminal device corresponding to the master pseudoterminal referred to by f.
|
||||
// unlockpt should be called before opening the slave side of a pty.
|
||||
func unlockpt(f *os.File) error {
|
||||
if _, err := C.grantpt(C.int(f.Fd())); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
48
vendor/github.com/containerd/console/tc_openbsd_nocgo.go
generated
vendored
48
vendor/github.com/containerd/console/tc_openbsd_nocgo.go
generated
vendored
@@ -1,48 +0,0 @@
|
||||
//go:build openbsd && !cgo
|
||||
// +build openbsd,!cgo
|
||||
|
||||
/*
|
||||
Copyright The containerd Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
//
|
||||
// Implementing the functions below requires cgo support. Non-cgo stubs
|
||||
// versions are defined below to enable cross-compilation of source code
|
||||
// that depends on these functions, but the resultant cross-compiled
|
||||
// binaries cannot actually be used. If the stub function(s) below are
|
||||
// actually invoked they will display an error message and cause the
|
||||
// calling process to exit.
|
||||
//
|
||||
|
||||
package console
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
const (
|
||||
cmdTcGet = unix.TIOCGETA
|
||||
cmdTcSet = unix.TIOCSETA
|
||||
)
|
||||
|
||||
func ptsname(f *os.File) (string, error) {
|
||||
panic("ptsname() support requires cgo.")
|
||||
}
|
||||
|
||||
func unlockpt(f *os.File) error {
|
||||
panic("unlockpt() support requires cgo.")
|
||||
}
|
||||
92
vendor/github.com/containerd/console/tc_unix.go
generated
vendored
92
vendor/github.com/containerd/console/tc_unix.go
generated
vendored
@@ -1,92 +0,0 @@
|
||||
//go:build darwin || freebsd || linux || netbsd || openbsd || zos
|
||||
// +build darwin freebsd linux netbsd openbsd zos
|
||||
|
||||
/*
|
||||
Copyright The containerd Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package console
|
||||
|
||||
import (
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
func tcget(fd uintptr, p *unix.Termios) error {
|
||||
termios, err := unix.IoctlGetTermios(int(fd), cmdTcGet)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*p = *termios
|
||||
return nil
|
||||
}
|
||||
|
||||
func tcset(fd uintptr, p *unix.Termios) error {
|
||||
return unix.IoctlSetTermios(int(fd), cmdTcSet, p)
|
||||
}
|
||||
|
||||
func tcgwinsz(fd uintptr) (WinSize, error) {
|
||||
var ws WinSize
|
||||
|
||||
uws, err := unix.IoctlGetWinsize(int(fd), unix.TIOCGWINSZ)
|
||||
if err != nil {
|
||||
return ws, err
|
||||
}
|
||||
|
||||
// Translate from unix.Winsize to console.WinSize
|
||||
ws.Height = uws.Row
|
||||
ws.Width = uws.Col
|
||||
ws.x = uws.Xpixel
|
||||
ws.y = uws.Ypixel
|
||||
return ws, nil
|
||||
}
|
||||
|
||||
func tcswinsz(fd uintptr, ws WinSize) error {
|
||||
// Translate from console.WinSize to unix.Winsize
|
||||
|
||||
var uws unix.Winsize
|
||||
uws.Row = ws.Height
|
||||
uws.Col = ws.Width
|
||||
uws.Xpixel = ws.x
|
||||
uws.Ypixel = ws.y
|
||||
|
||||
return unix.IoctlSetWinsize(int(fd), unix.TIOCSWINSZ, &uws)
|
||||
}
|
||||
|
||||
func setONLCR(fd uintptr, enable bool) error {
|
||||
var termios unix.Termios
|
||||
if err := tcget(fd, &termios); err != nil {
|
||||
return err
|
||||
}
|
||||
if enable {
|
||||
// Set +onlcr so we can act like a real terminal
|
||||
termios.Oflag |= unix.ONLCR
|
||||
} else {
|
||||
// Set -onlcr so we don't have to deal with \r.
|
||||
termios.Oflag &^= unix.ONLCR
|
||||
}
|
||||
return tcset(fd, &termios)
|
||||
}
|
||||
|
||||
func cfmakeraw(t unix.Termios) unix.Termios {
|
||||
t.Iflag &^= (unix.IGNBRK | unix.BRKINT | unix.PARMRK | unix.ISTRIP | unix.INLCR | unix.IGNCR | unix.ICRNL | unix.IXON)
|
||||
t.Oflag &^= unix.OPOST
|
||||
t.Lflag &^= (unix.ECHO | unix.ECHONL | unix.ICANON | unix.ISIG | unix.IEXTEN)
|
||||
t.Cflag &^= (unix.CSIZE | unix.PARENB)
|
||||
t.Cflag |= unix.CS8
|
||||
t.Cc[unix.VMIN] = 1
|
||||
t.Cc[unix.VTIME] = 0
|
||||
|
||||
return t
|
||||
}
|
||||
39
vendor/github.com/containerd/console/tc_zos.go
generated
vendored
39
vendor/github.com/containerd/console/tc_zos.go
generated
vendored
@@ -1,39 +0,0 @@
|
||||
/*
|
||||
Copyright The containerd Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package console
|
||||
|
||||
import (
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
const (
|
||||
cmdTcGet = unix.TCGETS
|
||||
cmdTcSet = unix.TCSETS
|
||||
)
|
||||
|
||||
// unlockpt is a no-op on zos.
|
||||
func unlockpt(_ *os.File) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ptsname retrieves the name of the first available pts for the given master.
|
||||
func ptsname(f *os.File) (string, error) {
|
||||
return "/dev/ttyp" + strings.TrimPrefix(f.Name(), "/dev/ptyp"), nil
|
||||
}
|
||||
35
vendor/github.com/google/cadvisor/container/libcontainer/handler.go
generated
vendored
35
vendor/github.com/google/cadvisor/container/libcontainer/handler.go
generated
vendored
@@ -28,7 +28,6 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/opencontainers/runc/libcontainer"
|
||||
"github.com/opencontainers/runc/libcontainer/cgroups"
|
||||
"github.com/opencontainers/runc/libcontainer/cgroups/fs2"
|
||||
"k8s.io/klog/v2"
|
||||
@@ -89,10 +88,7 @@ func (h *Handler) GetStats() (*info.ContainerStats, error) {
|
||||
}
|
||||
klog.V(4).Infof("Ignoring errors when gathering stats for root cgroup since some controllers don't have stats on the root cgroup: %v", err)
|
||||
}
|
||||
libcontainerStats := &libcontainer.Stats{
|
||||
CgroupStats: cgroupStats,
|
||||
}
|
||||
stats := newContainerStats(libcontainerStats, h.includedMetrics)
|
||||
stats := newContainerStats(cgroupStats, h.includedMetrics)
|
||||
|
||||
if h.includedMetrics.Has(container.ProcessSchedulerMetrics) {
|
||||
stats.Cpu.Schedstat, err = h.schedulerStatsFromProcs()
|
||||
@@ -888,28 +884,6 @@ func setHugepageStats(s *cgroups.Stats, ret *info.ContainerStats) {
|
||||
}
|
||||
}
|
||||
|
||||
func setNetworkStats(libcontainerStats *libcontainer.Stats, ret *info.ContainerStats) {
|
||||
ret.Network.Interfaces = make([]info.InterfaceStats, len(libcontainerStats.Interfaces))
|
||||
for i := range libcontainerStats.Interfaces {
|
||||
ret.Network.Interfaces[i] = info.InterfaceStats{
|
||||
Name: libcontainerStats.Interfaces[i].Name,
|
||||
RxBytes: libcontainerStats.Interfaces[i].RxBytes,
|
||||
RxPackets: libcontainerStats.Interfaces[i].RxPackets,
|
||||
RxErrors: libcontainerStats.Interfaces[i].RxErrors,
|
||||
RxDropped: libcontainerStats.Interfaces[i].RxDropped,
|
||||
TxBytes: libcontainerStats.Interfaces[i].TxBytes,
|
||||
TxPackets: libcontainerStats.Interfaces[i].TxPackets,
|
||||
TxErrors: libcontainerStats.Interfaces[i].TxErrors,
|
||||
TxDropped: libcontainerStats.Interfaces[i].TxDropped,
|
||||
}
|
||||
}
|
||||
|
||||
// Add to base struct for backwards compatibility.
|
||||
if len(ret.Network.Interfaces) > 0 {
|
||||
ret.Network.InterfaceStats = ret.Network.Interfaces[0]
|
||||
}
|
||||
}
|
||||
|
||||
// read from pids path not cpu
|
||||
func setThreadsStats(s *cgroups.Stats, ret *info.ContainerStats) {
|
||||
if s != nil {
|
||||
@@ -918,12 +892,12 @@ func setThreadsStats(s *cgroups.Stats, ret *info.ContainerStats) {
|
||||
}
|
||||
}
|
||||
|
||||
func newContainerStats(libcontainerStats *libcontainer.Stats, includedMetrics container.MetricSet) *info.ContainerStats {
|
||||
func newContainerStats(cgroupStats *cgroups.Stats, includedMetrics container.MetricSet) *info.ContainerStats {
|
||||
ret := &info.ContainerStats{
|
||||
Timestamp: time.Now(),
|
||||
}
|
||||
|
||||
if s := libcontainerStats.CgroupStats; s != nil {
|
||||
if s := cgroupStats; s != nil {
|
||||
setCPUStats(s, ret, includedMetrics.Has(container.PerCpuUsageMetrics))
|
||||
if includedMetrics.Has(container.DiskIOMetrics) {
|
||||
setDiskIoStats(s, ret)
|
||||
@@ -939,8 +913,5 @@ func newContainerStats(libcontainerStats *libcontainer.Stats, includedMetrics co
|
||||
setCPUSetStats(s, ret)
|
||||
}
|
||||
}
|
||||
if len(libcontainerStats.Interfaces) > 0 {
|
||||
setNetworkStats(libcontainerStats, ret)
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
6
vendor/github.com/google/cadvisor/utils/sysfs/sysfs.go
generated
vendored
6
vendor/github.com/google/cadvisor/utils/sysfs/sysfs.go
generated
vendored
@@ -254,10 +254,8 @@ func (fs *realSysFs) IsBlockDeviceHidden(name string) (bool, error) {
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("failed to read %s: %w", devHiddenPath, err)
|
||||
}
|
||||
if string(hidden) == "1" {
|
||||
return true, nil
|
||||
}
|
||||
return false, nil
|
||||
|
||||
return strings.TrimSpace(string(hidden)) == "1", nil
|
||||
}
|
||||
|
||||
func (fs *realSysFs) GetBlockDeviceScheduler(name string) (string, error) {
|
||||
|
||||
318
vendor/github.com/opencontainers/runc/libcontainer/README.md
generated
vendored
318
vendor/github.com/opencontainers/runc/libcontainer/README.md
generated
vendored
@@ -1,318 +0,0 @@
|
||||
# libcontainer
|
||||
|
||||
[](https://pkg.go.dev/github.com/opencontainers/runc/libcontainer)
|
||||
|
||||
Libcontainer provides a native Go implementation for creating containers
|
||||
with namespaces, cgroups, capabilities, and filesystem access controls.
|
||||
It allows you to manage the lifecycle of the container performing additional operations
|
||||
after the container is created.
|
||||
|
||||
|
||||
#### Container
|
||||
A container is a self contained execution environment that shares the kernel of the
|
||||
host system and which is (optionally) isolated from other containers in the system.
|
||||
|
||||
#### Using libcontainer
|
||||
|
||||
Because containers are spawned in a two step process you will need a binary that
|
||||
will be executed as the init process for the container. In libcontainer, we use
|
||||
the current binary (/proc/self/exe) to be executed as the init process, and use
|
||||
arg "init", we call the first step process "bootstrap", so you always need a "init"
|
||||
function as the entry of "bootstrap".
|
||||
|
||||
In addition to the go init function the early stage bootstrap is handled by importing
|
||||
[nsenter](https://github.com/opencontainers/runc/blob/master/libcontainer/nsenter/README.md).
|
||||
|
||||
```go
|
||||
import (
|
||||
_ "github.com/opencontainers/runc/libcontainer/nsenter"
|
||||
)
|
||||
|
||||
func init() {
|
||||
if len(os.Args) > 1 && os.Args[1] == "init" {
|
||||
runtime.GOMAXPROCS(1)
|
||||
runtime.LockOSThread()
|
||||
factory, _ := libcontainer.New("")
|
||||
if err := factory.StartInitialization(); err != nil {
|
||||
logrus.Fatal(err)
|
||||
}
|
||||
panic("--this line should have never been executed, congratulations--")
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Then to create a container you first have to initialize an instance of a factory
|
||||
that will handle the creation and initialization for a container.
|
||||
|
||||
```go
|
||||
factory, err := libcontainer.New("/var/lib/container", libcontainer.Cgroupfs, libcontainer.InitArgs(os.Args[0], "init"))
|
||||
if err != nil {
|
||||
logrus.Fatal(err)
|
||||
return
|
||||
}
|
||||
```
|
||||
|
||||
Once you have an instance of the factory created we can create a configuration
|
||||
struct describing how the container is to be created. A sample would look similar to this:
|
||||
|
||||
```go
|
||||
defaultMountFlags := unix.MS_NOEXEC | unix.MS_NOSUID | unix.MS_NODEV
|
||||
var devices []*configs.DeviceRule
|
||||
for _, device := range specconv.AllowedDevices {
|
||||
devices = append(devices, &device.Rule)
|
||||
}
|
||||
config := &configs.Config{
|
||||
Rootfs: "/your/path/to/rootfs",
|
||||
Capabilities: &configs.Capabilities{
|
||||
Bounding: []string{
|
||||
"CAP_CHOWN",
|
||||
"CAP_DAC_OVERRIDE",
|
||||
"CAP_FSETID",
|
||||
"CAP_FOWNER",
|
||||
"CAP_MKNOD",
|
||||
"CAP_NET_RAW",
|
||||
"CAP_SETGID",
|
||||
"CAP_SETUID",
|
||||
"CAP_SETFCAP",
|
||||
"CAP_SETPCAP",
|
||||
"CAP_NET_BIND_SERVICE",
|
||||
"CAP_SYS_CHROOT",
|
||||
"CAP_KILL",
|
||||
"CAP_AUDIT_WRITE",
|
||||
},
|
||||
Effective: []string{
|
||||
"CAP_CHOWN",
|
||||
"CAP_DAC_OVERRIDE",
|
||||
"CAP_FSETID",
|
||||
"CAP_FOWNER",
|
||||
"CAP_MKNOD",
|
||||
"CAP_NET_RAW",
|
||||
"CAP_SETGID",
|
||||
"CAP_SETUID",
|
||||
"CAP_SETFCAP",
|
||||
"CAP_SETPCAP",
|
||||
"CAP_NET_BIND_SERVICE",
|
||||
"CAP_SYS_CHROOT",
|
||||
"CAP_KILL",
|
||||
"CAP_AUDIT_WRITE",
|
||||
},
|
||||
Permitted: []string{
|
||||
"CAP_CHOWN",
|
||||
"CAP_DAC_OVERRIDE",
|
||||
"CAP_FSETID",
|
||||
"CAP_FOWNER",
|
||||
"CAP_MKNOD",
|
||||
"CAP_NET_RAW",
|
||||
"CAP_SETGID",
|
||||
"CAP_SETUID",
|
||||
"CAP_SETFCAP",
|
||||
"CAP_SETPCAP",
|
||||
"CAP_NET_BIND_SERVICE",
|
||||
"CAP_SYS_CHROOT",
|
||||
"CAP_KILL",
|
||||
"CAP_AUDIT_WRITE",
|
||||
},
|
||||
Ambient: []string{
|
||||
"CAP_CHOWN",
|
||||
"CAP_DAC_OVERRIDE",
|
||||
"CAP_FSETID",
|
||||
"CAP_FOWNER",
|
||||
"CAP_MKNOD",
|
||||
"CAP_NET_RAW",
|
||||
"CAP_SETGID",
|
||||
"CAP_SETUID",
|
||||
"CAP_SETFCAP",
|
||||
"CAP_SETPCAP",
|
||||
"CAP_NET_BIND_SERVICE",
|
||||
"CAP_SYS_CHROOT",
|
||||
"CAP_KILL",
|
||||
"CAP_AUDIT_WRITE",
|
||||
},
|
||||
},
|
||||
Namespaces: configs.Namespaces([]configs.Namespace{
|
||||
{Type: configs.NEWNS},
|
||||
{Type: configs.NEWUTS},
|
||||
{Type: configs.NEWIPC},
|
||||
{Type: configs.NEWPID},
|
||||
{Type: configs.NEWUSER},
|
||||
{Type: configs.NEWNET},
|
||||
{Type: configs.NEWCGROUP},
|
||||
}),
|
||||
Cgroups: &configs.Cgroup{
|
||||
Name: "test-container",
|
||||
Parent: "system",
|
||||
Resources: &configs.Resources{
|
||||
MemorySwappiness: nil,
|
||||
Devices: devices,
|
||||
},
|
||||
},
|
||||
MaskPaths: []string{
|
||||
"/proc/kcore",
|
||||
"/sys/firmware",
|
||||
},
|
||||
ReadonlyPaths: []string{
|
||||
"/proc/sys", "/proc/sysrq-trigger", "/proc/irq", "/proc/bus",
|
||||
},
|
||||
Devices: specconv.AllowedDevices,
|
||||
Hostname: "testing",
|
||||
Mounts: []*configs.Mount{
|
||||
{
|
||||
Source: "proc",
|
||||
Destination: "/proc",
|
||||
Device: "proc",
|
||||
Flags: defaultMountFlags,
|
||||
},
|
||||
{
|
||||
Source: "tmpfs",
|
||||
Destination: "/dev",
|
||||
Device: "tmpfs",
|
||||
Flags: unix.MS_NOSUID | unix.MS_STRICTATIME,
|
||||
Data: "mode=755",
|
||||
},
|
||||
{
|
||||
Source: "devpts",
|
||||
Destination: "/dev/pts",
|
||||
Device: "devpts",
|
||||
Flags: unix.MS_NOSUID | unix.MS_NOEXEC,
|
||||
Data: "newinstance,ptmxmode=0666,mode=0620,gid=5",
|
||||
},
|
||||
{
|
||||
Device: "tmpfs",
|
||||
Source: "shm",
|
||||
Destination: "/dev/shm",
|
||||
Data: "mode=1777,size=65536k",
|
||||
Flags: defaultMountFlags,
|
||||
},
|
||||
{
|
||||
Source: "mqueue",
|
||||
Destination: "/dev/mqueue",
|
||||
Device: "mqueue",
|
||||
Flags: defaultMountFlags,
|
||||
},
|
||||
{
|
||||
Source: "sysfs",
|
||||
Destination: "/sys",
|
||||
Device: "sysfs",
|
||||
Flags: defaultMountFlags | unix.MS_RDONLY,
|
||||
},
|
||||
},
|
||||
UidMappings: []configs.IDMap{
|
||||
{
|
||||
ContainerID: 0,
|
||||
HostID: 1000,
|
||||
Size: 65536,
|
||||
},
|
||||
},
|
||||
GidMappings: []configs.IDMap{
|
||||
{
|
||||
ContainerID: 0,
|
||||
HostID: 1000,
|
||||
Size: 65536,
|
||||
},
|
||||
},
|
||||
Networks: []*configs.Network{
|
||||
{
|
||||
Type: "loopback",
|
||||
Address: "127.0.0.1/0",
|
||||
Gateway: "localhost",
|
||||
},
|
||||
},
|
||||
Rlimits: []configs.Rlimit{
|
||||
{
|
||||
Type: unix.RLIMIT_NOFILE,
|
||||
Hard: uint64(1025),
|
||||
Soft: uint64(1025),
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
Once you have the configuration populated you can create a container:
|
||||
|
||||
```go
|
||||
container, err := factory.Create("container-id", config)
|
||||
if err != nil {
|
||||
logrus.Fatal(err)
|
||||
return
|
||||
}
|
||||
```
|
||||
|
||||
To spawn bash as the initial process inside the container and have the
|
||||
processes pid returned in order to wait, signal, or kill the process:
|
||||
|
||||
```go
|
||||
process := &libcontainer.Process{
|
||||
Args: []string{"/bin/bash"},
|
||||
Env: []string{"PATH=/bin"},
|
||||
User: "daemon",
|
||||
Stdin: os.Stdin,
|
||||
Stdout: os.Stdout,
|
||||
Stderr: os.Stderr,
|
||||
Init: true,
|
||||
}
|
||||
|
||||
err := container.Run(process)
|
||||
if err != nil {
|
||||
container.Destroy()
|
||||
logrus.Fatal(err)
|
||||
return
|
||||
}
|
||||
|
||||
// wait for the process to finish.
|
||||
_, err := process.Wait()
|
||||
if err != nil {
|
||||
logrus.Fatal(err)
|
||||
}
|
||||
|
||||
// destroy the container.
|
||||
container.Destroy()
|
||||
```
|
||||
|
||||
Additional ways to interact with a running container are:
|
||||
|
||||
```go
|
||||
// return all the pids for all processes running inside the container.
|
||||
processes, err := container.Processes()
|
||||
|
||||
// get detailed cpu, memory, io, and network statistics for the container and
|
||||
// it's processes.
|
||||
stats, err := container.Stats()
|
||||
|
||||
// pause all processes inside the container.
|
||||
container.Pause()
|
||||
|
||||
// resume all paused processes.
|
||||
container.Resume()
|
||||
|
||||
// send signal to container's init process.
|
||||
container.Signal(signal)
|
||||
|
||||
// update container resource constraints.
|
||||
container.Set(config)
|
||||
|
||||
// get current status of the container.
|
||||
status, err := container.Status()
|
||||
|
||||
// get current container's state information.
|
||||
state, err := container.State()
|
||||
```
|
||||
|
||||
|
||||
#### Checkpoint & Restore
|
||||
|
||||
libcontainer now integrates [CRIU](http://criu.org/) for checkpointing and restoring containers.
|
||||
This lets you save the state of a process running inside a container to disk, and then restore
|
||||
that state into a new process, on the same machine or on another machine.
|
||||
|
||||
`criu` version 1.5.2 or higher is required to use checkpoint and restore.
|
||||
If you don't already have `criu` installed, you can build it from source, following the
|
||||
[online instructions](http://criu.org/Installation). `criu` is also installed in the docker image
|
||||
generated when building libcontainer with docker.
|
||||
|
||||
|
||||
## Copyright and license
|
||||
|
||||
Code and documentation copyright 2014 Docker, inc.
|
||||
The code and documentation are released under the [Apache 2.0 license](../LICENSE).
|
||||
The documentation is also released under Creative Commons Attribution 4.0 International License.
|
||||
You may obtain a copy of the license, titled CC-BY-4.0, at http://creativecommons.org/licenses/by/4.0/.
|
||||
465
vendor/github.com/opencontainers/runc/libcontainer/SPEC.md
generated
vendored
465
vendor/github.com/opencontainers/runc/libcontainer/SPEC.md
generated
vendored
@@ -1,465 +0,0 @@
|
||||
## Container Specification - v1
|
||||
|
||||
This is the standard configuration for version 1 containers. It includes
|
||||
namespaces, standard filesystem setup, a default Linux capability set, and
|
||||
information about resource reservations. It also has information about any
|
||||
populated environment settings for the processes running inside a container.
|
||||
|
||||
Along with the configuration of how a container is created the standard also
|
||||
discusses actions that can be performed on a container to manage and inspect
|
||||
information about the processes running inside.
|
||||
|
||||
The v1 profile is meant to be able to accommodate the majority of applications
|
||||
with a strong security configuration.
|
||||
|
||||
### System Requirements and Compatibility
|
||||
|
||||
Minimum requirements:
|
||||
* Kernel version - 3.10 recommended 2.6.2x minimum(with backported patches)
|
||||
* Mounted cgroups with each subsystem in its own hierarchy
|
||||
|
||||
|
||||
### Namespaces
|
||||
|
||||
| Flag | Enabled |
|
||||
| --------------- | ------- |
|
||||
| CLONE_NEWPID | 1 |
|
||||
| CLONE_NEWUTS | 1 |
|
||||
| CLONE_NEWIPC | 1 |
|
||||
| CLONE_NEWNET | 1 |
|
||||
| CLONE_NEWNS | 1 |
|
||||
| CLONE_NEWUSER | 1 |
|
||||
| CLONE_NEWCGROUP | 1 |
|
||||
|
||||
Namespaces are created for the container via the `unshare` syscall.
|
||||
|
||||
|
||||
### Filesystem
|
||||
|
||||
A root filesystem must be provided to a container for execution. The container
|
||||
will use this root filesystem (rootfs) to jail and spawn processes inside where
|
||||
the binaries and system libraries are local to that directory. Any binaries
|
||||
to be executed must be contained within this rootfs.
|
||||
|
||||
Mounts that happen inside the container are automatically cleaned up when the
|
||||
container exits as the mount namespace is destroyed and the kernel will
|
||||
unmount all the mounts that were setup within that namespace.
|
||||
|
||||
For a container to execute properly there are certain filesystems that
|
||||
are required to be mounted within the rootfs that the runtime will setup.
|
||||
|
||||
| Path | Type | Flags | Data |
|
||||
| ----------- | ------ | -------------------------------------- | ---------------------------------------- |
|
||||
| /proc | proc | MS_NOEXEC,MS_NOSUID,MS_NODEV | |
|
||||
| /dev | tmpfs | MS_NOEXEC,MS_STRICTATIME | mode=755 |
|
||||
| /dev/shm | tmpfs | MS_NOEXEC,MS_NOSUID,MS_NODEV | mode=1777,size=65536k |
|
||||
| /dev/mqueue | mqueue | MS_NOEXEC,MS_NOSUID,MS_NODEV | |
|
||||
| /dev/pts | devpts | MS_NOEXEC,MS_NOSUID | newinstance,ptmxmode=0666,mode=620,gid=5 |
|
||||
| /sys | sysfs | MS_NOEXEC,MS_NOSUID,MS_NODEV,MS_RDONLY | |
|
||||
|
||||
|
||||
After a container's filesystems are mounted within the newly created
|
||||
mount namespace `/dev` will need to be populated with a set of device nodes.
|
||||
It is expected that a rootfs does not need to have any device nodes specified
|
||||
for `/dev` within the rootfs as the container will setup the correct devices
|
||||
that are required for executing a container's process.
|
||||
|
||||
| Path | Mode | Access |
|
||||
| ------------ | ---- | ---------- |
|
||||
| /dev/null | 0666 | rwm |
|
||||
| /dev/zero | 0666 | rwm |
|
||||
| /dev/full | 0666 | rwm |
|
||||
| /dev/tty | 0666 | rwm |
|
||||
| /dev/random | 0666 | rwm |
|
||||
| /dev/urandom | 0666 | rwm |
|
||||
|
||||
|
||||
**ptmx**
|
||||
`/dev/ptmx` will need to be a symlink to the host's `/dev/ptmx` within
|
||||
the container.
|
||||
|
||||
The use of a pseudo TTY is optional within a container and it should support both.
|
||||
If a pseudo is provided to the container `/dev/console` will need to be
|
||||
setup by binding the console in `/dev/` after it has been populated and mounted
|
||||
in tmpfs.
|
||||
|
||||
| Source | Destination | UID GID | Mode | Type |
|
||||
| --------------- | ------------ | ------- | ---- | ---- |
|
||||
| *pty host path* | /dev/console | 0 0 | 0600 | bind |
|
||||
|
||||
|
||||
After `/dev/null` has been setup we check for any external links between
|
||||
the container's io, STDIN, STDOUT, STDERR. If the container's io is pointing
|
||||
to `/dev/null` outside the container we close and `dup2` the `/dev/null`
|
||||
that is local to the container's rootfs.
|
||||
|
||||
|
||||
After the container has `/proc` mounted a few standard symlinks are setup
|
||||
within `/dev/` for the io.
|
||||
|
||||
| Source | Destination |
|
||||
| --------------- | ----------- |
|
||||
| /proc/self/fd | /dev/fd |
|
||||
| /proc/self/fd/0 | /dev/stdin |
|
||||
| /proc/self/fd/1 | /dev/stdout |
|
||||
| /proc/self/fd/2 | /dev/stderr |
|
||||
|
||||
A `pivot_root` is used to change the root for the process, effectively
|
||||
jailing the process inside the rootfs.
|
||||
|
||||
```c
|
||||
put_old = mkdir(...);
|
||||
pivot_root(rootfs, put_old);
|
||||
chdir("/");
|
||||
unmount(put_old, MS_DETACH);
|
||||
rmdir(put_old);
|
||||
```
|
||||
|
||||
For container's running with a rootfs inside `ramfs` a `MS_MOVE` combined
|
||||
with a `chroot` is required as `pivot_root` is not supported in `ramfs`.
|
||||
|
||||
```c
|
||||
mount(rootfs, "/", NULL, MS_MOVE, NULL);
|
||||
chroot(".");
|
||||
chdir("/");
|
||||
```
|
||||
|
||||
The `umask` is set back to `0022` after the filesystem setup has been completed.
|
||||
|
||||
### Resources
|
||||
|
||||
Cgroups are used to handle resource allocation for containers. This includes
|
||||
system resources like cpu, memory, and device access.
|
||||
|
||||
| Subsystem | Enabled |
|
||||
| ---------- | ------- |
|
||||
| devices | 1 |
|
||||
| memory | 1 |
|
||||
| cpu | 1 |
|
||||
| cpuacct | 1 |
|
||||
| cpuset | 1 |
|
||||
| blkio | 1 |
|
||||
| perf_event | 1 |
|
||||
| freezer | 1 |
|
||||
| hugetlb | 1 |
|
||||
| pids | 1 |
|
||||
|
||||
|
||||
All cgroup subsystem are joined so that statistics can be collected from
|
||||
each of the subsystems. Freezer does not expose any stats but is joined
|
||||
so that containers can be paused and resumed.
|
||||
|
||||
The parent process of the container's init must place the init pid inside
|
||||
the correct cgroups before the initialization begins. This is done so
|
||||
that no processes or threads escape the cgroups. This sync is
|
||||
done via a pipe ( specified in the runtime section below ) that the container's
|
||||
init process will block waiting for the parent to finish setup.
|
||||
|
||||
### IntelRdt
|
||||
|
||||
Intel platforms with new Xeon CPU support Resource Director Technology (RDT).
|
||||
Cache Allocation Technology (CAT) and Memory Bandwidth Allocation (MBA) are
|
||||
two sub-features of RDT.
|
||||
|
||||
Cache Allocation Technology (CAT) provides a way for the software to restrict
|
||||
cache allocation to a defined 'subset' of L3 cache which may be overlapping
|
||||
with other 'subsets'. The different subsets are identified by class of
|
||||
service (CLOS) and each CLOS has a capacity bitmask (CBM).
|
||||
|
||||
Memory Bandwidth Allocation (MBA) provides indirect and approximate throttle
|
||||
over memory bandwidth for the software. A user controls the resource by
|
||||
indicating the percentage of maximum memory bandwidth or memory bandwidth limit
|
||||
in MBps unit if MBA Software Controller is enabled.
|
||||
|
||||
It can be used to handle L3 cache and memory bandwidth resources allocation
|
||||
for containers if hardware and kernel support Intel RDT CAT and MBA features.
|
||||
|
||||
In Linux 4.10 kernel or newer, the interface is defined and exposed via
|
||||
"resource control" filesystem, which is a "cgroup-like" interface.
|
||||
|
||||
Comparing with cgroups, it has similar process management lifecycle and
|
||||
interfaces in a container. But unlike cgroups' hierarchy, it has single level
|
||||
filesystem layout.
|
||||
|
||||
CAT and MBA features are introduced in Linux 4.10 and 4.12 kernel via
|
||||
"resource control" filesystem.
|
||||
|
||||
Intel RDT "resource control" filesystem hierarchy:
|
||||
```
|
||||
mount -t resctrl resctrl /sys/fs/resctrl
|
||||
tree /sys/fs/resctrl
|
||||
/sys/fs/resctrl/
|
||||
|-- info
|
||||
| |-- L3
|
||||
| | |-- cbm_mask
|
||||
| | |-- min_cbm_bits
|
||||
| | |-- num_closids
|
||||
| |-- MB
|
||||
| |-- bandwidth_gran
|
||||
| |-- delay_linear
|
||||
| |-- min_bandwidth
|
||||
| |-- num_closids
|
||||
|-- ...
|
||||
|-- schemata
|
||||
|-- tasks
|
||||
|-- <container_id>
|
||||
|-- ...
|
||||
|-- schemata
|
||||
|-- tasks
|
||||
```
|
||||
|
||||
For runc, we can make use of `tasks` and `schemata` configuration for L3
|
||||
cache and memory bandwidth resources constraints.
|
||||
|
||||
The file `tasks` has a list of tasks that belongs to this group (e.g.,
|
||||
<container_id>" group). Tasks can be added to a group by writing the task ID
|
||||
to the "tasks" file (which will automatically remove them from the previous
|
||||
group to which they belonged). New tasks created by fork(2) and clone(2) are
|
||||
added to the same group as their parent.
|
||||
|
||||
The file `schemata` has a list of all the resources available to this group.
|
||||
Each resource (L3 cache, memory bandwidth) has its own line and format.
|
||||
|
||||
L3 cache schema:
|
||||
It has allocation bitmasks/values for L3 cache on each socket, which
|
||||
contains L3 cache id and capacity bitmask (CBM).
|
||||
```
|
||||
Format: "L3:<cache_id0>=<cbm0>;<cache_id1>=<cbm1>;..."
|
||||
```
|
||||
For example, on a two-socket machine, the schema line could be "L3:0=ff;1=c0"
|
||||
which means L3 cache id 0's CBM is 0xff, and L3 cache id 1's CBM is 0xc0.
|
||||
|
||||
The valid L3 cache CBM is a *contiguous bits set* and number of bits that can
|
||||
be set is less than the max bit. The max bits in the CBM is varied among
|
||||
supported Intel CPU models. Kernel will check if it is valid when writing.
|
||||
e.g., default value 0xfffff in root indicates the max bits of CBM is 20
|
||||
bits, which mapping to entire L3 cache capacity. Some valid CBM values to
|
||||
set in a group: 0xf, 0xf0, 0x3ff, 0x1f00 and etc.
|
||||
|
||||
Memory bandwidth schema:
|
||||
It has allocation values for memory bandwidth on each socket, which contains
|
||||
L3 cache id and memory bandwidth.
|
||||
```
|
||||
Format: "MB:<cache_id0>=bandwidth0;<cache_id1>=bandwidth1;..."
|
||||
```
|
||||
For example, on a two-socket machine, the schema line could be "MB:0=20;1=70"
|
||||
|
||||
The minimum bandwidth percentage value for each CPU model is predefined and
|
||||
can be looked up through "info/MB/min_bandwidth". The bandwidth granularity
|
||||
that is allocated is also dependent on the CPU model and can be looked up at
|
||||
"info/MB/bandwidth_gran". The available bandwidth control steps are:
|
||||
min_bw + N * bw_gran. Intermediate values are rounded to the next control
|
||||
step available on the hardware.
|
||||
|
||||
If MBA Software Controller is enabled through mount option "-o mba_MBps"
|
||||
mount -t resctrl resctrl -o mba_MBps /sys/fs/resctrl
|
||||
We could specify memory bandwidth in "MBps" (Mega Bytes per second) unit
|
||||
instead of "percentages". The kernel underneath would use a software feedback
|
||||
mechanism or a "Software Controller" which reads the actual bandwidth using
|
||||
MBM counters and adjust the memory bandwidth percentages to ensure:
|
||||
"actual memory bandwidth < user specified memory bandwidth".
|
||||
|
||||
For example, on a two-socket machine, the schema line could be
|
||||
"MB:0=5000;1=7000" which means 5000 MBps memory bandwidth limit on socket 0
|
||||
and 7000 MBps memory bandwidth limit on socket 1.
|
||||
|
||||
For more information about Intel RDT kernel interface:
|
||||
https://www.kernel.org/doc/Documentation/x86/intel_rdt_ui.txt
|
||||
|
||||
```
|
||||
An example for runc:
|
||||
Consider a two-socket machine with two L3 caches where the default CBM is
|
||||
0x7ff and the max CBM length is 11 bits, and minimum memory bandwidth of 10%
|
||||
with a memory bandwidth granularity of 10%.
|
||||
|
||||
Tasks inside the container only have access to the "upper" 7/11 of L3 cache
|
||||
on socket 0 and the "lower" 5/11 L3 cache on socket 1, and may use a
|
||||
maximum memory bandwidth of 20% on socket 0 and 70% on socket 1.
|
||||
|
||||
"linux": {
|
||||
"intelRdt": {
|
||||
"closID": "guaranteed_group",
|
||||
"l3CacheSchema": "L3:0=7f0;1=1f",
|
||||
"memBwSchema": "MB:0=20;1=70"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Security
|
||||
|
||||
The standard set of Linux capabilities that are set in a container
|
||||
provide a good default for security and flexibility for the applications.
|
||||
|
||||
|
||||
| Capability | Enabled |
|
||||
| -------------------- | ------- |
|
||||
| CAP_NET_RAW | 1 |
|
||||
| CAP_NET_BIND_SERVICE | 1 |
|
||||
| CAP_AUDIT_READ | 1 |
|
||||
| CAP_AUDIT_WRITE | 1 |
|
||||
| CAP_DAC_OVERRIDE | 1 |
|
||||
| CAP_SETFCAP | 1 |
|
||||
| CAP_SETPCAP | 1 |
|
||||
| CAP_SETGID | 1 |
|
||||
| CAP_SETUID | 1 |
|
||||
| CAP_MKNOD | 1 |
|
||||
| CAP_CHOWN | 1 |
|
||||
| CAP_FOWNER | 1 |
|
||||
| CAP_FSETID | 1 |
|
||||
| CAP_KILL | 1 |
|
||||
| CAP_SYS_CHROOT | 1 |
|
||||
| CAP_NET_BROADCAST | 0 |
|
||||
| CAP_SYS_MODULE | 0 |
|
||||
| CAP_SYS_RAWIO | 0 |
|
||||
| CAP_SYS_PACCT | 0 |
|
||||
| CAP_SYS_ADMIN | 0 |
|
||||
| CAP_SYS_NICE | 0 |
|
||||
| CAP_SYS_RESOURCE | 0 |
|
||||
| CAP_SYS_TIME | 0 |
|
||||
| CAP_SYS_TTY_CONFIG | 0 |
|
||||
| CAP_AUDIT_CONTROL | 0 |
|
||||
| CAP_MAC_OVERRIDE | 0 |
|
||||
| CAP_MAC_ADMIN | 0 |
|
||||
| CAP_NET_ADMIN | 0 |
|
||||
| CAP_SYSLOG | 0 |
|
||||
| CAP_DAC_READ_SEARCH | 0 |
|
||||
| CAP_LINUX_IMMUTABLE | 0 |
|
||||
| CAP_IPC_LOCK | 0 |
|
||||
| CAP_IPC_OWNER | 0 |
|
||||
| CAP_SYS_PTRACE | 0 |
|
||||
| CAP_SYS_BOOT | 0 |
|
||||
| CAP_LEASE | 0 |
|
||||
| CAP_WAKE_ALARM | 0 |
|
||||
| CAP_BLOCK_SUSPEND | 0 |
|
||||
|
||||
|
||||
Additional security layers like [apparmor](https://wiki.ubuntu.com/AppArmor)
|
||||
and [selinux](http://selinuxproject.org/page/Main_Page) can be used with
|
||||
the containers. A container should support setting an apparmor profile or
|
||||
selinux process and mount labels if provided in the configuration.
|
||||
|
||||
Standard apparmor profile:
|
||||
```c
|
||||
#include <tunables/global>
|
||||
profile <profile_name> flags=(attach_disconnected,mediate_deleted) {
|
||||
#include <abstractions/base>
|
||||
network,
|
||||
capability,
|
||||
file,
|
||||
umount,
|
||||
|
||||
deny @{PROC}/sys/fs/** wklx,
|
||||
deny @{PROC}/sysrq-trigger rwklx,
|
||||
deny @{PROC}/mem rwklx,
|
||||
deny @{PROC}/kmem rwklx,
|
||||
deny @{PROC}/sys/kernel/[^s][^h][^m]* wklx,
|
||||
deny @{PROC}/sys/kernel/*/** wklx,
|
||||
|
||||
deny mount,
|
||||
|
||||
deny /sys/[^f]*/** wklx,
|
||||
deny /sys/f[^s]*/** wklx,
|
||||
deny /sys/fs/[^c]*/** wklx,
|
||||
deny /sys/fs/c[^g]*/** wklx,
|
||||
deny /sys/fs/cg[^r]*/** wklx,
|
||||
deny /sys/firmware/efi/efivars/** rwklx,
|
||||
deny /sys/kernel/security/** rwklx,
|
||||
}
|
||||
```
|
||||
|
||||
*TODO: seccomp work is being done to find a good default config*
|
||||
|
||||
### Runtime and Init Process
|
||||
|
||||
During container creation the parent process needs to talk to the container's init
|
||||
process and have a form of synchronization. This is accomplished by creating
|
||||
a pipe that is passed to the container's init. When the init process first spawns
|
||||
it will block on its side of the pipe until the parent closes its side. This
|
||||
allows the parent to have time to set the new process inside a cgroup hierarchy
|
||||
and/or write any uid/gid mappings required for user namespaces.
|
||||
The pipe is passed to the init process via FD 3.
|
||||
|
||||
The application consuming libcontainer should be compiled statically. libcontainer
|
||||
does not define any init process and the arguments provided are used to `exec` the
|
||||
process inside the application. There should be no long running init within the
|
||||
container spec.
|
||||
|
||||
If a pseudo tty is provided to a container it will open and `dup2` the console
|
||||
as the container's STDIN, STDOUT, STDERR as well as mounting the console
|
||||
as `/dev/console`.
|
||||
|
||||
An extra set of mounts are provided to a container and setup for use. A container's
|
||||
rootfs can contain some non portable files inside that can cause side effects during
|
||||
execution of a process. These files are usually created and populated with the container
|
||||
specific information via the runtime.
|
||||
|
||||
**Extra runtime files:**
|
||||
* /etc/hosts
|
||||
* /etc/resolv.conf
|
||||
* /etc/hostname
|
||||
* /etc/localtime
|
||||
|
||||
|
||||
#### Defaults
|
||||
|
||||
There are a few defaults that can be overridden by users, but in their omission
|
||||
these apply to processes within a container.
|
||||
|
||||
| Type | Value |
|
||||
| ------------------- | ------------------------------ |
|
||||
| Parent Death Signal | SIGKILL |
|
||||
| UID | 0 |
|
||||
| GID | 0 |
|
||||
| GROUPS | 0, NULL |
|
||||
| CWD | "/" |
|
||||
| $HOME | Current user's home dir or "/" |
|
||||
| Readonly rootfs | false |
|
||||
| Pseudo TTY | false |
|
||||
|
||||
|
||||
## Actions
|
||||
|
||||
After a container is created there is a standard set of actions that can
|
||||
be done to the container. These actions are part of the public API for
|
||||
a container.
|
||||
|
||||
| Action | Description |
|
||||
| -------------- | ------------------------------------------------------------------ |
|
||||
| Get processes | Return all the pids for processes running inside a container |
|
||||
| Get Stats | Return resource statistics for the container as a whole |
|
||||
| Wait | Waits on the container's init process ( pid 1 ) |
|
||||
| Wait Process | Wait on any of the container's processes returning the exit status |
|
||||
| Destroy | Kill the container's init process and remove any filesystem state |
|
||||
| Signal | Send a signal to the container's init process |
|
||||
| Signal Process | Send a signal to any of the container's processes |
|
||||
| Pause | Pause all processes inside the container |
|
||||
| Resume | Resume all processes inside the container if paused |
|
||||
| Exec | Execute a new process inside of the container ( requires setns ) |
|
||||
| Set | Setup configs of the container after it's created |
|
||||
|
||||
### Execute a new process inside of a running container
|
||||
|
||||
User can execute a new process inside of a running container. Any binaries to be
|
||||
executed must be accessible within the container's rootfs.
|
||||
|
||||
The started process will run inside the container's rootfs. Any changes
|
||||
made by the process to the container's filesystem will persist after the
|
||||
process finished executing.
|
||||
|
||||
The started process will join all the container's existing namespaces. When the
|
||||
container is paused, the process will also be paused and will resume when
|
||||
the container is unpaused. The started process will only run when the container's
|
||||
primary process (PID 1) is running, and will not be restarted when the container
|
||||
is restarted.
|
||||
|
||||
#### Planned additions
|
||||
|
||||
The started process will have its own cgroups nested inside the container's
|
||||
cgroups. This is used for process tracking and optionally resource allocation
|
||||
handling for the new process. Freezer cgroup is required, the rest of the cgroups
|
||||
are optional. The process executor must place its pid inside the correct
|
||||
cgroups before starting the process. This is done so that no child processes or
|
||||
threads can escape the cgroups.
|
||||
|
||||
When the process is stopped, the process executor will try (in a best-effort way)
|
||||
to stop all its children and remove the sub-cgroups.
|
||||
16
vendor/github.com/opencontainers/runc/libcontainer/apparmor/apparmor.go
generated
vendored
16
vendor/github.com/opencontainers/runc/libcontainer/apparmor/apparmor.go
generated
vendored
@@ -1,16 +0,0 @@
|
||||
package apparmor
|
||||
|
||||
import "errors"
|
||||
|
||||
var (
|
||||
// IsEnabled returns true if apparmor is enabled for the host.
|
||||
IsEnabled = isEnabled
|
||||
|
||||
// ApplyProfile will apply the profile with the specified name to the process after
|
||||
// the next exec. It is only supported on Linux and produces an ErrApparmorNotEnabled
|
||||
// on other platforms.
|
||||
ApplyProfile = applyProfile
|
||||
|
||||
// ErrApparmorNotEnabled indicates that AppArmor is not enabled or not supported.
|
||||
ErrApparmorNotEnabled = errors.New("apparmor: config provided but apparmor not supported")
|
||||
)
|
||||
68
vendor/github.com/opencontainers/runc/libcontainer/apparmor/apparmor_linux.go
generated
vendored
68
vendor/github.com/opencontainers/runc/libcontainer/apparmor/apparmor_linux.go
generated
vendored
@@ -1,68 +0,0 @@
|
||||
package apparmor
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"sync"
|
||||
|
||||
"github.com/opencontainers/runc/libcontainer/utils"
|
||||
)
|
||||
|
||||
var (
|
||||
appArmorEnabled bool
|
||||
checkAppArmor sync.Once
|
||||
)
|
||||
|
||||
// isEnabled returns true if apparmor is enabled for the host.
|
||||
func isEnabled() bool {
|
||||
checkAppArmor.Do(func() {
|
||||
if _, err := os.Stat("/sys/kernel/security/apparmor"); err == nil {
|
||||
buf, err := os.ReadFile("/sys/module/apparmor/parameters/enabled")
|
||||
appArmorEnabled = err == nil && len(buf) > 1 && buf[0] == 'Y'
|
||||
}
|
||||
})
|
||||
return appArmorEnabled
|
||||
}
|
||||
|
||||
func setProcAttr(attr, value string) error {
|
||||
// Under AppArmor you can only change your own attr, so use /proc/self/
|
||||
// instead of /proc/<tid>/ like libapparmor does
|
||||
attrPath := "/proc/self/attr/apparmor/" + attr
|
||||
if _, err := os.Stat(attrPath); errors.Is(err, os.ErrNotExist) {
|
||||
// fall back to the old convention
|
||||
attrPath = "/proc/self/attr/" + attr
|
||||
}
|
||||
|
||||
f, err := os.OpenFile(attrPath, os.O_WRONLY, 0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
if err := utils.EnsureProcHandle(f); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = f.WriteString(value)
|
||||
return err
|
||||
}
|
||||
|
||||
// changeOnExec reimplements aa_change_onexec from libapparmor in Go
|
||||
func changeOnExec(name string) error {
|
||||
if err := setProcAttr("exec", "exec "+name); err != nil {
|
||||
return fmt.Errorf("apparmor failed to apply profile: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// applyProfile will apply the profile with the specified name to the process after
|
||||
// the next exec. It is only supported on Linux and produces an error on other
|
||||
// platforms.
|
||||
func applyProfile(name string) error {
|
||||
if name == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
return changeOnExec(name)
|
||||
}
|
||||
15
vendor/github.com/opencontainers/runc/libcontainer/apparmor/apparmor_unsupported.go
generated
vendored
15
vendor/github.com/opencontainers/runc/libcontainer/apparmor/apparmor_unsupported.go
generated
vendored
@@ -1,15 +0,0 @@
|
||||
//go:build !linux
|
||||
// +build !linux
|
||||
|
||||
package apparmor
|
||||
|
||||
func isEnabled() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func applyProfile(name string) error {
|
||||
if name != "" {
|
||||
return ErrApparmorNotEnabled
|
||||
}
|
||||
return nil
|
||||
}
|
||||
123
vendor/github.com/opencontainers/runc/libcontainer/capabilities/capabilities.go
generated
vendored
123
vendor/github.com/opencontainers/runc/libcontainer/capabilities/capabilities.go
generated
vendored
@@ -1,123 +0,0 @@
|
||||
//go:build linux
|
||||
// +build linux
|
||||
|
||||
package capabilities
|
||||
|
||||
import (
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/opencontainers/runc/libcontainer/configs"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/syndtr/gocapability/capability"
|
||||
)
|
||||
|
||||
const allCapabilityTypes = capability.CAPS | capability.BOUNDING | capability.AMBIENT
|
||||
|
||||
var (
|
||||
capabilityMap map[string]capability.Cap
|
||||
capTypes = []capability.CapType{
|
||||
capability.BOUNDING,
|
||||
capability.PERMITTED,
|
||||
capability.INHERITABLE,
|
||||
capability.EFFECTIVE,
|
||||
capability.AMBIENT,
|
||||
}
|
||||
)
|
||||
|
||||
func init() {
|
||||
capabilityMap = make(map[string]capability.Cap, capability.CAP_LAST_CAP+1)
|
||||
for _, c := range capability.List() {
|
||||
if c > capability.CAP_LAST_CAP {
|
||||
continue
|
||||
}
|
||||
capabilityMap["CAP_"+strings.ToUpper(c.String())] = c
|
||||
}
|
||||
}
|
||||
|
||||
// KnownCapabilities returns the list of the known capabilities.
|
||||
// Used by `runc features`.
|
||||
func KnownCapabilities() []string {
|
||||
list := capability.List()
|
||||
res := make([]string, len(list))
|
||||
for i, c := range list {
|
||||
res[i] = "CAP_" + strings.ToUpper(c.String())
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
// New creates a new Caps from the given Capabilities config. Unknown Capabilities
|
||||
// or Capabilities that are unavailable in the current environment are ignored,
|
||||
// printing a warning instead.
|
||||
func New(capConfig *configs.Capabilities) (*Caps, error) {
|
||||
var (
|
||||
err error
|
||||
c Caps
|
||||
)
|
||||
|
||||
unknownCaps := make(map[string]struct{})
|
||||
c.caps = map[capability.CapType][]capability.Cap{
|
||||
capability.BOUNDING: capSlice(capConfig.Bounding, unknownCaps),
|
||||
capability.EFFECTIVE: capSlice(capConfig.Effective, unknownCaps),
|
||||
capability.INHERITABLE: capSlice(capConfig.Inheritable, unknownCaps),
|
||||
capability.PERMITTED: capSlice(capConfig.Permitted, unknownCaps),
|
||||
capability.AMBIENT: capSlice(capConfig.Ambient, unknownCaps),
|
||||
}
|
||||
if c.pid, err = capability.NewPid2(0); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = c.pid.Load(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(unknownCaps) > 0 {
|
||||
logrus.Warn("ignoring unknown or unavailable capabilities: ", mapKeys(unknownCaps))
|
||||
}
|
||||
return &c, nil
|
||||
}
|
||||
|
||||
// capSlice converts the slice of capability names in caps, to their numeric
|
||||
// equivalent, and returns them as a slice. Unknown or unavailable capabilities
|
||||
// are not returned, but appended to unknownCaps.
|
||||
func capSlice(caps []string, unknownCaps map[string]struct{}) []capability.Cap {
|
||||
var out []capability.Cap
|
||||
for _, c := range caps {
|
||||
if v, ok := capabilityMap[c]; !ok {
|
||||
unknownCaps[c] = struct{}{}
|
||||
} else {
|
||||
out = append(out, v)
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// mapKeys returns the keys of input in sorted order
|
||||
func mapKeys(input map[string]struct{}) []string {
|
||||
var keys []string
|
||||
for c := range input {
|
||||
keys = append(keys, c)
|
||||
}
|
||||
sort.Strings(keys)
|
||||
return keys
|
||||
}
|
||||
|
||||
// Caps holds the capabilities for a container.
|
||||
type Caps struct {
|
||||
pid capability.Capabilities
|
||||
caps map[capability.CapType][]capability.Cap
|
||||
}
|
||||
|
||||
// ApplyBoundingSet sets the capability bounding set to those specified in the whitelist.
|
||||
func (c *Caps) ApplyBoundingSet() error {
|
||||
c.pid.Clear(capability.BOUNDING)
|
||||
c.pid.Set(capability.BOUNDING, c.caps[capability.BOUNDING]...)
|
||||
return c.pid.Apply(capability.BOUNDING)
|
||||
}
|
||||
|
||||
// Apply sets all the capabilities for the current process in the config.
|
||||
func (c *Caps) ApplyCaps() error {
|
||||
c.pid.Clear(allCapabilityTypes)
|
||||
for _, g := range capTypes {
|
||||
c.pid.Set(g, c.caps[g]...)
|
||||
}
|
||||
return c.pid.Apply(allCapabilityTypes)
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
//go:build !linux
|
||||
// +build !linux
|
||||
|
||||
package capabilities
|
||||
86
vendor/github.com/opencontainers/runc/libcontainer/configs/validate/rootless.go
generated
vendored
86
vendor/github.com/opencontainers/runc/libcontainer/configs/validate/rootless.go
generated
vendored
@@ -1,86 +0,0 @@
|
||||
package validate
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/opencontainers/runc/libcontainer/configs"
|
||||
)
|
||||
|
||||
// rootlessEUID makes sure that the config can be applied when runc
|
||||
// is being executed as a non-root user (euid != 0) in the current user namespace.
|
||||
func (v *ConfigValidator) rootlessEUID(config *configs.Config) error {
|
||||
if !config.RootlessEUID {
|
||||
return nil
|
||||
}
|
||||
if err := rootlessEUIDMappings(config); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := rootlessEUIDMount(config); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// XXX: We currently can't verify the user config at all, because
|
||||
// configs.Config doesn't store the user-related configs. So this
|
||||
// has to be verified by setupUser() in init_linux.go.
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func rootlessEUIDMappings(config *configs.Config) error {
|
||||
if !config.Namespaces.Contains(configs.NEWUSER) {
|
||||
return errors.New("rootless container requires user namespaces")
|
||||
}
|
||||
// We only require mappings if we are not joining another userns.
|
||||
if path := config.Namespaces.PathOf(configs.NEWUSER); path == "" {
|
||||
if len(config.UidMappings) == 0 {
|
||||
return errors.New("rootless containers requires at least one UID mapping")
|
||||
}
|
||||
if len(config.GidMappings) == 0 {
|
||||
return errors.New("rootless containers requires at least one GID mapping")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// mount verifies that the user isn't trying to set up any mounts they don't have
|
||||
// the rights to do. In addition, it makes sure that no mount has a `uid=` or
|
||||
// `gid=` option that doesn't resolve to root.
|
||||
func rootlessEUIDMount(config *configs.Config) error {
|
||||
// XXX: We could whitelist allowed devices at this point, but I'm not
|
||||
// convinced that's a good idea. The kernel is the best arbiter of
|
||||
// access control.
|
||||
|
||||
for _, mount := range config.Mounts {
|
||||
// Check that the options list doesn't contain any uid= or gid= entries
|
||||
// that don't resolve to root.
|
||||
for _, opt := range strings.Split(mount.Data, ",") {
|
||||
if strings.HasPrefix(opt, "uid=") {
|
||||
var uid int
|
||||
n, err := fmt.Sscanf(opt, "uid=%d", &uid)
|
||||
if n != 1 || err != nil {
|
||||
// Ignore unknown mount options.
|
||||
continue
|
||||
}
|
||||
if _, err := config.HostUID(uid); err != nil {
|
||||
return fmt.Errorf("cannot specify uid=%d mount option for rootless container: %w", uid, err)
|
||||
}
|
||||
}
|
||||
|
||||
if strings.HasPrefix(opt, "gid=") {
|
||||
var gid int
|
||||
n, err := fmt.Sscanf(opt, "gid=%d", &gid)
|
||||
if n != 1 || err != nil {
|
||||
// Ignore unknown mount options.
|
||||
continue
|
||||
}
|
||||
if _, err := config.HostGID(gid); err != nil {
|
||||
return fmt.Errorf("cannot specify gid=%d mount option for rootless container: %w", gid, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
306
vendor/github.com/opencontainers/runc/libcontainer/configs/validate/validator.go
generated
vendored
306
vendor/github.com/opencontainers/runc/libcontainer/configs/validate/validator.go
generated
vendored
@@ -1,306 +0,0 @@
|
||||
package validate
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/opencontainers/runc/libcontainer/cgroups"
|
||||
"github.com/opencontainers/runc/libcontainer/configs"
|
||||
"github.com/opencontainers/runc/libcontainer/intelrdt"
|
||||
selinux "github.com/opencontainers/selinux/go-selinux"
|
||||
"github.com/sirupsen/logrus"
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
type Validator interface {
|
||||
Validate(*configs.Config) error
|
||||
}
|
||||
|
||||
func New() Validator {
|
||||
return &ConfigValidator{}
|
||||
}
|
||||
|
||||
type ConfigValidator struct{}
|
||||
|
||||
type check func(config *configs.Config) error
|
||||
|
||||
func (v *ConfigValidator) Validate(config *configs.Config) error {
|
||||
checks := []check{
|
||||
v.cgroups,
|
||||
v.rootfs,
|
||||
v.network,
|
||||
v.hostname,
|
||||
v.security,
|
||||
v.usernamespace,
|
||||
v.cgroupnamespace,
|
||||
v.sysctl,
|
||||
v.intelrdt,
|
||||
v.rootlessEUID,
|
||||
}
|
||||
for _, c := range checks {
|
||||
if err := c(config); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
// Relaxed validation rules for backward compatibility
|
||||
warns := []check{
|
||||
v.mounts, // TODO (runc v1.x.x): make this an error instead of a warning
|
||||
}
|
||||
for _, c := range warns {
|
||||
if err := c(config); err != nil {
|
||||
logrus.WithError(err).Warn("invalid configuration")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// rootfs validates if the rootfs is an absolute path and is not a symlink
|
||||
// to the container's root filesystem.
|
||||
func (v *ConfigValidator) rootfs(config *configs.Config) error {
|
||||
if _, err := os.Stat(config.Rootfs); err != nil {
|
||||
return fmt.Errorf("invalid rootfs: %w", err)
|
||||
}
|
||||
cleaned, err := filepath.Abs(config.Rootfs)
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid rootfs: %w", err)
|
||||
}
|
||||
if cleaned, err = filepath.EvalSymlinks(cleaned); err != nil {
|
||||
return fmt.Errorf("invalid rootfs: %w", err)
|
||||
}
|
||||
if filepath.Clean(config.Rootfs) != cleaned {
|
||||
return errors.New("invalid rootfs: not an absolute path, or a symlink")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (v *ConfigValidator) network(config *configs.Config) error {
|
||||
if !config.Namespaces.Contains(configs.NEWNET) {
|
||||
if len(config.Networks) > 0 || len(config.Routes) > 0 {
|
||||
return errors.New("unable to apply network settings without a private NET namespace")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (v *ConfigValidator) hostname(config *configs.Config) error {
|
||||
if config.Hostname != "" && !config.Namespaces.Contains(configs.NEWUTS) {
|
||||
return errors.New("unable to set hostname without a private UTS namespace")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (v *ConfigValidator) security(config *configs.Config) error {
|
||||
// restrict sys without mount namespace
|
||||
if (len(config.MaskPaths) > 0 || len(config.ReadonlyPaths) > 0) &&
|
||||
!config.Namespaces.Contains(configs.NEWNS) {
|
||||
return errors.New("unable to restrict sys entries without a private MNT namespace")
|
||||
}
|
||||
if config.ProcessLabel != "" && !selinux.GetEnabled() {
|
||||
return errors.New("selinux label is specified in config, but selinux is disabled or not supported")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (v *ConfigValidator) usernamespace(config *configs.Config) error {
|
||||
if config.Namespaces.Contains(configs.NEWUSER) {
|
||||
if _, err := os.Stat("/proc/self/ns/user"); os.IsNotExist(err) {
|
||||
return errors.New("user namespaces aren't enabled in the kernel")
|
||||
}
|
||||
hasPath := config.Namespaces.PathOf(configs.NEWUSER) != ""
|
||||
hasMappings := config.UidMappings != nil || config.GidMappings != nil
|
||||
if !hasPath && !hasMappings {
|
||||
return errors.New("user namespaces enabled, but no namespace path to join nor mappings to apply specified")
|
||||
}
|
||||
// The hasPath && hasMappings validation case is handled in specconv --
|
||||
// we cache the mappings in Config during specconv in the hasPath case,
|
||||
// so we cannot do that validation here.
|
||||
} else {
|
||||
if config.UidMappings != nil || config.GidMappings != nil {
|
||||
return errors.New("user namespace mappings specified, but user namespace isn't enabled in the config")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (v *ConfigValidator) cgroupnamespace(config *configs.Config) error {
|
||||
if config.Namespaces.Contains(configs.NEWCGROUP) {
|
||||
if _, err := os.Stat("/proc/self/ns/cgroup"); os.IsNotExist(err) {
|
||||
return errors.New("cgroup namespaces aren't enabled in the kernel")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// convertSysctlVariableToDotsSeparator can return sysctl variables in dots separator format.
|
||||
// The '/' separator is also accepted in place of a '.'.
|
||||
// Convert the sysctl variables to dots separator format for validation.
|
||||
// More info: sysctl(8), sysctl.d(5).
|
||||
//
|
||||
// For example:
|
||||
// Input sysctl variable "net/ipv4/conf/eno2.100.rp_filter"
|
||||
// will return the converted value "net.ipv4.conf.eno2/100.rp_filter"
|
||||
func convertSysctlVariableToDotsSeparator(val string) string {
|
||||
if val == "" {
|
||||
return val
|
||||
}
|
||||
firstSepIndex := strings.IndexAny(val, "./")
|
||||
if firstSepIndex == -1 || val[firstSepIndex] == '.' {
|
||||
return val
|
||||
}
|
||||
|
||||
f := func(r rune) rune {
|
||||
switch r {
|
||||
case '.':
|
||||
return '/'
|
||||
case '/':
|
||||
return '.'
|
||||
}
|
||||
return r
|
||||
}
|
||||
return strings.Map(f, val)
|
||||
}
|
||||
|
||||
// sysctl validates that the specified sysctl keys are valid or not.
|
||||
// /proc/sys isn't completely namespaced and depending on which namespaces
|
||||
// are specified, a subset of sysctls are permitted.
|
||||
func (v *ConfigValidator) sysctl(config *configs.Config) error {
|
||||
validSysctlMap := map[string]bool{
|
||||
"kernel.msgmax": true,
|
||||
"kernel.msgmnb": true,
|
||||
"kernel.msgmni": true,
|
||||
"kernel.sem": true,
|
||||
"kernel.shmall": true,
|
||||
"kernel.shmmax": true,
|
||||
"kernel.shmmni": true,
|
||||
"kernel.shm_rmid_forced": true,
|
||||
}
|
||||
|
||||
var (
|
||||
netOnce sync.Once
|
||||
hostnet bool
|
||||
hostnetErr error
|
||||
)
|
||||
|
||||
for s := range config.Sysctl {
|
||||
s := convertSysctlVariableToDotsSeparator(s)
|
||||
if validSysctlMap[s] || strings.HasPrefix(s, "fs.mqueue.") {
|
||||
if config.Namespaces.Contains(configs.NEWIPC) {
|
||||
continue
|
||||
} else {
|
||||
return fmt.Errorf("sysctl %q is not allowed in the hosts ipc namespace", s)
|
||||
}
|
||||
}
|
||||
if strings.HasPrefix(s, "net.") {
|
||||
// Is container using host netns?
|
||||
// Here "host" means "current", not "initial".
|
||||
netOnce.Do(func() {
|
||||
if !config.Namespaces.Contains(configs.NEWNET) {
|
||||
hostnet = true
|
||||
return
|
||||
}
|
||||
path := config.Namespaces.PathOf(configs.NEWNET)
|
||||
if path == "" {
|
||||
// own netns, so hostnet = false
|
||||
return
|
||||
}
|
||||
hostnet, hostnetErr = isHostNetNS(path)
|
||||
})
|
||||
if hostnetErr != nil {
|
||||
return fmt.Errorf("invalid netns path: %w", hostnetErr)
|
||||
}
|
||||
if hostnet {
|
||||
return fmt.Errorf("sysctl %q not allowed in host network namespace", s)
|
||||
}
|
||||
continue
|
||||
}
|
||||
if config.Namespaces.Contains(configs.NEWUTS) {
|
||||
switch s {
|
||||
case "kernel.domainname":
|
||||
// This is namespaced and there's no explicit OCI field for it.
|
||||
continue
|
||||
case "kernel.hostname":
|
||||
// This is namespaced but there's a conflicting (dedicated) OCI field for it.
|
||||
return fmt.Errorf("sysctl %q is not allowed as it conflicts with the OCI %q field", s, "hostname")
|
||||
}
|
||||
}
|
||||
return fmt.Errorf("sysctl %q is not in a separate kernel namespace", s)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (v *ConfigValidator) intelrdt(config *configs.Config) error {
|
||||
if config.IntelRdt != nil {
|
||||
if config.IntelRdt.ClosID == "." || config.IntelRdt.ClosID == ".." || strings.Contains(config.IntelRdt.ClosID, "/") {
|
||||
return fmt.Errorf("invalid intelRdt.ClosID %q", config.IntelRdt.ClosID)
|
||||
}
|
||||
|
||||
if !intelrdt.IsCATEnabled() && config.IntelRdt.L3CacheSchema != "" {
|
||||
return errors.New("intelRdt.l3CacheSchema is specified in config, but Intel RDT/CAT is not enabled")
|
||||
}
|
||||
if !intelrdt.IsMBAEnabled() && config.IntelRdt.MemBwSchema != "" {
|
||||
return errors.New("intelRdt.memBwSchema is specified in config, but Intel RDT/MBA is not enabled")
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (v *ConfigValidator) cgroups(config *configs.Config) error {
|
||||
c := config.Cgroups
|
||||
if c == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if (c.Name != "" || c.Parent != "") && c.Path != "" {
|
||||
return fmt.Errorf("cgroup: either Path or Name and Parent should be used, got %+v", c)
|
||||
}
|
||||
|
||||
r := c.Resources
|
||||
if r == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if !cgroups.IsCgroup2UnifiedMode() && r.Unified != nil {
|
||||
return cgroups.ErrV1NoUnified
|
||||
}
|
||||
|
||||
if cgroups.IsCgroup2UnifiedMode() {
|
||||
_, err := cgroups.ConvertMemorySwapToCgroupV2Value(r.MemorySwap, r.Memory)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (v *ConfigValidator) mounts(config *configs.Config) error {
|
||||
for _, m := range config.Mounts {
|
||||
if !filepath.IsAbs(m.Destination) {
|
||||
return fmt.Errorf("invalid mount %+v: mount destination not absolute", m)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func isHostNetNS(path string) (bool, error) {
|
||||
const currentProcessNetns = "/proc/self/ns/net"
|
||||
|
||||
var st1, st2 unix.Stat_t
|
||||
|
||||
if err := unix.Stat(currentProcessNetns, &st1); err != nil {
|
||||
return false, &os.PathError{Op: "stat", Path: currentProcessNetns, Err: err}
|
||||
}
|
||||
if err := unix.Stat(path, &st2); err != nil {
|
||||
return false, &os.PathError{Op: "stat", Path: path, Err: err}
|
||||
}
|
||||
|
||||
return (st1.Dev == st2.Dev) && (st1.Ino == st2.Ino), nil
|
||||
}
|
||||
41
vendor/github.com/opencontainers/runc/libcontainer/console_linux.go
generated
vendored
41
vendor/github.com/opencontainers/runc/libcontainer/console_linux.go
generated
vendored
@@ -1,41 +0,0 @@
|
||||
package libcontainer
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
// mount initializes the console inside the rootfs mounting with the specified mount label
|
||||
// and applying the correct ownership of the console.
|
||||
func mountConsole(slavePath string) error {
|
||||
oldMask := unix.Umask(0o000)
|
||||
defer unix.Umask(oldMask)
|
||||
f, err := os.Create("/dev/console")
|
||||
if err != nil && !os.IsExist(err) {
|
||||
return err
|
||||
}
|
||||
if f != nil {
|
||||
f.Close()
|
||||
}
|
||||
return mount(slavePath, "/dev/console", "", "bind", unix.MS_BIND, "")
|
||||
}
|
||||
|
||||
// dupStdio opens the slavePath for the console and dups the fds to the current
|
||||
// processes stdio, fd 0,1,2.
|
||||
func dupStdio(slavePath string) error {
|
||||
fd, err := unix.Open(slavePath, unix.O_RDWR, 0)
|
||||
if err != nil {
|
||||
return &os.PathError{
|
||||
Op: "open",
|
||||
Path: slavePath,
|
||||
Err: err,
|
||||
}
|
||||
}
|
||||
for _, i := range []int{0, 1, 2} {
|
||||
if err := unix.Dup3(fd, i, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
130
vendor/github.com/opencontainers/runc/libcontainer/container.go
generated
vendored
130
vendor/github.com/opencontainers/runc/libcontainer/container.go
generated
vendored
@@ -1,130 +0,0 @@
|
||||
// Package libcontainer provides a native Go implementation for creating containers
|
||||
// with namespaces, cgroups, capabilities, and filesystem access controls.
|
||||
// It allows you to manage the lifecycle of the container performing additional operations
|
||||
// after the container is created.
|
||||
package libcontainer
|
||||
|
||||
import (
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/opencontainers/runc/libcontainer/configs"
|
||||
"github.com/opencontainers/runtime-spec/specs-go"
|
||||
)
|
||||
|
||||
// Status is the status of a container.
|
||||
type Status int
|
||||
|
||||
const (
|
||||
// Created is the status that denotes the container exists but has not been run yet.
|
||||
Created Status = iota
|
||||
// Running is the status that denotes the container exists and is running.
|
||||
Running
|
||||
// Pausing is the status that denotes the container exists, it is in the process of being paused.
|
||||
Pausing
|
||||
// Paused is the status that denotes the container exists, but all its processes are paused.
|
||||
Paused
|
||||
// Stopped is the status that denotes the container does not have a created or running process.
|
||||
Stopped
|
||||
)
|
||||
|
||||
func (s Status) String() string {
|
||||
switch s {
|
||||
case Created:
|
||||
return "created"
|
||||
case Running:
|
||||
return "running"
|
||||
case Pausing:
|
||||
return "pausing"
|
||||
case Paused:
|
||||
return "paused"
|
||||
case Stopped:
|
||||
return "stopped"
|
||||
default:
|
||||
return "unknown"
|
||||
}
|
||||
}
|
||||
|
||||
// BaseState represents the platform agnostic pieces relating to a
|
||||
// running container's state
|
||||
type BaseState struct {
|
||||
// ID is the container ID.
|
||||
ID string `json:"id"`
|
||||
|
||||
// InitProcessPid is the init process id in the parent namespace.
|
||||
InitProcessPid int `json:"init_process_pid"`
|
||||
|
||||
// InitProcessStartTime is the init process start time in clock cycles since boot time.
|
||||
InitProcessStartTime uint64 `json:"init_process_start"`
|
||||
|
||||
// Created is the unix timestamp for the creation time of the container in UTC
|
||||
Created time.Time `json:"created"`
|
||||
|
||||
// Config is the container's configuration.
|
||||
Config configs.Config `json:"config"`
|
||||
}
|
||||
|
||||
// BaseContainer is a libcontainer container object.
|
||||
//
|
||||
// Each container is thread-safe within the same process. Since a container can
|
||||
// be destroyed by a separate process, any function may return that the container
|
||||
// was not found. BaseContainer includes methods that are platform agnostic.
|
||||
type BaseContainer interface {
|
||||
// Returns the ID of the container
|
||||
ID() string
|
||||
|
||||
// Returns the current status of the container.
|
||||
Status() (Status, error)
|
||||
|
||||
// State returns the current container's state information.
|
||||
State() (*State, error)
|
||||
|
||||
// OCIState returns the current container's state information.
|
||||
OCIState() (*specs.State, error)
|
||||
|
||||
// Returns the current config of the container.
|
||||
Config() configs.Config
|
||||
|
||||
// Returns the PIDs inside this container. The PIDs are in the namespace of the calling process.
|
||||
//
|
||||
// Some of the returned PIDs may no longer refer to processes in the Container, unless
|
||||
// the Container state is PAUSED in which case every PID in the slice is valid.
|
||||
Processes() ([]int, error)
|
||||
|
||||
// Returns statistics for the container.
|
||||
Stats() (*Stats, error)
|
||||
|
||||
// Set resources of container as configured
|
||||
//
|
||||
// We can use this to change resources when containers are running.
|
||||
//
|
||||
Set(config configs.Config) error
|
||||
|
||||
// Start a process inside the container. Returns error if process fails to
|
||||
// start. You can track process lifecycle with passed Process structure.
|
||||
Start(process *Process) (err error)
|
||||
|
||||
// Run immediately starts the process inside the container. Returns error if process
|
||||
// fails to start. It does not block waiting for the exec fifo after start returns but
|
||||
// opens the fifo after start returns.
|
||||
Run(process *Process) (err error)
|
||||
|
||||
// Destroys the container, if its in a valid state, after killing any
|
||||
// remaining running processes.
|
||||
//
|
||||
// Any event registrations are removed before the container is destroyed.
|
||||
// No error is returned if the container is already destroyed.
|
||||
//
|
||||
// Running containers must first be stopped using Signal(..).
|
||||
// Paused containers must first be resumed using Resume(..).
|
||||
Destroy() error
|
||||
|
||||
// Signal sends the provided signal code to the container's initial process.
|
||||
//
|
||||
// If all is specified the signal is sent to all processes in the container
|
||||
// including the initial process.
|
||||
Signal(s os.Signal, all bool) error
|
||||
|
||||
// Exec signals the container to exec the users process at the end of the init.
|
||||
Exec() error
|
||||
}
|
||||
2267
vendor/github.com/opencontainers/runc/libcontainer/container_linux.go
generated
vendored
2267
vendor/github.com/opencontainers/runc/libcontainer/container_linux.go
generated
vendored
File diff suppressed because it is too large
Load Diff
34
vendor/github.com/opencontainers/runc/libcontainer/criu_opts_linux.go
generated
vendored
34
vendor/github.com/opencontainers/runc/libcontainer/criu_opts_linux.go
generated
vendored
@@ -1,34 +0,0 @@
|
||||
package libcontainer
|
||||
|
||||
import criu "github.com/checkpoint-restore/go-criu/v5/rpc"
|
||||
|
||||
type CriuPageServerInfo struct {
|
||||
Address string // IP address of CRIU page server
|
||||
Port int32 // port number of CRIU page server
|
||||
}
|
||||
|
||||
type VethPairName struct {
|
||||
ContainerInterfaceName string
|
||||
HostInterfaceName string
|
||||
}
|
||||
|
||||
type CriuOpts struct {
|
||||
ImagesDirectory string // directory for storing image files
|
||||
WorkDirectory string // directory to cd and write logs/pidfiles/stats to
|
||||
ParentImage string // directory for storing parent image files in pre-dump and dump
|
||||
LeaveRunning bool // leave container in running state after checkpoint
|
||||
TcpEstablished bool // checkpoint/restore established TCP connections
|
||||
ExternalUnixConnections bool // allow external unix connections
|
||||
ShellJob bool // allow to dump and restore shell jobs
|
||||
FileLocks bool // handle file locks, for safety
|
||||
PreDump bool // call criu predump to perform iterative checkpoint
|
||||
PageServer CriuPageServerInfo // allow to dump to criu page server
|
||||
VethPairs []VethPairName // pass the veth to criu when restore
|
||||
ManageCgroupsMode criu.CriuCgMode // dump or restore cgroup mode
|
||||
EmptyNs uint32 // don't c/r properties for namespace from this mask
|
||||
AutoDedup bool // auto deduplication for incremental dumps
|
||||
LazyPages bool // restore memory pages lazily using userfaultfd
|
||||
StatusFd int // fd for feedback when lazy server is ready
|
||||
LsmProfile string // LSM profile used to restore the container
|
||||
LsmMountContext string // LSM mount context value to use during restore
|
||||
}
|
||||
17
vendor/github.com/opencontainers/runc/libcontainer/eaccess_go119.go
generated
vendored
17
vendor/github.com/opencontainers/runc/libcontainer/eaccess_go119.go
generated
vendored
@@ -1,17 +0,0 @@
|
||||
//go:build !go1.20
|
||||
// +build !go1.20
|
||||
|
||||
package libcontainer
|
||||
|
||||
import "golang.org/x/sys/unix"
|
||||
|
||||
func eaccess(path string) error {
|
||||
// This check is similar to access(2) with X_OK except for
|
||||
// setuid/setgid binaries where it checks against the effective
|
||||
// (rather than real) uid and gid. It is not needed in go 1.20
|
||||
// and beyond and will be removed later.
|
||||
|
||||
// Relies on code added in https://go-review.googlesource.com/c/sys/+/468877
|
||||
// and older CLs linked from there.
|
||||
return unix.Faccessat(unix.AT_FDCWD, path, unix.X_OK, unix.AT_EACCESS)
|
||||
}
|
||||
10
vendor/github.com/opencontainers/runc/libcontainer/eaccess_stub.go
generated
vendored
10
vendor/github.com/opencontainers/runc/libcontainer/eaccess_stub.go
generated
vendored
@@ -1,10 +0,0 @@
|
||||
//go:build go1.20
|
||||
|
||||
package libcontainer
|
||||
|
||||
func eaccess(path string) error {
|
||||
// Not needed in Go 1.20+ as the functionality is already in there
|
||||
// (added by https://go.dev/cl/416115, https://go.dev/cl/414824,
|
||||
// and fixed in Go 1.20.2 by https://go.dev/cl/469956).
|
||||
return nil
|
||||
}
|
||||
13
vendor/github.com/opencontainers/runc/libcontainer/error.go
generated
vendored
13
vendor/github.com/opencontainers/runc/libcontainer/error.go
generated
vendored
@@ -1,13 +0,0 @@
|
||||
package libcontainer
|
||||
|
||||
import "errors"
|
||||
|
||||
var (
|
||||
ErrExist = errors.New("container with given ID already exists")
|
||||
ErrInvalidID = errors.New("invalid container ID format")
|
||||
ErrNotExist = errors.New("container does not exist")
|
||||
ErrPaused = errors.New("container paused")
|
||||
ErrRunning = errors.New("container still running")
|
||||
ErrNotRunning = errors.New("container not running")
|
||||
ErrNotPaused = errors.New("container not paused")
|
||||
)
|
||||
30
vendor/github.com/opencontainers/runc/libcontainer/factory.go
generated
vendored
30
vendor/github.com/opencontainers/runc/libcontainer/factory.go
generated
vendored
@@ -1,30 +0,0 @@
|
||||
package libcontainer
|
||||
|
||||
import (
|
||||
"github.com/opencontainers/runc/libcontainer/configs"
|
||||
)
|
||||
|
||||
type Factory interface {
|
||||
// Creates a new container with the given id and starts the initial process inside it.
|
||||
// id must be a string containing only letters, digits and underscores and must contain
|
||||
// between 1 and 1024 characters, inclusive.
|
||||
//
|
||||
// The id must not already be in use by an existing container. Containers created using
|
||||
// a factory with the same path (and filesystem) must have distinct ids.
|
||||
//
|
||||
// Returns the new container with a running process.
|
||||
//
|
||||
// On error, any partially created container parts are cleaned up (the operation is atomic).
|
||||
Create(id string, config *configs.Config) (Container, error)
|
||||
|
||||
// Load takes an ID for an existing container and returns the container information
|
||||
// from the state. This presents a read only view of the container.
|
||||
Load(id string) (Container, error)
|
||||
|
||||
// StartInitialization is an internal API to libcontainer used during the reexec of the
|
||||
// container.
|
||||
StartInitialization() error
|
||||
|
||||
// Type returns info string about factory type (e.g. lxc, libcontainer...)
|
||||
Type() string
|
||||
}
|
||||
402
vendor/github.com/opencontainers/runc/libcontainer/factory_linux.go
generated
vendored
402
vendor/github.com/opencontainers/runc/libcontainer/factory_linux.go
generated
vendored
@@ -1,402 +0,0 @@
|
||||
package libcontainer
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"runtime/debug"
|
||||
"strconv"
|
||||
|
||||
securejoin "github.com/cyphar/filepath-securejoin"
|
||||
"github.com/moby/sys/mountinfo"
|
||||
"golang.org/x/sys/unix"
|
||||
|
||||
"github.com/opencontainers/runc/libcontainer/cgroups/manager"
|
||||
"github.com/opencontainers/runc/libcontainer/configs"
|
||||
"github.com/opencontainers/runc/libcontainer/configs/validate"
|
||||
"github.com/opencontainers/runc/libcontainer/intelrdt"
|
||||
"github.com/opencontainers/runc/libcontainer/utils"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
const (
|
||||
stateFilename = "state.json"
|
||||
execFifoFilename = "exec.fifo"
|
||||
)
|
||||
|
||||
var idRegex = regexp.MustCompile(`^[\w+-\.]+$`)
|
||||
|
||||
// InitArgs returns an options func to configure a LinuxFactory with the
|
||||
// provided init binary path and arguments.
|
||||
func InitArgs(args ...string) func(*LinuxFactory) error {
|
||||
return func(l *LinuxFactory) (err error) {
|
||||
if len(args) > 0 {
|
||||
// Resolve relative paths to ensure that its available
|
||||
// after directory changes.
|
||||
if args[0], err = filepath.Abs(args[0]); err != nil {
|
||||
// The only error returned from filepath.Abs is
|
||||
// the one from os.Getwd, i.e. a system error.
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
l.InitArgs = args
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// TmpfsRoot is an option func to mount LinuxFactory.Root to tmpfs.
|
||||
func TmpfsRoot(l *LinuxFactory) error {
|
||||
mounted, err := mountinfo.Mounted(l.Root)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !mounted {
|
||||
if err := mount("tmpfs", l.Root, "", "tmpfs", 0, ""); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// CriuPath returns an option func to configure a LinuxFactory with the
|
||||
// provided criupath
|
||||
func CriuPath(criupath string) func(*LinuxFactory) error {
|
||||
return func(l *LinuxFactory) error {
|
||||
l.CriuPath = criupath
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// New returns a linux based container factory based in the root directory and
|
||||
// configures the factory with the provided option funcs.
|
||||
func New(root string, options ...func(*LinuxFactory) error) (Factory, error) {
|
||||
if root != "" {
|
||||
if err := os.MkdirAll(root, 0o700); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
l := &LinuxFactory{
|
||||
Root: root,
|
||||
InitPath: "/proc/self/exe",
|
||||
InitArgs: []string{os.Args[0], "init"},
|
||||
Validator: validate.New(),
|
||||
CriuPath: "criu",
|
||||
}
|
||||
|
||||
for _, opt := range options {
|
||||
if opt == nil {
|
||||
continue
|
||||
}
|
||||
if err := opt(l); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return l, nil
|
||||
}
|
||||
|
||||
// LinuxFactory implements the default factory interface for linux based systems.
|
||||
type LinuxFactory struct {
|
||||
// Root directory for the factory to store state.
|
||||
Root string
|
||||
|
||||
// InitPath is the path for calling the init responsibilities for spawning
|
||||
// a container.
|
||||
InitPath string
|
||||
|
||||
// InitArgs are arguments for calling the init responsibilities for spawning
|
||||
// a container.
|
||||
InitArgs []string
|
||||
|
||||
// CriuPath is the path to the criu binary used for checkpoint and restore of
|
||||
// containers.
|
||||
CriuPath string
|
||||
|
||||
// New{u,g}idmapPath is the path to the binaries used for mapping with
|
||||
// rootless containers.
|
||||
NewuidmapPath string
|
||||
NewgidmapPath string
|
||||
|
||||
// Validator provides validation to container configurations.
|
||||
Validator validate.Validator
|
||||
}
|
||||
|
||||
func (l *LinuxFactory) Create(id string, config *configs.Config) (Container, error) {
|
||||
if l.Root == "" {
|
||||
return nil, errors.New("root not set")
|
||||
}
|
||||
if err := l.validateID(id); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := l.Validator.Validate(config); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
containerRoot, err := securejoin.SecureJoin(l.Root, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if _, err := os.Stat(containerRoot); err == nil {
|
||||
return nil, ErrExist
|
||||
} else if !os.IsNotExist(err) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
cm, err := manager.New(config.Cgroups)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Check that cgroup does not exist or empty (no processes).
|
||||
// Note for cgroup v1 this check is not thorough, as there are multiple
|
||||
// separate hierarchies, while both Exists() and GetAllPids() only use
|
||||
// one for "devices" controller (assuming others are the same, which is
|
||||
// probably true in almost all scenarios). Checking all the hierarchies
|
||||
// would be too expensive.
|
||||
if cm.Exists() {
|
||||
pids, err := cm.GetAllPids()
|
||||
// Reading PIDs can race with cgroups removal, so ignore ENOENT and ENODEV.
|
||||
if err != nil && !errors.Is(err, os.ErrNotExist) && !errors.Is(err, unix.ENODEV) {
|
||||
return nil, fmt.Errorf("unable to get cgroup PIDs: %w", err)
|
||||
}
|
||||
if len(pids) != 0 {
|
||||
if config.Cgroups.Systemd {
|
||||
// systemd cgroup driver can't add a pid to an
|
||||
// existing systemd unit and will return an
|
||||
// error anyway, so let's error out early.
|
||||
return nil, fmt.Errorf("container's cgroup is not empty: %d process(es) found", len(pids))
|
||||
}
|
||||
// TODO: return an error.
|
||||
logrus.Warnf("container's cgroup is not empty: %d process(es) found", len(pids))
|
||||
logrus.Warn("DEPRECATED: running container in a non-empty cgroup won't be supported in runc 1.2; https://github.com/opencontainers/runc/issues/3132")
|
||||
}
|
||||
}
|
||||
|
||||
// Check that cgroup is not frozen. Do not use Exists() here
|
||||
// since in cgroup v1 it only checks "devices" controller.
|
||||
st, err := cm.GetFreezerState()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to get cgroup freezer state: %w", err)
|
||||
}
|
||||
if st == configs.Frozen {
|
||||
return nil, errors.New("container's cgroup unexpectedly frozen")
|
||||
}
|
||||
|
||||
if err := os.MkdirAll(containerRoot, 0o711); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := os.Chown(containerRoot, unix.Geteuid(), unix.Getegid()); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
c := &linuxContainer{
|
||||
id: id,
|
||||
root: containerRoot,
|
||||
config: config,
|
||||
initPath: l.InitPath,
|
||||
initArgs: l.InitArgs,
|
||||
criuPath: l.CriuPath,
|
||||
newuidmapPath: l.NewuidmapPath,
|
||||
newgidmapPath: l.NewgidmapPath,
|
||||
cgroupManager: cm,
|
||||
intelRdtManager: intelrdt.NewManager(config, id, ""),
|
||||
}
|
||||
c.state = &stoppedState{c: c}
|
||||
return c, nil
|
||||
}
|
||||
|
||||
func (l *LinuxFactory) Load(id string) (Container, error) {
|
||||
if l.Root == "" {
|
||||
return nil, errors.New("root not set")
|
||||
}
|
||||
// when load, we need to check id is valid or not.
|
||||
if err := l.validateID(id); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
containerRoot, err := securejoin.SecureJoin(l.Root, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
state, err := l.loadState(containerRoot)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
r := &nonChildProcess{
|
||||
processPid: state.InitProcessPid,
|
||||
processStartTime: state.InitProcessStartTime,
|
||||
fds: state.ExternalDescriptors,
|
||||
}
|
||||
cm, err := manager.NewWithPaths(state.Config.Cgroups, state.CgroupPaths)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
c := &linuxContainer{
|
||||
initProcess: r,
|
||||
initProcessStartTime: state.InitProcessStartTime,
|
||||
id: id,
|
||||
config: &state.Config,
|
||||
initPath: l.InitPath,
|
||||
initArgs: l.InitArgs,
|
||||
criuPath: l.CriuPath,
|
||||
newuidmapPath: l.NewuidmapPath,
|
||||
newgidmapPath: l.NewgidmapPath,
|
||||
cgroupManager: cm,
|
||||
intelRdtManager: intelrdt.NewManager(&state.Config, id, state.IntelRdtPath),
|
||||
root: containerRoot,
|
||||
created: state.Created,
|
||||
}
|
||||
c.state = &loadedState{c: c}
|
||||
if err := c.refreshState(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return c, nil
|
||||
}
|
||||
|
||||
func (l *LinuxFactory) Type() string {
|
||||
return "libcontainer"
|
||||
}
|
||||
|
||||
// StartInitialization loads a container by opening the pipe fd from the parent to read the configuration and state
|
||||
// This is a low level implementation detail of the reexec and should not be consumed externally
|
||||
func (l *LinuxFactory) StartInitialization() (err error) {
|
||||
// Get the INITPIPE.
|
||||
envInitPipe := os.Getenv("_LIBCONTAINER_INITPIPE")
|
||||
pipefd, err := strconv.Atoi(envInitPipe)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("unable to convert _LIBCONTAINER_INITPIPE: %w", err)
|
||||
logrus.Error(err)
|
||||
return err
|
||||
}
|
||||
pipe := os.NewFile(uintptr(pipefd), "pipe")
|
||||
defer pipe.Close()
|
||||
|
||||
defer func() {
|
||||
// We have an error during the initialization of the container's init,
|
||||
// send it back to the parent process in the form of an initError.
|
||||
if werr := writeSync(pipe, procError); werr != nil {
|
||||
fmt.Fprintln(os.Stderr, err)
|
||||
return
|
||||
}
|
||||
if werr := utils.WriteJSON(pipe, &initError{Message: err.Error()}); werr != nil {
|
||||
fmt.Fprintln(os.Stderr, err)
|
||||
return
|
||||
}
|
||||
}()
|
||||
|
||||
// Only init processes have FIFOFD.
|
||||
fifofd := -1
|
||||
envInitType := os.Getenv("_LIBCONTAINER_INITTYPE")
|
||||
it := initType(envInitType)
|
||||
if it == initStandard {
|
||||
envFifoFd := os.Getenv("_LIBCONTAINER_FIFOFD")
|
||||
if fifofd, err = strconv.Atoi(envFifoFd); err != nil {
|
||||
return fmt.Errorf("unable to convert _LIBCONTAINER_FIFOFD: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
var consoleSocket *os.File
|
||||
if envConsole := os.Getenv("_LIBCONTAINER_CONSOLE"); envConsole != "" {
|
||||
console, err := strconv.Atoi(envConsole)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to convert _LIBCONTAINER_CONSOLE: %w", err)
|
||||
}
|
||||
consoleSocket = os.NewFile(uintptr(console), "console-socket")
|
||||
defer consoleSocket.Close()
|
||||
}
|
||||
|
||||
logPipeFdStr := os.Getenv("_LIBCONTAINER_LOGPIPE")
|
||||
logPipeFd, err := strconv.Atoi(logPipeFdStr)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to convert _LIBCONTAINER_LOGPIPE: %w", err)
|
||||
}
|
||||
|
||||
// Get mount files (O_PATH).
|
||||
mountFds, err := parseMountFds()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// clear the current process's environment to clean any libcontainer
|
||||
// specific env vars.
|
||||
os.Clearenv()
|
||||
|
||||
defer func() {
|
||||
if e := recover(); e != nil {
|
||||
if ee, ok := e.(error); ok {
|
||||
err = fmt.Errorf("panic from initialization: %w, %s", ee, debug.Stack())
|
||||
} else {
|
||||
err = fmt.Errorf("panic from initialization: %v, %s", e, debug.Stack())
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
i, err := newContainerInit(it, pipe, consoleSocket, fifofd, logPipeFd, mountFds)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// If Init succeeds, syscall.Exec will not return, hence none of the defers will be called.
|
||||
return i.Init()
|
||||
}
|
||||
|
||||
func (l *LinuxFactory) loadState(root string) (*State, error) {
|
||||
stateFilePath, err := securejoin.SecureJoin(root, stateFilename)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
f, err := os.Open(stateFilePath)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
return nil, ErrNotExist
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
defer f.Close()
|
||||
var state *State
|
||||
if err := json.NewDecoder(f).Decode(&state); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return state, nil
|
||||
}
|
||||
|
||||
func (l *LinuxFactory) validateID(id string) error {
|
||||
if !idRegex.MatchString(id) || string(os.PathSeparator)+id != utils.CleanPath(string(os.PathSeparator)+id) {
|
||||
return ErrInvalidID
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// NewuidmapPath returns an option func to configure a LinuxFactory with the
|
||||
// provided ..
|
||||
func NewuidmapPath(newuidmapPath string) func(*LinuxFactory) error {
|
||||
return func(l *LinuxFactory) error {
|
||||
l.NewuidmapPath = newuidmapPath
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// NewgidmapPath returns an option func to configure a LinuxFactory with the
|
||||
// provided ..
|
||||
func NewgidmapPath(newgidmapPath string) func(*LinuxFactory) error {
|
||||
return func(l *LinuxFactory) error {
|
||||
l.NewgidmapPath = newgidmapPath
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func parseMountFds() ([]int, error) {
|
||||
fdsJson := os.Getenv("_LIBCONTAINER_MOUNT_FDS")
|
||||
if fdsJson == "" {
|
||||
// Always return the nil slice if no fd is present.
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
var mountFds []int
|
||||
if err := json.Unmarshal([]byte(fdsJson), &mountFds); err != nil {
|
||||
return nil, fmt.Errorf("Error unmarshalling _LIBCONTAINER_MOUNT_FDS: %w", err)
|
||||
}
|
||||
|
||||
return mountFds, nil
|
||||
}
|
||||
641
vendor/github.com/opencontainers/runc/libcontainer/init_linux.go
generated
vendored
641
vendor/github.com/opencontainers/runc/libcontainer/init_linux.go
generated
vendored
@@ -1,641 +0,0 @@
|
||||
package libcontainer
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
|
||||
"github.com/containerd/console"
|
||||
"github.com/opencontainers/runtime-spec/specs-go"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/vishvananda/netlink"
|
||||
"golang.org/x/sys/unix"
|
||||
|
||||
"github.com/opencontainers/runc/libcontainer/capabilities"
|
||||
"github.com/opencontainers/runc/libcontainer/cgroups"
|
||||
"github.com/opencontainers/runc/libcontainer/configs"
|
||||
"github.com/opencontainers/runc/libcontainer/system"
|
||||
"github.com/opencontainers/runc/libcontainer/user"
|
||||
"github.com/opencontainers/runc/libcontainer/utils"
|
||||
)
|
||||
|
||||
type initType string
|
||||
|
||||
const (
|
||||
initSetns initType = "setns"
|
||||
initStandard initType = "standard"
|
||||
)
|
||||
|
||||
type pid struct {
|
||||
Pid int `json:"stage2_pid"`
|
||||
PidFirstChild int `json:"stage1_pid"`
|
||||
}
|
||||
|
||||
// network is an internal struct used to setup container networks.
|
||||
type network struct {
|
||||
configs.Network
|
||||
|
||||
// TempVethPeerName is a unique temporary veth peer name that was placed into
|
||||
// the container's namespace.
|
||||
TempVethPeerName string `json:"temp_veth_peer_name"`
|
||||
}
|
||||
|
||||
// initConfig is used for transferring parameters from Exec() to Init()
|
||||
type initConfig struct {
|
||||
Args []string `json:"args"`
|
||||
Env []string `json:"env"`
|
||||
Cwd string `json:"cwd"`
|
||||
Capabilities *configs.Capabilities `json:"capabilities"`
|
||||
ProcessLabel string `json:"process_label"`
|
||||
AppArmorProfile string `json:"apparmor_profile"`
|
||||
NoNewPrivileges bool `json:"no_new_privileges"`
|
||||
User string `json:"user"`
|
||||
AdditionalGroups []string `json:"additional_groups"`
|
||||
Config *configs.Config `json:"config"`
|
||||
Networks []*network `json:"network"`
|
||||
PassedFilesCount int `json:"passed_files_count"`
|
||||
ContainerId string `json:"containerid"`
|
||||
Rlimits []configs.Rlimit `json:"rlimits"`
|
||||
CreateConsole bool `json:"create_console"`
|
||||
ConsoleWidth uint16 `json:"console_width"`
|
||||
ConsoleHeight uint16 `json:"console_height"`
|
||||
RootlessEUID bool `json:"rootless_euid,omitempty"`
|
||||
RootlessCgroups bool `json:"rootless_cgroups,omitempty"`
|
||||
SpecState *specs.State `json:"spec_state,omitempty"`
|
||||
Cgroup2Path string `json:"cgroup2_path,omitempty"`
|
||||
}
|
||||
|
||||
type initer interface {
|
||||
Init() error
|
||||
}
|
||||
|
||||
func newContainerInit(t initType, pipe *os.File, consoleSocket *os.File, fifoFd, logFd int, mountFds []int) (initer, error) {
|
||||
var config *initConfig
|
||||
if err := json.NewDecoder(pipe).Decode(&config); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := populateProcessEnvironment(config.Env); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Clean the RLIMIT_NOFILE cache in go runtime.
|
||||
// Issue: https://github.com/opencontainers/runc/issues/4195
|
||||
maybeClearRlimitNofileCache(config.Rlimits)
|
||||
|
||||
switch t {
|
||||
case initSetns:
|
||||
// mountFds must be nil in this case. We don't mount while doing runc exec.
|
||||
if mountFds != nil {
|
||||
return nil, errors.New("mountFds must be nil. Can't mount while doing runc exec.")
|
||||
}
|
||||
|
||||
return &linuxSetnsInit{
|
||||
pipe: pipe,
|
||||
consoleSocket: consoleSocket,
|
||||
config: config,
|
||||
logFd: logFd,
|
||||
}, nil
|
||||
case initStandard:
|
||||
return &linuxStandardInit{
|
||||
pipe: pipe,
|
||||
consoleSocket: consoleSocket,
|
||||
parentPid: unix.Getppid(),
|
||||
config: config,
|
||||
fifoFd: fifoFd,
|
||||
logFd: logFd,
|
||||
mountFds: mountFds,
|
||||
}, nil
|
||||
}
|
||||
return nil, fmt.Errorf("unknown init type %q", t)
|
||||
}
|
||||
|
||||
// populateProcessEnvironment loads the provided environment variables into the
|
||||
// current processes's environment.
|
||||
func populateProcessEnvironment(env []string) error {
|
||||
for _, pair := range env {
|
||||
p := strings.SplitN(pair, "=", 2)
|
||||
if len(p) < 2 {
|
||||
return errors.New("invalid environment variable: missing '='")
|
||||
}
|
||||
name, val := p[0], p[1]
|
||||
if name == "" {
|
||||
return errors.New("invalid environment variable: name cannot be empty")
|
||||
}
|
||||
if strings.IndexByte(name, 0) >= 0 {
|
||||
return fmt.Errorf("invalid environment variable %q: name contains nul byte (\\x00)", name)
|
||||
}
|
||||
if strings.IndexByte(val, 0) >= 0 {
|
||||
return fmt.Errorf("invalid environment variable %q: value contains nul byte (\\x00)", name)
|
||||
}
|
||||
if err := os.Setenv(name, val); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// verifyCwd ensures that the current directory is actually inside the mount
|
||||
// namespace root of the current process.
|
||||
func verifyCwd() error {
|
||||
// getcwd(2) on Linux detects if cwd is outside of the rootfs of the
|
||||
// current mount namespace root, and in that case prefixes "(unreachable)"
|
||||
// to the returned string. glibc's getcwd(3) and Go's Getwd() both detect
|
||||
// when this happens and return ENOENT rather than returning a non-absolute
|
||||
// path. In both cases we can therefore easily detect if we have an invalid
|
||||
// cwd by checking the return value of getcwd(3). See getcwd(3) for more
|
||||
// details, and CVE-2024-21626 for the security issue that motivated this
|
||||
// check.
|
||||
//
|
||||
// We have to use unix.Getwd() here because os.Getwd() has a workaround for
|
||||
// $PWD which involves doing stat(.), which can fail if the current
|
||||
// directory is inaccessible to the container process.
|
||||
if wd, err := unix.Getwd(); errors.Is(err, unix.ENOENT) {
|
||||
return errors.New("current working directory is outside of container mount namespace root -- possible container breakout detected")
|
||||
} else if err != nil {
|
||||
return fmt.Errorf("failed to verify if current working directory is safe: %w", err)
|
||||
} else if !filepath.IsAbs(wd) {
|
||||
// We shouldn't ever hit this, but check just in case.
|
||||
return fmt.Errorf("current working directory is not absolute -- possible container breakout detected: cwd is %q", wd)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// finalizeNamespace drops the caps, sets the correct user
|
||||
// and working dir, and closes any leaked file descriptors
|
||||
// before executing the command inside the namespace
|
||||
func finalizeNamespace(config *initConfig) error {
|
||||
// Ensure that all unwanted fds we may have accidentally
|
||||
// inherited are marked close-on-exec so they stay out of the
|
||||
// container
|
||||
if err := utils.CloseExecFrom(config.PassedFilesCount + 3); err != nil {
|
||||
return fmt.Errorf("error closing exec fds: %w", err)
|
||||
}
|
||||
|
||||
// we only do chdir if it's specified
|
||||
doChdir := config.Cwd != ""
|
||||
if doChdir {
|
||||
// First, attempt the chdir before setting up the user.
|
||||
// This could allow us to access a directory that the user running runc can access
|
||||
// but the container user cannot.
|
||||
err := unix.Chdir(config.Cwd)
|
||||
switch {
|
||||
case err == nil:
|
||||
doChdir = false
|
||||
case os.IsPermission(err):
|
||||
// If we hit an EPERM, we should attempt again after setting up user.
|
||||
// This will allow us to successfully chdir if the container user has access
|
||||
// to the directory, but the user running runc does not.
|
||||
// This is useful in cases where the cwd is also a volume that's been chowned to the container user.
|
||||
default:
|
||||
return fmt.Errorf("chdir to cwd (%q) set in config.json failed: %w", config.Cwd, err)
|
||||
}
|
||||
}
|
||||
|
||||
caps := &configs.Capabilities{}
|
||||
if config.Capabilities != nil {
|
||||
caps = config.Capabilities
|
||||
} else if config.Config.Capabilities != nil {
|
||||
caps = config.Config.Capabilities
|
||||
}
|
||||
w, err := capabilities.New(caps)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// drop capabilities in bounding set before changing user
|
||||
if err := w.ApplyBoundingSet(); err != nil {
|
||||
return fmt.Errorf("unable to apply bounding set: %w", err)
|
||||
}
|
||||
// preserve existing capabilities while we change users
|
||||
if err := system.SetKeepCaps(); err != nil {
|
||||
return fmt.Errorf("unable to set keep caps: %w", err)
|
||||
}
|
||||
if err := setupUser(config); err != nil {
|
||||
return fmt.Errorf("unable to setup user: %w", err)
|
||||
}
|
||||
// Change working directory AFTER the user has been set up, if we haven't done it yet.
|
||||
if doChdir {
|
||||
if err := unix.Chdir(config.Cwd); err != nil {
|
||||
return fmt.Errorf("chdir to cwd (%q) set in config.json failed: %w", config.Cwd, err)
|
||||
}
|
||||
}
|
||||
// Make sure our final working directory is inside the container.
|
||||
if err := verifyCwd(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := system.ClearKeepCaps(); err != nil {
|
||||
return fmt.Errorf("unable to clear keep caps: %w", err)
|
||||
}
|
||||
if err := w.ApplyCaps(); err != nil {
|
||||
return fmt.Errorf("unable to apply caps: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// setupConsole sets up the console from inside the container, and sends the
|
||||
// master pty fd to the config.Pipe (using cmsg). This is done to ensure that
|
||||
// consoles are scoped to a container properly (see runc#814 and the many
|
||||
// issues related to that). This has to be run *after* we've pivoted to the new
|
||||
// rootfs (and the users' configuration is entirely set up).
|
||||
func setupConsole(socket *os.File, config *initConfig, mount bool) error {
|
||||
defer socket.Close()
|
||||
// At this point, /dev/ptmx points to something that we would expect. We
|
||||
// used to change the owner of the slave path, but since the /dev/pts mount
|
||||
// can have gid=X set (at the users' option). So touching the owner of the
|
||||
// slave PTY is not necessary, as the kernel will handle that for us. Note
|
||||
// however, that setupUser (specifically fixStdioPermissions) *will* change
|
||||
// the UID owner of the console to be the user the process will run as (so
|
||||
// they can actually control their console).
|
||||
|
||||
pty, slavePath, err := console.NewPty()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// After we return from here, we don't need the console anymore.
|
||||
defer pty.Close()
|
||||
|
||||
if config.ConsoleHeight != 0 && config.ConsoleWidth != 0 {
|
||||
err = pty.Resize(console.WinSize{
|
||||
Height: config.ConsoleHeight,
|
||||
Width: config.ConsoleWidth,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Mount the console inside our rootfs.
|
||||
if mount {
|
||||
if err := mountConsole(slavePath); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
// While we can access console.master, using the API is a good idea.
|
||||
if err := utils.SendFd(socket, pty.Name(), pty.Fd()); err != nil {
|
||||
return err
|
||||
}
|
||||
// Now, dup over all the things.
|
||||
return dupStdio(slavePath)
|
||||
}
|
||||
|
||||
// syncParentReady sends to the given pipe a JSON payload which indicates that
|
||||
// the init is ready to Exec the child process. It then waits for the parent to
|
||||
// indicate that it is cleared to Exec.
|
||||
func syncParentReady(pipe io.ReadWriter) error {
|
||||
// Tell parent.
|
||||
if err := writeSync(pipe, procReady); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Wait for parent to give the all-clear.
|
||||
return readSync(pipe, procRun)
|
||||
}
|
||||
|
||||
// syncParentHooks sends to the given pipe a JSON payload which indicates that
|
||||
// the parent should execute pre-start hooks. It then waits for the parent to
|
||||
// indicate that it is cleared to resume.
|
||||
func syncParentHooks(pipe io.ReadWriter) error {
|
||||
// Tell parent.
|
||||
if err := writeSync(pipe, procHooks); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Wait for parent to give the all-clear.
|
||||
return readSync(pipe, procResume)
|
||||
}
|
||||
|
||||
// syncParentSeccomp sends to the given pipe a JSON payload which
|
||||
// indicates that the parent should pick up the seccomp fd with pidfd_getfd()
|
||||
// and send it to the seccomp agent over a unix socket. It then waits for
|
||||
// the parent to indicate that it is cleared to resume and closes the seccompFd.
|
||||
// If the seccompFd is -1, there isn't anything to sync with the parent, so it
|
||||
// returns no error.
|
||||
func syncParentSeccomp(pipe io.ReadWriter, seccompFd int) error {
|
||||
if seccompFd == -1 {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Tell parent.
|
||||
if err := writeSyncWithFd(pipe, procSeccomp, seccompFd); err != nil {
|
||||
unix.Close(seccompFd)
|
||||
return err
|
||||
}
|
||||
|
||||
// Wait for parent to give the all-clear.
|
||||
if err := readSync(pipe, procSeccompDone); err != nil {
|
||||
unix.Close(seccompFd)
|
||||
return fmt.Errorf("sync parent seccomp: %w", err)
|
||||
}
|
||||
|
||||
if err := unix.Close(seccompFd); err != nil {
|
||||
return fmt.Errorf("close seccomp fd: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// setupUser changes the groups, gid, and uid for the user inside the container
|
||||
func setupUser(config *initConfig) error {
|
||||
// Set up defaults.
|
||||
defaultExecUser := user.ExecUser{
|
||||
Uid: 0,
|
||||
Gid: 0,
|
||||
Home: "/",
|
||||
}
|
||||
|
||||
passwdPath, err := user.GetPasswdPath()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
groupPath, err := user.GetGroupPath()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
execUser, err := user.GetExecUserPath(config.User, &defaultExecUser, passwdPath, groupPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var addGroups []int
|
||||
if len(config.AdditionalGroups) > 0 {
|
||||
addGroups, err = user.GetAdditionalGroupsPath(config.AdditionalGroups, groupPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Rather than just erroring out later in setuid(2) and setgid(2), check
|
||||
// that the user is mapped here.
|
||||
if _, err := config.Config.HostUID(execUser.Uid); err != nil {
|
||||
return errors.New("cannot set uid to unmapped user in user namespace")
|
||||
}
|
||||
if _, err := config.Config.HostGID(execUser.Gid); err != nil {
|
||||
return errors.New("cannot set gid to unmapped user in user namespace")
|
||||
}
|
||||
|
||||
if config.RootlessEUID {
|
||||
// We cannot set any additional groups in a rootless container and thus
|
||||
// we bail if the user asked us to do so. TODO: We currently can't do
|
||||
// this check earlier, but if libcontainer.Process.User was typesafe
|
||||
// this might work.
|
||||
if len(addGroups) > 0 {
|
||||
return errors.New("cannot set any additional groups in a rootless container")
|
||||
}
|
||||
}
|
||||
|
||||
// Before we change to the container's user make sure that the processes
|
||||
// STDIO is correctly owned by the user that we are switching to.
|
||||
if err := fixStdioPermissions(execUser); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
setgroups, err := os.ReadFile("/proc/self/setgroups")
|
||||
if err != nil && !os.IsNotExist(err) {
|
||||
return err
|
||||
}
|
||||
|
||||
// This isn't allowed in an unprivileged user namespace since Linux 3.19.
|
||||
// There's nothing we can do about /etc/group entries, so we silently
|
||||
// ignore setting groups here (since the user didn't explicitly ask us to
|
||||
// set the group).
|
||||
allowSupGroups := !config.RootlessEUID && string(bytes.TrimSpace(setgroups)) != "deny"
|
||||
|
||||
if allowSupGroups {
|
||||
suppGroups := append(execUser.Sgids, addGroups...)
|
||||
if err := unix.Setgroups(suppGroups); err != nil {
|
||||
return &os.SyscallError{Syscall: "setgroups", Err: err}
|
||||
}
|
||||
}
|
||||
|
||||
if err := system.Setgid(execUser.Gid); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := system.Setuid(execUser.Uid); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// if we didn't get HOME already, set it based on the user's HOME
|
||||
if envHome := os.Getenv("HOME"); envHome == "" {
|
||||
if err := os.Setenv("HOME", execUser.Home); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// fixStdioPermissions fixes the permissions of PID 1's STDIO within the container to the specified user.
|
||||
// The ownership needs to match because it is created outside of the container and needs to be
|
||||
// localized.
|
||||
func fixStdioPermissions(u *user.ExecUser) error {
|
||||
var null unix.Stat_t
|
||||
if err := unix.Stat("/dev/null", &null); err != nil {
|
||||
return &os.PathError{Op: "stat", Path: "/dev/null", Err: err}
|
||||
}
|
||||
for _, file := range []*os.File{os.Stdin, os.Stdout, os.Stderr} {
|
||||
var s unix.Stat_t
|
||||
if err := unix.Fstat(int(file.Fd()), &s); err != nil {
|
||||
return &os.PathError{Op: "fstat", Path: file.Name(), Err: err}
|
||||
}
|
||||
|
||||
// Skip chown if uid is already the one we want or any of the STDIO descriptors
|
||||
// were redirected to /dev/null.
|
||||
if int(s.Uid) == u.Uid || s.Rdev == null.Rdev {
|
||||
continue
|
||||
}
|
||||
|
||||
// We only change the uid (as it is possible for the mount to
|
||||
// prefer a different gid, and there's no reason for us to change it).
|
||||
// The reason why we don't just leave the default uid=X mount setup is
|
||||
// that users expect to be able to actually use their console. Without
|
||||
// this code, you couldn't effectively run as a non-root user inside a
|
||||
// container and also have a console set up.
|
||||
if err := file.Chown(u.Uid, int(s.Gid)); err != nil {
|
||||
// If we've hit an EINVAL then s.Gid isn't mapped in the user
|
||||
// namespace. If we've hit an EPERM then the inode's current owner
|
||||
// is not mapped in our user namespace (in particular,
|
||||
// privileged_wrt_inode_uidgid() has failed). Read-only
|
||||
// /dev can result in EROFS error. In any case, it's
|
||||
// better for us to just not touch the stdio rather
|
||||
// than bail at this point.
|
||||
|
||||
if errors.Is(err, unix.EINVAL) || errors.Is(err, unix.EPERM) || errors.Is(err, unix.EROFS) {
|
||||
continue
|
||||
}
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// setupNetwork sets up and initializes any network interface inside the container.
|
||||
func setupNetwork(config *initConfig) error {
|
||||
for _, config := range config.Networks {
|
||||
strategy, err := getStrategy(config.Type)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := strategy.initialize(config); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func setupRoute(config *configs.Config) error {
|
||||
for _, config := range config.Routes {
|
||||
_, dst, err := net.ParseCIDR(config.Destination)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
src := net.ParseIP(config.Source)
|
||||
if src == nil {
|
||||
return fmt.Errorf("Invalid source for route: %s", config.Source)
|
||||
}
|
||||
gw := net.ParseIP(config.Gateway)
|
||||
if gw == nil {
|
||||
return fmt.Errorf("Invalid gateway for route: %s", config.Gateway)
|
||||
}
|
||||
l, err := netlink.LinkByName(config.InterfaceName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
route := &netlink.Route{
|
||||
Scope: netlink.SCOPE_UNIVERSE,
|
||||
Dst: dst,
|
||||
Src: src,
|
||||
Gw: gw,
|
||||
LinkIndex: l.Attrs().Index,
|
||||
}
|
||||
if err := netlink.RouteAdd(route); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func maybeClearRlimitNofileCache(limits []configs.Rlimit) {
|
||||
for _, rlimit := range limits {
|
||||
if rlimit.Type == syscall.RLIMIT_NOFILE {
|
||||
system.ClearRlimitNofileCache(&syscall.Rlimit{
|
||||
Cur: rlimit.Soft,
|
||||
Max: rlimit.Hard,
|
||||
})
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func setupRlimits(limits []configs.Rlimit, pid int) error {
|
||||
for _, rlimit := range limits {
|
||||
if err := unix.Prlimit(pid, rlimit.Type, &unix.Rlimit{Max: rlimit.Hard, Cur: rlimit.Soft}, nil); err != nil {
|
||||
return fmt.Errorf("error setting rlimit type %v: %w", rlimit.Type, err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
const _P_PID = 1
|
||||
|
||||
//nolint:structcheck,unused
|
||||
type siginfo struct {
|
||||
si_signo int32
|
||||
si_errno int32
|
||||
si_code int32
|
||||
// below here is a union; si_pid is the only field we use
|
||||
si_pid int32
|
||||
// Pad to 128 bytes as detailed in blockUntilWaitable
|
||||
pad [96]byte
|
||||
}
|
||||
|
||||
// isWaitable returns true if the process has exited false otherwise.
|
||||
// Its based off blockUntilWaitable in src/os/wait_waitid.go
|
||||
func isWaitable(pid int) (bool, error) {
|
||||
si := &siginfo{}
|
||||
_, _, e := unix.Syscall6(unix.SYS_WAITID, _P_PID, uintptr(pid), uintptr(unsafe.Pointer(si)), unix.WEXITED|unix.WNOWAIT|unix.WNOHANG, 0, 0)
|
||||
if e != 0 {
|
||||
return false, &os.SyscallError{Syscall: "waitid", Err: e}
|
||||
}
|
||||
|
||||
return si.si_pid != 0, nil
|
||||
}
|
||||
|
||||
// signalAllProcesses freezes then iterates over all the processes inside the
|
||||
// manager's cgroups sending the signal s to them.
|
||||
// If s is SIGKILL then it will wait for each process to exit.
|
||||
// For all other signals it will check if the process is ready to report its
|
||||
// exit status and only if it is will a wait be performed.
|
||||
func signalAllProcesses(m cgroups.Manager, s os.Signal) error {
|
||||
var procs []*os.Process
|
||||
if err := m.Freeze(configs.Frozen); err != nil {
|
||||
logrus.Warn(err)
|
||||
}
|
||||
pids, err := m.GetAllPids()
|
||||
if err != nil {
|
||||
if err := m.Freeze(configs.Thawed); err != nil {
|
||||
logrus.Warn(err)
|
||||
}
|
||||
return err
|
||||
}
|
||||
for _, pid := range pids {
|
||||
p, err := os.FindProcess(pid)
|
||||
if err != nil {
|
||||
logrus.Warn(err)
|
||||
continue
|
||||
}
|
||||
procs = append(procs, p)
|
||||
if err := p.Signal(s); err != nil {
|
||||
logrus.Warn(err)
|
||||
}
|
||||
}
|
||||
if err := m.Freeze(configs.Thawed); err != nil {
|
||||
logrus.Warn(err)
|
||||
}
|
||||
|
||||
subreaper, err := system.GetSubreaper()
|
||||
if err != nil {
|
||||
// The error here means that PR_GET_CHILD_SUBREAPER is not
|
||||
// supported because this code might run on a kernel older
|
||||
// than 3.4. We don't want to throw an error in that case,
|
||||
// and we simplify things, considering there is no subreaper
|
||||
// set.
|
||||
subreaper = 0
|
||||
}
|
||||
|
||||
for _, p := range procs {
|
||||
if s != unix.SIGKILL {
|
||||
if ok, err := isWaitable(p.Pid); err != nil {
|
||||
if !errors.Is(err, unix.ECHILD) {
|
||||
logrus.Warn("signalAllProcesses: ", p.Pid, err)
|
||||
}
|
||||
continue
|
||||
} else if !ok {
|
||||
// Not ready to report so don't wait
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
// In case a subreaper has been setup, this code must not
|
||||
// wait for the process. Otherwise, we cannot be sure the
|
||||
// current process will be reaped by the subreaper, while
|
||||
// the subreaper might be waiting for this process in order
|
||||
// to retrieve its exit code.
|
||||
if subreaper == 0 {
|
||||
if _, err := p.Wait(); err != nil {
|
||||
if !errors.Is(err, unix.ECHILD) {
|
||||
logrus.Warn("wait: ", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
45
vendor/github.com/opencontainers/runc/libcontainer/keys/keyctl.go
generated
vendored
45
vendor/github.com/opencontainers/runc/libcontainer/keys/keyctl.go
generated
vendored
@@ -1,45 +0,0 @@
|
||||
package keys
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
type KeySerial uint32
|
||||
|
||||
func JoinSessionKeyring(name string) (KeySerial, error) {
|
||||
sessKeyID, err := unix.KeyctlJoinSessionKeyring(name)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("unable to create session key: %w", err)
|
||||
}
|
||||
return KeySerial(sessKeyID), nil
|
||||
}
|
||||
|
||||
// ModKeyringPerm modifies permissions on a keyring by reading the current permissions,
|
||||
// anding the bits with the given mask (clearing permissions) and setting
|
||||
// additional permission bits
|
||||
func ModKeyringPerm(ringID KeySerial, mask, setbits uint32) error {
|
||||
dest, err := unix.KeyctlString(unix.KEYCTL_DESCRIBE, int(ringID))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
res := strings.Split(dest, ";")
|
||||
if len(res) < 5 {
|
||||
return errors.New("Destination buffer for key description is too small")
|
||||
}
|
||||
|
||||
// parse permissions
|
||||
perm64, err := strconv.ParseUint(res[3], 16, 32)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
perm := (uint32(perm64) & mask) | setbits
|
||||
|
||||
return unix.KeyctlSetperm(int(ringID), perm)
|
||||
}
|
||||
56
vendor/github.com/opencontainers/runc/libcontainer/logs/logs.go
generated
vendored
56
vendor/github.com/opencontainers/runc/libcontainer/logs/logs.go
generated
vendored
@@ -1,56 +0,0 @@
|
||||
package logs
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"encoding/json"
|
||||
"io"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
func ForwardLogs(logPipe io.ReadCloser) chan error {
|
||||
done := make(chan error, 1)
|
||||
s := bufio.NewScanner(logPipe)
|
||||
|
||||
logger := logrus.StandardLogger()
|
||||
if logger.ReportCaller {
|
||||
// Need a copy of the standard logger, but with ReportCaller
|
||||
// turned off, as the logs are merely forwarded and their
|
||||
// true source is not this file/line/function.
|
||||
logNoCaller := *logrus.StandardLogger()
|
||||
logNoCaller.ReportCaller = false
|
||||
logger = &logNoCaller
|
||||
}
|
||||
|
||||
go func() {
|
||||
for s.Scan() {
|
||||
processEntry(s.Bytes(), logger)
|
||||
}
|
||||
if err := logPipe.Close(); err != nil {
|
||||
logrus.Errorf("error closing log source: %v", err)
|
||||
}
|
||||
// The only error we want to return is when reading from
|
||||
// logPipe has failed.
|
||||
done <- s.Err()
|
||||
close(done)
|
||||
}()
|
||||
|
||||
return done
|
||||
}
|
||||
|
||||
func processEntry(text []byte, logger *logrus.Logger) {
|
||||
if len(text) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
var jl struct {
|
||||
Level logrus.Level `json:"level"`
|
||||
Msg string `json:"msg"`
|
||||
}
|
||||
if err := json.Unmarshal(text, &jl); err != nil {
|
||||
logrus.Errorf("failed to decode %q to json: %v", text, err)
|
||||
return
|
||||
}
|
||||
|
||||
logger.Log(jl.Level, jl.Msg)
|
||||
}
|
||||
97
vendor/github.com/opencontainers/runc/libcontainer/message_linux.go
generated
vendored
97
vendor/github.com/opencontainers/runc/libcontainer/message_linux.go
generated
vendored
@@ -1,97 +0,0 @@
|
||||
package libcontainer
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
|
||||
"github.com/vishvananda/netlink/nl"
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
// list of known message types we want to send to bootstrap program
|
||||
// The number is randomly chosen to not conflict with known netlink types
|
||||
const (
|
||||
InitMsg uint16 = 62000
|
||||
CloneFlagsAttr uint16 = 27281
|
||||
NsPathsAttr uint16 = 27282
|
||||
UidmapAttr uint16 = 27283
|
||||
GidmapAttr uint16 = 27284
|
||||
SetgroupAttr uint16 = 27285
|
||||
OomScoreAdjAttr uint16 = 27286
|
||||
RootlessEUIDAttr uint16 = 27287
|
||||
UidmapPathAttr uint16 = 27288
|
||||
GidmapPathAttr uint16 = 27289
|
||||
MountSourcesAttr uint16 = 27290
|
||||
)
|
||||
|
||||
type Int32msg struct {
|
||||
Type uint16
|
||||
Value uint32
|
||||
}
|
||||
|
||||
// Serialize serializes the message.
|
||||
// Int32msg has the following representation
|
||||
// | nlattr len | nlattr type |
|
||||
// | uint32 value |
|
||||
func (msg *Int32msg) Serialize() []byte {
|
||||
buf := make([]byte, msg.Len())
|
||||
native := nl.NativeEndian()
|
||||
native.PutUint16(buf[0:2], uint16(msg.Len()))
|
||||
native.PutUint16(buf[2:4], msg.Type)
|
||||
native.PutUint32(buf[4:8], msg.Value)
|
||||
return buf
|
||||
}
|
||||
|
||||
func (msg *Int32msg) Len() int {
|
||||
return unix.NLA_HDRLEN + 4
|
||||
}
|
||||
|
||||
// Bytemsg has the following representation
|
||||
// | nlattr len | nlattr type |
|
||||
// | value | pad |
|
||||
type Bytemsg struct {
|
||||
Type uint16
|
||||
Value []byte
|
||||
}
|
||||
|
||||
func (msg *Bytemsg) Serialize() []byte {
|
||||
l := msg.Len()
|
||||
if l > math.MaxUint16 {
|
||||
// We cannot return nil nor an error here, so we panic with
|
||||
// a specific type instead, which is handled via recover in
|
||||
// bootstrapData.
|
||||
panic(netlinkError{fmt.Errorf("netlink: cannot serialize bytemsg of length %d (larger than UINT16_MAX)", l)})
|
||||
}
|
||||
buf := make([]byte, (l+unix.NLA_ALIGNTO-1) & ^(unix.NLA_ALIGNTO-1))
|
||||
native := nl.NativeEndian()
|
||||
native.PutUint16(buf[0:2], uint16(l))
|
||||
native.PutUint16(buf[2:4], msg.Type)
|
||||
copy(buf[4:], msg.Value)
|
||||
return buf
|
||||
}
|
||||
|
||||
func (msg *Bytemsg) Len() int {
|
||||
return unix.NLA_HDRLEN + len(msg.Value) + 1 // null-terminated
|
||||
}
|
||||
|
||||
type Boolmsg struct {
|
||||
Type uint16
|
||||
Value bool
|
||||
}
|
||||
|
||||
func (msg *Boolmsg) Serialize() []byte {
|
||||
buf := make([]byte, msg.Len())
|
||||
native := nl.NativeEndian()
|
||||
native.PutUint16(buf[0:2], uint16(msg.Len()))
|
||||
native.PutUint16(buf[2:4], msg.Type)
|
||||
if msg.Value {
|
||||
native.PutUint32(buf[4:8], uint32(1))
|
||||
} else {
|
||||
native.PutUint32(buf[4:8], uint32(0))
|
||||
}
|
||||
return buf
|
||||
}
|
||||
|
||||
func (msg *Boolmsg) Len() int {
|
||||
return unix.NLA_HDRLEN + 4 // alignment
|
||||
}
|
||||
101
vendor/github.com/opencontainers/runc/libcontainer/mount_linux.go
generated
vendored
101
vendor/github.com/opencontainers/runc/libcontainer/mount_linux.go
generated
vendored
@@ -1,101 +0,0 @@
|
||||
package libcontainer
|
||||
|
||||
import (
|
||||
"io/fs"
|
||||
"strconv"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
// mountError holds an error from a failed mount or unmount operation.
|
||||
type mountError struct {
|
||||
op string
|
||||
source string
|
||||
target string
|
||||
procfd string
|
||||
flags uintptr
|
||||
data string
|
||||
err error
|
||||
}
|
||||
|
||||
// Error provides a string error representation.
|
||||
func (e *mountError) Error() string {
|
||||
out := e.op + " "
|
||||
|
||||
if e.source != "" {
|
||||
out += e.source + ":" + e.target
|
||||
} else {
|
||||
out += e.target
|
||||
}
|
||||
if e.procfd != "" {
|
||||
out += " (via " + e.procfd + ")"
|
||||
}
|
||||
|
||||
if e.flags != uintptr(0) {
|
||||
out += ", flags: 0x" + strconv.FormatUint(uint64(e.flags), 16)
|
||||
}
|
||||
if e.data != "" {
|
||||
out += ", data: " + e.data
|
||||
}
|
||||
|
||||
out += ": " + e.err.Error()
|
||||
return out
|
||||
}
|
||||
|
||||
// Unwrap returns the underlying error.
|
||||
// This is a convention used by Go 1.13+ standard library.
|
||||
func (e *mountError) Unwrap() error {
|
||||
return e.err
|
||||
}
|
||||
|
||||
// mount is a simple unix.Mount wrapper. If procfd is not empty, it is used
|
||||
// instead of target (and the target is only used to add context to an error).
|
||||
func mount(source, target, procfd, fstype string, flags uintptr, data string) error {
|
||||
dst := target
|
||||
if procfd != "" {
|
||||
dst = procfd
|
||||
}
|
||||
if err := unix.Mount(source, dst, fstype, flags, data); err != nil {
|
||||
return &mountError{
|
||||
op: "mount",
|
||||
source: source,
|
||||
target: target,
|
||||
procfd: procfd,
|
||||
flags: flags,
|
||||
data: data,
|
||||
err: err,
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// unmount is a simple unix.Unmount wrapper.
|
||||
func unmount(target string, flags int) error {
|
||||
err := unix.Unmount(target, flags)
|
||||
if err != nil {
|
||||
return &mountError{
|
||||
op: "unmount",
|
||||
target: target,
|
||||
flags: uintptr(flags),
|
||||
err: err,
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// syscallMode returns the syscall-specific mode bits from Go's portable mode bits.
|
||||
// Copy from https://cs.opensource.google/go/go/+/refs/tags/go1.20.7:src/os/file_posix.go;l=61-75
|
||||
func syscallMode(i fs.FileMode) (o uint32) {
|
||||
o |= uint32(i.Perm())
|
||||
if i&fs.ModeSetuid != 0 {
|
||||
o |= unix.S_ISUID
|
||||
}
|
||||
if i&fs.ModeSetgid != 0 {
|
||||
o |= unix.S_ISGID
|
||||
}
|
||||
if i&fs.ModeSticky != 0 {
|
||||
o |= unix.S_ISVTX
|
||||
}
|
||||
// No mapping for Go's ModeTemporary (plan9 only).
|
||||
return
|
||||
}
|
||||
100
vendor/github.com/opencontainers/runc/libcontainer/network_linux.go
generated
vendored
100
vendor/github.com/opencontainers/runc/libcontainer/network_linux.go
generated
vendored
@@ -1,100 +0,0 @@
|
||||
package libcontainer
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
|
||||
"github.com/opencontainers/runc/libcontainer/configs"
|
||||
"github.com/opencontainers/runc/types"
|
||||
"github.com/vishvananda/netlink"
|
||||
)
|
||||
|
||||
var strategies = map[string]networkStrategy{
|
||||
"loopback": &loopback{},
|
||||
}
|
||||
|
||||
// networkStrategy represents a specific network configuration for
|
||||
// a container's networking stack
|
||||
type networkStrategy interface {
|
||||
create(*network, int) error
|
||||
initialize(*network) error
|
||||
detach(*configs.Network) error
|
||||
attach(*configs.Network) error
|
||||
}
|
||||
|
||||
// getStrategy returns the specific network strategy for the
|
||||
// provided type.
|
||||
func getStrategy(tpe string) (networkStrategy, error) {
|
||||
s, exists := strategies[tpe]
|
||||
if !exists {
|
||||
return nil, fmt.Errorf("unknown strategy type %q", tpe)
|
||||
}
|
||||
return s, nil
|
||||
}
|
||||
|
||||
// Returns the network statistics for the network interfaces represented by the NetworkRuntimeInfo.
|
||||
func getNetworkInterfaceStats(interfaceName string) (*types.NetworkInterface, error) {
|
||||
out := &types.NetworkInterface{Name: interfaceName}
|
||||
// This can happen if the network runtime information is missing - possible if the
|
||||
// container was created by an old version of libcontainer.
|
||||
if interfaceName == "" {
|
||||
return out, nil
|
||||
}
|
||||
type netStatsPair struct {
|
||||
// Where to write the output.
|
||||
Out *uint64
|
||||
// The network stats file to read.
|
||||
File string
|
||||
}
|
||||
// Ingress for host veth is from the container. Hence tx_bytes stat on the host veth is actually number of bytes received by the container.
|
||||
netStats := []netStatsPair{
|
||||
{Out: &out.RxBytes, File: "tx_bytes"},
|
||||
{Out: &out.RxPackets, File: "tx_packets"},
|
||||
{Out: &out.RxErrors, File: "tx_errors"},
|
||||
{Out: &out.RxDropped, File: "tx_dropped"},
|
||||
|
||||
{Out: &out.TxBytes, File: "rx_bytes"},
|
||||
{Out: &out.TxPackets, File: "rx_packets"},
|
||||
{Out: &out.TxErrors, File: "rx_errors"},
|
||||
{Out: &out.TxDropped, File: "rx_dropped"},
|
||||
}
|
||||
for _, netStat := range netStats {
|
||||
data, err := readSysfsNetworkStats(interfaceName, netStat.File)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
*(netStat.Out) = data
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// Reads the specified statistics available under /sys/class/net/<EthInterface>/statistics
|
||||
func readSysfsNetworkStats(ethInterface, statsFile string) (uint64, error) {
|
||||
data, err := os.ReadFile(filepath.Join("/sys/class/net", ethInterface, "statistics", statsFile))
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return strconv.ParseUint(string(bytes.TrimSpace(data)), 10, 64)
|
||||
}
|
||||
|
||||
// loopback is a network strategy that provides a basic loopback device
|
||||
type loopback struct{}
|
||||
|
||||
func (l *loopback) create(n *network, nspid int) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (l *loopback) initialize(config *network) error {
|
||||
return netlink.LinkSetUp(&netlink.Device{LinkAttrs: netlink.LinkAttrs{Name: "lo"}})
|
||||
}
|
||||
|
||||
func (l *loopback) attach(n *configs.Network) (err error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (l *loopback) detach(n *configs.Network) (err error) {
|
||||
return nil
|
||||
}
|
||||
84
vendor/github.com/opencontainers/runc/libcontainer/notify_linux.go
generated
vendored
84
vendor/github.com/opencontainers/runc/libcontainer/notify_linux.go
generated
vendored
@@ -1,84 +0,0 @@
|
||||
package libcontainer
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
type PressureLevel uint
|
||||
|
||||
const (
|
||||
LowPressure PressureLevel = iota
|
||||
MediumPressure
|
||||
CriticalPressure
|
||||
)
|
||||
|
||||
func registerMemoryEvent(cgDir string, evName string, arg string) (<-chan struct{}, error) {
|
||||
evFile, err := os.Open(filepath.Join(cgDir, evName))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
fd, err := unix.Eventfd(0, unix.EFD_CLOEXEC)
|
||||
if err != nil {
|
||||
evFile.Close()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
eventfd := os.NewFile(uintptr(fd), "eventfd")
|
||||
|
||||
eventControlPath := filepath.Join(cgDir, "cgroup.event_control")
|
||||
data := fmt.Sprintf("%d %d %s", eventfd.Fd(), evFile.Fd(), arg)
|
||||
if err := os.WriteFile(eventControlPath, []byte(data), 0o700); err != nil {
|
||||
eventfd.Close()
|
||||
evFile.Close()
|
||||
return nil, err
|
||||
}
|
||||
ch := make(chan struct{})
|
||||
go func() {
|
||||
defer func() {
|
||||
eventfd.Close()
|
||||
evFile.Close()
|
||||
close(ch)
|
||||
}()
|
||||
buf := make([]byte, 8)
|
||||
for {
|
||||
if _, err := eventfd.Read(buf); err != nil {
|
||||
return
|
||||
}
|
||||
// When a cgroup is destroyed, an event is sent to eventfd.
|
||||
// So if the control path is gone, return instead of notifying.
|
||||
if _, err := os.Lstat(eventControlPath); os.IsNotExist(err) {
|
||||
return
|
||||
}
|
||||
ch <- struct{}{}
|
||||
}
|
||||
}()
|
||||
return ch, nil
|
||||
}
|
||||
|
||||
// notifyOnOOM returns channel on which you can expect event about OOM,
|
||||
// if process died without OOM this channel will be closed.
|
||||
func notifyOnOOM(dir string) (<-chan struct{}, error) {
|
||||
if dir == "" {
|
||||
return nil, errors.New("memory controller missing")
|
||||
}
|
||||
|
||||
return registerMemoryEvent(dir, "memory.oom_control", "")
|
||||
}
|
||||
|
||||
func notifyMemoryPressure(dir string, level PressureLevel) (<-chan struct{}, error) {
|
||||
if dir == "" {
|
||||
return nil, errors.New("memory controller missing")
|
||||
}
|
||||
|
||||
if level > CriticalPressure {
|
||||
return nil, fmt.Errorf("invalid pressure level %d", level)
|
||||
}
|
||||
|
||||
levelStr := []string{"low", "medium", "critical"}[level]
|
||||
return registerMemoryEvent(dir, "memory.pressure_level", levelStr)
|
||||
}
|
||||
80
vendor/github.com/opencontainers/runc/libcontainer/notify_v2_linux.go
generated
vendored
80
vendor/github.com/opencontainers/runc/libcontainer/notify_v2_linux.go
generated
vendored
@@ -1,80 +0,0 @@
|
||||
package libcontainer
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"unsafe"
|
||||
|
||||
"github.com/opencontainers/runc/libcontainer/cgroups/fscommon"
|
||||
"github.com/sirupsen/logrus"
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
func registerMemoryEventV2(cgDir, evName, cgEvName string) (<-chan struct{}, error) {
|
||||
fd, err := unix.InotifyInit()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to init inotify: %w", err)
|
||||
}
|
||||
// watching oom kill
|
||||
evFd, err := unix.InotifyAddWatch(fd, filepath.Join(cgDir, evName), unix.IN_MODIFY)
|
||||
if err != nil {
|
||||
unix.Close(fd)
|
||||
return nil, fmt.Errorf("unable to add inotify watch: %w", err)
|
||||
}
|
||||
// Because no `unix.IN_DELETE|unix.IN_DELETE_SELF` event for cgroup file system, so watching all process exited
|
||||
cgFd, err := unix.InotifyAddWatch(fd, filepath.Join(cgDir, cgEvName), unix.IN_MODIFY)
|
||||
if err != nil {
|
||||
unix.Close(fd)
|
||||
return nil, fmt.Errorf("unable to add inotify watch: %w", err)
|
||||
}
|
||||
ch := make(chan struct{})
|
||||
go func() {
|
||||
var (
|
||||
buffer [unix.SizeofInotifyEvent + unix.PathMax + 1]byte
|
||||
offset uint32
|
||||
)
|
||||
defer func() {
|
||||
unix.Close(fd)
|
||||
close(ch)
|
||||
}()
|
||||
|
||||
for {
|
||||
n, err := unix.Read(fd, buffer[:])
|
||||
if err != nil {
|
||||
logrus.Warnf("unable to read event data from inotify, got error: %v", err)
|
||||
return
|
||||
}
|
||||
if n < unix.SizeofInotifyEvent {
|
||||
logrus.Warnf("we should read at least %d bytes from inotify, but got %d bytes.", unix.SizeofInotifyEvent, n)
|
||||
return
|
||||
}
|
||||
offset = 0
|
||||
for offset <= uint32(n-unix.SizeofInotifyEvent) {
|
||||
rawEvent := (*unix.InotifyEvent)(unsafe.Pointer(&buffer[offset]))
|
||||
offset += unix.SizeofInotifyEvent + rawEvent.Len
|
||||
if rawEvent.Mask&unix.IN_MODIFY != unix.IN_MODIFY {
|
||||
continue
|
||||
}
|
||||
switch int(rawEvent.Wd) {
|
||||
case evFd:
|
||||
oom, err := fscommon.GetValueByKey(cgDir, evName, "oom_kill")
|
||||
if err != nil || oom > 0 {
|
||||
ch <- struct{}{}
|
||||
}
|
||||
case cgFd:
|
||||
pids, err := fscommon.GetValueByKey(cgDir, cgEvName, "populated")
|
||||
if err != nil || pids == 0 {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}()
|
||||
return ch, nil
|
||||
}
|
||||
|
||||
// notifyOnOOMV2 returns channel on which you can expect event about OOM,
|
||||
// if process died without OOM this channel will be closed.
|
||||
func notifyOnOOMV2(path string) (<-chan struct{}, error) {
|
||||
return registerMemoryEventV2(path, "memory.events", "cgroup.events")
|
||||
}
|
||||
126
vendor/github.com/opencontainers/runc/libcontainer/process.go
generated
vendored
126
vendor/github.com/opencontainers/runc/libcontainer/process.go
generated
vendored
@@ -1,126 +0,0 @@
|
||||
package libcontainer
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io"
|
||||
"math"
|
||||
"os"
|
||||
|
||||
"github.com/opencontainers/runc/libcontainer/configs"
|
||||
)
|
||||
|
||||
var errInvalidProcess = errors.New("invalid process")
|
||||
|
||||
type processOperations interface {
|
||||
wait() (*os.ProcessState, error)
|
||||
signal(sig os.Signal) error
|
||||
pid() int
|
||||
}
|
||||
|
||||
// Process specifies the configuration and IO for a process inside
|
||||
// a container.
|
||||
type Process struct {
|
||||
// The command to be run followed by any arguments.
|
||||
Args []string
|
||||
|
||||
// Env specifies the environment variables for the process.
|
||||
Env []string
|
||||
|
||||
// User will set the uid and gid of the executing process running inside the container
|
||||
// local to the container's user and group configuration.
|
||||
User string
|
||||
|
||||
// AdditionalGroups specifies the gids that should be added to supplementary groups
|
||||
// in addition to those that the user belongs to.
|
||||
AdditionalGroups []string
|
||||
|
||||
// Cwd will change the processes current working directory inside the container's rootfs.
|
||||
Cwd string
|
||||
|
||||
// Stdin is a pointer to a reader which provides the standard input stream.
|
||||
Stdin io.Reader
|
||||
|
||||
// Stdout is a pointer to a writer which receives the standard output stream.
|
||||
Stdout io.Writer
|
||||
|
||||
// Stderr is a pointer to a writer which receives the standard error stream.
|
||||
Stderr io.Writer
|
||||
|
||||
// ExtraFiles specifies additional open files to be inherited by the container
|
||||
ExtraFiles []*os.File
|
||||
|
||||
// Initial sizings for the console
|
||||
ConsoleWidth uint16
|
||||
ConsoleHeight uint16
|
||||
|
||||
// Capabilities specify the capabilities to keep when executing the process inside the container
|
||||
// All capabilities not specified will be dropped from the processes capability mask
|
||||
Capabilities *configs.Capabilities
|
||||
|
||||
// AppArmorProfile specifies the profile to apply to the process and is
|
||||
// changed at the time the process is execed
|
||||
AppArmorProfile string
|
||||
|
||||
// Label specifies the label to apply to the process. It is commonly used by selinux
|
||||
Label string
|
||||
|
||||
// NoNewPrivileges controls whether processes can gain additional privileges.
|
||||
NoNewPrivileges *bool
|
||||
|
||||
// Rlimits specifies the resource limits, such as max open files, to set in the container
|
||||
// If Rlimits are not set, the container will inherit rlimits from the parent process
|
||||
Rlimits []configs.Rlimit
|
||||
|
||||
// ConsoleSocket provides the masterfd console.
|
||||
ConsoleSocket *os.File
|
||||
|
||||
// Init specifies whether the process is the first process in the container.
|
||||
Init bool
|
||||
|
||||
ops processOperations
|
||||
|
||||
LogLevel string
|
||||
|
||||
// SubCgroupPaths specifies sub-cgroups to run the process in.
|
||||
// Map keys are controller names, map values are paths (relative to
|
||||
// container's top-level cgroup).
|
||||
//
|
||||
// If empty, the default top-level container's cgroup is used.
|
||||
//
|
||||
// For cgroup v2, the only key allowed is "".
|
||||
SubCgroupPaths map[string]string
|
||||
}
|
||||
|
||||
// Wait waits for the process to exit.
|
||||
// Wait releases any resources associated with the Process
|
||||
func (p Process) Wait() (*os.ProcessState, error) {
|
||||
if p.ops == nil {
|
||||
return nil, errInvalidProcess
|
||||
}
|
||||
return p.ops.wait()
|
||||
}
|
||||
|
||||
// Pid returns the process ID
|
||||
func (p Process) Pid() (int, error) {
|
||||
// math.MinInt32 is returned here, because it's invalid value
|
||||
// for the kill() system call.
|
||||
if p.ops == nil {
|
||||
return math.MinInt32, errInvalidProcess
|
||||
}
|
||||
return p.ops.pid(), nil
|
||||
}
|
||||
|
||||
// Signal sends a signal to the Process.
|
||||
func (p Process) Signal(sig os.Signal) error {
|
||||
if p.ops == nil {
|
||||
return errInvalidProcess
|
||||
}
|
||||
return p.ops.signal(sig)
|
||||
}
|
||||
|
||||
// IO holds the process's STDIO
|
||||
type IO struct {
|
||||
Stdin io.WriteCloser
|
||||
Stdout io.ReadCloser
|
||||
Stderr io.ReadCloser
|
||||
}
|
||||
823
vendor/github.com/opencontainers/runc/libcontainer/process_linux.go
generated
vendored
823
vendor/github.com/opencontainers/runc/libcontainer/process_linux.go
generated
vendored
@@ -1,823 +0,0 @@
|
||||
package libcontainer
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/opencontainers/runc/libcontainer/cgroups"
|
||||
"github.com/opencontainers/runc/libcontainer/cgroups/fs2"
|
||||
"github.com/opencontainers/runc/libcontainer/configs"
|
||||
"github.com/opencontainers/runc/libcontainer/intelrdt"
|
||||
"github.com/opencontainers/runc/libcontainer/logs"
|
||||
"github.com/opencontainers/runc/libcontainer/system"
|
||||
"github.com/opencontainers/runc/libcontainer/utils"
|
||||
"github.com/opencontainers/runtime-spec/specs-go"
|
||||
"github.com/sirupsen/logrus"
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
type parentProcess interface {
|
||||
// pid returns the pid for the running process.
|
||||
pid() int
|
||||
|
||||
// start starts the process execution.
|
||||
start() error
|
||||
|
||||
// send a SIGKILL to the process and wait for the exit.
|
||||
terminate() error
|
||||
|
||||
// wait waits on the process returning the process state.
|
||||
wait() (*os.ProcessState, error)
|
||||
|
||||
// startTime returns the process start time.
|
||||
startTime() (uint64, error)
|
||||
signal(os.Signal) error
|
||||
externalDescriptors() []string
|
||||
setExternalDescriptors(fds []string)
|
||||
forwardChildLogs() chan error
|
||||
}
|
||||
|
||||
type filePair struct {
|
||||
parent *os.File
|
||||
child *os.File
|
||||
}
|
||||
|
||||
type setnsProcess struct {
|
||||
cmd *exec.Cmd
|
||||
messageSockPair filePair
|
||||
logFilePair filePair
|
||||
cgroupPaths map[string]string
|
||||
rootlessCgroups bool
|
||||
manager cgroups.Manager
|
||||
intelRdtPath string
|
||||
config *initConfig
|
||||
fds []string
|
||||
process *Process
|
||||
bootstrapData io.Reader
|
||||
initProcessPid int
|
||||
}
|
||||
|
||||
func (p *setnsProcess) startTime() (uint64, error) {
|
||||
stat, err := system.Stat(p.pid())
|
||||
return stat.StartTime, err
|
||||
}
|
||||
|
||||
func (p *setnsProcess) signal(sig os.Signal) error {
|
||||
s, ok := sig.(unix.Signal)
|
||||
if !ok {
|
||||
return errors.New("os: unsupported signal type")
|
||||
}
|
||||
return unix.Kill(p.pid(), s)
|
||||
}
|
||||
|
||||
func (p *setnsProcess) start() (retErr error) {
|
||||
defer p.messageSockPair.parent.Close()
|
||||
// get the "before" value of oom kill count
|
||||
oom, _ := p.manager.OOMKillCount()
|
||||
err := p.cmd.Start()
|
||||
// close the write-side of the pipes (controlled by child)
|
||||
p.messageSockPair.child.Close()
|
||||
p.logFilePair.child.Close()
|
||||
if err != nil {
|
||||
return fmt.Errorf("error starting setns process: %w", err)
|
||||
}
|
||||
|
||||
waitInit := initWaiter(p.messageSockPair.parent)
|
||||
defer func() {
|
||||
if retErr != nil {
|
||||
if newOom, err := p.manager.OOMKillCount(); err == nil && newOom != oom {
|
||||
// Someone in this cgroup was killed, this _might_ be us.
|
||||
retErr = fmt.Errorf("%w (possibly OOM-killed)", retErr)
|
||||
}
|
||||
werr := <-waitInit
|
||||
if werr != nil {
|
||||
logrus.WithError(werr).Warn()
|
||||
}
|
||||
err := ignoreTerminateErrors(p.terminate())
|
||||
if err != nil {
|
||||
logrus.WithError(err).Warn("unable to terminate setnsProcess")
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
if p.bootstrapData != nil {
|
||||
if _, err := io.Copy(p.messageSockPair.parent, p.bootstrapData); err != nil {
|
||||
return fmt.Errorf("error copying bootstrap data to pipe: %w", err)
|
||||
}
|
||||
}
|
||||
err = <-waitInit
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := p.execSetns(); err != nil {
|
||||
return fmt.Errorf("error executing setns process: %w", err)
|
||||
}
|
||||
for _, path := range p.cgroupPaths {
|
||||
if err := cgroups.WriteCgroupProc(path, p.pid()); err != nil && !p.rootlessCgroups {
|
||||
// On cgroup v2 + nesting + domain controllers, WriteCgroupProc may fail with EBUSY.
|
||||
// https://github.com/opencontainers/runc/issues/2356#issuecomment-621277643
|
||||
// Try to join the cgroup of InitProcessPid.
|
||||
if cgroups.IsCgroup2UnifiedMode() && p.initProcessPid != 0 {
|
||||
initProcCgroupFile := fmt.Sprintf("/proc/%d/cgroup", p.initProcessPid)
|
||||
initCg, initCgErr := cgroups.ParseCgroupFile(initProcCgroupFile)
|
||||
if initCgErr == nil {
|
||||
if initCgPath, ok := initCg[""]; ok {
|
||||
initCgDirpath := filepath.Join(fs2.UnifiedMountpoint, initCgPath)
|
||||
logrus.Debugf("adding pid %d to cgroups %v failed (%v), attempting to join %q (obtained from %s)",
|
||||
p.pid(), p.cgroupPaths, err, initCg, initCgDirpath)
|
||||
// NOTE: initCgDirPath is not guaranteed to exist because we didn't pause the container.
|
||||
err = cgroups.WriteCgroupProc(initCgDirpath, p.pid())
|
||||
}
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
return fmt.Errorf("error adding pid %d to cgroups: %w", p.pid(), err)
|
||||
}
|
||||
}
|
||||
}
|
||||
if p.intelRdtPath != "" {
|
||||
// if Intel RDT "resource control" filesystem path exists
|
||||
_, err := os.Stat(p.intelRdtPath)
|
||||
if err == nil {
|
||||
if err := intelrdt.WriteIntelRdtTasks(p.intelRdtPath, p.pid()); err != nil {
|
||||
return fmt.Errorf("error adding pid %d to Intel RDT: %w", p.pid(), err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if err := utils.WriteJSON(p.messageSockPair.parent, p.config); err != nil {
|
||||
return fmt.Errorf("error writing config to pipe: %w", err)
|
||||
}
|
||||
|
||||
ierr := parseSync(p.messageSockPair.parent, func(sync *syncT) error {
|
||||
switch sync.Type {
|
||||
case procReady:
|
||||
// Set rlimits, this has to be done here because we lose permissions
|
||||
// to raise the limits once we enter a user-namespace
|
||||
if err := setupRlimits(p.config.Rlimits, p.pid()); err != nil {
|
||||
return fmt.Errorf("error setting rlimits for ready process: %w", err)
|
||||
}
|
||||
|
||||
// Sync with child.
|
||||
return writeSync(p.messageSockPair.parent, procRun)
|
||||
case procHooks:
|
||||
// This shouldn't happen.
|
||||
panic("unexpected procHooks in setns")
|
||||
case procSeccomp:
|
||||
if p.config.Config.Seccomp.ListenerPath == "" {
|
||||
return errors.New("listenerPath is not set")
|
||||
}
|
||||
|
||||
seccompFd, err := recvSeccompFd(uintptr(p.pid()), uintptr(sync.Fd))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer unix.Close(seccompFd)
|
||||
|
||||
bundle, annotations := utils.Annotations(p.config.Config.Labels)
|
||||
containerProcessState := &specs.ContainerProcessState{
|
||||
Version: specs.Version,
|
||||
Fds: []string{specs.SeccompFdName},
|
||||
Pid: p.cmd.Process.Pid,
|
||||
Metadata: p.config.Config.Seccomp.ListenerMetadata,
|
||||
State: specs.State{
|
||||
Version: specs.Version,
|
||||
ID: p.config.ContainerId,
|
||||
Status: specs.StateRunning,
|
||||
Pid: p.initProcessPid,
|
||||
Bundle: bundle,
|
||||
Annotations: annotations,
|
||||
},
|
||||
}
|
||||
if err := sendContainerProcessState(p.config.Config.Seccomp.ListenerPath,
|
||||
containerProcessState, seccompFd); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Sync with child.
|
||||
if err := writeSync(p.messageSockPair.parent, procSeccompDone); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
default:
|
||||
return errors.New("invalid JSON payload from child")
|
||||
}
|
||||
})
|
||||
|
||||
if err := unix.Shutdown(int(p.messageSockPair.parent.Fd()), unix.SHUT_WR); err != nil {
|
||||
return &os.PathError{Op: "shutdown", Path: "(init pipe)", Err: err}
|
||||
}
|
||||
// Must be done after Shutdown so the child will exit and we can wait for it.
|
||||
if ierr != nil {
|
||||
_, _ = p.wait()
|
||||
return ierr
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// execSetns runs the process that executes C code to perform the setns calls
|
||||
// because setns support requires the C process to fork off a child and perform the setns
|
||||
// before the go runtime boots, we wait on the process to die and receive the child's pid
|
||||
// over the provided pipe.
|
||||
func (p *setnsProcess) execSetns() error {
|
||||
status, err := p.cmd.Process.Wait()
|
||||
if err != nil {
|
||||
_ = p.cmd.Wait()
|
||||
return fmt.Errorf("error waiting on setns process to finish: %w", err)
|
||||
}
|
||||
if !status.Success() {
|
||||
_ = p.cmd.Wait()
|
||||
return &exec.ExitError{ProcessState: status}
|
||||
}
|
||||
var pid *pid
|
||||
if err := json.NewDecoder(p.messageSockPair.parent).Decode(&pid); err != nil {
|
||||
_ = p.cmd.Wait()
|
||||
return fmt.Errorf("error reading pid from init pipe: %w", err)
|
||||
}
|
||||
|
||||
// Clean up the zombie parent process
|
||||
// On Unix systems FindProcess always succeeds.
|
||||
firstChildProcess, _ := os.FindProcess(pid.PidFirstChild)
|
||||
|
||||
// Ignore the error in case the child has already been reaped for any reason
|
||||
_, _ = firstChildProcess.Wait()
|
||||
|
||||
process, err := os.FindProcess(pid.Pid)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
p.cmd.Process = process
|
||||
p.process.ops = p
|
||||
return nil
|
||||
}
|
||||
|
||||
// terminate sends a SIGKILL to the forked process for the setns routine then waits to
|
||||
// avoid the process becoming a zombie.
|
||||
func (p *setnsProcess) terminate() error {
|
||||
if p.cmd.Process == nil {
|
||||
return nil
|
||||
}
|
||||
err := p.cmd.Process.Kill()
|
||||
if _, werr := p.wait(); err == nil {
|
||||
err = werr
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (p *setnsProcess) wait() (*os.ProcessState, error) {
|
||||
err := p.cmd.Wait()
|
||||
|
||||
// Return actual ProcessState even on Wait error
|
||||
return p.cmd.ProcessState, err
|
||||
}
|
||||
|
||||
func (p *setnsProcess) pid() int {
|
||||
return p.cmd.Process.Pid
|
||||
}
|
||||
|
||||
func (p *setnsProcess) externalDescriptors() []string {
|
||||
return p.fds
|
||||
}
|
||||
|
||||
func (p *setnsProcess) setExternalDescriptors(newFds []string) {
|
||||
p.fds = newFds
|
||||
}
|
||||
|
||||
func (p *setnsProcess) forwardChildLogs() chan error {
|
||||
return logs.ForwardLogs(p.logFilePair.parent)
|
||||
}
|
||||
|
||||
type initProcess struct {
|
||||
cmd *exec.Cmd
|
||||
messageSockPair filePair
|
||||
logFilePair filePair
|
||||
config *initConfig
|
||||
manager cgroups.Manager
|
||||
intelRdtManager *intelrdt.Manager
|
||||
container *linuxContainer
|
||||
fds []string
|
||||
process *Process
|
||||
bootstrapData io.Reader
|
||||
sharePidns bool
|
||||
}
|
||||
|
||||
func (p *initProcess) pid() int {
|
||||
return p.cmd.Process.Pid
|
||||
}
|
||||
|
||||
func (p *initProcess) externalDescriptors() []string {
|
||||
return p.fds
|
||||
}
|
||||
|
||||
// getChildPid receives the final child's pid over the provided pipe.
|
||||
func (p *initProcess) getChildPid() (int, error) {
|
||||
var pid pid
|
||||
if err := json.NewDecoder(p.messageSockPair.parent).Decode(&pid); err != nil {
|
||||
_ = p.cmd.Wait()
|
||||
return -1, err
|
||||
}
|
||||
|
||||
// Clean up the zombie parent process
|
||||
// On Unix systems FindProcess always succeeds.
|
||||
firstChildProcess, _ := os.FindProcess(pid.PidFirstChild)
|
||||
|
||||
// Ignore the error in case the child has already been reaped for any reason
|
||||
_, _ = firstChildProcess.Wait()
|
||||
|
||||
return pid.Pid, nil
|
||||
}
|
||||
|
||||
func (p *initProcess) waitForChildExit(childPid int) error {
|
||||
status, err := p.cmd.Process.Wait()
|
||||
if err != nil {
|
||||
_ = p.cmd.Wait()
|
||||
return err
|
||||
}
|
||||
if !status.Success() {
|
||||
_ = p.cmd.Wait()
|
||||
return &exec.ExitError{ProcessState: status}
|
||||
}
|
||||
|
||||
process, err := os.FindProcess(childPid)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
p.cmd.Process = process
|
||||
p.process.ops = p
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *initProcess) start() (retErr error) {
|
||||
defer p.messageSockPair.parent.Close() //nolint: errcheck
|
||||
err := p.cmd.Start()
|
||||
p.process.ops = p
|
||||
// close the write-side of the pipes (controlled by child)
|
||||
_ = p.messageSockPair.child.Close()
|
||||
_ = p.logFilePair.child.Close()
|
||||
if err != nil {
|
||||
p.process.ops = nil
|
||||
return fmt.Errorf("unable to start init: %w", err)
|
||||
}
|
||||
|
||||
waitInit := initWaiter(p.messageSockPair.parent)
|
||||
defer func() {
|
||||
if retErr != nil {
|
||||
// Find out if init is killed by the kernel's OOM killer.
|
||||
// Get the count before killing init as otherwise cgroup
|
||||
// might be removed by systemd.
|
||||
oom, err := p.manager.OOMKillCount()
|
||||
if err != nil {
|
||||
logrus.WithError(err).Warn("unable to get oom kill count")
|
||||
} else if oom > 0 {
|
||||
// Does not matter what the particular error was,
|
||||
// its cause is most probably OOM, so report that.
|
||||
const oomError = "container init was OOM-killed (memory limit too low?)"
|
||||
|
||||
if logrus.GetLevel() >= logrus.DebugLevel {
|
||||
// Only show the original error if debug is set,
|
||||
// as it is not generally very useful.
|
||||
retErr = fmt.Errorf(oomError+": %w", retErr)
|
||||
} else {
|
||||
retErr = errors.New(oomError)
|
||||
}
|
||||
}
|
||||
|
||||
werr := <-waitInit
|
||||
if werr != nil {
|
||||
logrus.WithError(werr).Warn()
|
||||
}
|
||||
|
||||
// Terminate the process to ensure we can remove cgroups.
|
||||
if err := ignoreTerminateErrors(p.terminate()); err != nil {
|
||||
logrus.WithError(err).Warn("unable to terminate initProcess")
|
||||
}
|
||||
|
||||
_ = p.manager.Destroy()
|
||||
if p.intelRdtManager != nil {
|
||||
_ = p.intelRdtManager.Destroy()
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
// Do this before syncing with child so that no children can escape the
|
||||
// cgroup. We don't need to worry about not doing this and not being root
|
||||
// because we'd be using the rootless cgroup manager in that case.
|
||||
if err := p.manager.Apply(p.pid()); err != nil {
|
||||
return fmt.Errorf("unable to apply cgroup configuration: %w", err)
|
||||
}
|
||||
if p.intelRdtManager != nil {
|
||||
if err := p.intelRdtManager.Apply(p.pid()); err != nil {
|
||||
return fmt.Errorf("unable to apply Intel RDT configuration: %w", err)
|
||||
}
|
||||
}
|
||||
if _, err := io.Copy(p.messageSockPair.parent, p.bootstrapData); err != nil {
|
||||
return fmt.Errorf("can't copy bootstrap data to pipe: %w", err)
|
||||
}
|
||||
err = <-waitInit
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
childPid, err := p.getChildPid()
|
||||
if err != nil {
|
||||
return fmt.Errorf("can't get final child's PID from pipe: %w", err)
|
||||
}
|
||||
|
||||
// Save the standard descriptor names before the container process
|
||||
// can potentially move them (e.g., via dup2()). If we don't do this now,
|
||||
// we won't know at checkpoint time which file descriptor to look up.
|
||||
fds, err := getPipeFds(childPid)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error getting pipe fds for pid %d: %w", childPid, err)
|
||||
}
|
||||
p.setExternalDescriptors(fds)
|
||||
|
||||
// Wait for our first child to exit
|
||||
if err := p.waitForChildExit(childPid); err != nil {
|
||||
return fmt.Errorf("error waiting for our first child to exit: %w", err)
|
||||
}
|
||||
|
||||
if err := p.createNetworkInterfaces(); err != nil {
|
||||
return fmt.Errorf("error creating network interfaces: %w", err)
|
||||
}
|
||||
if err := p.updateSpecState(); err != nil {
|
||||
return fmt.Errorf("error updating spec state: %w", err)
|
||||
}
|
||||
if err := p.sendConfig(); err != nil {
|
||||
return fmt.Errorf("error sending config to init process: %w", err)
|
||||
}
|
||||
var (
|
||||
sentRun bool
|
||||
sentResume bool
|
||||
)
|
||||
|
||||
ierr := parseSync(p.messageSockPair.parent, func(sync *syncT) error {
|
||||
switch sync.Type {
|
||||
case procSeccomp:
|
||||
if p.config.Config.Seccomp.ListenerPath == "" {
|
||||
return errors.New("listenerPath is not set")
|
||||
}
|
||||
|
||||
seccompFd, err := recvSeccompFd(uintptr(childPid), uintptr(sync.Fd))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer unix.Close(seccompFd)
|
||||
|
||||
s, err := p.container.currentOCIState()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// initProcessStartTime hasn't been set yet.
|
||||
s.Pid = p.cmd.Process.Pid
|
||||
s.Status = specs.StateCreating
|
||||
containerProcessState := &specs.ContainerProcessState{
|
||||
Version: specs.Version,
|
||||
Fds: []string{specs.SeccompFdName},
|
||||
Pid: s.Pid,
|
||||
Metadata: p.config.Config.Seccomp.ListenerMetadata,
|
||||
State: *s,
|
||||
}
|
||||
if err := sendContainerProcessState(p.config.Config.Seccomp.ListenerPath,
|
||||
containerProcessState, seccompFd); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Sync with child.
|
||||
if err := writeSync(p.messageSockPair.parent, procSeccompDone); err != nil {
|
||||
return err
|
||||
}
|
||||
case procReady:
|
||||
// Set rlimits, this has to be done here because we lose permissions
|
||||
// to raise the limits once we enter a user-namespace
|
||||
if err := setupRlimits(p.config.Rlimits, p.pid()); err != nil {
|
||||
return fmt.Errorf("error setting rlimits for ready process: %w", err)
|
||||
}
|
||||
// call prestart and CreateRuntime hooks
|
||||
if !p.config.Config.Namespaces.Contains(configs.NEWNS) {
|
||||
// Setup cgroup before the hook, so that the prestart and CreateRuntime hook could apply cgroup permissions.
|
||||
if err := p.manager.Set(p.config.Config.Cgroups.Resources); err != nil {
|
||||
return fmt.Errorf("error setting cgroup config for ready process: %w", err)
|
||||
}
|
||||
if p.intelRdtManager != nil {
|
||||
if err := p.intelRdtManager.Set(p.config.Config); err != nil {
|
||||
return fmt.Errorf("error setting Intel RDT config for ready process: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
if len(p.config.Config.Hooks) != 0 {
|
||||
s, err := p.container.currentOCIState()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// initProcessStartTime hasn't been set yet.
|
||||
s.Pid = p.cmd.Process.Pid
|
||||
s.Status = specs.StateCreating
|
||||
hooks := p.config.Config.Hooks
|
||||
|
||||
if err := hooks[configs.Prestart].RunHooks(s); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := hooks[configs.CreateRuntime].RunHooks(s); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// generate a timestamp indicating when the container was started
|
||||
p.container.created = time.Now().UTC()
|
||||
p.container.state = &createdState{
|
||||
c: p.container,
|
||||
}
|
||||
|
||||
// NOTE: If the procRun state has been synced and the
|
||||
// runc-create process has been killed for some reason,
|
||||
// the runc-init[2:stage] process will be leaky. And
|
||||
// the runc command also fails to parse root directory
|
||||
// because the container doesn't have state.json.
|
||||
//
|
||||
// In order to cleanup the runc-init[2:stage] by
|
||||
// runc-delete/stop, we should store the status before
|
||||
// procRun sync.
|
||||
state, uerr := p.container.updateState(p)
|
||||
if uerr != nil {
|
||||
return fmt.Errorf("unable to store init state: %w", err)
|
||||
}
|
||||
p.container.initProcessStartTime = state.InitProcessStartTime
|
||||
|
||||
// Sync with child.
|
||||
if err := writeSync(p.messageSockPair.parent, procRun); err != nil {
|
||||
return err
|
||||
}
|
||||
sentRun = true
|
||||
case procHooks:
|
||||
// Setup cgroup before prestart hook, so that the prestart hook could apply cgroup permissions.
|
||||
if err := p.manager.Set(p.config.Config.Cgroups.Resources); err != nil {
|
||||
return fmt.Errorf("error setting cgroup config for procHooks process: %w", err)
|
||||
}
|
||||
if p.intelRdtManager != nil {
|
||||
if err := p.intelRdtManager.Set(p.config.Config); err != nil {
|
||||
return fmt.Errorf("error setting Intel RDT config for procHooks process: %w", err)
|
||||
}
|
||||
}
|
||||
if len(p.config.Config.Hooks) != 0 {
|
||||
s, err := p.container.currentOCIState()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// initProcessStartTime hasn't been set yet.
|
||||
s.Pid = p.cmd.Process.Pid
|
||||
s.Status = specs.StateCreating
|
||||
hooks := p.config.Config.Hooks
|
||||
|
||||
if err := hooks[configs.Prestart].RunHooks(s); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := hooks[configs.CreateRuntime].RunHooks(s); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
// Sync with child.
|
||||
if err := writeSync(p.messageSockPair.parent, procResume); err != nil {
|
||||
return err
|
||||
}
|
||||
sentResume = true
|
||||
default:
|
||||
return errors.New("invalid JSON payload from child")
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
if !sentRun {
|
||||
return fmt.Errorf("error during container init: %w", ierr)
|
||||
}
|
||||
if p.config.Config.Namespaces.Contains(configs.NEWNS) && !sentResume {
|
||||
return errors.New("could not synchronise after executing prestart and CreateRuntime hooks with container process")
|
||||
}
|
||||
if err := unix.Shutdown(int(p.messageSockPair.parent.Fd()), unix.SHUT_WR); err != nil {
|
||||
return &os.PathError{Op: "shutdown", Path: "(init pipe)", Err: err}
|
||||
}
|
||||
|
||||
// Must be done after Shutdown so the child will exit and we can wait for it.
|
||||
if ierr != nil {
|
||||
_, _ = p.wait()
|
||||
return ierr
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *initProcess) wait() (*os.ProcessState, error) {
|
||||
err := p.cmd.Wait()
|
||||
// we should kill all processes in cgroup when init is died if we use host PID namespace
|
||||
if p.sharePidns {
|
||||
_ = signalAllProcesses(p.manager, unix.SIGKILL)
|
||||
}
|
||||
return p.cmd.ProcessState, err
|
||||
}
|
||||
|
||||
func (p *initProcess) terminate() error {
|
||||
if p.cmd.Process == nil {
|
||||
return nil
|
||||
}
|
||||
err := p.cmd.Process.Kill()
|
||||
if _, werr := p.wait(); err == nil {
|
||||
err = werr
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (p *initProcess) startTime() (uint64, error) {
|
||||
stat, err := system.Stat(p.pid())
|
||||
return stat.StartTime, err
|
||||
}
|
||||
|
||||
func (p *initProcess) updateSpecState() error {
|
||||
s, err := p.container.currentOCIState()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
p.config.SpecState = s
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *initProcess) sendConfig() error {
|
||||
// send the config to the container's init process, we don't use JSON Encode
|
||||
// here because there might be a problem in JSON decoder in some cases, see:
|
||||
// https://github.com/docker/docker/issues/14203#issuecomment-174177790
|
||||
return utils.WriteJSON(p.messageSockPair.parent, p.config)
|
||||
}
|
||||
|
||||
func (p *initProcess) createNetworkInterfaces() error {
|
||||
for _, config := range p.config.Config.Networks {
|
||||
strategy, err := getStrategy(config.Type)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
n := &network{
|
||||
Network: *config,
|
||||
}
|
||||
if err := strategy.create(n, p.pid()); err != nil {
|
||||
return err
|
||||
}
|
||||
p.config.Networks = append(p.config.Networks, n)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *initProcess) signal(sig os.Signal) error {
|
||||
s, ok := sig.(unix.Signal)
|
||||
if !ok {
|
||||
return errors.New("os: unsupported signal type")
|
||||
}
|
||||
return unix.Kill(p.pid(), s)
|
||||
}
|
||||
|
||||
func (p *initProcess) setExternalDescriptors(newFds []string) {
|
||||
p.fds = newFds
|
||||
}
|
||||
|
||||
func (p *initProcess) forwardChildLogs() chan error {
|
||||
return logs.ForwardLogs(p.logFilePair.parent)
|
||||
}
|
||||
|
||||
func recvSeccompFd(childPid, childFd uintptr) (int, error) {
|
||||
pidfd, _, errno := unix.Syscall(unix.SYS_PIDFD_OPEN, childPid, 0, 0)
|
||||
if errno != 0 {
|
||||
return -1, fmt.Errorf("performing SYS_PIDFD_OPEN syscall: %w", errno)
|
||||
}
|
||||
defer unix.Close(int(pidfd))
|
||||
|
||||
seccompFd, _, errno := unix.Syscall(unix.SYS_PIDFD_GETFD, pidfd, childFd, 0)
|
||||
if errno != 0 {
|
||||
return -1, fmt.Errorf("performing SYS_PIDFD_GETFD syscall: %w", errno)
|
||||
}
|
||||
|
||||
return int(seccompFd), nil
|
||||
}
|
||||
|
||||
func sendContainerProcessState(listenerPath string, state *specs.ContainerProcessState, fd int) error {
|
||||
conn, err := net.Dial("unix", listenerPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to connect with seccomp agent specified in the seccomp profile: %w", err)
|
||||
}
|
||||
|
||||
socket, err := conn.(*net.UnixConn).File()
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot get seccomp socket: %w", err)
|
||||
}
|
||||
defer socket.Close()
|
||||
|
||||
b, err := json.Marshal(state)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot marshall seccomp state: %w", err)
|
||||
}
|
||||
|
||||
err = utils.SendFds(socket, b, fd)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot send seccomp fd to %s: %w", listenerPath, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func getPipeFds(pid int) ([]string, error) {
|
||||
fds := make([]string, 3)
|
||||
|
||||
dirPath := filepath.Join("/proc", strconv.Itoa(pid), "/fd")
|
||||
for i := 0; i < 3; i++ {
|
||||
// XXX: This breaks if the path is not a valid symlink (which can
|
||||
// happen in certain particularly unlucky mount namespace setups).
|
||||
f := filepath.Join(dirPath, strconv.Itoa(i))
|
||||
target, err := os.Readlink(f)
|
||||
if err != nil {
|
||||
// Ignore permission errors, for rootless containers and other
|
||||
// non-dumpable processes. if we can't get the fd for a particular
|
||||
// file, there's not much we can do.
|
||||
if os.IsPermission(err) {
|
||||
continue
|
||||
}
|
||||
return fds, err
|
||||
}
|
||||
fds[i] = target
|
||||
}
|
||||
return fds, nil
|
||||
}
|
||||
|
||||
// InitializeIO creates pipes for use with the process's stdio and returns the
|
||||
// opposite side for each. Do not use this if you want to have a pseudoterminal
|
||||
// set up for you by libcontainer (TODO: fix that too).
|
||||
// TODO: This is mostly unnecessary, and should be handled by clients.
|
||||
func (p *Process) InitializeIO(rootuid, rootgid int) (i *IO, err error) {
|
||||
var fds []uintptr
|
||||
i = &IO{}
|
||||
// cleanup in case of an error
|
||||
defer func() {
|
||||
if err != nil {
|
||||
for _, fd := range fds {
|
||||
_ = unix.Close(int(fd))
|
||||
}
|
||||
}
|
||||
}()
|
||||
// STDIN
|
||||
r, w, err := os.Pipe()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
fds = append(fds, r.Fd(), w.Fd())
|
||||
p.Stdin, i.Stdin = r, w
|
||||
// STDOUT
|
||||
if r, w, err = os.Pipe(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
fds = append(fds, r.Fd(), w.Fd())
|
||||
p.Stdout, i.Stdout = w, r
|
||||
// STDERR
|
||||
if r, w, err = os.Pipe(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
fds = append(fds, r.Fd(), w.Fd())
|
||||
p.Stderr, i.Stderr = w, r
|
||||
// change ownership of the pipes in case we are in a user namespace
|
||||
for _, fd := range fds {
|
||||
if err := unix.Fchown(int(fd), rootuid, rootgid); err != nil {
|
||||
return nil, &os.PathError{Op: "fchown", Path: "fd " + strconv.Itoa(int(fd)), Err: err}
|
||||
}
|
||||
}
|
||||
return i, nil
|
||||
}
|
||||
|
||||
// initWaiter returns a channel to wait on for making sure
|
||||
// runc init has finished the initial setup.
|
||||
func initWaiter(r io.Reader) chan error {
|
||||
ch := make(chan error, 1)
|
||||
go func() {
|
||||
defer close(ch)
|
||||
|
||||
inited := make([]byte, 1)
|
||||
n, err := r.Read(inited)
|
||||
if err == nil {
|
||||
if n < 1 {
|
||||
err = errors.New("short read")
|
||||
} else if inited[0] != 0 {
|
||||
err = fmt.Errorf("unexpected %d != 0", inited[0])
|
||||
} else {
|
||||
ch <- nil
|
||||
return
|
||||
}
|
||||
}
|
||||
ch <- fmt.Errorf("waiting for init preliminary setup: %w", err)
|
||||
}()
|
||||
|
||||
return ch
|
||||
}
|
||||
128
vendor/github.com/opencontainers/runc/libcontainer/restored_process.go
generated
vendored
128
vendor/github.com/opencontainers/runc/libcontainer/restored_process.go
generated
vendored
@@ -1,128 +0,0 @@
|
||||
package libcontainer
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"os"
|
||||
"os/exec"
|
||||
|
||||
"github.com/opencontainers/runc/libcontainer/system"
|
||||
)
|
||||
|
||||
func newRestoredProcess(cmd *exec.Cmd, fds []string) (*restoredProcess, error) {
|
||||
var err error
|
||||
pid := cmd.Process.Pid
|
||||
stat, err := system.Stat(pid)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &restoredProcess{
|
||||
cmd: cmd,
|
||||
processStartTime: stat.StartTime,
|
||||
fds: fds,
|
||||
}, nil
|
||||
}
|
||||
|
||||
type restoredProcess struct {
|
||||
cmd *exec.Cmd
|
||||
processStartTime uint64
|
||||
fds []string
|
||||
}
|
||||
|
||||
func (p *restoredProcess) start() error {
|
||||
return errors.New("restored process cannot be started")
|
||||
}
|
||||
|
||||
func (p *restoredProcess) pid() int {
|
||||
return p.cmd.Process.Pid
|
||||
}
|
||||
|
||||
func (p *restoredProcess) terminate() error {
|
||||
err := p.cmd.Process.Kill()
|
||||
if _, werr := p.wait(); err == nil {
|
||||
err = werr
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (p *restoredProcess) wait() (*os.ProcessState, error) {
|
||||
// TODO: how do we wait on the actual process?
|
||||
// maybe use --exec-cmd in criu
|
||||
err := p.cmd.Wait()
|
||||
if err != nil {
|
||||
var exitErr *exec.ExitError
|
||||
if !errors.As(err, &exitErr) {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
st := p.cmd.ProcessState
|
||||
return st, nil
|
||||
}
|
||||
|
||||
func (p *restoredProcess) startTime() (uint64, error) {
|
||||
return p.processStartTime, nil
|
||||
}
|
||||
|
||||
func (p *restoredProcess) signal(s os.Signal) error {
|
||||
return p.cmd.Process.Signal(s)
|
||||
}
|
||||
|
||||
func (p *restoredProcess) externalDescriptors() []string {
|
||||
return p.fds
|
||||
}
|
||||
|
||||
func (p *restoredProcess) setExternalDescriptors(newFds []string) {
|
||||
p.fds = newFds
|
||||
}
|
||||
|
||||
func (p *restoredProcess) forwardChildLogs() chan error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// nonChildProcess represents a process where the calling process is not
|
||||
// the parent process. This process is created when a factory loads a container from
|
||||
// a persisted state.
|
||||
type nonChildProcess struct {
|
||||
processPid int
|
||||
processStartTime uint64
|
||||
fds []string
|
||||
}
|
||||
|
||||
func (p *nonChildProcess) start() error {
|
||||
return errors.New("restored process cannot be started")
|
||||
}
|
||||
|
||||
func (p *nonChildProcess) pid() int {
|
||||
return p.processPid
|
||||
}
|
||||
|
||||
func (p *nonChildProcess) terminate() error {
|
||||
return errors.New("restored process cannot be terminated")
|
||||
}
|
||||
|
||||
func (p *nonChildProcess) wait() (*os.ProcessState, error) {
|
||||
return nil, errors.New("restored process cannot be waited on")
|
||||
}
|
||||
|
||||
func (p *nonChildProcess) startTime() (uint64, error) {
|
||||
return p.processStartTime, nil
|
||||
}
|
||||
|
||||
func (p *nonChildProcess) signal(s os.Signal) error {
|
||||
proc, err := os.FindProcess(p.processPid)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return proc.Signal(s)
|
||||
}
|
||||
|
||||
func (p *nonChildProcess) externalDescriptors() []string {
|
||||
return p.fds
|
||||
}
|
||||
|
||||
func (p *nonChildProcess) setExternalDescriptors(newFds []string) {
|
||||
p.fds = newFds
|
||||
}
|
||||
|
||||
func (p *nonChildProcess) forwardChildLogs() chan error {
|
||||
return nil
|
||||
}
|
||||
1155
vendor/github.com/opencontainers/runc/libcontainer/rootfs_linux.go
generated
vendored
1155
vendor/github.com/opencontainers/runc/libcontainer/rootfs_linux.go
generated
vendored
File diff suppressed because it is too large
Load Diff
113
vendor/github.com/opencontainers/runc/libcontainer/seccomp/config.go
generated
vendored
113
vendor/github.com/opencontainers/runc/libcontainer/seccomp/config.go
generated
vendored
@@ -1,113 +0,0 @@
|
||||
package seccomp
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
|
||||
"github.com/opencontainers/runc/libcontainer/configs"
|
||||
)
|
||||
|
||||
var operators = map[string]configs.Operator{
|
||||
"SCMP_CMP_NE": configs.NotEqualTo,
|
||||
"SCMP_CMP_LT": configs.LessThan,
|
||||
"SCMP_CMP_LE": configs.LessThanOrEqualTo,
|
||||
"SCMP_CMP_EQ": configs.EqualTo,
|
||||
"SCMP_CMP_GE": configs.GreaterThanOrEqualTo,
|
||||
"SCMP_CMP_GT": configs.GreaterThan,
|
||||
"SCMP_CMP_MASKED_EQ": configs.MaskEqualTo,
|
||||
}
|
||||
|
||||
// KnownOperators returns the list of the known operations.
|
||||
// Used by `runc features`.
|
||||
func KnownOperators() []string {
|
||||
var res []string
|
||||
for k := range operators {
|
||||
res = append(res, k)
|
||||
}
|
||||
sort.Strings(res)
|
||||
return res
|
||||
}
|
||||
|
||||
var actions = map[string]configs.Action{
|
||||
"SCMP_ACT_KILL": configs.Kill,
|
||||
"SCMP_ACT_ERRNO": configs.Errno,
|
||||
"SCMP_ACT_TRAP": configs.Trap,
|
||||
"SCMP_ACT_ALLOW": configs.Allow,
|
||||
"SCMP_ACT_TRACE": configs.Trace,
|
||||
"SCMP_ACT_LOG": configs.Log,
|
||||
"SCMP_ACT_NOTIFY": configs.Notify,
|
||||
"SCMP_ACT_KILL_THREAD": configs.KillThread,
|
||||
"SCMP_ACT_KILL_PROCESS": configs.KillProcess,
|
||||
}
|
||||
|
||||
// KnownActions returns the list of the known actions.
|
||||
// Used by `runc features`.
|
||||
func KnownActions() []string {
|
||||
var res []string
|
||||
for k := range actions {
|
||||
res = append(res, k)
|
||||
}
|
||||
sort.Strings(res)
|
||||
return res
|
||||
}
|
||||
|
||||
var archs = map[string]string{
|
||||
"SCMP_ARCH_X86": "x86",
|
||||
"SCMP_ARCH_X86_64": "amd64",
|
||||
"SCMP_ARCH_X32": "x32",
|
||||
"SCMP_ARCH_ARM": "arm",
|
||||
"SCMP_ARCH_AARCH64": "arm64",
|
||||
"SCMP_ARCH_MIPS": "mips",
|
||||
"SCMP_ARCH_MIPS64": "mips64",
|
||||
"SCMP_ARCH_MIPS64N32": "mips64n32",
|
||||
"SCMP_ARCH_MIPSEL": "mipsel",
|
||||
"SCMP_ARCH_MIPSEL64": "mipsel64",
|
||||
"SCMP_ARCH_MIPSEL64N32": "mipsel64n32",
|
||||
"SCMP_ARCH_PPC": "ppc",
|
||||
"SCMP_ARCH_PPC64": "ppc64",
|
||||
"SCMP_ARCH_PPC64LE": "ppc64le",
|
||||
"SCMP_ARCH_RISCV64": "riscv64",
|
||||
"SCMP_ARCH_S390": "s390",
|
||||
"SCMP_ARCH_S390X": "s390x",
|
||||
}
|
||||
|
||||
// KnownArchs returns the list of the known archs.
|
||||
// Used by `runc features`.
|
||||
func KnownArchs() []string {
|
||||
var res []string
|
||||
for k := range archs {
|
||||
res = append(res, k)
|
||||
}
|
||||
sort.Strings(res)
|
||||
return res
|
||||
}
|
||||
|
||||
// ConvertStringToOperator converts a string into a Seccomp comparison operator.
|
||||
// Comparison operators use the names they are assigned by Libseccomp's header.
|
||||
// Attempting to convert a string that is not a valid operator results in an
|
||||
// error.
|
||||
func ConvertStringToOperator(in string) (configs.Operator, error) {
|
||||
if op, ok := operators[in]; ok {
|
||||
return op, nil
|
||||
}
|
||||
return 0, fmt.Errorf("string %s is not a valid operator for seccomp", in)
|
||||
}
|
||||
|
||||
// ConvertStringToAction converts a string into a Seccomp rule match action.
|
||||
// Actions use the names they are assigned in Libseccomp's header.
|
||||
// Attempting to convert a string that is not a valid action results in an
|
||||
// error.
|
||||
func ConvertStringToAction(in string) (configs.Action, error) {
|
||||
if act, ok := actions[in]; ok {
|
||||
return act, nil
|
||||
}
|
||||
return 0, fmt.Errorf("string %s is not a valid action for seccomp", in)
|
||||
}
|
||||
|
||||
// ConvertStringToArch converts a string into a Seccomp comparison arch.
|
||||
func ConvertStringToArch(in string) (string, error) {
|
||||
if arch, ok := archs[in]; ok {
|
||||
return arch, nil
|
||||
}
|
||||
return "", fmt.Errorf("string %s is not a valid arch for seccomp", in)
|
||||
}
|
||||
721
vendor/github.com/opencontainers/runc/libcontainer/seccomp/patchbpf/enosys_linux.go
generated
vendored
721
vendor/github.com/opencontainers/runc/libcontainer/seccomp/patchbpf/enosys_linux.go
generated
vendored
@@ -1,721 +0,0 @@
|
||||
//go:build cgo && seccomp
|
||||
// +build cgo,seccomp
|
||||
|
||||
package patchbpf
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"runtime"
|
||||
"unsafe"
|
||||
|
||||
libseccomp "github.com/seccomp/libseccomp-golang"
|
||||
"github.com/sirupsen/logrus"
|
||||
"golang.org/x/net/bpf"
|
||||
"golang.org/x/sys/unix"
|
||||
|
||||
"github.com/opencontainers/runc/libcontainer/configs"
|
||||
"github.com/opencontainers/runc/libcontainer/utils"
|
||||
)
|
||||
|
||||
// #cgo pkg-config: libseccomp
|
||||
/*
|
||||
#include <errno.h>
|
||||
#include <stdint.h>
|
||||
#include <seccomp.h>
|
||||
#include <linux/seccomp.h>
|
||||
|
||||
const uint32_t C_ACT_ERRNO_ENOSYS = SCMP_ACT_ERRNO(ENOSYS);
|
||||
|
||||
// Copied from <linux/seccomp.h>.
|
||||
|
||||
#ifndef SECCOMP_SET_MODE_FILTER
|
||||
# define SECCOMP_SET_MODE_FILTER 1
|
||||
#endif
|
||||
const uintptr_t C_SET_MODE_FILTER = SECCOMP_SET_MODE_FILTER;
|
||||
|
||||
#ifndef SECCOMP_FILTER_FLAG_LOG
|
||||
# define SECCOMP_FILTER_FLAG_LOG (1UL << 1)
|
||||
#endif
|
||||
const uintptr_t C_FILTER_FLAG_LOG = SECCOMP_FILTER_FLAG_LOG;
|
||||
|
||||
#ifndef SECCOMP_FILTER_FLAG_NEW_LISTENER
|
||||
# define SECCOMP_FILTER_FLAG_NEW_LISTENER (1UL << 3)
|
||||
#endif
|
||||
const uintptr_t C_FILTER_FLAG_NEW_LISTENER = SECCOMP_FILTER_FLAG_NEW_LISTENER;
|
||||
|
||||
#ifndef AUDIT_ARCH_RISCV64
|
||||
#ifndef EM_RISCV
|
||||
#define EM_RISCV 243
|
||||
#endif
|
||||
#define AUDIT_ARCH_RISCV64 (EM_RISCV|__AUDIT_ARCH_64BIT|__AUDIT_ARCH_LE)
|
||||
#endif
|
||||
|
||||
// We use the AUDIT_ARCH_* values because those are the ones used by the kernel
|
||||
// and SCMP_ARCH_* sometimes has fake values (such as SCMP_ARCH_X32). But we
|
||||
// use <seccomp.h> so we get libseccomp's fallback definitions of AUDIT_ARCH_*.
|
||||
|
||||
const uint32_t C_AUDIT_ARCH_I386 = AUDIT_ARCH_I386;
|
||||
const uint32_t C_AUDIT_ARCH_X86_64 = AUDIT_ARCH_X86_64;
|
||||
const uint32_t C_AUDIT_ARCH_ARM = AUDIT_ARCH_ARM;
|
||||
const uint32_t C_AUDIT_ARCH_AARCH64 = AUDIT_ARCH_AARCH64;
|
||||
const uint32_t C_AUDIT_ARCH_MIPS = AUDIT_ARCH_MIPS;
|
||||
const uint32_t C_AUDIT_ARCH_MIPS64 = AUDIT_ARCH_MIPS64;
|
||||
const uint32_t C_AUDIT_ARCH_MIPS64N32 = AUDIT_ARCH_MIPS64N32;
|
||||
const uint32_t C_AUDIT_ARCH_MIPSEL = AUDIT_ARCH_MIPSEL;
|
||||
const uint32_t C_AUDIT_ARCH_MIPSEL64 = AUDIT_ARCH_MIPSEL64;
|
||||
const uint32_t C_AUDIT_ARCH_MIPSEL64N32 = AUDIT_ARCH_MIPSEL64N32;
|
||||
const uint32_t C_AUDIT_ARCH_PPC = AUDIT_ARCH_PPC;
|
||||
const uint32_t C_AUDIT_ARCH_PPC64 = AUDIT_ARCH_PPC64;
|
||||
const uint32_t C_AUDIT_ARCH_PPC64LE = AUDIT_ARCH_PPC64LE;
|
||||
const uint32_t C_AUDIT_ARCH_S390 = AUDIT_ARCH_S390;
|
||||
const uint32_t C_AUDIT_ARCH_S390X = AUDIT_ARCH_S390X;
|
||||
const uint32_t C_AUDIT_ARCH_RISCV64 = AUDIT_ARCH_RISCV64;
|
||||
*/
|
||||
import "C"
|
||||
|
||||
var retErrnoEnosys = uint32(C.C_ACT_ERRNO_ENOSYS)
|
||||
|
||||
// This syscall is used for multiplexing "large" syscalls on s390(x). Unknown
|
||||
// syscalls will end up with this syscall number, so we need to explicitly
|
||||
// return -ENOSYS for this syscall on those architectures.
|
||||
const s390xMultiplexSyscall libseccomp.ScmpSyscall = 0
|
||||
|
||||
func isAllowAction(action configs.Action) bool {
|
||||
switch action {
|
||||
// Trace is considered an "allow" action because a good tracer should
|
||||
// support future syscalls (by handling -ENOSYS on its own), and giving
|
||||
// -ENOSYS will be disruptive for emulation.
|
||||
case configs.Allow, configs.Log, configs.Trace:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func parseProgram(rdr io.Reader) ([]bpf.RawInstruction, error) {
|
||||
var program []bpf.RawInstruction
|
||||
loop:
|
||||
for {
|
||||
// Read the next instruction. We have to use NativeEndian because
|
||||
// seccomp_export_bpf outputs the program in *host* endian-ness.
|
||||
var insn unix.SockFilter
|
||||
if err := binary.Read(rdr, utils.NativeEndian, &insn); err != nil {
|
||||
if errors.Is(err, io.EOF) {
|
||||
// Parsing complete.
|
||||
break loop
|
||||
}
|
||||
if errors.Is(err, io.ErrUnexpectedEOF) {
|
||||
// Parsing stopped mid-instruction.
|
||||
return nil, fmt.Errorf("program parsing halted mid-instruction: %w", err)
|
||||
}
|
||||
// All other errors.
|
||||
return nil, fmt.Errorf("error parsing instructions: %w", err)
|
||||
}
|
||||
program = append(program, bpf.RawInstruction{
|
||||
Op: insn.Code,
|
||||
Jt: insn.Jt,
|
||||
Jf: insn.Jf,
|
||||
K: insn.K,
|
||||
})
|
||||
}
|
||||
return program, nil
|
||||
}
|
||||
|
||||
func disassembleFilter(filter *libseccomp.ScmpFilter) ([]bpf.Instruction, error) {
|
||||
rdr, wtr, err := os.Pipe()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error creating scratch pipe: %w", err)
|
||||
}
|
||||
defer wtr.Close()
|
||||
defer rdr.Close()
|
||||
|
||||
readerBuffer := new(bytes.Buffer)
|
||||
errChan := make(chan error, 1)
|
||||
go func() {
|
||||
_, err := io.Copy(readerBuffer, rdr)
|
||||
errChan <- err
|
||||
close(errChan)
|
||||
}()
|
||||
|
||||
if err := filter.ExportBPF(wtr); err != nil {
|
||||
return nil, fmt.Errorf("error exporting BPF: %w", err)
|
||||
}
|
||||
// Close so that the reader actually gets EOF.
|
||||
_ = wtr.Close()
|
||||
|
||||
if copyErr := <-errChan; copyErr != nil {
|
||||
return nil, fmt.Errorf("error reading from ExportBPF pipe: %w", copyErr)
|
||||
}
|
||||
|
||||
// Parse the instructions.
|
||||
rawProgram, err := parseProgram(readerBuffer)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("parsing generated BPF filter: %w", err)
|
||||
}
|
||||
program, ok := bpf.Disassemble(rawProgram)
|
||||
if !ok {
|
||||
return nil, errors.New("could not disassemble entire BPF filter")
|
||||
}
|
||||
return program, nil
|
||||
}
|
||||
|
||||
type linuxAuditArch uint32
|
||||
|
||||
const invalidArch linuxAuditArch = 0
|
||||
|
||||
func scmpArchToAuditArch(arch libseccomp.ScmpArch) (linuxAuditArch, error) {
|
||||
switch arch {
|
||||
case libseccomp.ArchNative:
|
||||
// Convert to actual native architecture.
|
||||
arch, err := libseccomp.GetNativeArch()
|
||||
if err != nil {
|
||||
return invalidArch, fmt.Errorf("unable to get native arch: %w", err)
|
||||
}
|
||||
return scmpArchToAuditArch(arch)
|
||||
case libseccomp.ArchX86:
|
||||
return linuxAuditArch(C.C_AUDIT_ARCH_I386), nil
|
||||
case libseccomp.ArchAMD64, libseccomp.ArchX32:
|
||||
// NOTE: x32 is treated like x86_64 except all x32 syscalls have the
|
||||
// 30th bit of the syscall number set to indicate that it's not a
|
||||
// normal x86_64 syscall.
|
||||
return linuxAuditArch(C.C_AUDIT_ARCH_X86_64), nil
|
||||
case libseccomp.ArchARM:
|
||||
return linuxAuditArch(C.C_AUDIT_ARCH_ARM), nil
|
||||
case libseccomp.ArchARM64:
|
||||
return linuxAuditArch(C.C_AUDIT_ARCH_AARCH64), nil
|
||||
case libseccomp.ArchMIPS:
|
||||
return linuxAuditArch(C.C_AUDIT_ARCH_MIPS), nil
|
||||
case libseccomp.ArchMIPS64:
|
||||
return linuxAuditArch(C.C_AUDIT_ARCH_MIPS64), nil
|
||||
case libseccomp.ArchMIPS64N32:
|
||||
return linuxAuditArch(C.C_AUDIT_ARCH_MIPS64N32), nil
|
||||
case libseccomp.ArchMIPSEL:
|
||||
return linuxAuditArch(C.C_AUDIT_ARCH_MIPSEL), nil
|
||||
case libseccomp.ArchMIPSEL64:
|
||||
return linuxAuditArch(C.C_AUDIT_ARCH_MIPSEL64), nil
|
||||
case libseccomp.ArchMIPSEL64N32:
|
||||
return linuxAuditArch(C.C_AUDIT_ARCH_MIPSEL64N32), nil
|
||||
case libseccomp.ArchPPC:
|
||||
return linuxAuditArch(C.C_AUDIT_ARCH_PPC), nil
|
||||
case libseccomp.ArchPPC64:
|
||||
return linuxAuditArch(C.C_AUDIT_ARCH_PPC64), nil
|
||||
case libseccomp.ArchPPC64LE:
|
||||
return linuxAuditArch(C.C_AUDIT_ARCH_PPC64LE), nil
|
||||
case libseccomp.ArchS390:
|
||||
return linuxAuditArch(C.C_AUDIT_ARCH_S390), nil
|
||||
case libseccomp.ArchS390X:
|
||||
return linuxAuditArch(C.C_AUDIT_ARCH_S390X), nil
|
||||
case libseccomp.ArchRISCV64:
|
||||
return linuxAuditArch(C.C_AUDIT_ARCH_RISCV64), nil
|
||||
default:
|
||||
return invalidArch, fmt.Errorf("unknown architecture: %v", arch)
|
||||
}
|
||||
}
|
||||
|
||||
type lastSyscallMap map[linuxAuditArch]map[libseccomp.ScmpArch]libseccomp.ScmpSyscall
|
||||
|
||||
// Figure out largest syscall number referenced in the filter for each
|
||||
// architecture. We will be generating code based on the native architecture
|
||||
// representation, but SCMP_ARCH_X32 means we have to track cases where the
|
||||
// same architecture has different largest syscalls based on the mode.
|
||||
func findLastSyscalls(config *configs.Seccomp) (lastSyscallMap, error) {
|
||||
scmpArchs := make(map[libseccomp.ScmpArch]struct{})
|
||||
for _, ociArch := range config.Architectures {
|
||||
arch, err := libseccomp.GetArchFromString(ociArch)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to validate seccomp architecture: %w", err)
|
||||
}
|
||||
scmpArchs[arch] = struct{}{}
|
||||
}
|
||||
// On architectures like ppc64le, Docker inexplicably doesn't include the
|
||||
// native architecture in the architecture list which results in no
|
||||
// architectures being present in the list at all (rendering the ENOSYS
|
||||
// stub a no-op). So, always include the native architecture.
|
||||
if nativeScmpArch, err := libseccomp.GetNativeArch(); err != nil {
|
||||
return nil, fmt.Errorf("unable to get native arch: %w", err)
|
||||
} else if _, ok := scmpArchs[nativeScmpArch]; !ok {
|
||||
logrus.Debugf("seccomp: adding implied native architecture %v to config set", nativeScmpArch)
|
||||
scmpArchs[nativeScmpArch] = struct{}{}
|
||||
}
|
||||
logrus.Debugf("seccomp: configured architecture set: %s", scmpArchs)
|
||||
|
||||
// Only loop over architectures which are present in the filter. Any other
|
||||
// architectures will get the libseccomp bad architecture action anyway.
|
||||
lastSyscalls := make(lastSyscallMap)
|
||||
for arch := range scmpArchs {
|
||||
auditArch, err := scmpArchToAuditArch(arch)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot map architecture %v to AUDIT_ARCH_ constant: %w", arch, err)
|
||||
}
|
||||
|
||||
if _, ok := lastSyscalls[auditArch]; !ok {
|
||||
lastSyscalls[auditArch] = map[libseccomp.ScmpArch]libseccomp.ScmpSyscall{}
|
||||
}
|
||||
if _, ok := lastSyscalls[auditArch][arch]; ok {
|
||||
// Because of ArchNative we may hit the same entry multiple times.
|
||||
// Just skip it if we've seen this (linuxAuditArch, ScmpArch)
|
||||
// combination before.
|
||||
continue
|
||||
}
|
||||
|
||||
// Find the largest syscall in the filter for this architecture.
|
||||
var largestSyscall libseccomp.ScmpSyscall
|
||||
for _, rule := range config.Syscalls {
|
||||
sysno, err := libseccomp.GetSyscallFromNameByArch(rule.Name, arch)
|
||||
if err != nil {
|
||||
// Ignore unknown syscalls.
|
||||
continue
|
||||
}
|
||||
if sysno > largestSyscall {
|
||||
largestSyscall = sysno
|
||||
}
|
||||
}
|
||||
if largestSyscall != 0 {
|
||||
logrus.Debugf("seccomp: largest syscall number for arch %v is %v", arch, largestSyscall)
|
||||
lastSyscalls[auditArch][arch] = largestSyscall
|
||||
} else {
|
||||
logrus.Warnf("could not find any syscalls for arch %v", arch)
|
||||
delete(lastSyscalls[auditArch], arch)
|
||||
}
|
||||
}
|
||||
return lastSyscalls, nil
|
||||
}
|
||||
|
||||
// FIXME FIXME FIXME
|
||||
//
|
||||
// This solution is less than ideal. In the future it would be great to have
|
||||
// per-arch information about which syscalls were added in which kernel
|
||||
// versions so we can create far more accurate filter rules (handling holes in
|
||||
// the syscall table and determining -ENOSYS requirements based on kernel
|
||||
// minimum version alone.
|
||||
//
|
||||
// This implementation can in principle cause issues with syscalls like
|
||||
// close_range(2) which were added out-of-order in the syscall table between
|
||||
// kernel releases.
|
||||
func generateEnosysStub(lastSyscalls lastSyscallMap) ([]bpf.Instruction, error) {
|
||||
// A jump-table for each linuxAuditArch used to generate the initial
|
||||
// conditional jumps -- measured from the *END* of the program so they
|
||||
// remain valid after prepending to the tail.
|
||||
archJumpTable := map[linuxAuditArch]uint32{}
|
||||
|
||||
// Generate our own -ENOSYS rules for each architecture. They have to be
|
||||
// generated in reverse (prepended to the tail of the program) because the
|
||||
// JumpIf jumps need to be computed from the end of the program.
|
||||
programTail := []bpf.Instruction{
|
||||
// Fall-through rules jump into the filter.
|
||||
bpf.Jump{Skip: 1},
|
||||
// Rules which jump to here get -ENOSYS.
|
||||
bpf.RetConstant{Val: retErrnoEnosys},
|
||||
}
|
||||
|
||||
// Generate the syscall -ENOSYS rules.
|
||||
for auditArch, maxSyscalls := range lastSyscalls {
|
||||
// The number of instructions from the tail of this section which need
|
||||
// to be jumped in order to reach the -ENOSYS return. If the section
|
||||
// does not jump, it will fall through to the actual filter.
|
||||
baseJumpEnosys := uint32(len(programTail) - 1)
|
||||
baseJumpFilter := baseJumpEnosys + 1
|
||||
|
||||
// Add the load instruction for the syscall number -- we jump here
|
||||
// directly from the arch code so we need to do it here. Sadly we can't
|
||||
// share this code between architecture branches.
|
||||
section := []bpf.Instruction{
|
||||
// load [0] (syscall number)
|
||||
bpf.LoadAbsolute{Off: 0, Size: 4}, // NOTE: We assume sizeof(int) == 4.
|
||||
}
|
||||
|
||||
switch len(maxSyscalls) {
|
||||
case 0:
|
||||
// No syscalls found for this arch -- skip it and move on.
|
||||
continue
|
||||
case 1:
|
||||
// Get the only syscall and scmpArch in the map.
|
||||
var (
|
||||
scmpArch libseccomp.ScmpArch
|
||||
sysno libseccomp.ScmpSyscall
|
||||
)
|
||||
for arch, no := range maxSyscalls {
|
||||
sysno = no
|
||||
scmpArch = arch
|
||||
}
|
||||
|
||||
switch scmpArch {
|
||||
// Return -ENOSYS for setup(2) on s390(x). This syscall is used for
|
||||
// multiplexing "large syscall number" syscalls, but if the syscall
|
||||
// number is not known to the kernel then the syscall number is
|
||||
// left unchanged (and because it is sysno=0, you'll end up with
|
||||
// EPERM for syscalls the kernel doesn't know about).
|
||||
//
|
||||
// The actual setup(2) syscall is never used by userspace anymore
|
||||
// (and hasn't existed for decades) outside of this multiplexing
|
||||
// scheme so returning -ENOSYS is fine.
|
||||
case libseccomp.ArchS390, libseccomp.ArchS390X:
|
||||
section = append(section, []bpf.Instruction{
|
||||
// jne [setup=0],1
|
||||
bpf.JumpIf{
|
||||
Cond: bpf.JumpNotEqual,
|
||||
Val: uint32(s390xMultiplexSyscall),
|
||||
SkipTrue: 1,
|
||||
},
|
||||
// ret [ENOSYS]
|
||||
bpf.RetConstant{Val: retErrnoEnosys},
|
||||
}...)
|
||||
}
|
||||
|
||||
// The simplest case just boils down to a single jgt instruction,
|
||||
// with special handling if baseJumpEnosys is larger than 255 (and
|
||||
// thus a long jump is required).
|
||||
var sectionTail []bpf.Instruction
|
||||
if baseJumpEnosys+1 <= 255 {
|
||||
sectionTail = []bpf.Instruction{
|
||||
// jgt [syscall],[baseJumpEnosys+1]
|
||||
bpf.JumpIf{
|
||||
Cond: bpf.JumpGreaterThan,
|
||||
Val: uint32(sysno),
|
||||
SkipTrue: uint8(baseJumpEnosys + 1),
|
||||
},
|
||||
// ja [baseJumpFilter]
|
||||
bpf.Jump{Skip: baseJumpFilter},
|
||||
}
|
||||
} else {
|
||||
sectionTail = []bpf.Instruction{
|
||||
// jle [syscall],1
|
||||
bpf.JumpIf{Cond: bpf.JumpLessOrEqual, Val: uint32(sysno), SkipTrue: 1},
|
||||
// ja [baseJumpEnosys+1]
|
||||
bpf.Jump{Skip: baseJumpEnosys + 1},
|
||||
// ja [baseJumpFilter]
|
||||
bpf.Jump{Skip: baseJumpFilter},
|
||||
}
|
||||
}
|
||||
|
||||
// If we're on x86 we need to add a check for x32 and if we're in
|
||||
// the wrong mode we jump over the section.
|
||||
if uint32(auditArch) == uint32(C.C_AUDIT_ARCH_X86_64) {
|
||||
// Generate a prefix to check the mode.
|
||||
switch scmpArch {
|
||||
case libseccomp.ArchAMD64:
|
||||
sectionTail = append([]bpf.Instruction{
|
||||
// jset (1<<30),[len(tail)-1]
|
||||
bpf.JumpIf{
|
||||
Cond: bpf.JumpBitsSet,
|
||||
Val: 1 << 30,
|
||||
SkipTrue: uint8(len(sectionTail) - 1),
|
||||
},
|
||||
}, sectionTail...)
|
||||
case libseccomp.ArchX32:
|
||||
sectionTail = append([]bpf.Instruction{
|
||||
// jset (1<<30),0,[len(tail)-1]
|
||||
bpf.JumpIf{
|
||||
Cond: bpf.JumpBitsNotSet,
|
||||
Val: 1 << 30,
|
||||
SkipTrue: uint8(len(sectionTail) - 1),
|
||||
},
|
||||
}, sectionTail...)
|
||||
default:
|
||||
return nil, fmt.Errorf("unknown amd64 native architecture %#x", scmpArch)
|
||||
}
|
||||
}
|
||||
|
||||
section = append(section, sectionTail...)
|
||||
case 2:
|
||||
// x32 and x86_64 are a unique case, we can't handle any others.
|
||||
if uint32(auditArch) != uint32(C.C_AUDIT_ARCH_X86_64) {
|
||||
return nil, fmt.Errorf("unknown architecture overlap on native arch %#x", auditArch)
|
||||
}
|
||||
|
||||
x32sysno, ok := maxSyscalls[libseccomp.ArchX32]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("missing %v in overlapping x86_64 arch: %v", libseccomp.ArchX32, maxSyscalls)
|
||||
}
|
||||
x86sysno, ok := maxSyscalls[libseccomp.ArchAMD64]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("missing %v in overlapping x86_64 arch: %v", libseccomp.ArchAMD64, maxSyscalls)
|
||||
}
|
||||
|
||||
// The x32 ABI indicates that a syscall is being made by an x32
|
||||
// process by setting the 30th bit of the syscall number, but we
|
||||
// need to do some special-casing depending on whether we need to
|
||||
// do long jumps.
|
||||
if baseJumpEnosys+2 <= 255 {
|
||||
// For the simple case we want to have something like:
|
||||
// jset (1<<30),1
|
||||
// jgt [x86 syscall],[baseJumpEnosys+2],1
|
||||
// jgt [x32 syscall],[baseJumpEnosys+1]
|
||||
// ja [baseJumpFilter]
|
||||
section = append(section, []bpf.Instruction{
|
||||
// jset (1<<30),1
|
||||
bpf.JumpIf{Cond: bpf.JumpBitsSet, Val: 1 << 30, SkipTrue: 1},
|
||||
// jgt [x86 syscall],[baseJumpEnosys+1],1
|
||||
bpf.JumpIf{
|
||||
Cond: bpf.JumpGreaterThan,
|
||||
Val: uint32(x86sysno),
|
||||
SkipTrue: uint8(baseJumpEnosys + 2), SkipFalse: 1,
|
||||
},
|
||||
// jgt [x32 syscall],[baseJumpEnosys]
|
||||
bpf.JumpIf{
|
||||
Cond: bpf.JumpGreaterThan,
|
||||
Val: uint32(x32sysno),
|
||||
SkipTrue: uint8(baseJumpEnosys + 1),
|
||||
},
|
||||
// ja [baseJumpFilter]
|
||||
bpf.Jump{Skip: baseJumpFilter},
|
||||
}...)
|
||||
} else {
|
||||
// But if the [baseJumpEnosys+2] jump is larger than 255 we
|
||||
// need to do a long jump like so:
|
||||
// jset (1<<30),1
|
||||
// jgt [x86 syscall],1,2
|
||||
// jle [x32 syscall],1
|
||||
// ja [baseJumpEnosys+1]
|
||||
// ja [baseJumpFilter]
|
||||
section = append(section, []bpf.Instruction{
|
||||
// jset (1<<30),1
|
||||
bpf.JumpIf{Cond: bpf.JumpBitsSet, Val: 1 << 30, SkipTrue: 1},
|
||||
// jgt [x86 syscall],1,2
|
||||
bpf.JumpIf{
|
||||
Cond: bpf.JumpGreaterThan,
|
||||
Val: uint32(x86sysno),
|
||||
SkipTrue: 1, SkipFalse: 2,
|
||||
},
|
||||
// jle [x32 syscall],[baseJumpEnosys]
|
||||
bpf.JumpIf{
|
||||
Cond: bpf.JumpLessOrEqual,
|
||||
Val: uint32(x32sysno),
|
||||
SkipTrue: 1,
|
||||
},
|
||||
// ja [baseJumpEnosys+1]
|
||||
bpf.Jump{Skip: baseJumpEnosys + 1},
|
||||
// ja [baseJumpFilter]
|
||||
bpf.Jump{Skip: baseJumpFilter},
|
||||
}...)
|
||||
}
|
||||
default:
|
||||
return nil, fmt.Errorf("invalid number of architecture overlaps: %v", len(maxSyscalls))
|
||||
}
|
||||
|
||||
// Prepend this section to the tail.
|
||||
programTail = append(section, programTail...)
|
||||
|
||||
// Update jump table.
|
||||
archJumpTable[auditArch] = uint32(len(programTail))
|
||||
}
|
||||
|
||||
// Add a dummy "jump to filter" for any architecture we might miss below.
|
||||
// Such architectures will probably get the BadArch action of the filter
|
||||
// regardless.
|
||||
programTail = append([]bpf.Instruction{
|
||||
// ja [end of stub and start of filter]
|
||||
bpf.Jump{Skip: uint32(len(programTail))},
|
||||
}, programTail...)
|
||||
|
||||
// Generate the jump rules for each architecture. This has to be done in
|
||||
// reverse as well for the same reason as above. We add to programTail
|
||||
// directly because the jumps are impacted by each architecture rule we add
|
||||
// as well.
|
||||
//
|
||||
// TODO: Maybe we want to optimise to avoid long jumps here? So sort the
|
||||
// architectures based on how large the jumps are going to be, or
|
||||
// re-sort the candidate architectures each time to make sure that we
|
||||
// pick the largest jump which is going to be smaller than 255.
|
||||
for auditArch := range lastSyscalls {
|
||||
// We jump forwards but the jump table is calculated from the *END*.
|
||||
jump := uint32(len(programTail)) - archJumpTable[auditArch]
|
||||
|
||||
// Same routine as above -- this is a basic jeq check, complicated
|
||||
// slightly if it turns out that we need to do a long jump.
|
||||
if jump <= 255 {
|
||||
programTail = append([]bpf.Instruction{
|
||||
// jeq [arch],[jump]
|
||||
bpf.JumpIf{
|
||||
Cond: bpf.JumpEqual,
|
||||
Val: uint32(auditArch),
|
||||
SkipTrue: uint8(jump),
|
||||
},
|
||||
}, programTail...)
|
||||
} else {
|
||||
programTail = append([]bpf.Instruction{
|
||||
// jne [arch],1
|
||||
bpf.JumpIf{
|
||||
Cond: bpf.JumpNotEqual,
|
||||
Val: uint32(auditArch),
|
||||
SkipTrue: 1,
|
||||
},
|
||||
// ja [jump]
|
||||
bpf.Jump{Skip: jump},
|
||||
}, programTail...)
|
||||
}
|
||||
}
|
||||
|
||||
// Prepend the load instruction for the architecture.
|
||||
programTail = append([]bpf.Instruction{
|
||||
// load [4] (architecture)
|
||||
bpf.LoadAbsolute{Off: 4, Size: 4}, // NOTE: We assume sizeof(int) == 4.
|
||||
}, programTail...)
|
||||
|
||||
// And that's all folks!
|
||||
return programTail, nil
|
||||
}
|
||||
|
||||
func assemble(program []bpf.Instruction) ([]unix.SockFilter, error) {
|
||||
rawProgram, err := bpf.Assemble(program)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error assembling program: %w", err)
|
||||
}
|
||||
|
||||
// Convert to []unix.SockFilter for unix.SockFilter.
|
||||
var filter []unix.SockFilter
|
||||
for _, insn := range rawProgram {
|
||||
filter = append(filter, unix.SockFilter{
|
||||
Code: insn.Op,
|
||||
Jt: insn.Jt,
|
||||
Jf: insn.Jf,
|
||||
K: insn.K,
|
||||
})
|
||||
}
|
||||
return filter, nil
|
||||
}
|
||||
|
||||
func generatePatch(config *configs.Seccomp) ([]bpf.Instruction, error) {
|
||||
// Patch the generated cBPF only when there is not a defaultErrnoRet set
|
||||
// and it is different from ENOSYS
|
||||
if config.DefaultErrnoRet != nil && *config.DefaultErrnoRet == uint(retErrnoEnosys) {
|
||||
return nil, nil
|
||||
}
|
||||
// We only add the stub if the default action is not permissive.
|
||||
if isAllowAction(config.DefaultAction) {
|
||||
logrus.Debugf("seccomp: skipping -ENOSYS stub filter generation")
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
lastSyscalls, err := findLastSyscalls(config)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error finding last syscalls for -ENOSYS stub: %w", err)
|
||||
}
|
||||
stubProgram, err := generateEnosysStub(lastSyscalls)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error generating -ENOSYS stub: %w", err)
|
||||
}
|
||||
return stubProgram, nil
|
||||
}
|
||||
|
||||
func enosysPatchFilter(config *configs.Seccomp, filter *libseccomp.ScmpFilter) ([]unix.SockFilter, error) {
|
||||
program, err := disassembleFilter(filter)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error disassembling original filter: %w", err)
|
||||
}
|
||||
|
||||
patch, err := generatePatch(config)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error generating patch for filter: %w", err)
|
||||
}
|
||||
fullProgram := append(patch, program...)
|
||||
|
||||
logrus.Debugf("seccomp: prepending -ENOSYS stub filter to user filter...")
|
||||
for idx, insn := range patch {
|
||||
logrus.Debugf(" [%4.1d] %s", idx, insn)
|
||||
}
|
||||
logrus.Debugf(" [....] --- original filter ---")
|
||||
|
||||
fprog, err := assemble(fullProgram)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error assembling modified filter: %w", err)
|
||||
}
|
||||
return fprog, nil
|
||||
}
|
||||
|
||||
func filterFlags(config *configs.Seccomp, filter *libseccomp.ScmpFilter) (flags uint, noNewPrivs bool, err error) {
|
||||
// Ignore the error since pre-2.4 libseccomp is treated as API level 0.
|
||||
apiLevel, _ := libseccomp.GetAPI()
|
||||
|
||||
noNewPrivs, err = filter.GetNoNewPrivsBit()
|
||||
if err != nil {
|
||||
return 0, false, fmt.Errorf("unable to fetch no_new_privs filter bit: %w", err)
|
||||
}
|
||||
|
||||
if apiLevel >= 3 {
|
||||
if logBit, err := filter.GetLogBit(); err != nil {
|
||||
return 0, false, fmt.Errorf("unable to fetch SECCOMP_FILTER_FLAG_LOG bit: %w", err)
|
||||
} else if logBit {
|
||||
flags |= uint(C.C_FILTER_FLAG_LOG)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Support seccomp flags not yet added to libseccomp-golang...
|
||||
|
||||
for _, call := range config.Syscalls {
|
||||
if call.Action == configs.Notify {
|
||||
flags |= uint(C.C_FILTER_FLAG_NEW_LISTENER)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func sysSeccompSetFilter(flags uint, filter []unix.SockFilter) (fd int, err error) {
|
||||
fprog := unix.SockFprog{
|
||||
Len: uint16(len(filter)),
|
||||
Filter: &filter[0],
|
||||
}
|
||||
fd = -1 // only return a valid fd when C_FILTER_FLAG_NEW_LISTENER is set
|
||||
// If no seccomp flags were requested we can use the old-school prctl(2).
|
||||
if flags == 0 {
|
||||
err = unix.Prctl(unix.PR_SET_SECCOMP,
|
||||
unix.SECCOMP_MODE_FILTER,
|
||||
uintptr(unsafe.Pointer(&fprog)), 0, 0)
|
||||
} else {
|
||||
fdptr, _, errno := unix.RawSyscall(unix.SYS_SECCOMP,
|
||||
uintptr(C.C_SET_MODE_FILTER),
|
||||
uintptr(flags), uintptr(unsafe.Pointer(&fprog)))
|
||||
if errno != 0 {
|
||||
err = errno
|
||||
}
|
||||
if flags&uint(C.C_FILTER_FLAG_NEW_LISTENER) != 0 {
|
||||
fd = int(fdptr)
|
||||
}
|
||||
}
|
||||
runtime.KeepAlive(filter)
|
||||
runtime.KeepAlive(fprog)
|
||||
return
|
||||
}
|
||||
|
||||
// PatchAndLoad takes a seccomp configuration and a libseccomp filter which has
|
||||
// been pre-configured with the set of rules in the seccomp config. It then
|
||||
// patches said filter to handle -ENOSYS in a much nicer manner than the
|
||||
// default libseccomp default action behaviour, and loads the patched filter
|
||||
// into the kernel for the current process.
|
||||
func PatchAndLoad(config *configs.Seccomp, filter *libseccomp.ScmpFilter) (int, error) {
|
||||
// Generate a patched filter.
|
||||
fprog, err := enosysPatchFilter(config, filter)
|
||||
if err != nil {
|
||||
return -1, fmt.Errorf("error patching filter: %w", err)
|
||||
}
|
||||
|
||||
// Get the set of libseccomp flags set.
|
||||
seccompFlags, noNewPrivs, err := filterFlags(config, filter)
|
||||
if err != nil {
|
||||
return -1, fmt.Errorf("unable to fetch seccomp filter flags: %w", err)
|
||||
}
|
||||
|
||||
// Set no_new_privs if it was requested, though in runc we handle
|
||||
// no_new_privs separately so warn if we hit this path.
|
||||
if noNewPrivs {
|
||||
logrus.Warnf("potentially misconfigured filter -- setting no_new_privs in seccomp path")
|
||||
if err := unix.Prctl(unix.PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0); err != nil {
|
||||
return -1, fmt.Errorf("error enabling no_new_privs bit: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Finally, load the filter.
|
||||
fd, err := sysSeccompSetFilter(seccompFlags, fprog)
|
||||
if err != nil {
|
||||
return -1, fmt.Errorf("error loading seccomp filter: %w", err)
|
||||
}
|
||||
|
||||
return fd, nil
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
//go:build !linux || !cgo || !seccomp
|
||||
// +build !linux !cgo !seccomp
|
||||
|
||||
package patchbpf
|
||||
268
vendor/github.com/opencontainers/runc/libcontainer/seccomp/seccomp_linux.go
generated
vendored
268
vendor/github.com/opencontainers/runc/libcontainer/seccomp/seccomp_linux.go
generated
vendored
@@ -1,268 +0,0 @@
|
||||
//go:build cgo && seccomp
|
||||
// +build cgo,seccomp
|
||||
|
||||
package seccomp
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
libseccomp "github.com/seccomp/libseccomp-golang"
|
||||
"github.com/sirupsen/logrus"
|
||||
"golang.org/x/sys/unix"
|
||||
|
||||
"github.com/opencontainers/runc/libcontainer/configs"
|
||||
"github.com/opencontainers/runc/libcontainer/seccomp/patchbpf"
|
||||
)
|
||||
|
||||
var (
|
||||
actTrace = libseccomp.ActTrace.SetReturnCode(int16(unix.EPERM))
|
||||
actErrno = libseccomp.ActErrno.SetReturnCode(int16(unix.EPERM))
|
||||
)
|
||||
|
||||
const (
|
||||
// Linux system calls can have at most 6 arguments
|
||||
syscallMaxArguments int = 6
|
||||
)
|
||||
|
||||
// InitSeccomp installs the seccomp filters to be used in the container as
|
||||
// specified in config.
|
||||
// Returns the seccomp file descriptor if any of the filters include a
|
||||
// SCMP_ACT_NOTIFY action, otherwise returns -1.
|
||||
func InitSeccomp(config *configs.Seccomp) (int, error) {
|
||||
if config == nil {
|
||||
return -1, errors.New("cannot initialize Seccomp - nil config passed")
|
||||
}
|
||||
|
||||
defaultAction, err := getAction(config.DefaultAction, config.DefaultErrnoRet)
|
||||
if err != nil {
|
||||
return -1, errors.New("error initializing seccomp - invalid default action")
|
||||
}
|
||||
|
||||
// Ignore the error since pre-2.4 libseccomp is treated as API level 0.
|
||||
apiLevel, _ := libseccomp.GetAPI()
|
||||
for _, call := range config.Syscalls {
|
||||
if call.Action == configs.Notify {
|
||||
if apiLevel < 6 {
|
||||
return -1, fmt.Errorf("seccomp notify unsupported: API level: got %d, want at least 6. Please try with libseccomp >= 2.5.0 and Linux >= 5.7", apiLevel)
|
||||
}
|
||||
|
||||
// We can't allow the write syscall to notify to the seccomp agent.
|
||||
// After InitSeccomp() is called, we need to syncParentSeccomp() to write the seccomp fd plain
|
||||
// number, so the parent sends it to the seccomp agent. If we use SCMP_ACT_NOTIFY on write, we
|
||||
// never can write the seccomp fd to the parent and therefore the seccomp agent never receives
|
||||
// the seccomp fd and runc is hang during initialization.
|
||||
//
|
||||
// Note that read()/close(), that are also used in syncParentSeccomp(), _can_ use SCMP_ACT_NOTIFY.
|
||||
// Because we write the seccomp fd on the pipe to the parent, the parent is able to proceed and
|
||||
// send the seccomp fd to the agent (it is another process and not subject to the seccomp
|
||||
// filter). We will be blocked on read()/close() inside syncParentSeccomp() but if the seccomp
|
||||
// agent allows those syscalls to proceed, initialization works just fine and the agent can
|
||||
// handle future read()/close() syscalls as it wanted.
|
||||
if call.Name == "write" {
|
||||
return -1, errors.New("SCMP_ACT_NOTIFY cannot be used for the write syscall")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// See comment on why write is not allowed. The same reason applies, as this can mean handling write too.
|
||||
if defaultAction == libseccomp.ActNotify {
|
||||
return -1, errors.New("SCMP_ACT_NOTIFY cannot be used as default action")
|
||||
}
|
||||
|
||||
filter, err := libseccomp.NewFilter(defaultAction)
|
||||
if err != nil {
|
||||
return -1, fmt.Errorf("error creating filter: %w", err)
|
||||
}
|
||||
|
||||
// Add extra architectures
|
||||
for _, arch := range config.Architectures {
|
||||
scmpArch, err := libseccomp.GetArchFromString(arch)
|
||||
if err != nil {
|
||||
return -1, fmt.Errorf("error validating Seccomp architecture: %w", err)
|
||||
}
|
||||
if err := filter.AddArch(scmpArch); err != nil {
|
||||
return -1, fmt.Errorf("error adding architecture to seccomp filter: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Unset no new privs bit
|
||||
if err := filter.SetNoNewPrivsBit(false); err != nil {
|
||||
return -1, fmt.Errorf("error setting no new privileges: %w", err)
|
||||
}
|
||||
|
||||
// Add a rule for each syscall
|
||||
for _, call := range config.Syscalls {
|
||||
if call == nil {
|
||||
return -1, errors.New("encountered nil syscall while initializing Seccomp")
|
||||
}
|
||||
|
||||
if err := matchCall(filter, call, defaultAction); err != nil {
|
||||
return -1, err
|
||||
}
|
||||
}
|
||||
|
||||
seccompFd, err := patchbpf.PatchAndLoad(config, filter)
|
||||
if err != nil {
|
||||
return -1, fmt.Errorf("error loading seccomp filter into kernel: %w", err)
|
||||
}
|
||||
|
||||
return seccompFd, nil
|
||||
}
|
||||
|
||||
// Convert Libcontainer Action to Libseccomp ScmpAction
|
||||
func getAction(act configs.Action, errnoRet *uint) (libseccomp.ScmpAction, error) {
|
||||
switch act {
|
||||
case configs.Kill, configs.KillThread:
|
||||
return libseccomp.ActKillThread, nil
|
||||
case configs.Errno:
|
||||
if errnoRet != nil {
|
||||
return libseccomp.ActErrno.SetReturnCode(int16(*errnoRet)), nil
|
||||
}
|
||||
return actErrno, nil
|
||||
case configs.Trap:
|
||||
return libseccomp.ActTrap, nil
|
||||
case configs.Allow:
|
||||
return libseccomp.ActAllow, nil
|
||||
case configs.Trace:
|
||||
if errnoRet != nil {
|
||||
return libseccomp.ActTrace.SetReturnCode(int16(*errnoRet)), nil
|
||||
}
|
||||
return actTrace, nil
|
||||
case configs.Log:
|
||||
return libseccomp.ActLog, nil
|
||||
case configs.Notify:
|
||||
return libseccomp.ActNotify, nil
|
||||
case configs.KillProcess:
|
||||
return libseccomp.ActKillProcess, nil
|
||||
default:
|
||||
return libseccomp.ActInvalid, errors.New("invalid action, cannot use in rule")
|
||||
}
|
||||
}
|
||||
|
||||
// Convert Libcontainer Operator to Libseccomp ScmpCompareOp
|
||||
func getOperator(op configs.Operator) (libseccomp.ScmpCompareOp, error) {
|
||||
switch op {
|
||||
case configs.EqualTo:
|
||||
return libseccomp.CompareEqual, nil
|
||||
case configs.NotEqualTo:
|
||||
return libseccomp.CompareNotEqual, nil
|
||||
case configs.GreaterThan:
|
||||
return libseccomp.CompareGreater, nil
|
||||
case configs.GreaterThanOrEqualTo:
|
||||
return libseccomp.CompareGreaterEqual, nil
|
||||
case configs.LessThan:
|
||||
return libseccomp.CompareLess, nil
|
||||
case configs.LessThanOrEqualTo:
|
||||
return libseccomp.CompareLessOrEqual, nil
|
||||
case configs.MaskEqualTo:
|
||||
return libseccomp.CompareMaskedEqual, nil
|
||||
default:
|
||||
return libseccomp.CompareInvalid, errors.New("invalid operator, cannot use in rule")
|
||||
}
|
||||
}
|
||||
|
||||
// Convert Libcontainer Arg to Libseccomp ScmpCondition
|
||||
func getCondition(arg *configs.Arg) (libseccomp.ScmpCondition, error) {
|
||||
cond := libseccomp.ScmpCondition{}
|
||||
|
||||
if arg == nil {
|
||||
return cond, errors.New("cannot convert nil to syscall condition")
|
||||
}
|
||||
|
||||
op, err := getOperator(arg.Op)
|
||||
if err != nil {
|
||||
return cond, err
|
||||
}
|
||||
|
||||
return libseccomp.MakeCondition(arg.Index, op, arg.Value, arg.ValueTwo)
|
||||
}
|
||||
|
||||
// Add a rule to match a single syscall
|
||||
func matchCall(filter *libseccomp.ScmpFilter, call *configs.Syscall, defAct libseccomp.ScmpAction) error {
|
||||
if call == nil || filter == nil {
|
||||
return errors.New("cannot use nil as syscall to block")
|
||||
}
|
||||
|
||||
if len(call.Name) == 0 {
|
||||
return errors.New("empty string is not a valid syscall")
|
||||
}
|
||||
|
||||
// Convert the call's action to the libseccomp equivalent
|
||||
callAct, err := getAction(call.Action, call.ErrnoRet)
|
||||
if err != nil {
|
||||
return fmt.Errorf("action in seccomp profile is invalid: %w", err)
|
||||
}
|
||||
if callAct == defAct {
|
||||
// This rule is redundant, silently skip it
|
||||
// to avoid error from AddRule.
|
||||
return nil
|
||||
}
|
||||
|
||||
// If we can't resolve the syscall, assume it is not supported
|
||||
// by this kernel. Warn about it, don't error out.
|
||||
callNum, err := libseccomp.GetSyscallFromName(call.Name)
|
||||
if err != nil {
|
||||
logrus.Debugf("unknown seccomp syscall %q ignored", call.Name)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Unconditional match - just add the rule
|
||||
if len(call.Args) == 0 {
|
||||
if err := filter.AddRule(callNum, callAct); err != nil {
|
||||
return fmt.Errorf("error adding seccomp filter rule for syscall %s: %w", call.Name, err)
|
||||
}
|
||||
} else {
|
||||
// If two or more arguments have the same condition,
|
||||
// Revert to old behavior, adding each condition as a separate rule
|
||||
argCounts := make([]uint, syscallMaxArguments)
|
||||
conditions := []libseccomp.ScmpCondition{}
|
||||
|
||||
for _, cond := range call.Args {
|
||||
newCond, err := getCondition(cond)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error creating seccomp syscall condition for syscall %s: %w", call.Name, err)
|
||||
}
|
||||
|
||||
argCounts[cond.Index] += 1
|
||||
|
||||
conditions = append(conditions, newCond)
|
||||
}
|
||||
|
||||
hasMultipleArgs := false
|
||||
for _, count := range argCounts {
|
||||
if count > 1 {
|
||||
hasMultipleArgs = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if hasMultipleArgs {
|
||||
// Revert to old behavior
|
||||
// Add each condition attached to a separate rule
|
||||
for _, cond := range conditions {
|
||||
condArr := []libseccomp.ScmpCondition{cond}
|
||||
|
||||
if err := filter.AddRuleConditional(callNum, callAct, condArr); err != nil {
|
||||
return fmt.Errorf("error adding seccomp rule for syscall %s: %w", call.Name, err)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// No conditions share same argument
|
||||
// Use new, proper behavior
|
||||
if err := filter.AddRuleConditional(callNum, callAct, conditions); err != nil {
|
||||
return fmt.Errorf("error adding seccomp rule for syscall %s: %w", call.Name, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Version returns major, minor, and micro.
|
||||
func Version() (uint, uint, uint) {
|
||||
return libseccomp.GetLibraryVersion()
|
||||
}
|
||||
|
||||
// Enabled is true if seccomp support is compiled in.
|
||||
const Enabled = true
|
||||
28
vendor/github.com/opencontainers/runc/libcontainer/seccomp/seccomp_unsupported.go
generated
vendored
28
vendor/github.com/opencontainers/runc/libcontainer/seccomp/seccomp_unsupported.go
generated
vendored
@@ -1,28 +0,0 @@
|
||||
//go:build !linux || !cgo || !seccomp
|
||||
// +build !linux !cgo !seccomp
|
||||
|
||||
package seccomp
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/opencontainers/runc/libcontainer/configs"
|
||||
)
|
||||
|
||||
var ErrSeccompNotEnabled = errors.New("seccomp: config provided but seccomp not supported")
|
||||
|
||||
// InitSeccomp does nothing because seccomp is not supported.
|
||||
func InitSeccomp(config *configs.Seccomp) (int, error) {
|
||||
if config != nil {
|
||||
return -1, ErrSeccompNotEnabled
|
||||
}
|
||||
return -1, nil
|
||||
}
|
||||
|
||||
// Version returns major, minor, and micro.
|
||||
func Version() (uint, uint, uint) {
|
||||
return 0, 0, 0
|
||||
}
|
||||
|
||||
// Enabled is true if seccomp support is compiled in.
|
||||
const Enabled = false
|
||||
149
vendor/github.com/opencontainers/runc/libcontainer/setns_init_linux.go
generated
vendored
149
vendor/github.com/opencontainers/runc/libcontainer/setns_init_linux.go
generated
vendored
@@ -1,149 +0,0 @@
|
||||
package libcontainer
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strconv"
|
||||
|
||||
"github.com/opencontainers/selinux/go-selinux"
|
||||
"github.com/sirupsen/logrus"
|
||||
"golang.org/x/sys/unix"
|
||||
|
||||
"github.com/opencontainers/runc/libcontainer/apparmor"
|
||||
"github.com/opencontainers/runc/libcontainer/keys"
|
||||
"github.com/opencontainers/runc/libcontainer/seccomp"
|
||||
"github.com/opencontainers/runc/libcontainer/system"
|
||||
"github.com/opencontainers/runc/libcontainer/utils"
|
||||
)
|
||||
|
||||
// linuxSetnsInit performs the container's initialization for running a new process
|
||||
// inside an existing container.
|
||||
type linuxSetnsInit struct {
|
||||
pipe *os.File
|
||||
consoleSocket *os.File
|
||||
config *initConfig
|
||||
logFd int
|
||||
}
|
||||
|
||||
func (l *linuxSetnsInit) getSessionRingName() string {
|
||||
return "_ses." + l.config.ContainerId
|
||||
}
|
||||
|
||||
func (l *linuxSetnsInit) Init() error {
|
||||
if !l.config.Config.NoNewKeyring {
|
||||
if err := selinux.SetKeyLabel(l.config.ProcessLabel); err != nil {
|
||||
return err
|
||||
}
|
||||
defer selinux.SetKeyLabel("") //nolint: errcheck
|
||||
// Do not inherit the parent's session keyring.
|
||||
if _, err := keys.JoinSessionKeyring(l.getSessionRingName()); err != nil {
|
||||
// Same justification as in standart_init_linux.go as to why we
|
||||
// don't bail on ENOSYS.
|
||||
//
|
||||
// TODO(cyphar): And we should have logging here too.
|
||||
if !errors.Is(err, unix.ENOSYS) {
|
||||
return fmt.Errorf("unable to join session keyring: %w", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if l.config.CreateConsole {
|
||||
if err := setupConsole(l.consoleSocket, l.config, false); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := system.Setctty(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if l.config.NoNewPrivileges {
|
||||
if err := unix.Prctl(unix.PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Tell our parent that we're ready to exec. This must be done before the
|
||||
// Seccomp rules have been applied, because we need to be able to read and
|
||||
// write to a socket.
|
||||
if err := syncParentReady(l.pipe); err != nil {
|
||||
return fmt.Errorf("sync ready: %w", err)
|
||||
}
|
||||
|
||||
if err := selinux.SetExecLabel(l.config.ProcessLabel); err != nil {
|
||||
return err
|
||||
}
|
||||
defer selinux.SetExecLabel("") //nolint: errcheck
|
||||
// Without NoNewPrivileges seccomp is a privileged operation, so we need to
|
||||
// do this before dropping capabilities; otherwise do it as late as possible
|
||||
// just before execve so as few syscalls take place after it as possible.
|
||||
if l.config.Config.Seccomp != nil && !l.config.NoNewPrivileges {
|
||||
seccompFd, err := seccomp.InitSeccomp(l.config.Config.Seccomp)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := syncParentSeccomp(l.pipe, seccompFd); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if err := finalizeNamespace(l.config); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := apparmor.ApplyProfile(l.config.AppArmorProfile); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Check for the arg before waiting to make sure it exists and it is
|
||||
// returned as a create time error.
|
||||
name, err := exec.LookPath(l.config.Args[0])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// exec.LookPath in Go < 1.20 might return no error for an executable
|
||||
// residing on a file system mounted with noexec flag, so perform this
|
||||
// extra check now while we can still return a proper error.
|
||||
// TODO: remove this once go < 1.20 is not supported.
|
||||
if err := eaccess(name); err != nil {
|
||||
return &os.PathError{Op: "eaccess", Path: name, Err: err}
|
||||
}
|
||||
|
||||
// Set seccomp as close to execve as possible, so as few syscalls take
|
||||
// place afterward (reducing the amount of syscalls that users need to
|
||||
// enable in their seccomp profiles).
|
||||
if l.config.Config.Seccomp != nil && l.config.NoNewPrivileges {
|
||||
seccompFd, err := seccomp.InitSeccomp(l.config.Config.Seccomp)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to init seccomp: %w", err)
|
||||
}
|
||||
|
||||
if err := syncParentSeccomp(l.pipe, seccompFd); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
logrus.Debugf("setns_init: about to exec")
|
||||
// Close the log pipe fd so the parent's ForwardLogs can exit.
|
||||
if err := unix.Close(l.logFd); err != nil {
|
||||
return &os.PathError{Op: "close log pipe", Path: "fd " + strconv.Itoa(l.logFd), Err: err}
|
||||
}
|
||||
|
||||
// Close all file descriptors we are not passing to the container. This is
|
||||
// necessary because the execve target could use internal runc fds as the
|
||||
// execve path, potentially giving access to binary files from the host
|
||||
// (which can then be opened by container processes, leading to container
|
||||
// escapes). Note that because this operation will close any open file
|
||||
// descriptors that are referenced by (*os.File) handles from underneath
|
||||
// the Go runtime, we must not do any file operations after this point
|
||||
// (otherwise the (*os.File) finaliser could close the wrong file). See
|
||||
// CVE-2024-21626 for more information as to why this protection is
|
||||
// necessary.
|
||||
//
|
||||
// This is not needed for runc-dmz, because the extra execve(2) step means
|
||||
// that all O_CLOEXEC file descriptors have already been closed and thus
|
||||
// the second execve(2) from runc-dmz cannot access internal file
|
||||
// descriptors from runc.
|
||||
if err := utils.UnsafeCloseFrom(l.config.PassedFilesCount + 3); err != nil {
|
||||
return err
|
||||
}
|
||||
return system.Exec(name, l.config.Args[0:], os.Environ())
|
||||
}
|
||||
282
vendor/github.com/opencontainers/runc/libcontainer/standard_init_linux.go
generated
vendored
282
vendor/github.com/opencontainers/runc/libcontainer/standard_init_linux.go
generated
vendored
@@ -1,282 +0,0 @@
|
||||
package libcontainer
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strconv"
|
||||
|
||||
"github.com/opencontainers/runtime-spec/specs-go"
|
||||
"github.com/opencontainers/selinux/go-selinux"
|
||||
"github.com/sirupsen/logrus"
|
||||
"golang.org/x/sys/unix"
|
||||
|
||||
"github.com/opencontainers/runc/libcontainer/apparmor"
|
||||
"github.com/opencontainers/runc/libcontainer/configs"
|
||||
"github.com/opencontainers/runc/libcontainer/keys"
|
||||
"github.com/opencontainers/runc/libcontainer/seccomp"
|
||||
"github.com/opencontainers/runc/libcontainer/system"
|
||||
"github.com/opencontainers/runc/libcontainer/utils"
|
||||
)
|
||||
|
||||
type linuxStandardInit struct {
|
||||
pipe *os.File
|
||||
consoleSocket *os.File
|
||||
parentPid int
|
||||
fifoFd int
|
||||
logFd int
|
||||
mountFds []int
|
||||
config *initConfig
|
||||
}
|
||||
|
||||
func (l *linuxStandardInit) getSessionRingParams() (string, uint32, uint32) {
|
||||
var newperms uint32
|
||||
|
||||
if l.config.Config.Namespaces.Contains(configs.NEWUSER) {
|
||||
// With user ns we need 'other' search permissions.
|
||||
newperms = 0x8
|
||||
} else {
|
||||
// Without user ns we need 'UID' search permissions.
|
||||
newperms = 0x80000
|
||||
}
|
||||
|
||||
// Create a unique per session container name that we can join in setns;
|
||||
// However, other containers can also join it.
|
||||
return "_ses." + l.config.ContainerId, 0xffffffff, newperms
|
||||
}
|
||||
|
||||
func (l *linuxStandardInit) Init() error {
|
||||
if !l.config.Config.NoNewKeyring {
|
||||
if err := selinux.SetKeyLabel(l.config.ProcessLabel); err != nil {
|
||||
return err
|
||||
}
|
||||
defer selinux.SetKeyLabel("") //nolint: errcheck
|
||||
ringname, keepperms, newperms := l.getSessionRingParams()
|
||||
|
||||
// Do not inherit the parent's session keyring.
|
||||
if sessKeyId, err := keys.JoinSessionKeyring(ringname); err != nil {
|
||||
// If keyrings aren't supported then it is likely we are on an
|
||||
// older kernel (or inside an LXC container). While we could bail,
|
||||
// the security feature we are using here is best-effort (it only
|
||||
// really provides marginal protection since VFS credentials are
|
||||
// the only significant protection of keyrings).
|
||||
//
|
||||
// TODO(cyphar): Log this so people know what's going on, once we
|
||||
// have proper logging in 'runc init'.
|
||||
if !errors.Is(err, unix.ENOSYS) {
|
||||
return fmt.Errorf("unable to join session keyring: %w", err)
|
||||
}
|
||||
} else {
|
||||
// Make session keyring searchable. If we've gotten this far we
|
||||
// bail on any error -- we don't want to have a keyring with bad
|
||||
// permissions.
|
||||
if err := keys.ModKeyringPerm(sessKeyId, keepperms, newperms); err != nil {
|
||||
return fmt.Errorf("unable to mod keyring permissions: %w", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if err := setupNetwork(l.config); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := setupRoute(l.config.Config); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// initialises the labeling system
|
||||
selinux.GetEnabled()
|
||||
|
||||
// We don't need the mountFds after prepareRootfs() nor if it fails.
|
||||
err := prepareRootfs(l.pipe, l.config, l.mountFds)
|
||||
for _, m := range l.mountFds {
|
||||
if m == -1 {
|
||||
continue
|
||||
}
|
||||
|
||||
if err := unix.Close(m); err != nil {
|
||||
return fmt.Errorf("Unable to close mountFds fds: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Set up the console. This has to be done *before* we finalize the rootfs,
|
||||
// but *after* we've given the user the chance to set up all of the mounts
|
||||
// they wanted.
|
||||
if l.config.CreateConsole {
|
||||
if err := setupConsole(l.consoleSocket, l.config, true); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := system.Setctty(); err != nil {
|
||||
return &os.SyscallError{Syscall: "ioctl(setctty)", Err: err}
|
||||
}
|
||||
}
|
||||
|
||||
// Finish the rootfs setup.
|
||||
if l.config.Config.Namespaces.Contains(configs.NEWNS) {
|
||||
if err := finalizeRootfs(l.config.Config); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if hostname := l.config.Config.Hostname; hostname != "" {
|
||||
if err := unix.Sethostname([]byte(hostname)); err != nil {
|
||||
return &os.SyscallError{Syscall: "sethostname", Err: err}
|
||||
}
|
||||
}
|
||||
if err := apparmor.ApplyProfile(l.config.AppArmorProfile); err != nil {
|
||||
return fmt.Errorf("unable to apply apparmor profile: %w", err)
|
||||
}
|
||||
|
||||
for key, value := range l.config.Config.Sysctl {
|
||||
if err := writeSystemProperty(key, value); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
for _, path := range l.config.Config.ReadonlyPaths {
|
||||
if err := readonlyPath(path); err != nil {
|
||||
return fmt.Errorf("can't make %q read-only: %w", path, err)
|
||||
}
|
||||
}
|
||||
for _, path := range l.config.Config.MaskPaths {
|
||||
if err := maskPath(path, l.config.Config.MountLabel); err != nil {
|
||||
return fmt.Errorf("can't mask path %s: %w", path, err)
|
||||
}
|
||||
}
|
||||
pdeath, err := system.GetParentDeathSignal()
|
||||
if err != nil {
|
||||
return fmt.Errorf("can't get pdeath signal: %w", err)
|
||||
}
|
||||
if l.config.NoNewPrivileges {
|
||||
if err := unix.Prctl(unix.PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0); err != nil {
|
||||
return &os.SyscallError{Syscall: "prctl(SET_NO_NEW_PRIVS)", Err: err}
|
||||
}
|
||||
}
|
||||
|
||||
// Tell our parent that we're ready to exec. This must be done before the
|
||||
// Seccomp rules have been applied, because we need to be able to read and
|
||||
// write to a socket.
|
||||
if err := syncParentReady(l.pipe); err != nil {
|
||||
return fmt.Errorf("sync ready: %w", err)
|
||||
}
|
||||
if err := selinux.SetExecLabel(l.config.ProcessLabel); err != nil {
|
||||
return fmt.Errorf("can't set process label: %w", err)
|
||||
}
|
||||
defer selinux.SetExecLabel("") //nolint: errcheck
|
||||
// Without NoNewPrivileges seccomp is a privileged operation, so we need to
|
||||
// do this before dropping capabilities; otherwise do it as late as possible
|
||||
// just before execve so as few syscalls take place after it as possible.
|
||||
if l.config.Config.Seccomp != nil && !l.config.NoNewPrivileges {
|
||||
seccompFd, err := seccomp.InitSeccomp(l.config.Config.Seccomp)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := syncParentSeccomp(l.pipe, seccompFd); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if err := finalizeNamespace(l.config); err != nil {
|
||||
return err
|
||||
}
|
||||
// finalizeNamespace can change user/group which clears the parent death
|
||||
// signal, so we restore it here.
|
||||
if err := pdeath.Restore(); err != nil {
|
||||
return fmt.Errorf("can't restore pdeath signal: %w", err)
|
||||
}
|
||||
// Compare the parent from the initial start of the init process and make
|
||||
// sure that it did not change. if the parent changes that means it died
|
||||
// and we were reparented to something else so we should just kill ourself
|
||||
// and not cause problems for someone else.
|
||||
if unix.Getppid() != l.parentPid {
|
||||
return unix.Kill(unix.Getpid(), unix.SIGKILL)
|
||||
}
|
||||
// Check for the arg before waiting to make sure it exists and it is
|
||||
// returned as a create time error.
|
||||
name, err := exec.LookPath(l.config.Args[0])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// exec.LookPath in Go < 1.20 might return no error for an executable
|
||||
// residing on a file system mounted with noexec flag, so perform this
|
||||
// extra check now while we can still return a proper error.
|
||||
// TODO: remove this once go < 1.20 is not supported.
|
||||
if err := eaccess(name); err != nil {
|
||||
return &os.PathError{Op: "eaccess", Path: name, Err: err}
|
||||
}
|
||||
|
||||
// Set seccomp as close to execve as possible, so as few syscalls take
|
||||
// place afterward (reducing the amount of syscalls that users need to
|
||||
// enable in their seccomp profiles). However, this needs to be done
|
||||
// before closing the pipe since we need it to pass the seccompFd to
|
||||
// the parent.
|
||||
if l.config.Config.Seccomp != nil && l.config.NoNewPrivileges {
|
||||
seccompFd, err := seccomp.InitSeccomp(l.config.Config.Seccomp)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to init seccomp: %w", err)
|
||||
}
|
||||
|
||||
if err := syncParentSeccomp(l.pipe, seccompFd); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
// Close the pipe to signal that we have completed our init.
|
||||
logrus.Debugf("init: closing the pipe to signal completion")
|
||||
_ = l.pipe.Close()
|
||||
|
||||
// Close the log pipe fd so the parent's ForwardLogs can exit.
|
||||
if err := unix.Close(l.logFd); err != nil {
|
||||
return &os.PathError{Op: "close log pipe", Path: "fd " + strconv.Itoa(l.logFd), Err: err}
|
||||
}
|
||||
|
||||
// Wait for the FIFO to be opened on the other side before exec-ing the
|
||||
// user process. We open it through /proc/self/fd/$fd, because the fd that
|
||||
// was given to us was an O_PATH fd to the fifo itself. Linux allows us to
|
||||
// re-open an O_PATH fd through /proc.
|
||||
fifoPath := "/proc/self/fd/" + strconv.Itoa(l.fifoFd)
|
||||
fd, err := unix.Open(fifoPath, unix.O_WRONLY|unix.O_CLOEXEC, 0)
|
||||
if err != nil {
|
||||
return &os.PathError{Op: "open exec fifo", Path: fifoPath, Err: err}
|
||||
}
|
||||
if _, err := unix.Write(fd, []byte("0")); err != nil {
|
||||
return &os.PathError{Op: "write exec fifo", Path: fifoPath, Err: err}
|
||||
}
|
||||
|
||||
// Close the O_PATH fifofd fd before exec because the kernel resets
|
||||
// dumpable in the wrong order. This has been fixed in newer kernels, but
|
||||
// we keep this to ensure CVE-2016-9962 doesn't re-emerge on older kernels.
|
||||
// N.B. the core issue itself (passing dirfds to the host filesystem) has
|
||||
// since been resolved.
|
||||
// https://github.com/torvalds/linux/blob/v4.9/fs/exec.c#L1290-L1318
|
||||
_ = unix.Close(l.fifoFd)
|
||||
|
||||
s := l.config.SpecState
|
||||
s.Pid = unix.Getpid()
|
||||
s.Status = specs.StateCreated
|
||||
if err := l.config.Config.Hooks[configs.StartContainer].RunHooks(s); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Close all file descriptors we are not passing to the container. This is
|
||||
// necessary because the execve target could use internal runc fds as the
|
||||
// execve path, potentially giving access to binary files from the host
|
||||
// (which can then be opened by container processes, leading to container
|
||||
// escapes). Note that because this operation will close any open file
|
||||
// descriptors that are referenced by (*os.File) handles from underneath
|
||||
// the Go runtime, we must not do any file operations after this point
|
||||
// (otherwise the (*os.File) finaliser could close the wrong file). See
|
||||
// CVE-2024-21626 for more information as to why this protection is
|
||||
// necessary.
|
||||
//
|
||||
// This is not needed for runc-dmz, because the extra execve(2) step means
|
||||
// that all O_CLOEXEC file descriptors have already been closed and thus
|
||||
// the second execve(2) from runc-dmz cannot access internal file
|
||||
// descriptors from runc.
|
||||
if err := utils.UnsafeCloseFrom(l.config.PassedFilesCount + 3); err != nil {
|
||||
return err
|
||||
}
|
||||
return system.Exec(name, l.config.Args[0:], os.Environ())
|
||||
}
|
||||
243
vendor/github.com/opencontainers/runc/libcontainer/state_linux.go
generated
vendored
243
vendor/github.com/opencontainers/runc/libcontainer/state_linux.go
generated
vendored
@@ -1,243 +0,0 @@
|
||||
package libcontainer
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/opencontainers/runc/libcontainer/configs"
|
||||
"github.com/opencontainers/runtime-spec/specs-go"
|
||||
"github.com/sirupsen/logrus"
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
func newStateTransitionError(from, to containerState) error {
|
||||
return &stateTransitionError{
|
||||
From: from.status().String(),
|
||||
To: to.status().String(),
|
||||
}
|
||||
}
|
||||
|
||||
// stateTransitionError is returned when an invalid state transition happens from one
|
||||
// state to another.
|
||||
type stateTransitionError struct {
|
||||
From string
|
||||
To string
|
||||
}
|
||||
|
||||
func (s *stateTransitionError) Error() string {
|
||||
return fmt.Sprintf("invalid state transition from %s to %s", s.From, s.To)
|
||||
}
|
||||
|
||||
type containerState interface {
|
||||
transition(containerState) error
|
||||
destroy() error
|
||||
status() Status
|
||||
}
|
||||
|
||||
func destroy(c *linuxContainer) error {
|
||||
if !c.config.Namespaces.Contains(configs.NEWPID) ||
|
||||
c.config.Namespaces.PathOf(configs.NEWPID) != "" {
|
||||
if err := signalAllProcesses(c.cgroupManager, unix.SIGKILL); err != nil {
|
||||
logrus.Warn(err)
|
||||
}
|
||||
}
|
||||
err := c.cgroupManager.Destroy()
|
||||
if c.intelRdtManager != nil {
|
||||
if ierr := c.intelRdtManager.Destroy(); err == nil {
|
||||
err = ierr
|
||||
}
|
||||
}
|
||||
if rerr := os.RemoveAll(c.root); err == nil {
|
||||
err = rerr
|
||||
}
|
||||
c.initProcess = nil
|
||||
if herr := runPoststopHooks(c); err == nil {
|
||||
err = herr
|
||||
}
|
||||
c.state = &stoppedState{c: c}
|
||||
return err
|
||||
}
|
||||
|
||||
func runPoststopHooks(c *linuxContainer) error {
|
||||
hooks := c.config.Hooks
|
||||
if hooks == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
s, err := c.currentOCIState()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
s.Status = specs.StateStopped
|
||||
|
||||
if err := hooks[configs.Poststop].RunHooks(s); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// stoppedState represents a container is a stopped/destroyed state.
|
||||
type stoppedState struct {
|
||||
c *linuxContainer
|
||||
}
|
||||
|
||||
func (b *stoppedState) status() Status {
|
||||
return Stopped
|
||||
}
|
||||
|
||||
func (b *stoppedState) transition(s containerState) error {
|
||||
switch s.(type) {
|
||||
case *runningState, *restoredState:
|
||||
b.c.state = s
|
||||
return nil
|
||||
case *stoppedState:
|
||||
return nil
|
||||
}
|
||||
return newStateTransitionError(b, s)
|
||||
}
|
||||
|
||||
func (b *stoppedState) destroy() error {
|
||||
return destroy(b.c)
|
||||
}
|
||||
|
||||
// runningState represents a container that is currently running.
|
||||
type runningState struct {
|
||||
c *linuxContainer
|
||||
}
|
||||
|
||||
func (r *runningState) status() Status {
|
||||
return Running
|
||||
}
|
||||
|
||||
func (r *runningState) transition(s containerState) error {
|
||||
switch s.(type) {
|
||||
case *stoppedState:
|
||||
if r.c.runType() == Running {
|
||||
return ErrRunning
|
||||
}
|
||||
r.c.state = s
|
||||
return nil
|
||||
case *pausedState:
|
||||
r.c.state = s
|
||||
return nil
|
||||
case *runningState:
|
||||
return nil
|
||||
}
|
||||
return newStateTransitionError(r, s)
|
||||
}
|
||||
|
||||
func (r *runningState) destroy() error {
|
||||
if r.c.runType() == Running {
|
||||
return ErrRunning
|
||||
}
|
||||
return destroy(r.c)
|
||||
}
|
||||
|
||||
type createdState struct {
|
||||
c *linuxContainer
|
||||
}
|
||||
|
||||
func (i *createdState) status() Status {
|
||||
return Created
|
||||
}
|
||||
|
||||
func (i *createdState) transition(s containerState) error {
|
||||
switch s.(type) {
|
||||
case *runningState, *pausedState, *stoppedState:
|
||||
i.c.state = s
|
||||
return nil
|
||||
case *createdState:
|
||||
return nil
|
||||
}
|
||||
return newStateTransitionError(i, s)
|
||||
}
|
||||
|
||||
func (i *createdState) destroy() error {
|
||||
_ = i.c.initProcess.signal(unix.SIGKILL)
|
||||
return destroy(i.c)
|
||||
}
|
||||
|
||||
// pausedState represents a container that is currently pause. It cannot be destroyed in a
|
||||
// paused state and must transition back to running first.
|
||||
type pausedState struct {
|
||||
c *linuxContainer
|
||||
}
|
||||
|
||||
func (p *pausedState) status() Status {
|
||||
return Paused
|
||||
}
|
||||
|
||||
func (p *pausedState) transition(s containerState) error {
|
||||
switch s.(type) {
|
||||
case *runningState, *stoppedState:
|
||||
p.c.state = s
|
||||
return nil
|
||||
case *pausedState:
|
||||
return nil
|
||||
}
|
||||
return newStateTransitionError(p, s)
|
||||
}
|
||||
|
||||
func (p *pausedState) destroy() error {
|
||||
t := p.c.runType()
|
||||
if t != Running && t != Created {
|
||||
if err := p.c.cgroupManager.Freeze(configs.Thawed); err != nil {
|
||||
return err
|
||||
}
|
||||
return destroy(p.c)
|
||||
}
|
||||
return ErrPaused
|
||||
}
|
||||
|
||||
// restoredState is the same as the running state but also has associated checkpoint
|
||||
// information that maybe need destroyed when the container is stopped and destroy is called.
|
||||
type restoredState struct {
|
||||
imageDir string
|
||||
c *linuxContainer
|
||||
}
|
||||
|
||||
func (r *restoredState) status() Status {
|
||||
return Running
|
||||
}
|
||||
|
||||
func (r *restoredState) transition(s containerState) error {
|
||||
switch s.(type) {
|
||||
case *stoppedState, *runningState:
|
||||
return nil
|
||||
}
|
||||
return newStateTransitionError(r, s)
|
||||
}
|
||||
|
||||
func (r *restoredState) destroy() error {
|
||||
if _, err := os.Stat(filepath.Join(r.c.root, "checkpoint")); err != nil {
|
||||
if !os.IsNotExist(err) {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return destroy(r.c)
|
||||
}
|
||||
|
||||
// loadedState is used whenever a container is restored, loaded, or setting additional
|
||||
// processes inside and it should not be destroyed when it is exiting.
|
||||
type loadedState struct {
|
||||
c *linuxContainer
|
||||
s Status
|
||||
}
|
||||
|
||||
func (n *loadedState) status() Status {
|
||||
return n.s
|
||||
}
|
||||
|
||||
func (n *loadedState) transition(s containerState) error {
|
||||
n.c.state = s
|
||||
return nil
|
||||
}
|
||||
|
||||
func (n *loadedState) destroy() error {
|
||||
if err := n.c.refreshState(); err != nil {
|
||||
return err
|
||||
}
|
||||
return n.c.state.destroy()
|
||||
}
|
||||
13
vendor/github.com/opencontainers/runc/libcontainer/stats_linux.go
generated
vendored
13
vendor/github.com/opencontainers/runc/libcontainer/stats_linux.go
generated
vendored
@@ -1,13 +0,0 @@
|
||||
package libcontainer
|
||||
|
||||
import (
|
||||
"github.com/opencontainers/runc/libcontainer/cgroups"
|
||||
"github.com/opencontainers/runc/libcontainer/intelrdt"
|
||||
"github.com/opencontainers/runc/types"
|
||||
)
|
||||
|
||||
type Stats struct {
|
||||
Interfaces []*types.NetworkInterface
|
||||
CgroupStats *cgroups.Stats
|
||||
IntelRdtStats *intelrdt.Stats
|
||||
}
|
||||
126
vendor/github.com/opencontainers/runc/libcontainer/sync.go
generated
vendored
126
vendor/github.com/opencontainers/runc/libcontainer/sync.go
generated
vendored
@@ -1,126 +0,0 @@
|
||||
package libcontainer
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"github.com/opencontainers/runc/libcontainer/utils"
|
||||
)
|
||||
|
||||
type syncType string
|
||||
|
||||
// Constants that are used for synchronisation between the parent and child
|
||||
// during container setup. They come in pairs (with procError being a generic
|
||||
// response which is followed by an &initError).
|
||||
//
|
||||
// [ child ] <-> [ parent ]
|
||||
//
|
||||
// procHooks --> [run hooks]
|
||||
// <-- procResume
|
||||
//
|
||||
// procReady --> [final setup]
|
||||
// <-- procRun
|
||||
//
|
||||
// procSeccomp --> [pick up seccomp fd with pidfd_getfd()]
|
||||
// <-- procSeccompDone
|
||||
const (
|
||||
procError syncType = "procError"
|
||||
procReady syncType = "procReady"
|
||||
procRun syncType = "procRun"
|
||||
procHooks syncType = "procHooks"
|
||||
procResume syncType = "procResume"
|
||||
procSeccomp syncType = "procSeccomp"
|
||||
procSeccompDone syncType = "procSeccompDone"
|
||||
)
|
||||
|
||||
type syncT struct {
|
||||
Type syncType `json:"type"`
|
||||
Fd int `json:"fd"`
|
||||
}
|
||||
|
||||
// initError is used to wrap errors for passing them via JSON,
|
||||
// as encoding/json can't unmarshal into error type.
|
||||
type initError struct {
|
||||
Message string `json:"message,omitempty"`
|
||||
}
|
||||
|
||||
func (i initError) Error() string {
|
||||
return i.Message
|
||||
}
|
||||
|
||||
// writeSync is used to write to a synchronisation pipe. An error is returned
|
||||
// if there was a problem writing the payload.
|
||||
func writeSync(pipe io.Writer, sync syncType) error {
|
||||
return writeSyncWithFd(pipe, sync, -1)
|
||||
}
|
||||
|
||||
// writeSyncWithFd is used to write to a synchronisation pipe. An error is
|
||||
// returned if there was a problem writing the payload.
|
||||
func writeSyncWithFd(pipe io.Writer, sync syncType, fd int) error {
|
||||
if err := utils.WriteJSON(pipe, syncT{sync, fd}); err != nil {
|
||||
return fmt.Errorf("writing syncT %q: %w", string(sync), err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// readSync is used to read from a synchronisation pipe. An error is returned
|
||||
// if we got an initError, the pipe was closed, or we got an unexpected flag.
|
||||
func readSync(pipe io.Reader, expected syncType) error {
|
||||
var procSync syncT
|
||||
if err := json.NewDecoder(pipe).Decode(&procSync); err != nil {
|
||||
if errors.Is(err, io.EOF) {
|
||||
return errors.New("parent closed synchronisation channel")
|
||||
}
|
||||
return fmt.Errorf("failed reading error from parent: %w", err)
|
||||
}
|
||||
|
||||
if procSync.Type == procError {
|
||||
var ierr initError
|
||||
|
||||
if err := json.NewDecoder(pipe).Decode(&ierr); err != nil {
|
||||
return fmt.Errorf("failed reading error from parent: %w", err)
|
||||
}
|
||||
|
||||
return &ierr
|
||||
}
|
||||
|
||||
if procSync.Type != expected {
|
||||
return errors.New("invalid synchronisation flag from parent")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// parseSync runs the given callback function on each syncT received from the
|
||||
// child. It will return once io.EOF is returned from the given pipe.
|
||||
func parseSync(pipe io.Reader, fn func(*syncT) error) error {
|
||||
dec := json.NewDecoder(pipe)
|
||||
for {
|
||||
var sync syncT
|
||||
if err := dec.Decode(&sync); err != nil {
|
||||
if errors.Is(err, io.EOF) {
|
||||
break
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// We handle this case outside fn for cleanliness reasons.
|
||||
var ierr *initError
|
||||
if sync.Type == procError {
|
||||
if err := dec.Decode(&ierr); err != nil && !errors.Is(err, io.EOF) {
|
||||
return fmt.Errorf("error decoding proc error from init: %w", err)
|
||||
}
|
||||
if ierr != nil {
|
||||
return ierr
|
||||
}
|
||||
// Programmer error.
|
||||
panic("No error following JSON procError payload.")
|
||||
}
|
||||
|
||||
if err := fn(&sync); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
155
vendor/github.com/opencontainers/runc/types/events.go
generated
vendored
155
vendor/github.com/opencontainers/runc/types/events.go
generated
vendored
@@ -1,155 +0,0 @@
|
||||
package types
|
||||
|
||||
import "github.com/opencontainers/runc/libcontainer/intelrdt"
|
||||
|
||||
// Event struct for encoding the event data to json.
|
||||
type Event struct {
|
||||
Type string `json:"type"`
|
||||
ID string `json:"id"`
|
||||
Data interface{} `json:"data,omitempty"`
|
||||
}
|
||||
|
||||
// stats is the runc specific stats structure for stability when encoding and decoding stats.
|
||||
type Stats struct {
|
||||
CPU Cpu `json:"cpu"`
|
||||
CPUSet CPUSet `json:"cpuset"`
|
||||
Memory Memory `json:"memory"`
|
||||
Pids Pids `json:"pids"`
|
||||
Blkio Blkio `json:"blkio"`
|
||||
Hugetlb map[string]Hugetlb `json:"hugetlb"`
|
||||
IntelRdt IntelRdt `json:"intel_rdt"`
|
||||
NetworkInterfaces []*NetworkInterface `json:"network_interfaces"`
|
||||
}
|
||||
|
||||
type Hugetlb struct {
|
||||
Usage uint64 `json:"usage,omitempty"`
|
||||
Max uint64 `json:"max,omitempty"`
|
||||
Failcnt uint64 `json:"failcnt"`
|
||||
}
|
||||
|
||||
type BlkioEntry struct {
|
||||
Major uint64 `json:"major,omitempty"`
|
||||
Minor uint64 `json:"minor,omitempty"`
|
||||
Op string `json:"op,omitempty"`
|
||||
Value uint64 `json:"value,omitempty"`
|
||||
}
|
||||
|
||||
type Blkio struct {
|
||||
IoServiceBytesRecursive []BlkioEntry `json:"ioServiceBytesRecursive,omitempty"`
|
||||
IoServicedRecursive []BlkioEntry `json:"ioServicedRecursive,omitempty"`
|
||||
IoQueuedRecursive []BlkioEntry `json:"ioQueueRecursive,omitempty"`
|
||||
IoServiceTimeRecursive []BlkioEntry `json:"ioServiceTimeRecursive,omitempty"`
|
||||
IoWaitTimeRecursive []BlkioEntry `json:"ioWaitTimeRecursive,omitempty"`
|
||||
IoMergedRecursive []BlkioEntry `json:"ioMergedRecursive,omitempty"`
|
||||
IoTimeRecursive []BlkioEntry `json:"ioTimeRecursive,omitempty"`
|
||||
SectorsRecursive []BlkioEntry `json:"sectorsRecursive,omitempty"`
|
||||
}
|
||||
|
||||
type Pids struct {
|
||||
Current uint64 `json:"current,omitempty"`
|
||||
Limit uint64 `json:"limit,omitempty"`
|
||||
}
|
||||
|
||||
type Throttling struct {
|
||||
Periods uint64 `json:"periods,omitempty"`
|
||||
ThrottledPeriods uint64 `json:"throttledPeriods,omitempty"`
|
||||
ThrottledTime uint64 `json:"throttledTime,omitempty"`
|
||||
}
|
||||
|
||||
type CpuUsage struct {
|
||||
// Units: nanoseconds.
|
||||
Total uint64 `json:"total,omitempty"`
|
||||
Percpu []uint64 `json:"percpu,omitempty"`
|
||||
PercpuKernel []uint64 `json:"percpu_kernel,omitempty"`
|
||||
PercpuUser []uint64 `json:"percpu_user,omitempty"`
|
||||
Kernel uint64 `json:"kernel"`
|
||||
User uint64 `json:"user"`
|
||||
}
|
||||
|
||||
type Cpu struct {
|
||||
Usage CpuUsage `json:"usage,omitempty"`
|
||||
Throttling Throttling `json:"throttling,omitempty"`
|
||||
}
|
||||
|
||||
type CPUSet struct {
|
||||
CPUs []uint16 `json:"cpus,omitempty"`
|
||||
CPUExclusive uint64 `json:"cpu_exclusive"`
|
||||
Mems []uint16 `json:"mems,omitempty"`
|
||||
MemHardwall uint64 `json:"mem_hardwall"`
|
||||
MemExclusive uint64 `json:"mem_exclusive"`
|
||||
MemoryMigrate uint64 `json:"memory_migrate"`
|
||||
MemorySpreadPage uint64 `json:"memory_spread_page"`
|
||||
MemorySpreadSlab uint64 `json:"memory_spread_slab"`
|
||||
MemoryPressure uint64 `json:"memory_pressure"`
|
||||
SchedLoadBalance uint64 `json:"sched_load_balance"`
|
||||
SchedRelaxDomainLevel int64 `json:"sched_relax_domain_level"`
|
||||
}
|
||||
|
||||
type MemoryEntry struct {
|
||||
Limit uint64 `json:"limit"`
|
||||
Usage uint64 `json:"usage,omitempty"`
|
||||
Max uint64 `json:"max,omitempty"`
|
||||
Failcnt uint64 `json:"failcnt"`
|
||||
}
|
||||
|
||||
type Memory struct {
|
||||
Cache uint64 `json:"cache,omitempty"`
|
||||
Usage MemoryEntry `json:"usage,omitempty"`
|
||||
Swap MemoryEntry `json:"swap,omitempty"`
|
||||
Kernel MemoryEntry `json:"kernel,omitempty"`
|
||||
KernelTCP MemoryEntry `json:"kernelTCP,omitempty"`
|
||||
Raw map[string]uint64 `json:"raw,omitempty"`
|
||||
}
|
||||
|
||||
type L3CacheInfo struct {
|
||||
CbmMask string `json:"cbm_mask,omitempty"`
|
||||
MinCbmBits uint64 `json:"min_cbm_bits,omitempty"`
|
||||
NumClosids uint64 `json:"num_closids,omitempty"`
|
||||
}
|
||||
|
||||
type MemBwInfo struct {
|
||||
BandwidthGran uint64 `json:"bandwidth_gran,omitempty"`
|
||||
DelayLinear uint64 `json:"delay_linear,omitempty"`
|
||||
MinBandwidth uint64 `json:"min_bandwidth,omitempty"`
|
||||
NumClosids uint64 `json:"num_closids,omitempty"`
|
||||
}
|
||||
|
||||
type IntelRdt struct {
|
||||
// The read-only L3 cache information
|
||||
L3CacheInfo *L3CacheInfo `json:"l3_cache_info,omitempty"`
|
||||
|
||||
// The read-only L3 cache schema in root
|
||||
L3CacheSchemaRoot string `json:"l3_cache_schema_root,omitempty"`
|
||||
|
||||
// The L3 cache schema in 'container_id' group
|
||||
L3CacheSchema string `json:"l3_cache_schema,omitempty"`
|
||||
|
||||
// The read-only memory bandwidth information
|
||||
MemBwInfo *MemBwInfo `json:"mem_bw_info,omitempty"`
|
||||
|
||||
// The read-only memory bandwidth schema in root
|
||||
MemBwSchemaRoot string `json:"mem_bw_schema_root,omitempty"`
|
||||
|
||||
// The memory bandwidth schema in 'container_id' group
|
||||
MemBwSchema string `json:"mem_bw_schema,omitempty"`
|
||||
|
||||
// The memory bandwidth monitoring statistics from NUMA nodes in 'container_id' group
|
||||
MBMStats *[]intelrdt.MBMNumaNodeStats `json:"mbm_stats,omitempty"`
|
||||
|
||||
// The cache monitoring technology statistics from NUMA nodes in 'container_id' group
|
||||
CMTStats *[]intelrdt.CMTNumaNodeStats `json:"cmt_stats,omitempty"`
|
||||
}
|
||||
|
||||
type NetworkInterface struct {
|
||||
// Name is the name of the network interface.
|
||||
Name string
|
||||
|
||||
RxBytes uint64
|
||||
RxPackets uint64
|
||||
RxErrors uint64
|
||||
RxDropped uint64
|
||||
TxBytes uint64
|
||||
TxPackets uint64
|
||||
TxErrors uint64
|
||||
TxDropped uint64
|
||||
}
|
||||
4
vendor/github.com/seccomp/libseccomp-golang/.gitignore
generated
vendored
4
vendor/github.com/seccomp/libseccomp-golang/.gitignore
generated
vendored
@@ -1,4 +0,0 @@
|
||||
*~
|
||||
*.swp
|
||||
*.orig
|
||||
tags
|
||||
4
vendor/github.com/seccomp/libseccomp-golang/.golangci.yml
generated
vendored
4
vendor/github.com/seccomp/libseccomp-golang/.golangci.yml
generated
vendored
@@ -1,4 +0,0 @@
|
||||
# For documentation, see https://golangci-lint.run/usage/configuration/
|
||||
linters:
|
||||
enable:
|
||||
- gofumpt
|
||||
42
vendor/github.com/seccomp/libseccomp-golang/CHANGELOG
generated
vendored
42
vendor/github.com/seccomp/libseccomp-golang/CHANGELOG
generated
vendored
@@ -1,42 +0,0 @@
|
||||
libseccomp-golang: Releases
|
||||
===============================================================================
|
||||
https://github.com/seccomp/libseccomp-golang
|
||||
|
||||
* Version 0.10.0 - June 9, 2022
|
||||
- Minimum supported version of libseccomp bumped to v2.3.1
|
||||
- Add seccomp userspace notification API (ActNotify, filter.*Notif*)
|
||||
- Add filter.{Get,Set}SSB (to support SCMP_FLTATR_CTL_SSB)
|
||||
- Add filter.{Get,Set}Optimize (to support SCMP_FLTATR_CTL_OPTIMIZE)
|
||||
- Add filter.{Get,Set}RawRC (to support SCMP_FLTATR_API_SYSRAWRC)
|
||||
- Add ArchPARISC, ArchPARISC64, ArchRISCV64
|
||||
- Add ActKillProcess and ActKillThread; deprecate ActKill
|
||||
- Add go module support
|
||||
- Return ErrSyscallDoesNotExist when unable to resolve a syscall
|
||||
- Fix some functions to check for both kernel level API and libseccomp version
|
||||
- Fix MakeCondition to use sanitizeCompareOp
|
||||
- Fix AddRule to handle EACCES (from libseccomp >= 2.5.0)
|
||||
- Updated the main docs and converted to README.md
|
||||
- Added CONTRIBUTING.md, SECURITY.md, and administrative docs under doc/admin
|
||||
- Add GitHub action CI, enable more linters
|
||||
- test: test against various libseccomp versions
|
||||
- test: fix and simplify execInSubprocess
|
||||
- test: fix APILevelIsSupported
|
||||
- Refactor the Errno(-1 * retCode) pattern
|
||||
- Refactor/unify libseccomp version / API level checks
|
||||
- Code cleanups (linter, formatting, spelling fixes)
|
||||
- Cleanup: use errors.New instead of fmt.Errorf where appropriate
|
||||
- Cleanup: remove duplicated cgo stuff, redundant linux build tag
|
||||
|
||||
* Version 0.9.1 - May 21, 2019
|
||||
- Minimum supported version of libseccomp bumped to v2.2.0
|
||||
- Use Libseccomp's `seccomp_version` API to retrieve library version
|
||||
- Unconditionally set TSync attribute for filters, due to Go's heavily threaded nature
|
||||
- Fix CVE-2017-18367 - Multiple syscall arguments were incorrectly combined with logical-OR, instead of logical-AND
|
||||
- Fix a failure to build on Debian-based distributions due to CGo code
|
||||
- Fix unit test failures on 32-bit architectures
|
||||
- Improve several errors to be more verbose about their causes
|
||||
- Add support for SCMP_ACT_LOG (with libseccomp versions 2.4.x and higher), permitting syscalls but logging their execution
|
||||
- Add support for SCMP_FLTATR_CTL_LOG (with libseccomp versions 2.4.x and higher), logging not-allowed actions when they are denied
|
||||
|
||||
* Version 0.9.0 - January 5, 2017
|
||||
- Initial tagged release
|
||||
120
vendor/github.com/seccomp/libseccomp-golang/CONTRIBUTING.md
generated
vendored
120
vendor/github.com/seccomp/libseccomp-golang/CONTRIBUTING.md
generated
vendored
@@ -1,120 +0,0 @@
|
||||
How to Submit Patches to the libseccomp-golang Project
|
||||
===============================================================================
|
||||
https://github.com/seccomp/libseccomp-golang
|
||||
|
||||
This document is intended to act as a guide to help you contribute to the
|
||||
libseccomp-golang project. It is not perfect, and there will always be
|
||||
exceptions to the rules described here, but by following the instructions below
|
||||
you should have a much easier time getting your work merged with the upstream
|
||||
project.
|
||||
|
||||
## Test Your Code Using Existing Tests
|
||||
|
||||
A number of tests and lint related recipes are provided in the Makefile, if
|
||||
you want to run the standard regression tests, you can execute the following:
|
||||
|
||||
# make check
|
||||
|
||||
In order to use it, the 'golangci-lint' tool is needed, which can be found at:
|
||||
|
||||
* https://github.com/golangci/golangci-lint
|
||||
|
||||
## Add New Tests for New Functionality
|
||||
|
||||
Any submissions which add functionality, or significantly change the existing
|
||||
code, should include additional tests to verify the proper operation of the
|
||||
proposed changes.
|
||||
|
||||
## Explain Your Work
|
||||
|
||||
At the top of every patch you should include a description of the problem you
|
||||
are trying to solve, how you solved it, and why you chose the solution you
|
||||
implemented. If you are submitting a bug fix, it is also incredibly helpful
|
||||
if you can describe/include a reproducer for the problem in the description as
|
||||
well as instructions on how to test for the bug and verify that it has been
|
||||
fixed.
|
||||
|
||||
## Sign Your Work
|
||||
|
||||
The sign-off is a simple line at the end of the patch description, which
|
||||
certifies that you wrote it or otherwise have the right to pass it on as an
|
||||
open-source patch. The "Developer's Certificate of Origin" pledge is taken
|
||||
from the Linux Kernel and the rules are pretty simple:
|
||||
|
||||
Developer's Certificate of Origin 1.1
|
||||
|
||||
By making a contribution to this project, I certify that:
|
||||
|
||||
(a) The contribution was created in whole or in part by me and I
|
||||
have the right to submit it under the open source license
|
||||
indicated in the file; or
|
||||
|
||||
(b) The contribution is based upon previous work that, to the best
|
||||
of my knowledge, is covered under an appropriate open source
|
||||
license and I have the right under that license to submit that
|
||||
work with modifications, whether created in whole or in part
|
||||
by me, under the same open source license (unless I am
|
||||
permitted to submit under a different license), as indicated
|
||||
in the file; or
|
||||
|
||||
(c) The contribution was provided directly to me by some other
|
||||
person who certified (a), (b) or (c) and I have not modified
|
||||
it.
|
||||
|
||||
(d) I understand and agree that this project and the contribution
|
||||
are public and that a record of the contribution (including all
|
||||
personal information I submit with it, including my sign-off) is
|
||||
maintained indefinitely and may be redistributed consistent with
|
||||
this project or the open source license(s) involved.
|
||||
|
||||
... then you just add a line to the bottom of your patch description, with
|
||||
your real name, saying:
|
||||
|
||||
Signed-off-by: Random J Developer <random@developer.example.org>
|
||||
|
||||
You can add this to your commit description in `git` with `git commit -s`
|
||||
|
||||
## Post Your Patches Upstream
|
||||
|
||||
The libseccomp project accepts both GitHub pull requests and patches sent via
|
||||
the mailing list. GitHub pull requests are preferred. This sections below
|
||||
explain how to contribute via either method. Please read each step and perform
|
||||
all steps that apply to your chosen contribution method.
|
||||
|
||||
### Submitting via Email
|
||||
|
||||
Depending on how you decided to work with the libseccomp code base and what
|
||||
tools you are using there are different ways to generate your patch(es).
|
||||
However, regardless of what tools you use, you should always generate your
|
||||
patches using the "unified" diff/patch format and the patches should always
|
||||
apply to the libseccomp source tree using the following command from the top
|
||||
directory of the libseccomp sources:
|
||||
|
||||
# patch -p1 < changes.patch
|
||||
|
||||
If you are not using git, stacked git (stgit), or some other tool which can
|
||||
generate patch files for you automatically, you may find the following command
|
||||
helpful in generating patches, where "libseccomp.orig/" is the unmodified
|
||||
source code directory and "libseccomp/" is the source code directory with your
|
||||
changes:
|
||||
|
||||
# diff -purN libseccomp.orig/ libseccomp/
|
||||
|
||||
When in doubt please generate your patch and try applying it to an unmodified
|
||||
copy of the libseccomp sources; if it fails for you, it will fail for the rest
|
||||
of us.
|
||||
|
||||
Finally, you will need to email your patches to the mailing list so they can
|
||||
be reviewed and potentially merged into the main libseccomp repository. When
|
||||
sending patches to the mailing list it is important to send your email in text
|
||||
form, no HTML mail please, and ensure that your email client does not mangle
|
||||
your patches. It should be possible to save your raw email to disk and apply
|
||||
it directly to the libseccomp source code; if that fails then you likely have
|
||||
a problem with your email client. When in doubt try a test first by sending
|
||||
yourself an email with your patch and attempting to apply the emailed patch to
|
||||
the libseccomp repository; if it fails for you, it will fail for the rest of
|
||||
us trying to test your patch and include it in the main libseccomp repository.
|
||||
|
||||
### Submitting via GitHub
|
||||
|
||||
See [this guide](https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/creating-a-pull-request) if you've never done this before.
|
||||
22
vendor/github.com/seccomp/libseccomp-golang/LICENSE
generated
vendored
22
vendor/github.com/seccomp/libseccomp-golang/LICENSE
generated
vendored
@@ -1,22 +0,0 @@
|
||||
Copyright (c) 2015 Matthew Heon <mheon@redhat.com>
|
||||
Copyright (c) 2015 Paul Moore <pmoore@redhat.com>
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
- Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
- Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
31
vendor/github.com/seccomp/libseccomp-golang/Makefile
generated
vendored
31
vendor/github.com/seccomp/libseccomp-golang/Makefile
generated
vendored
@@ -1,31 +0,0 @@
|
||||
# libseccomp-golang
|
||||
|
||||
.PHONY: all check check-build check-syntax fix-syntax vet test lint
|
||||
|
||||
all: check-build
|
||||
|
||||
check: lint test
|
||||
|
||||
check-build:
|
||||
go build
|
||||
|
||||
check-syntax:
|
||||
gofmt -d .
|
||||
|
||||
fix-syntax:
|
||||
gofmt -w .
|
||||
|
||||
vet:
|
||||
go vet -v ./...
|
||||
|
||||
# Previous bugs have made the tests freeze until the timeout. Golang default
|
||||
# timeout for tests is 10 minutes, which is too long, considering current tests
|
||||
# can be executed in less than 1 second. Reduce the timeout, so problems can
|
||||
# be noticed earlier in the CI.
|
||||
TEST_TIMEOUT=10s
|
||||
|
||||
test:
|
||||
go test -v -timeout $(TEST_TIMEOUT)
|
||||
|
||||
lint:
|
||||
golangci-lint run .
|
||||
59
vendor/github.com/seccomp/libseccomp-golang/README.md
generated
vendored
59
vendor/github.com/seccomp/libseccomp-golang/README.md
generated
vendored
@@ -1,59 +0,0 @@
|
||||

|
||||
===============================================================================
|
||||
https://github.com/seccomp/libseccomp-golang
|
||||
|
||||
[](https://pkg.go.dev/github.com/seccomp/libseccomp-golang)
|
||||
[](https://github.com/seccomp/libseccomp-golang/actions/workflows/validate.yml)
|
||||
[](https://github.com/seccomp/libseccomp-golang/actions/workflows/test.yml)
|
||||
|
||||
The libseccomp library provides an easy to use, platform independent, interface
|
||||
to the Linux Kernel's syscall filtering mechanism. The libseccomp API is
|
||||
designed to abstract away the underlying BPF based syscall filter language and
|
||||
present a more conventional function-call based filtering interface that should
|
||||
be familiar to, and easily adopted by, application developers.
|
||||
|
||||
The libseccomp-golang library provides a Go based interface to the libseccomp
|
||||
library.
|
||||
|
||||
## Online Resources
|
||||
|
||||
The library source repository currently lives on GitHub at the following URLs:
|
||||
|
||||
* https://github.com/seccomp/libseccomp-golang
|
||||
* https://github.com/seccomp/libseccomp
|
||||
|
||||
Documentation for this package is also available at:
|
||||
|
||||
* https://pkg.go.dev/github.com/seccomp/libseccomp-golang
|
||||
|
||||
## Verifying Releases
|
||||
|
||||
Starting with libseccomp-golang v0.10.0, the git tag corresponding to each
|
||||
release should be signed by one of the libseccomp-golang maintainers. It is
|
||||
recommended that before use you verify the release tags using the following
|
||||
command:
|
||||
|
||||
% git tag -v <tag>
|
||||
|
||||
At present, only the following keys, specified via the fingerprints below, are
|
||||
authorized to sign official libseccomp-golang release tags:
|
||||
|
||||
Paul Moore <paul@paul-moore.com>
|
||||
7100 AADF AE6E 6E94 0D2E 0AD6 55E4 5A5A E8CA 7C8A
|
||||
|
||||
Tom Hromatka <tom.hromatka@oracle.com>
|
||||
47A6 8FCE 37C7 D702 4FD6 5E11 356C E62C 2B52 4099
|
||||
|
||||
Kir Kolyshkin <kolyshkin@gmail.com>
|
||||
C242 8CD7 5720 FACD CF76 B6EA 17DE 5ECB 75A1 100E
|
||||
|
||||
More information on GnuPG and git tag verification can be found at their
|
||||
respective websites: https://git-scm.com/docs/git and https://gnupg.org.
|
||||
|
||||
## Installing the package
|
||||
|
||||
% go get github.com/seccomp/libseccomp-golang
|
||||
|
||||
## Contributing
|
||||
|
||||
See [CONTRIBUTING.md](CONTRIBUTING.md).
|
||||
48
vendor/github.com/seccomp/libseccomp-golang/SECURITY.md
generated
vendored
48
vendor/github.com/seccomp/libseccomp-golang/SECURITY.md
generated
vendored
@@ -1,48 +0,0 @@
|
||||
The libseccomp-golang Security Vulnerability Handling Process
|
||||
===============================================================================
|
||||
https://github.com/seccomp/libseccomp-golang
|
||||
|
||||
This document document attempts to describe the processes through which
|
||||
sensitive security relevant bugs can be responsibly disclosed to the
|
||||
libseccomp-golang project and how the project maintainers should handle these
|
||||
reports. Just like the other libseccomp-golang process documents, this
|
||||
document should be treated as a guiding document and not a hard, unyielding set
|
||||
of regulations; the bug reporters and project maintainers are encouraged to
|
||||
work together to address the issues as best they can, in a manner which works
|
||||
best for all parties involved.
|
||||
|
||||
### Reporting Problems
|
||||
|
||||
Problems with the libseccomp-golang library that are not suitable for immediate
|
||||
public disclosure should be emailed to the current libseccomp-golang
|
||||
maintainers, the list is below. We typically request at most a 90 day time
|
||||
period to address the issue before it is made public, but we will make every
|
||||
effort to address the issue as quickly as possible and shorten the disclosure
|
||||
window.
|
||||
|
||||
* Paul Moore, paul@paul-moore.com
|
||||
* Tom Hromatka, tom.hromatka@oracle.com
|
||||
* Kir Kolyshkin, kolyshkin@gmail.com
|
||||
|
||||
### Resolving Sensitive Security Issues
|
||||
|
||||
Upon disclosure of a bug, the maintainers should work together to investigate
|
||||
the problem and decide on a solution. In order to prevent an early disclosure
|
||||
of the problem, those working on the solution should do so privately and
|
||||
outside of the traditional libseccomp-golang development practices. One
|
||||
possible solution to this is to leverage the GitHub "Security" functionality to
|
||||
create a private development fork that can be shared among the maintainers, and
|
||||
optionally the reporter. A placeholder GitHub issue may be created, but
|
||||
details should remain extremely limited until such time as the problem has been
|
||||
fixed and responsibly disclosed. If a CVE, or other tag, has been assigned to
|
||||
the problem, the GitHub issue title should include the vulnerability tag once
|
||||
the problem has been disclosed.
|
||||
|
||||
### Public Disclosure
|
||||
|
||||
Whenever possible, responsible reporting and patching practices should be
|
||||
followed, including notification to the linux-distros and oss-security mailing
|
||||
lists.
|
||||
|
||||
* https://oss-security.openwall.org/wiki/mailing-lists/distros
|
||||
* https://oss-security.openwall.org/wiki/mailing-lists/oss-security
|
||||
1188
vendor/github.com/seccomp/libseccomp-golang/seccomp.go
generated
vendored
1188
vendor/github.com/seccomp/libseccomp-golang/seccomp.go
generated
vendored
File diff suppressed because it is too large
Load Diff
884
vendor/github.com/seccomp/libseccomp-golang/seccomp_internal.go
generated
vendored
884
vendor/github.com/seccomp/libseccomp-golang/seccomp_internal.go
generated
vendored
@@ -1,884 +0,0 @@
|
||||
// Internal functions for libseccomp Go bindings
|
||||
// No exported functions
|
||||
|
||||
package seccomp
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
// Unexported C wrapping code - provides the C-Golang interface
|
||||
// Get the seccomp header in scope
|
||||
// Need stdlib.h for free() on cstrings
|
||||
|
||||
// To compile libseccomp-golang against a specific version of libseccomp:
|
||||
// cd ../libseccomp && mkdir -p prefix
|
||||
// ./configure --prefix=$PWD/prefix && make && make install
|
||||
// cd ../libseccomp-golang
|
||||
// PKG_CONFIG_PATH=$PWD/../libseccomp/prefix/lib/pkgconfig/ make
|
||||
// LD_PRELOAD=$PWD/../libseccomp/prefix/lib/libseccomp.so.2.5.0 PKG_CONFIG_PATH=$PWD/../libseccomp/prefix/lib/pkgconfig/ make test
|
||||
|
||||
// #cgo pkg-config: libseccomp
|
||||
/*
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <seccomp.h>
|
||||
|
||||
#if (SCMP_VER_MAJOR < 2) || \
|
||||
(SCMP_VER_MAJOR == 2 && SCMP_VER_MINOR < 3) || \
|
||||
(SCMP_VER_MAJOR == 2 && SCMP_VER_MINOR == 3 && SCMP_VER_MICRO < 1)
|
||||
#error This package requires libseccomp >= v2.3.1
|
||||
#endif
|
||||
|
||||
#define ARCH_BAD ~0
|
||||
|
||||
const uint32_t C_ARCH_BAD = ARCH_BAD;
|
||||
|
||||
#ifndef SCMP_ARCH_PPC
|
||||
#define SCMP_ARCH_PPC ARCH_BAD
|
||||
#endif
|
||||
|
||||
#ifndef SCMP_ARCH_PPC64
|
||||
#define SCMP_ARCH_PPC64 ARCH_BAD
|
||||
#endif
|
||||
|
||||
#ifndef SCMP_ARCH_PPC64LE
|
||||
#define SCMP_ARCH_PPC64LE ARCH_BAD
|
||||
#endif
|
||||
|
||||
#ifndef SCMP_ARCH_S390
|
||||
#define SCMP_ARCH_S390 ARCH_BAD
|
||||
#endif
|
||||
|
||||
#ifndef SCMP_ARCH_S390X
|
||||
#define SCMP_ARCH_S390X ARCH_BAD
|
||||
#endif
|
||||
|
||||
#ifndef SCMP_ARCH_PARISC
|
||||
#define SCMP_ARCH_PARISC ARCH_BAD
|
||||
#endif
|
||||
|
||||
#ifndef SCMP_ARCH_PARISC64
|
||||
#define SCMP_ARCH_PARISC64 ARCH_BAD
|
||||
#endif
|
||||
|
||||
#ifndef SCMP_ARCH_RISCV64
|
||||
#define SCMP_ARCH_RISCV64 ARCH_BAD
|
||||
#endif
|
||||
|
||||
const uint32_t C_ARCH_NATIVE = SCMP_ARCH_NATIVE;
|
||||
const uint32_t C_ARCH_X86 = SCMP_ARCH_X86;
|
||||
const uint32_t C_ARCH_X86_64 = SCMP_ARCH_X86_64;
|
||||
const uint32_t C_ARCH_X32 = SCMP_ARCH_X32;
|
||||
const uint32_t C_ARCH_ARM = SCMP_ARCH_ARM;
|
||||
const uint32_t C_ARCH_AARCH64 = SCMP_ARCH_AARCH64;
|
||||
const uint32_t C_ARCH_MIPS = SCMP_ARCH_MIPS;
|
||||
const uint32_t C_ARCH_MIPS64 = SCMP_ARCH_MIPS64;
|
||||
const uint32_t C_ARCH_MIPS64N32 = SCMP_ARCH_MIPS64N32;
|
||||
const uint32_t C_ARCH_MIPSEL = SCMP_ARCH_MIPSEL;
|
||||
const uint32_t C_ARCH_MIPSEL64 = SCMP_ARCH_MIPSEL64;
|
||||
const uint32_t C_ARCH_MIPSEL64N32 = SCMP_ARCH_MIPSEL64N32;
|
||||
const uint32_t C_ARCH_PPC = SCMP_ARCH_PPC;
|
||||
const uint32_t C_ARCH_PPC64 = SCMP_ARCH_PPC64;
|
||||
const uint32_t C_ARCH_PPC64LE = SCMP_ARCH_PPC64LE;
|
||||
const uint32_t C_ARCH_S390 = SCMP_ARCH_S390;
|
||||
const uint32_t C_ARCH_S390X = SCMP_ARCH_S390X;
|
||||
const uint32_t C_ARCH_PARISC = SCMP_ARCH_PARISC;
|
||||
const uint32_t C_ARCH_PARISC64 = SCMP_ARCH_PARISC64;
|
||||
const uint32_t C_ARCH_RISCV64 = SCMP_ARCH_RISCV64;
|
||||
|
||||
#ifndef SCMP_ACT_LOG
|
||||
#define SCMP_ACT_LOG 0x7ffc0000U
|
||||
#endif
|
||||
|
||||
#ifndef SCMP_ACT_KILL_PROCESS
|
||||
#define SCMP_ACT_KILL_PROCESS 0x80000000U
|
||||
#endif
|
||||
|
||||
#ifndef SCMP_ACT_KILL_THREAD
|
||||
#define SCMP_ACT_KILL_THREAD 0x00000000U
|
||||
#endif
|
||||
|
||||
#ifndef SCMP_ACT_NOTIFY
|
||||
#define SCMP_ACT_NOTIFY 0x7fc00000U
|
||||
#endif
|
||||
|
||||
const uint32_t C_ACT_KILL = SCMP_ACT_KILL;
|
||||
const uint32_t C_ACT_KILL_PROCESS = SCMP_ACT_KILL_PROCESS;
|
||||
const uint32_t C_ACT_KILL_THREAD = SCMP_ACT_KILL_THREAD;
|
||||
const uint32_t C_ACT_TRAP = SCMP_ACT_TRAP;
|
||||
const uint32_t C_ACT_ERRNO = SCMP_ACT_ERRNO(0);
|
||||
const uint32_t C_ACT_TRACE = SCMP_ACT_TRACE(0);
|
||||
const uint32_t C_ACT_LOG = SCMP_ACT_LOG;
|
||||
const uint32_t C_ACT_ALLOW = SCMP_ACT_ALLOW;
|
||||
const uint32_t C_ACT_NOTIFY = SCMP_ACT_NOTIFY;
|
||||
|
||||
// The libseccomp SCMP_FLTATR_CTL_LOG member of the scmp_filter_attr enum was
|
||||
// added in v2.4.0
|
||||
#if SCMP_VER_MAJOR == 2 && SCMP_VER_MINOR < 4
|
||||
#define SCMP_FLTATR_CTL_LOG _SCMP_FLTATR_MIN
|
||||
#endif
|
||||
|
||||
// The following SCMP_FLTATR_* were added in libseccomp v2.5.0.
|
||||
#if SCMP_VER_MAJOR == 2 && SCMP_VER_MINOR < 5
|
||||
#define SCMP_FLTATR_CTL_SSB _SCMP_FLTATR_MIN
|
||||
#define SCMP_FLTATR_CTL_OPTIMIZE _SCMP_FLTATR_MIN
|
||||
#define SCMP_FLTATR_API_SYSRAWRC _SCMP_FLTATR_MIN
|
||||
#endif
|
||||
|
||||
const uint32_t C_ATTRIBUTE_DEFAULT = (uint32_t)SCMP_FLTATR_ACT_DEFAULT;
|
||||
const uint32_t C_ATTRIBUTE_BADARCH = (uint32_t)SCMP_FLTATR_ACT_BADARCH;
|
||||
const uint32_t C_ATTRIBUTE_NNP = (uint32_t)SCMP_FLTATR_CTL_NNP;
|
||||
const uint32_t C_ATTRIBUTE_TSYNC = (uint32_t)SCMP_FLTATR_CTL_TSYNC;
|
||||
const uint32_t C_ATTRIBUTE_LOG = (uint32_t)SCMP_FLTATR_CTL_LOG;
|
||||
const uint32_t C_ATTRIBUTE_SSB = (uint32_t)SCMP_FLTATR_CTL_SSB;
|
||||
const uint32_t C_ATTRIBUTE_OPTIMIZE = (uint32_t)SCMP_FLTATR_CTL_OPTIMIZE;
|
||||
const uint32_t C_ATTRIBUTE_SYSRAWRC = (uint32_t)SCMP_FLTATR_API_SYSRAWRC;
|
||||
|
||||
const int C_CMP_NE = (int)SCMP_CMP_NE;
|
||||
const int C_CMP_LT = (int)SCMP_CMP_LT;
|
||||
const int C_CMP_LE = (int)SCMP_CMP_LE;
|
||||
const int C_CMP_EQ = (int)SCMP_CMP_EQ;
|
||||
const int C_CMP_GE = (int)SCMP_CMP_GE;
|
||||
const int C_CMP_GT = (int)SCMP_CMP_GT;
|
||||
const int C_CMP_MASKED_EQ = (int)SCMP_CMP_MASKED_EQ;
|
||||
|
||||
const int C_VERSION_MAJOR = SCMP_VER_MAJOR;
|
||||
const int C_VERSION_MINOR = SCMP_VER_MINOR;
|
||||
const int C_VERSION_MICRO = SCMP_VER_MICRO;
|
||||
|
||||
#if SCMP_VER_MAJOR == 2 && SCMP_VER_MINOR >= 3
|
||||
unsigned int get_major_version()
|
||||
{
|
||||
return seccomp_version()->major;
|
||||
}
|
||||
|
||||
unsigned int get_minor_version()
|
||||
{
|
||||
return seccomp_version()->minor;
|
||||
}
|
||||
|
||||
unsigned int get_micro_version()
|
||||
{
|
||||
return seccomp_version()->micro;
|
||||
}
|
||||
#else
|
||||
unsigned int get_major_version()
|
||||
{
|
||||
return (unsigned int)C_VERSION_MAJOR;
|
||||
}
|
||||
|
||||
unsigned int get_minor_version()
|
||||
{
|
||||
return (unsigned int)C_VERSION_MINOR;
|
||||
}
|
||||
|
||||
unsigned int get_micro_version()
|
||||
{
|
||||
return (unsigned int)C_VERSION_MICRO;
|
||||
}
|
||||
#endif
|
||||
|
||||
// The libseccomp API level functions were added in v2.4.0
|
||||
#if SCMP_VER_MAJOR == 2 && SCMP_VER_MINOR < 4
|
||||
const unsigned int seccomp_api_get(void)
|
||||
{
|
||||
// libseccomp-golang requires libseccomp v2.2.0, at a minimum, which
|
||||
// supported API level 2. However, the kernel may not support API level
|
||||
// 2 constructs which are the seccomp() system call and the TSYNC
|
||||
// filter flag. Return the "reserved" value of 0 here to indicate that
|
||||
// proper API level support is not available in libseccomp.
|
||||
return 0;
|
||||
}
|
||||
|
||||
int seccomp_api_set(unsigned int level)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
#endif
|
||||
|
||||
typedef struct scmp_arg_cmp* scmp_cast_t;
|
||||
|
||||
void* make_arg_cmp_array(unsigned int length)
|
||||
{
|
||||
return calloc(length, sizeof(struct scmp_arg_cmp));
|
||||
}
|
||||
|
||||
// Wrapper to add an scmp_arg_cmp struct to an existing arg_cmp array
|
||||
void add_struct_arg_cmp(
|
||||
struct scmp_arg_cmp* arr,
|
||||
unsigned int pos,
|
||||
unsigned int arg,
|
||||
int compare,
|
||||
uint64_t a,
|
||||
uint64_t b
|
||||
)
|
||||
{
|
||||
arr[pos].arg = arg;
|
||||
arr[pos].op = compare;
|
||||
arr[pos].datum_a = a;
|
||||
arr[pos].datum_b = b;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// The seccomp notify API functions were added in v2.5.0
|
||||
#if SCMP_VER_MAJOR == 2 && SCMP_VER_MINOR < 5
|
||||
|
||||
struct seccomp_data {
|
||||
int nr;
|
||||
__u32 arch;
|
||||
__u64 instruction_pointer;
|
||||
__u64 args[6];
|
||||
};
|
||||
|
||||
struct seccomp_notif {
|
||||
__u64 id;
|
||||
__u32 pid;
|
||||
__u32 flags;
|
||||
struct seccomp_data data;
|
||||
};
|
||||
|
||||
struct seccomp_notif_resp {
|
||||
__u64 id;
|
||||
__s64 val;
|
||||
__s32 error;
|
||||
__u32 flags;
|
||||
};
|
||||
|
||||
int seccomp_notify_alloc(struct seccomp_notif **req, struct seccomp_notif_resp **resp) {
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
int seccomp_notify_fd(const scmp_filter_ctx ctx) {
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
void seccomp_notify_free(struct seccomp_notif *req, struct seccomp_notif_resp *resp) {
|
||||
}
|
||||
int seccomp_notify_id_valid(int fd, uint64_t id) {
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
int seccomp_notify_receive(int fd, struct seccomp_notif *req) {
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
int seccomp_notify_respond(int fd, struct seccomp_notif_resp *resp) {
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
#endif
|
||||
*/
|
||||
import "C"
|
||||
|
||||
// Nonexported types
|
||||
type scmpFilterAttr uint32
|
||||
|
||||
// Nonexported constants
|
||||
|
||||
const (
|
||||
filterAttrActDefault scmpFilterAttr = iota
|
||||
filterAttrActBadArch
|
||||
filterAttrNNP
|
||||
filterAttrTsync
|
||||
filterAttrLog
|
||||
filterAttrSSB
|
||||
filterAttrOptimize
|
||||
filterAttrRawRC
|
||||
)
|
||||
|
||||
const (
|
||||
// An error return from certain libseccomp functions
|
||||
scmpError C.int = -1
|
||||
// Comparison boundaries to check for architecture validity
|
||||
archStart ScmpArch = ArchNative
|
||||
archEnd ScmpArch = ArchRISCV64
|
||||
// Comparison boundaries to check for action validity
|
||||
actionStart ScmpAction = ActKillThread
|
||||
actionEnd ScmpAction = ActKillProcess
|
||||
// Comparison boundaries to check for comparison operator validity
|
||||
compareOpStart ScmpCompareOp = CompareNotEqual
|
||||
compareOpEnd ScmpCompareOp = CompareMaskedEqual
|
||||
)
|
||||
|
||||
var (
|
||||
// errBadFilter is thrown on bad filter context.
|
||||
errBadFilter = errors.New("filter is invalid or uninitialized")
|
||||
errDefAction = errors.New("requested action matches default action of filter")
|
||||
// Constants representing library major, minor, and micro versions
|
||||
verMajor = uint(C.get_major_version())
|
||||
verMinor = uint(C.get_minor_version())
|
||||
verMicro = uint(C.get_micro_version())
|
||||
)
|
||||
|
||||
// Nonexported functions
|
||||
|
||||
// checkVersion returns an error if the libseccomp version being used
|
||||
// is less than the one specified by major, minor, and micro arguments.
|
||||
// Argument op is an arbitrary non-empty operation description, which
|
||||
// is used as a part of the error message returned.
|
||||
//
|
||||
// Most users should use checkAPI instead.
|
||||
func checkVersion(op string, major, minor, micro uint) error {
|
||||
if (verMajor > major) ||
|
||||
(verMajor == major && verMinor > minor) ||
|
||||
(verMajor == major && verMinor == minor && verMicro >= micro) {
|
||||
return nil
|
||||
}
|
||||
return &VersionError{
|
||||
op: op,
|
||||
major: major,
|
||||
minor: minor,
|
||||
micro: micro,
|
||||
}
|
||||
}
|
||||
|
||||
func ensureSupportedVersion() error {
|
||||
return checkVersion("seccomp", 2, 3, 1)
|
||||
}
|
||||
|
||||
// Get the API level
|
||||
func getAPI() (uint, error) {
|
||||
api := C.seccomp_api_get()
|
||||
if api == 0 {
|
||||
return 0, errors.New("API level operations are not supported")
|
||||
}
|
||||
|
||||
return uint(api), nil
|
||||
}
|
||||
|
||||
// Set the API level
|
||||
func setAPI(api uint) error {
|
||||
if retCode := C.seccomp_api_set(C.uint(api)); retCode != 0 {
|
||||
e := errRc(retCode)
|
||||
if e == syscall.EOPNOTSUPP {
|
||||
return errors.New("API level operations are not supported")
|
||||
}
|
||||
|
||||
return fmt.Errorf("could not set API level: %w", e)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Filter helpers
|
||||
|
||||
// Filter finalizer - ensure that kernel context for filters is freed
|
||||
func filterFinalizer(f *ScmpFilter) {
|
||||
f.Release()
|
||||
}
|
||||
|
||||
func errRc(rc C.int) error {
|
||||
return syscall.Errno(-1 * rc)
|
||||
}
|
||||
|
||||
// Get a raw filter attribute
|
||||
func (f *ScmpFilter) getFilterAttr(attr scmpFilterAttr) (C.uint32_t, error) {
|
||||
f.lock.Lock()
|
||||
defer f.lock.Unlock()
|
||||
|
||||
if !f.valid {
|
||||
return 0x0, errBadFilter
|
||||
}
|
||||
|
||||
var attribute C.uint32_t
|
||||
|
||||
retCode := C.seccomp_attr_get(f.filterCtx, attr.toNative(), &attribute)
|
||||
if retCode != 0 {
|
||||
return 0x0, errRc(retCode)
|
||||
}
|
||||
|
||||
return attribute, nil
|
||||
}
|
||||
|
||||
// Set a raw filter attribute
|
||||
func (f *ScmpFilter) setFilterAttr(attr scmpFilterAttr, value C.uint32_t) error {
|
||||
f.lock.Lock()
|
||||
defer f.lock.Unlock()
|
||||
|
||||
if !f.valid {
|
||||
return errBadFilter
|
||||
}
|
||||
|
||||
retCode := C.seccomp_attr_set(f.filterCtx, attr.toNative(), value)
|
||||
if retCode != 0 {
|
||||
return errRc(retCode)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// DOES NOT LOCK OR CHECK VALIDITY
|
||||
// Assumes caller has already done this
|
||||
// Wrapper for seccomp_rule_add_... functions
|
||||
func (f *ScmpFilter) addRuleWrapper(call ScmpSyscall, action ScmpAction, exact bool, length C.uint, cond C.scmp_cast_t) error {
|
||||
if length != 0 && cond == nil {
|
||||
return errors.New("null conditions list, but length is nonzero")
|
||||
}
|
||||
|
||||
var retCode C.int
|
||||
if exact {
|
||||
retCode = C.seccomp_rule_add_exact_array(f.filterCtx, action.toNative(), C.int(call), length, cond)
|
||||
} else {
|
||||
retCode = C.seccomp_rule_add_array(f.filterCtx, action.toNative(), C.int(call), length, cond)
|
||||
}
|
||||
|
||||
if retCode != 0 {
|
||||
switch e := errRc(retCode); e {
|
||||
case syscall.EFAULT:
|
||||
return fmt.Errorf("unrecognized syscall %#x", int32(call))
|
||||
// libseccomp >= v2.5.0 returns EACCES, older versions return EPERM.
|
||||
// TODO: remove EPERM once libseccomp < v2.5.0 is not supported.
|
||||
case syscall.EPERM, syscall.EACCES:
|
||||
return errDefAction
|
||||
case syscall.EINVAL:
|
||||
return errors.New("two checks on same syscall argument")
|
||||
default:
|
||||
return e
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Generic add function for filter rules
|
||||
func (f *ScmpFilter) addRuleGeneric(call ScmpSyscall, action ScmpAction, exact bool, conds []ScmpCondition) error {
|
||||
f.lock.Lock()
|
||||
defer f.lock.Unlock()
|
||||
|
||||
if !f.valid {
|
||||
return errBadFilter
|
||||
}
|
||||
|
||||
if len(conds) == 0 {
|
||||
if err := f.addRuleWrapper(call, action, exact, 0, nil); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
argsArr := C.make_arg_cmp_array(C.uint(len(conds)))
|
||||
if argsArr == nil {
|
||||
return errors.New("error allocating memory for conditions")
|
||||
}
|
||||
defer C.free(argsArr)
|
||||
|
||||
for i, cond := range conds {
|
||||
C.add_struct_arg_cmp(C.scmp_cast_t(argsArr), C.uint(i),
|
||||
C.uint(cond.Argument), cond.Op.toNative(),
|
||||
C.uint64_t(cond.Operand1), C.uint64_t(cond.Operand2))
|
||||
}
|
||||
|
||||
if err := f.addRuleWrapper(call, action, exact, C.uint(len(conds)), C.scmp_cast_t(argsArr)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Generic Helpers
|
||||
|
||||
// Helper - Sanitize Arch token input
|
||||
func sanitizeArch(in ScmpArch) error {
|
||||
if in < archStart || in > archEnd {
|
||||
return fmt.Errorf("unrecognized architecture %#x", uint(in))
|
||||
}
|
||||
|
||||
if in.toNative() == C.C_ARCH_BAD {
|
||||
return fmt.Errorf("architecture %v is not supported on this version of the library", in)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func sanitizeAction(in ScmpAction) error {
|
||||
inTmp := in & 0x0000FFFF
|
||||
if inTmp < actionStart || inTmp > actionEnd {
|
||||
return fmt.Errorf("unrecognized action %#x", uint(inTmp))
|
||||
}
|
||||
|
||||
if inTmp != ActTrace && inTmp != ActErrno && (in&0xFFFF0000) != 0 {
|
||||
return errors.New("highest 16 bits must be zeroed except for Trace and Errno")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func sanitizeCompareOp(in ScmpCompareOp) error {
|
||||
if in < compareOpStart || in > compareOpEnd {
|
||||
return fmt.Errorf("unrecognized comparison operator %#x", uint(in))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func archFromNative(a C.uint32_t) (ScmpArch, error) {
|
||||
switch a {
|
||||
case C.C_ARCH_X86:
|
||||
return ArchX86, nil
|
||||
case C.C_ARCH_X86_64:
|
||||
return ArchAMD64, nil
|
||||
case C.C_ARCH_X32:
|
||||
return ArchX32, nil
|
||||
case C.C_ARCH_ARM:
|
||||
return ArchARM, nil
|
||||
case C.C_ARCH_NATIVE:
|
||||
return ArchNative, nil
|
||||
case C.C_ARCH_AARCH64:
|
||||
return ArchARM64, nil
|
||||
case C.C_ARCH_MIPS:
|
||||
return ArchMIPS, nil
|
||||
case C.C_ARCH_MIPS64:
|
||||
return ArchMIPS64, nil
|
||||
case C.C_ARCH_MIPS64N32:
|
||||
return ArchMIPS64N32, nil
|
||||
case C.C_ARCH_MIPSEL:
|
||||
return ArchMIPSEL, nil
|
||||
case C.C_ARCH_MIPSEL64:
|
||||
return ArchMIPSEL64, nil
|
||||
case C.C_ARCH_MIPSEL64N32:
|
||||
return ArchMIPSEL64N32, nil
|
||||
case C.C_ARCH_PPC:
|
||||
return ArchPPC, nil
|
||||
case C.C_ARCH_PPC64:
|
||||
return ArchPPC64, nil
|
||||
case C.C_ARCH_PPC64LE:
|
||||
return ArchPPC64LE, nil
|
||||
case C.C_ARCH_S390:
|
||||
return ArchS390, nil
|
||||
case C.C_ARCH_S390X:
|
||||
return ArchS390X, nil
|
||||
case C.C_ARCH_PARISC:
|
||||
return ArchPARISC, nil
|
||||
case C.C_ARCH_PARISC64:
|
||||
return ArchPARISC64, nil
|
||||
case C.C_ARCH_RISCV64:
|
||||
return ArchRISCV64, nil
|
||||
default:
|
||||
return 0x0, fmt.Errorf("unrecognized architecture %#x", uint32(a))
|
||||
}
|
||||
}
|
||||
|
||||
// Only use with sanitized arches, no error handling
|
||||
func (a ScmpArch) toNative() C.uint32_t {
|
||||
switch a {
|
||||
case ArchX86:
|
||||
return C.C_ARCH_X86
|
||||
case ArchAMD64:
|
||||
return C.C_ARCH_X86_64
|
||||
case ArchX32:
|
||||
return C.C_ARCH_X32
|
||||
case ArchARM:
|
||||
return C.C_ARCH_ARM
|
||||
case ArchARM64:
|
||||
return C.C_ARCH_AARCH64
|
||||
case ArchMIPS:
|
||||
return C.C_ARCH_MIPS
|
||||
case ArchMIPS64:
|
||||
return C.C_ARCH_MIPS64
|
||||
case ArchMIPS64N32:
|
||||
return C.C_ARCH_MIPS64N32
|
||||
case ArchMIPSEL:
|
||||
return C.C_ARCH_MIPSEL
|
||||
case ArchMIPSEL64:
|
||||
return C.C_ARCH_MIPSEL64
|
||||
case ArchMIPSEL64N32:
|
||||
return C.C_ARCH_MIPSEL64N32
|
||||
case ArchPPC:
|
||||
return C.C_ARCH_PPC
|
||||
case ArchPPC64:
|
||||
return C.C_ARCH_PPC64
|
||||
case ArchPPC64LE:
|
||||
return C.C_ARCH_PPC64LE
|
||||
case ArchS390:
|
||||
return C.C_ARCH_S390
|
||||
case ArchS390X:
|
||||
return C.C_ARCH_S390X
|
||||
case ArchPARISC:
|
||||
return C.C_ARCH_PARISC
|
||||
case ArchPARISC64:
|
||||
return C.C_ARCH_PARISC64
|
||||
case ArchRISCV64:
|
||||
return C.C_ARCH_RISCV64
|
||||
case ArchNative:
|
||||
return C.C_ARCH_NATIVE
|
||||
default:
|
||||
return 0x0
|
||||
}
|
||||
}
|
||||
|
||||
// Only use with sanitized ops, no error handling
|
||||
func (a ScmpCompareOp) toNative() C.int {
|
||||
switch a {
|
||||
case CompareNotEqual:
|
||||
return C.C_CMP_NE
|
||||
case CompareLess:
|
||||
return C.C_CMP_LT
|
||||
case CompareLessOrEqual:
|
||||
return C.C_CMP_LE
|
||||
case CompareEqual:
|
||||
return C.C_CMP_EQ
|
||||
case CompareGreaterEqual:
|
||||
return C.C_CMP_GE
|
||||
case CompareGreater:
|
||||
return C.C_CMP_GT
|
||||
case CompareMaskedEqual:
|
||||
return C.C_CMP_MASKED_EQ
|
||||
default:
|
||||
return 0x0
|
||||
}
|
||||
}
|
||||
|
||||
func actionFromNative(a C.uint32_t) (ScmpAction, error) {
|
||||
aTmp := a & 0xFFFF
|
||||
switch a & 0xFFFF0000 {
|
||||
case C.C_ACT_KILL_PROCESS:
|
||||
return ActKillProcess, nil
|
||||
case C.C_ACT_KILL_THREAD:
|
||||
return ActKillThread, nil
|
||||
case C.C_ACT_TRAP:
|
||||
return ActTrap, nil
|
||||
case C.C_ACT_ERRNO:
|
||||
return ActErrno.SetReturnCode(int16(aTmp)), nil
|
||||
case C.C_ACT_TRACE:
|
||||
return ActTrace.SetReturnCode(int16(aTmp)), nil
|
||||
case C.C_ACT_LOG:
|
||||
return ActLog, nil
|
||||
case C.C_ACT_ALLOW:
|
||||
return ActAllow, nil
|
||||
case C.C_ACT_NOTIFY:
|
||||
return ActNotify, nil
|
||||
default:
|
||||
return 0x0, fmt.Errorf("unrecognized action %#x", uint32(a))
|
||||
}
|
||||
}
|
||||
|
||||
// Only use with sanitized actions, no error handling
|
||||
func (a ScmpAction) toNative() C.uint32_t {
|
||||
switch a & 0xFFFF {
|
||||
case ActKillProcess:
|
||||
return C.C_ACT_KILL_PROCESS
|
||||
case ActKillThread:
|
||||
return C.C_ACT_KILL_THREAD
|
||||
case ActTrap:
|
||||
return C.C_ACT_TRAP
|
||||
case ActErrno:
|
||||
return C.C_ACT_ERRNO | (C.uint32_t(a) >> 16)
|
||||
case ActTrace:
|
||||
return C.C_ACT_TRACE | (C.uint32_t(a) >> 16)
|
||||
case ActLog:
|
||||
return C.C_ACT_LOG
|
||||
case ActAllow:
|
||||
return C.C_ACT_ALLOW
|
||||
case ActNotify:
|
||||
return C.C_ACT_NOTIFY
|
||||
default:
|
||||
return 0x0
|
||||
}
|
||||
}
|
||||
|
||||
// Internal only, assumes safe attribute
|
||||
func (a scmpFilterAttr) toNative() uint32 {
|
||||
switch a {
|
||||
case filterAttrActDefault:
|
||||
return uint32(C.C_ATTRIBUTE_DEFAULT)
|
||||
case filterAttrActBadArch:
|
||||
return uint32(C.C_ATTRIBUTE_BADARCH)
|
||||
case filterAttrNNP:
|
||||
return uint32(C.C_ATTRIBUTE_NNP)
|
||||
case filterAttrTsync:
|
||||
return uint32(C.C_ATTRIBUTE_TSYNC)
|
||||
case filterAttrLog:
|
||||
return uint32(C.C_ATTRIBUTE_LOG)
|
||||
case filterAttrSSB:
|
||||
return uint32(C.C_ATTRIBUTE_SSB)
|
||||
case filterAttrOptimize:
|
||||
return uint32(C.C_ATTRIBUTE_OPTIMIZE)
|
||||
case filterAttrRawRC:
|
||||
return uint32(C.C_ATTRIBUTE_SYSRAWRC)
|
||||
default:
|
||||
return 0x0
|
||||
}
|
||||
}
|
||||
|
||||
func syscallFromNative(a C.int) ScmpSyscall {
|
||||
return ScmpSyscall(a)
|
||||
}
|
||||
|
||||
func notifReqFromNative(req *C.struct_seccomp_notif) (*ScmpNotifReq, error) {
|
||||
scmpArgs := make([]uint64, 6)
|
||||
for i := 0; i < len(scmpArgs); i++ {
|
||||
scmpArgs[i] = uint64(req.data.args[i])
|
||||
}
|
||||
|
||||
arch, err := archFromNative(req.data.arch)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
scmpData := ScmpNotifData{
|
||||
Syscall: syscallFromNative(req.data.nr),
|
||||
Arch: arch,
|
||||
InstrPointer: uint64(req.data.instruction_pointer),
|
||||
Args: scmpArgs,
|
||||
}
|
||||
|
||||
scmpReq := &ScmpNotifReq{
|
||||
ID: uint64(req.id),
|
||||
Pid: uint32(req.pid),
|
||||
Flags: uint32(req.flags),
|
||||
Data: scmpData,
|
||||
}
|
||||
|
||||
return scmpReq, nil
|
||||
}
|
||||
|
||||
func (scmpResp *ScmpNotifResp) toNative(resp *C.struct_seccomp_notif_resp) {
|
||||
resp.id = C.__u64(scmpResp.ID)
|
||||
resp.val = C.__s64(scmpResp.Val)
|
||||
resp.error = (C.__s32(scmpResp.Error) * -1) // kernel requires a negated value
|
||||
resp.flags = C.__u32(scmpResp.Flags)
|
||||
}
|
||||
|
||||
// checkAPI checks that both the API level and the seccomp version is equal to
|
||||
// or greater than the specified minLevel and major, minor, micro,
|
||||
// respectively, and returns an error otherwise. Argument op is an arbitrary
|
||||
// non-empty operation description, used as a part of the error message
|
||||
// returned.
|
||||
func checkAPI(op string, minLevel uint, major, minor, micro uint) error {
|
||||
// Ignore error from getAPI, as it returns level == 0 in case of error.
|
||||
level, _ := getAPI()
|
||||
if level >= minLevel {
|
||||
return checkVersion(op, major, minor, micro)
|
||||
}
|
||||
return &VersionError{
|
||||
op: op,
|
||||
curAPI: level,
|
||||
minAPI: minLevel,
|
||||
major: major,
|
||||
minor: minor,
|
||||
micro: micro,
|
||||
}
|
||||
}
|
||||
|
||||
// Userspace Notification API
|
||||
// Calls to C.seccomp_notify* hidden from seccomp.go
|
||||
|
||||
func notifSupported() error {
|
||||
return checkAPI("seccomp notification", 6, 2, 5, 0)
|
||||
}
|
||||
|
||||
func (f *ScmpFilter) getNotifFd() (ScmpFd, error) {
|
||||
f.lock.Lock()
|
||||
defer f.lock.Unlock()
|
||||
|
||||
if !f.valid {
|
||||
return -1, errBadFilter
|
||||
}
|
||||
if err := notifSupported(); err != nil {
|
||||
return -1, err
|
||||
}
|
||||
|
||||
fd := C.seccomp_notify_fd(f.filterCtx)
|
||||
|
||||
return ScmpFd(fd), nil
|
||||
}
|
||||
|
||||
func notifReceive(fd ScmpFd) (*ScmpNotifReq, error) {
|
||||
var req *C.struct_seccomp_notif
|
||||
var resp *C.struct_seccomp_notif_resp
|
||||
|
||||
if err := notifSupported(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// we only use the request here; the response is unused
|
||||
if retCode := C.seccomp_notify_alloc(&req, &resp); retCode != 0 {
|
||||
return nil, errRc(retCode)
|
||||
}
|
||||
|
||||
defer func() {
|
||||
C.seccomp_notify_free(req, resp)
|
||||
}()
|
||||
|
||||
for {
|
||||
retCode, errno := C.seccomp_notify_receive(C.int(fd), req)
|
||||
if retCode == 0 {
|
||||
break
|
||||
}
|
||||
|
||||
if errno == syscall.EINTR {
|
||||
continue
|
||||
}
|
||||
|
||||
if errno == syscall.ENOENT {
|
||||
return nil, errno
|
||||
}
|
||||
|
||||
return nil, errRc(retCode)
|
||||
}
|
||||
|
||||
return notifReqFromNative(req)
|
||||
}
|
||||
|
||||
func notifRespond(fd ScmpFd, scmpResp *ScmpNotifResp) error {
|
||||
var req *C.struct_seccomp_notif
|
||||
var resp *C.struct_seccomp_notif_resp
|
||||
|
||||
if err := notifSupported(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// we only use the response here; the request is discarded
|
||||
if retCode := C.seccomp_notify_alloc(&req, &resp); retCode != 0 {
|
||||
return errRc(retCode)
|
||||
}
|
||||
|
||||
defer func() {
|
||||
C.seccomp_notify_free(req, resp)
|
||||
}()
|
||||
|
||||
scmpResp.toNative(resp)
|
||||
|
||||
for {
|
||||
retCode, errno := C.seccomp_notify_respond(C.int(fd), resp)
|
||||
if retCode == 0 {
|
||||
break
|
||||
}
|
||||
|
||||
if errno == syscall.EINTR {
|
||||
continue
|
||||
}
|
||||
|
||||
if errno == syscall.ENOENT {
|
||||
return errno
|
||||
}
|
||||
|
||||
return errRc(retCode)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func notifIDValid(fd ScmpFd, id uint64) error {
|
||||
if err := notifSupported(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for {
|
||||
retCode, errno := C.seccomp_notify_id_valid(C.int(fd), C.uint64_t(id))
|
||||
if retCode == 0 {
|
||||
break
|
||||
}
|
||||
|
||||
if errno == syscall.EINTR {
|
||||
continue
|
||||
}
|
||||
|
||||
if errno == syscall.ENOENT {
|
||||
return errno
|
||||
}
|
||||
|
||||
return errRc(retCode)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
24
vendor/github.com/syndtr/gocapability/LICENSE
generated
vendored
24
vendor/github.com/syndtr/gocapability/LICENSE
generated
vendored
@@ -1,24 +0,0 @@
|
||||
Copyright 2013 Suryandaru Triandana <syndtr@gmail.com>
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
133
vendor/github.com/syndtr/gocapability/capability/capability.go
generated
vendored
133
vendor/github.com/syndtr/gocapability/capability/capability.go
generated
vendored
@@ -1,133 +0,0 @@
|
||||
// Copyright (c) 2013, Suryandaru Triandana <syndtr@gmail.com>
|
||||
// All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// Package capability provides utilities for manipulating POSIX capabilities.
|
||||
package capability
|
||||
|
||||
type Capabilities interface {
|
||||
// Get check whether a capability present in the given
|
||||
// capabilities set. The 'which' value should be one of EFFECTIVE,
|
||||
// PERMITTED, INHERITABLE, BOUNDING or AMBIENT.
|
||||
Get(which CapType, what Cap) bool
|
||||
|
||||
// Empty check whether all capability bits of the given capabilities
|
||||
// set are zero. The 'which' value should be one of EFFECTIVE,
|
||||
// PERMITTED, INHERITABLE, BOUNDING or AMBIENT.
|
||||
Empty(which CapType) bool
|
||||
|
||||
// Full check whether all capability bits of the given capabilities
|
||||
// set are one. The 'which' value should be one of EFFECTIVE,
|
||||
// PERMITTED, INHERITABLE, BOUNDING or AMBIENT.
|
||||
Full(which CapType) bool
|
||||
|
||||
// Set sets capabilities of the given capabilities sets. The
|
||||
// 'which' value should be one or combination (OR'ed) of EFFECTIVE,
|
||||
// PERMITTED, INHERITABLE, BOUNDING or AMBIENT.
|
||||
Set(which CapType, caps ...Cap)
|
||||
|
||||
// Unset unsets capabilities of the given capabilities sets. The
|
||||
// 'which' value should be one or combination (OR'ed) of EFFECTIVE,
|
||||
// PERMITTED, INHERITABLE, BOUNDING or AMBIENT.
|
||||
Unset(which CapType, caps ...Cap)
|
||||
|
||||
// Fill sets all bits of the given capabilities kind to one. The
|
||||
// 'kind' value should be one or combination (OR'ed) of CAPS,
|
||||
// BOUNDS or AMBS.
|
||||
Fill(kind CapType)
|
||||
|
||||
// Clear sets all bits of the given capabilities kind to zero. The
|
||||
// 'kind' value should be one or combination (OR'ed) of CAPS,
|
||||
// BOUNDS or AMBS.
|
||||
Clear(kind CapType)
|
||||
|
||||
// String return current capabilities state of the given capabilities
|
||||
// set as string. The 'which' value should be one of EFFECTIVE,
|
||||
// PERMITTED, INHERITABLE BOUNDING or AMBIENT
|
||||
StringCap(which CapType) string
|
||||
|
||||
// String return current capabilities state as string.
|
||||
String() string
|
||||
|
||||
// Load load actual capabilities value. This will overwrite all
|
||||
// outstanding changes.
|
||||
Load() error
|
||||
|
||||
// Apply apply the capabilities settings, so all changes will take
|
||||
// effect.
|
||||
Apply(kind CapType) error
|
||||
}
|
||||
|
||||
// NewPid initializes a new Capabilities object for given pid when
|
||||
// it is nonzero, or for the current process if pid is 0.
|
||||
//
|
||||
// Deprecated: Replace with NewPid2. For example, replace:
|
||||
//
|
||||
// c, err := NewPid(0)
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
//
|
||||
// with:
|
||||
//
|
||||
// c, err := NewPid2(0)
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
// err = c.Load()
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
func NewPid(pid int) (Capabilities, error) {
|
||||
c, err := newPid(pid)
|
||||
if err != nil {
|
||||
return c, err
|
||||
}
|
||||
err = c.Load()
|
||||
return c, err
|
||||
}
|
||||
|
||||
// NewPid2 initializes a new Capabilities object for given pid when
|
||||
// it is nonzero, or for the current process if pid is 0. This
|
||||
// does not load the process's current capabilities; to do that you
|
||||
// must call Load explicitly.
|
||||
func NewPid2(pid int) (Capabilities, error) {
|
||||
return newPid(pid)
|
||||
}
|
||||
|
||||
// NewFile initializes a new Capabilities object for given file path.
|
||||
//
|
||||
// Deprecated: Replace with NewFile2. For example, replace:
|
||||
//
|
||||
// c, err := NewFile(path)
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
//
|
||||
// with:
|
||||
//
|
||||
// c, err := NewFile2(path)
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
// err = c.Load()
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
func NewFile(path string) (Capabilities, error) {
|
||||
c, err := newFile(path)
|
||||
if err != nil {
|
||||
return c, err
|
||||
}
|
||||
err = c.Load()
|
||||
return c, err
|
||||
}
|
||||
|
||||
// NewFile2 creates a new initialized Capabilities object for given
|
||||
// file path. This does not load the process's current capabilities;
|
||||
// to do that you must call Load explicitly.
|
||||
func NewFile2(path string) (Capabilities, error) {
|
||||
return newFile(path)
|
||||
}
|
||||
642
vendor/github.com/syndtr/gocapability/capability/capability_linux.go
generated
vendored
642
vendor/github.com/syndtr/gocapability/capability/capability_linux.go
generated
vendored
@@ -1,642 +0,0 @@
|
||||
// Copyright (c) 2013, Suryandaru Triandana <syndtr@gmail.com>
|
||||
// All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
package capability
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"strings"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
var errUnknownVers = errors.New("unknown capability version")
|
||||
|
||||
const (
|
||||
linuxCapVer1 = 0x19980330
|
||||
linuxCapVer2 = 0x20071026
|
||||
linuxCapVer3 = 0x20080522
|
||||
)
|
||||
|
||||
var (
|
||||
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")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
var b []byte = make([]byte, 11)
|
||||
_, err = f.Read(b)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Sscanf(string(b), "%d", &capLastCap)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func mkStringCap(c Capabilities, which CapType) (ret string) {
|
||||
for i, first := Cap(0), true; i <= CAP_LAST_CAP; i++ {
|
||||
if !c.Get(which, i) {
|
||||
continue
|
||||
}
|
||||
if first {
|
||||
first = false
|
||||
} else {
|
||||
ret += ", "
|
||||
}
|
||||
ret += i.String()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func mkString(c Capabilities, max CapType) (ret string) {
|
||||
ret = "{"
|
||||
for i := CapType(1); i <= max; i <<= 1 {
|
||||
ret += " " + i.String() + "=\""
|
||||
if c.Empty(i) {
|
||||
ret += "empty"
|
||||
} else if c.Full(i) {
|
||||
ret += "full"
|
||||
} else {
|
||||
ret += c.StringCap(i)
|
||||
}
|
||||
ret += "\""
|
||||
}
|
||||
ret += " }"
|
||||
return
|
||||
}
|
||||
|
||||
func newPid(pid int) (c Capabilities, err error) {
|
||||
switch capVers {
|
||||
case linuxCapVer1:
|
||||
p := new(capsV1)
|
||||
p.hdr.version = capVers
|
||||
p.hdr.pid = int32(pid)
|
||||
c = p
|
||||
case linuxCapVer2, linuxCapVer3:
|
||||
p := new(capsV3)
|
||||
p.hdr.version = capVers
|
||||
p.hdr.pid = int32(pid)
|
||||
c = p
|
||||
default:
|
||||
err = errUnknownVers
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
type capsV1 struct {
|
||||
hdr capHeader
|
||||
data capData
|
||||
}
|
||||
|
||||
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 {
|
||||
hdr capHeader
|
||||
data [2]capData
|
||||
bounds [2]uint32
|
||||
ambient [2]uint32
|
||||
}
|
||||
|
||||
func (c *capsV3) Get(which CapType, what Cap) bool {
|
||||
var i uint
|
||||
if what > 31 {
|
||||
i = uint(what) >> 5
|
||||
what %= 32
|
||||
}
|
||||
|
||||
switch which {
|
||||
case EFFECTIVE:
|
||||
return (1<<uint(what))&c.data[i].effective != 0
|
||||
case PERMITTED:
|
||||
return (1<<uint(what))&c.data[i].permitted != 0
|
||||
case INHERITABLE:
|
||||
return (1<<uint(what))&c.data[i].inheritable != 0
|
||||
case BOUNDING:
|
||||
return (1<<uint(what))&c.bounds[i] != 0
|
||||
case AMBIENT:
|
||||
return (1<<uint(what))&c.ambient[i] != 0
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func (c *capsV3) getData(which CapType, dest []uint32) {
|
||||
switch which {
|
||||
case EFFECTIVE:
|
||||
dest[0] = c.data[0].effective
|
||||
dest[1] = c.data[1].effective
|
||||
case PERMITTED:
|
||||
dest[0] = c.data[0].permitted
|
||||
dest[1] = c.data[1].permitted
|
||||
case INHERITABLE:
|
||||
dest[0] = c.data[0].inheritable
|
||||
dest[1] = c.data[1].inheritable
|
||||
case BOUNDING:
|
||||
dest[0] = c.bounds[0]
|
||||
dest[1] = c.bounds[1]
|
||||
case AMBIENT:
|
||||
dest[0] = c.ambient[0]
|
||||
dest[1] = c.ambient[1]
|
||||
}
|
||||
}
|
||||
|
||||
func (c *capsV3) Empty(which CapType) bool {
|
||||
var data [2]uint32
|
||||
c.getData(which, data[:])
|
||||
return data[0] == 0 && data[1] == 0
|
||||
}
|
||||
|
||||
func (c *capsV3) Full(which CapType) bool {
|
||||
var data [2]uint32
|
||||
c.getData(which, data[:])
|
||||
if (data[0] & 0xffffffff) != 0xffffffff {
|
||||
return false
|
||||
}
|
||||
return (data[1] & capUpperMask) == capUpperMask
|
||||
}
|
||||
|
||||
func (c *capsV3) Set(which CapType, caps ...Cap) {
|
||||
for _, what := range caps {
|
||||
var i uint
|
||||
if what > 31 {
|
||||
i = uint(what) >> 5
|
||||
what %= 32
|
||||
}
|
||||
|
||||
if which&EFFECTIVE != 0 {
|
||||
c.data[i].effective |= 1 << uint(what)
|
||||
}
|
||||
if which&PERMITTED != 0 {
|
||||
c.data[i].permitted |= 1 << uint(what)
|
||||
}
|
||||
if which&INHERITABLE != 0 {
|
||||
c.data[i].inheritable |= 1 << uint(what)
|
||||
}
|
||||
if which&BOUNDING != 0 {
|
||||
c.bounds[i] |= 1 << uint(what)
|
||||
}
|
||||
if which&AMBIENT != 0 {
|
||||
c.ambient[i] |= 1 << uint(what)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *capsV3) Unset(which CapType, caps ...Cap) {
|
||||
for _, what := range caps {
|
||||
var i uint
|
||||
if what > 31 {
|
||||
i = uint(what) >> 5
|
||||
what %= 32
|
||||
}
|
||||
|
||||
if which&EFFECTIVE != 0 {
|
||||
c.data[i].effective &= ^(1 << uint(what))
|
||||
}
|
||||
if which&PERMITTED != 0 {
|
||||
c.data[i].permitted &= ^(1 << uint(what))
|
||||
}
|
||||
if which&INHERITABLE != 0 {
|
||||
c.data[i].inheritable &= ^(1 << uint(what))
|
||||
}
|
||||
if which&BOUNDING != 0 {
|
||||
c.bounds[i] &= ^(1 << uint(what))
|
||||
}
|
||||
if which&AMBIENT != 0 {
|
||||
c.ambient[i] &= ^(1 << uint(what))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *capsV3) Fill(kind CapType) {
|
||||
if kind&CAPS == CAPS {
|
||||
c.data[0].effective = 0xffffffff
|
||||
c.data[0].permitted = 0xffffffff
|
||||
c.data[0].inheritable = 0
|
||||
c.data[1].effective = 0xffffffff
|
||||
c.data[1].permitted = 0xffffffff
|
||||
c.data[1].inheritable = 0
|
||||
}
|
||||
|
||||
if kind&BOUNDS == BOUNDS {
|
||||
c.bounds[0] = 0xffffffff
|
||||
c.bounds[1] = 0xffffffff
|
||||
}
|
||||
if kind&AMBS == AMBS {
|
||||
c.ambient[0] = 0xffffffff
|
||||
c.ambient[1] = 0xffffffff
|
||||
}
|
||||
}
|
||||
|
||||
func (c *capsV3) Clear(kind CapType) {
|
||||
if kind&CAPS == CAPS {
|
||||
c.data[0].effective = 0
|
||||
c.data[0].permitted = 0
|
||||
c.data[0].inheritable = 0
|
||||
c.data[1].effective = 0
|
||||
c.data[1].permitted = 0
|
||||
c.data[1].inheritable = 0
|
||||
}
|
||||
|
||||
if kind&BOUNDS == BOUNDS {
|
||||
c.bounds[0] = 0
|
||||
c.bounds[1] = 0
|
||||
}
|
||||
if kind&AMBS == AMBS {
|
||||
c.ambient[0] = 0
|
||||
c.ambient[1] = 0
|
||||
}
|
||||
}
|
||||
|
||||
func (c *capsV3) StringCap(which CapType) (ret string) {
|
||||
return mkStringCap(c, which)
|
||||
}
|
||||
|
||||
func (c *capsV3) String() (ret string) {
|
||||
return mkString(c, BOUNDING)
|
||||
}
|
||||
|
||||
func (c *capsV3) Load() (err error) {
|
||||
err = capget(&c.hdr, &c.data[0])
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
var status_path string
|
||||
|
||||
if c.hdr.pid == 0 {
|
||||
status_path = fmt.Sprintf("/proc/self/status")
|
||||
} else {
|
||||
status_path = fmt.Sprintf("/proc/%d/status", c.hdr.pid)
|
||||
}
|
||||
|
||||
f, err := os.Open(status_path)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
b := bufio.NewReader(f)
|
||||
for {
|
||||
line, e := b.ReadString('\n')
|
||||
if e != nil {
|
||||
if e != io.EOF {
|
||||
err = e
|
||||
}
|
||||
break
|
||||
}
|
||||
if strings.HasPrefix(line, "CapB") {
|
||||
fmt.Sscanf(line[4:], "nd: %08x%08x", &c.bounds[1], &c.bounds[0])
|
||||
continue
|
||||
}
|
||||
if strings.HasPrefix(line, "CapA") {
|
||||
fmt.Sscanf(line[4:], "mb: %08x%08x", &c.ambient[1], &c.ambient[0])
|
||||
continue
|
||||
}
|
||||
}
|
||||
f.Close()
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (c *capsV3) Apply(kind CapType) (err error) {
|
||||
if kind&BOUNDS == BOUNDS {
|
||||
var data [2]capData
|
||||
err = capget(&c.hdr, &data[0])
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if (1<<uint(CAP_SETPCAP))&data[0].effective != 0 {
|
||||
for i := Cap(0); i <= CAP_LAST_CAP; i++ {
|
||||
if c.Get(BOUNDING, i) {
|
||||
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.
|
||||
if errno, ok := err.(syscall.Errno); ok && errno == syscall.EINVAL {
|
||||
err = nil
|
||||
continue
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if kind&CAPS == CAPS {
|
||||
err = capset(&c.hdr, &c.data[0])
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
if errno, ok := err.(syscall.Errno); ok && errno == syscall.EINVAL {
|
||||
err = nil
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func newFile(path string) (c Capabilities, err error) {
|
||||
c = &capsFile{path: path}
|
||||
return
|
||||
}
|
||||
|
||||
type capsFile struct {
|
||||
path string
|
||||
data vfscapData
|
||||
}
|
||||
|
||||
func (c *capsFile) Get(which CapType, what Cap) bool {
|
||||
var i uint
|
||||
if what > 31 {
|
||||
if c.data.version == 1 {
|
||||
return false
|
||||
}
|
||||
i = uint(what) >> 5
|
||||
what %= 32
|
||||
}
|
||||
|
||||
switch which {
|
||||
case EFFECTIVE:
|
||||
return (1<<uint(what))&c.data.effective[i] != 0
|
||||
case PERMITTED:
|
||||
return (1<<uint(what))&c.data.data[i].permitted != 0
|
||||
case INHERITABLE:
|
||||
return (1<<uint(what))&c.data.data[i].inheritable != 0
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func (c *capsFile) getData(which CapType, dest []uint32) {
|
||||
switch which {
|
||||
case EFFECTIVE:
|
||||
dest[0] = c.data.effective[0]
|
||||
dest[1] = c.data.effective[1]
|
||||
case PERMITTED:
|
||||
dest[0] = c.data.data[0].permitted
|
||||
dest[1] = c.data.data[1].permitted
|
||||
case INHERITABLE:
|
||||
dest[0] = c.data.data[0].inheritable
|
||||
dest[1] = c.data.data[1].inheritable
|
||||
}
|
||||
}
|
||||
|
||||
func (c *capsFile) Empty(which CapType) bool {
|
||||
var data [2]uint32
|
||||
c.getData(which, data[:])
|
||||
return data[0] == 0 && data[1] == 0
|
||||
}
|
||||
|
||||
func (c *capsFile) Full(which CapType) bool {
|
||||
var data [2]uint32
|
||||
c.getData(which, data[:])
|
||||
if c.data.version == 0 {
|
||||
return (data[0] & 0x7fffffff) == 0x7fffffff
|
||||
}
|
||||
if (data[0] & 0xffffffff) != 0xffffffff {
|
||||
return false
|
||||
}
|
||||
return (data[1] & capUpperMask) == capUpperMask
|
||||
}
|
||||
|
||||
func (c *capsFile) Set(which CapType, caps ...Cap) {
|
||||
for _, what := range caps {
|
||||
var i uint
|
||||
if what > 31 {
|
||||
if c.data.version == 1 {
|
||||
continue
|
||||
}
|
||||
i = uint(what) >> 5
|
||||
what %= 32
|
||||
}
|
||||
|
||||
if which&EFFECTIVE != 0 {
|
||||
c.data.effective[i] |= 1 << uint(what)
|
||||
}
|
||||
if which&PERMITTED != 0 {
|
||||
c.data.data[i].permitted |= 1 << uint(what)
|
||||
}
|
||||
if which&INHERITABLE != 0 {
|
||||
c.data.data[i].inheritable |= 1 << uint(what)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *capsFile) Unset(which CapType, caps ...Cap) {
|
||||
for _, what := range caps {
|
||||
var i uint
|
||||
if what > 31 {
|
||||
if c.data.version == 1 {
|
||||
continue
|
||||
}
|
||||
i = uint(what) >> 5
|
||||
what %= 32
|
||||
}
|
||||
|
||||
if which&EFFECTIVE != 0 {
|
||||
c.data.effective[i] &= ^(1 << uint(what))
|
||||
}
|
||||
if which&PERMITTED != 0 {
|
||||
c.data.data[i].permitted &= ^(1 << uint(what))
|
||||
}
|
||||
if which&INHERITABLE != 0 {
|
||||
c.data.data[i].inheritable &= ^(1 << uint(what))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *capsFile) Fill(kind CapType) {
|
||||
if kind&CAPS == CAPS {
|
||||
c.data.effective[0] = 0xffffffff
|
||||
c.data.data[0].permitted = 0xffffffff
|
||||
c.data.data[0].inheritable = 0
|
||||
if c.data.version == 2 {
|
||||
c.data.effective[1] = 0xffffffff
|
||||
c.data.data[1].permitted = 0xffffffff
|
||||
c.data.data[1].inheritable = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *capsFile) Clear(kind CapType) {
|
||||
if kind&CAPS == CAPS {
|
||||
c.data.effective[0] = 0
|
||||
c.data.data[0].permitted = 0
|
||||
c.data.data[0].inheritable = 0
|
||||
if c.data.version == 2 {
|
||||
c.data.effective[1] = 0
|
||||
c.data.data[1].permitted = 0
|
||||
c.data.data[1].inheritable = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *capsFile) StringCap(which CapType) (ret string) {
|
||||
return mkStringCap(c, which)
|
||||
}
|
||||
|
||||
func (c *capsFile) String() (ret string) {
|
||||
return mkString(c, INHERITABLE)
|
||||
}
|
||||
|
||||
func (c *capsFile) Load() (err error) {
|
||||
return getVfsCap(c.path, &c.data)
|
||||
}
|
||||
|
||||
func (c *capsFile) Apply(kind CapType) (err error) {
|
||||
if kind&CAPS == CAPS {
|
||||
return setVfsCap(c.path, &c.data)
|
||||
}
|
||||
return
|
||||
}
|
||||
19
vendor/github.com/syndtr/gocapability/capability/capability_noop.go
generated
vendored
19
vendor/github.com/syndtr/gocapability/capability/capability_noop.go
generated
vendored
@@ -1,19 +0,0 @@
|
||||
// Copyright (c) 2013, Suryandaru Triandana <syndtr@gmail.com>
|
||||
// All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// +build !linux
|
||||
|
||||
package capability
|
||||
|
||||
import "errors"
|
||||
|
||||
func newPid(pid int) (Capabilities, error) {
|
||||
return nil, errors.New("not supported")
|
||||
}
|
||||
|
||||
func newFile(path string) (Capabilities, error) {
|
||||
return nil, errors.New("not supported")
|
||||
}
|
||||
309
vendor/github.com/syndtr/gocapability/capability/enum.go
generated
vendored
309
vendor/github.com/syndtr/gocapability/capability/enum.go
generated
vendored
@@ -1,309 +0,0 @@
|
||||
// Copyright (c) 2013, Suryandaru Triandana <syndtr@gmail.com>
|
||||
// All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
package capability
|
||||
|
||||
type CapType uint
|
||||
|
||||
func (c CapType) String() string {
|
||||
switch c {
|
||||
case EFFECTIVE:
|
||||
return "effective"
|
||||
case PERMITTED:
|
||||
return "permitted"
|
||||
case INHERITABLE:
|
||||
return "inheritable"
|
||||
case BOUNDING:
|
||||
return "bounding"
|
||||
case CAPS:
|
||||
return "caps"
|
||||
case AMBIENT:
|
||||
return "ambient"
|
||||
}
|
||||
return "unknown"
|
||||
}
|
||||
|
||||
const (
|
||||
EFFECTIVE CapType = 1 << iota
|
||||
PERMITTED
|
||||
INHERITABLE
|
||||
BOUNDING
|
||||
AMBIENT
|
||||
|
||||
CAPS = EFFECTIVE | PERMITTED | INHERITABLE
|
||||
BOUNDS = BOUNDING
|
||||
AMBS = AMBIENT
|
||||
)
|
||||
|
||||
//go:generate go run enumgen/gen.go
|
||||
type Cap int
|
||||
|
||||
// POSIX-draft defined capabilities and Linux extensions.
|
||||
//
|
||||
// Defined in https://github.com/torvalds/linux/blob/master/include/uapi/linux/capability.h
|
||||
const (
|
||||
// In a system with the [_POSIX_CHOWN_RESTRICTED] option defined, this
|
||||
// overrides the restriction of changing file ownership and group
|
||||
// ownership.
|
||||
CAP_CHOWN = Cap(0)
|
||||
|
||||
// Override all DAC access, including ACL execute access if
|
||||
// [_POSIX_ACL] is defined. Excluding DAC access covered by
|
||||
// CAP_LINUX_IMMUTABLE.
|
||||
CAP_DAC_OVERRIDE = Cap(1)
|
||||
|
||||
// Overrides all DAC restrictions regarding read and search on files
|
||||
// and directories, including ACL restrictions if [_POSIX_ACL] is
|
||||
// defined. Excluding DAC access covered by CAP_LINUX_IMMUTABLE.
|
||||
CAP_DAC_READ_SEARCH = Cap(2)
|
||||
|
||||
// Overrides all restrictions about allowed operations on files, where
|
||||
// file owner ID must be equal to the user ID, except where CAP_FSETID
|
||||
// is applicable. It doesn't override MAC and DAC restrictions.
|
||||
CAP_FOWNER = Cap(3)
|
||||
|
||||
// Overrides the following restrictions that the effective user ID
|
||||
// shall match the file owner ID when setting the S_ISUID and S_ISGID
|
||||
// bits on that file; that the effective group ID (or one of the
|
||||
// supplementary group IDs) shall match the file owner ID when setting
|
||||
// the S_ISGID bit on that file; that the S_ISUID and S_ISGID bits are
|
||||
// cleared on successful return from chown(2) (not implemented).
|
||||
CAP_FSETID = Cap(4)
|
||||
|
||||
// Overrides the restriction that the real or effective user ID of a
|
||||
// process sending a signal must match the real or effective user ID
|
||||
// of the process receiving the signal.
|
||||
CAP_KILL = Cap(5)
|
||||
|
||||
// Allows setgid(2) manipulation
|
||||
// Allows setgroups(2)
|
||||
// Allows forged gids on socket credentials passing.
|
||||
CAP_SETGID = Cap(6)
|
||||
|
||||
// Allows set*uid(2) manipulation (including fsuid).
|
||||
// Allows forged pids on socket credentials passing.
|
||||
CAP_SETUID = Cap(7)
|
||||
|
||||
// Linux-specific capabilities
|
||||
|
||||
// Without VFS support for capabilities:
|
||||
// Transfer any capability in your permitted set to any pid,
|
||||
// remove any capability in your permitted set from any pid
|
||||
// With VFS support for capabilities (neither of above, but)
|
||||
// Add any capability from current's capability bounding set
|
||||
// to the current process' inheritable set
|
||||
// Allow taking bits out of capability bounding set
|
||||
// Allow modification of the securebits for a process
|
||||
CAP_SETPCAP = Cap(8)
|
||||
|
||||
// Allow modification of S_IMMUTABLE and S_APPEND file attributes
|
||||
CAP_LINUX_IMMUTABLE = Cap(9)
|
||||
|
||||
// Allows binding to TCP/UDP sockets below 1024
|
||||
// Allows binding to ATM VCIs below 32
|
||||
CAP_NET_BIND_SERVICE = Cap(10)
|
||||
|
||||
// Allow broadcasting, listen to multicast
|
||||
CAP_NET_BROADCAST = Cap(11)
|
||||
|
||||
// Allow interface configuration
|
||||
// Allow administration of IP firewall, masquerading and accounting
|
||||
// Allow setting debug option on sockets
|
||||
// Allow modification of routing tables
|
||||
// Allow setting arbitrary process / process group ownership on
|
||||
// sockets
|
||||
// Allow binding to any address for transparent proxying (also via NET_RAW)
|
||||
// Allow setting TOS (type of service)
|
||||
// Allow setting promiscuous mode
|
||||
// Allow clearing driver statistics
|
||||
// Allow multicasting
|
||||
// Allow read/write of device-specific registers
|
||||
// Allow activation of ATM control sockets
|
||||
CAP_NET_ADMIN = Cap(12)
|
||||
|
||||
// Allow use of RAW sockets
|
||||
// Allow use of PACKET sockets
|
||||
// Allow binding to any address for transparent proxying (also via NET_ADMIN)
|
||||
CAP_NET_RAW = Cap(13)
|
||||
|
||||
// Allow locking of shared memory segments
|
||||
// Allow mlock and mlockall (which doesn't really have anything to do
|
||||
// with IPC)
|
||||
CAP_IPC_LOCK = Cap(14)
|
||||
|
||||
// Override IPC ownership checks
|
||||
CAP_IPC_OWNER = Cap(15)
|
||||
|
||||
// Insert and remove kernel modules - modify kernel without limit
|
||||
CAP_SYS_MODULE = Cap(16)
|
||||
|
||||
// Allow ioperm/iopl access
|
||||
// Allow sending USB messages to any device via /proc/bus/usb
|
||||
CAP_SYS_RAWIO = Cap(17)
|
||||
|
||||
// Allow use of chroot()
|
||||
CAP_SYS_CHROOT = Cap(18)
|
||||
|
||||
// Allow ptrace() of any process
|
||||
CAP_SYS_PTRACE = Cap(19)
|
||||
|
||||
// Allow configuration of process accounting
|
||||
CAP_SYS_PACCT = Cap(20)
|
||||
|
||||
// Allow configuration of the secure attention key
|
||||
// Allow administration of the random device
|
||||
// Allow examination and configuration of disk quotas
|
||||
// Allow setting the domainname
|
||||
// Allow setting the hostname
|
||||
// Allow calling bdflush()
|
||||
// Allow mount() and umount(), setting up new smb connection
|
||||
// Allow some autofs root ioctls
|
||||
// Allow nfsservctl
|
||||
// Allow VM86_REQUEST_IRQ
|
||||
// Allow to read/write pci config on alpha
|
||||
// Allow irix_prctl on mips (setstacksize)
|
||||
// Allow flushing all cache on m68k (sys_cacheflush)
|
||||
// Allow removing semaphores
|
||||
// Used instead of CAP_CHOWN to "chown" IPC message queues, semaphores
|
||||
// and shared memory
|
||||
// Allow locking/unlocking of shared memory segment
|
||||
// Allow turning swap on/off
|
||||
// Allow forged pids on socket credentials passing
|
||||
// Allow setting readahead and flushing buffers on block devices
|
||||
// Allow setting geometry in floppy driver
|
||||
// Allow turning DMA on/off in xd driver
|
||||
// Allow administration of md devices (mostly the above, but some
|
||||
// extra ioctls)
|
||||
// Allow tuning the ide driver
|
||||
// Allow access to the nvram device
|
||||
// Allow administration of apm_bios, serial and bttv (TV) device
|
||||
// Allow manufacturer commands in isdn CAPI support driver
|
||||
// Allow reading non-standardized portions of pci configuration space
|
||||
// Allow DDI debug ioctl on sbpcd driver
|
||||
// Allow setting up serial ports
|
||||
// Allow sending raw qic-117 commands
|
||||
// Allow enabling/disabling tagged queuing on SCSI controllers and sending
|
||||
// arbitrary SCSI commands
|
||||
// Allow setting encryption key on loopback filesystem
|
||||
// Allow setting zone reclaim policy
|
||||
// Allow everything under CAP_BPF and CAP_PERFMON for backward compatibility
|
||||
CAP_SYS_ADMIN = Cap(21)
|
||||
|
||||
// Allow use of reboot()
|
||||
CAP_SYS_BOOT = Cap(22)
|
||||
|
||||
// Allow raising priority and setting priority on other (different
|
||||
// UID) processes
|
||||
// Allow use of FIFO and round-robin (realtime) scheduling on own
|
||||
// processes and setting the scheduling algorithm used by another
|
||||
// process.
|
||||
// Allow setting cpu affinity on other processes
|
||||
CAP_SYS_NICE = Cap(23)
|
||||
|
||||
// Override resource limits. Set resource limits.
|
||||
// Override quota limits.
|
||||
// Override reserved space on ext2 filesystem
|
||||
// Modify data journaling mode on ext3 filesystem (uses journaling
|
||||
// resources)
|
||||
// NOTE: ext2 honors fsuid when checking for resource overrides, so
|
||||
// you can override using fsuid too
|
||||
// Override size restrictions on IPC message queues
|
||||
// Allow more than 64hz interrupts from the real-time clock
|
||||
// Override max number of consoles on console allocation
|
||||
// Override max number of keymaps
|
||||
// Control memory reclaim behavior
|
||||
CAP_SYS_RESOURCE = Cap(24)
|
||||
|
||||
// Allow manipulation of system clock
|
||||
// Allow irix_stime on mips
|
||||
// Allow setting the real-time clock
|
||||
CAP_SYS_TIME = Cap(25)
|
||||
|
||||
// Allow configuration of tty devices
|
||||
// Allow vhangup() of tty
|
||||
CAP_SYS_TTY_CONFIG = Cap(26)
|
||||
|
||||
// Allow the privileged aspects of mknod()
|
||||
CAP_MKNOD = Cap(27)
|
||||
|
||||
// Allow taking of leases on files
|
||||
CAP_LEASE = Cap(28)
|
||||
|
||||
CAP_AUDIT_WRITE = Cap(29)
|
||||
CAP_AUDIT_CONTROL = Cap(30)
|
||||
CAP_SETFCAP = Cap(31)
|
||||
|
||||
// Override MAC access.
|
||||
// The base kernel enforces no MAC policy.
|
||||
// An LSM may enforce a MAC policy, and if it does and it chooses
|
||||
// to implement capability based overrides of that policy, this is
|
||||
// the capability it should use to do so.
|
||||
CAP_MAC_OVERRIDE = Cap(32)
|
||||
|
||||
// Allow MAC configuration or state changes.
|
||||
// The base kernel requires no MAC configuration.
|
||||
// An LSM may enforce a MAC policy, and if it does and it chooses
|
||||
// to implement capability based checks on modifications to that
|
||||
// policy or the data required to maintain it, this is the
|
||||
// capability it should use to do so.
|
||||
CAP_MAC_ADMIN = Cap(33)
|
||||
|
||||
// Allow configuring the kernel's syslog (printk behaviour)
|
||||
CAP_SYSLOG = Cap(34)
|
||||
|
||||
// Allow triggering something that will wake the system
|
||||
CAP_WAKE_ALARM = Cap(35)
|
||||
|
||||
// Allow preventing system suspends
|
||||
CAP_BLOCK_SUSPEND = Cap(36)
|
||||
|
||||
// Allow reading the audit log via multicast netlink socket
|
||||
CAP_AUDIT_READ = Cap(37)
|
||||
|
||||
// Allow system performance and observability privileged operations
|
||||
// using perf_events, i915_perf and other kernel subsystems
|
||||
CAP_PERFMON = Cap(38)
|
||||
|
||||
// CAP_BPF allows the following BPF operations:
|
||||
// - Creating all types of BPF maps
|
||||
// - Advanced verifier features
|
||||
// - Indirect variable access
|
||||
// - Bounded loops
|
||||
// - BPF to BPF function calls
|
||||
// - Scalar precision tracking
|
||||
// - Larger complexity limits
|
||||
// - Dead code elimination
|
||||
// - And potentially other features
|
||||
// - Loading BPF Type Format (BTF) data
|
||||
// - Retrieve xlated and JITed code of BPF programs
|
||||
// - Use bpf_spin_lock() helper
|
||||
//
|
||||
// CAP_PERFMON relaxes the verifier checks further:
|
||||
// - BPF progs can use of pointer-to-integer conversions
|
||||
// - speculation attack hardening measures are bypassed
|
||||
// - bpf_probe_read to read arbitrary kernel memory is allowed
|
||||
// - bpf_trace_printk to print kernel memory is allowed
|
||||
//
|
||||
// CAP_SYS_ADMIN is required to use bpf_probe_write_user.
|
||||
//
|
||||
// CAP_SYS_ADMIN is required to iterate system wide loaded
|
||||
// programs, maps, links, BTFs and convert their IDs to file descriptors.
|
||||
//
|
||||
// CAP_PERFMON and CAP_BPF are required to load tracing programs.
|
||||
// CAP_NET_ADMIN and CAP_BPF are required to load networking programs.
|
||||
CAP_BPF = Cap(39)
|
||||
|
||||
// Allow checkpoint/restore related operations.
|
||||
// Introduced in kernel 5.9
|
||||
CAP_CHECKPOINT_RESTORE = Cap(40)
|
||||
)
|
||||
|
||||
var (
|
||||
// Highest valid capability of the running kernel.
|
||||
CAP_LAST_CAP = Cap(63)
|
||||
|
||||
capUpperMask = ^uint32(0)
|
||||
)
|
||||
138
vendor/github.com/syndtr/gocapability/capability/enum_gen.go
generated
vendored
138
vendor/github.com/syndtr/gocapability/capability/enum_gen.go
generated
vendored
@@ -1,138 +0,0 @@
|
||||
// generated file; DO NOT EDIT - use go generate in directory with source
|
||||
|
||||
package capability
|
||||
|
||||
func (c Cap) String() string {
|
||||
switch c {
|
||||
case CAP_CHOWN:
|
||||
return "chown"
|
||||
case CAP_DAC_OVERRIDE:
|
||||
return "dac_override"
|
||||
case CAP_DAC_READ_SEARCH:
|
||||
return "dac_read_search"
|
||||
case CAP_FOWNER:
|
||||
return "fowner"
|
||||
case CAP_FSETID:
|
||||
return "fsetid"
|
||||
case CAP_KILL:
|
||||
return "kill"
|
||||
case CAP_SETGID:
|
||||
return "setgid"
|
||||
case CAP_SETUID:
|
||||
return "setuid"
|
||||
case CAP_SETPCAP:
|
||||
return "setpcap"
|
||||
case CAP_LINUX_IMMUTABLE:
|
||||
return "linux_immutable"
|
||||
case CAP_NET_BIND_SERVICE:
|
||||
return "net_bind_service"
|
||||
case CAP_NET_BROADCAST:
|
||||
return "net_broadcast"
|
||||
case CAP_NET_ADMIN:
|
||||
return "net_admin"
|
||||
case CAP_NET_RAW:
|
||||
return "net_raw"
|
||||
case CAP_IPC_LOCK:
|
||||
return "ipc_lock"
|
||||
case CAP_IPC_OWNER:
|
||||
return "ipc_owner"
|
||||
case CAP_SYS_MODULE:
|
||||
return "sys_module"
|
||||
case CAP_SYS_RAWIO:
|
||||
return "sys_rawio"
|
||||
case CAP_SYS_CHROOT:
|
||||
return "sys_chroot"
|
||||
case CAP_SYS_PTRACE:
|
||||
return "sys_ptrace"
|
||||
case CAP_SYS_PACCT:
|
||||
return "sys_pacct"
|
||||
case CAP_SYS_ADMIN:
|
||||
return "sys_admin"
|
||||
case CAP_SYS_BOOT:
|
||||
return "sys_boot"
|
||||
case CAP_SYS_NICE:
|
||||
return "sys_nice"
|
||||
case CAP_SYS_RESOURCE:
|
||||
return "sys_resource"
|
||||
case CAP_SYS_TIME:
|
||||
return "sys_time"
|
||||
case CAP_SYS_TTY_CONFIG:
|
||||
return "sys_tty_config"
|
||||
case CAP_MKNOD:
|
||||
return "mknod"
|
||||
case CAP_LEASE:
|
||||
return "lease"
|
||||
case CAP_AUDIT_WRITE:
|
||||
return "audit_write"
|
||||
case CAP_AUDIT_CONTROL:
|
||||
return "audit_control"
|
||||
case CAP_SETFCAP:
|
||||
return "setfcap"
|
||||
case CAP_MAC_OVERRIDE:
|
||||
return "mac_override"
|
||||
case CAP_MAC_ADMIN:
|
||||
return "mac_admin"
|
||||
case CAP_SYSLOG:
|
||||
return "syslog"
|
||||
case CAP_WAKE_ALARM:
|
||||
return "wake_alarm"
|
||||
case CAP_BLOCK_SUSPEND:
|
||||
return "block_suspend"
|
||||
case CAP_AUDIT_READ:
|
||||
return "audit_read"
|
||||
case CAP_PERFMON:
|
||||
return "perfmon"
|
||||
case CAP_BPF:
|
||||
return "bpf"
|
||||
case CAP_CHECKPOINT_RESTORE:
|
||||
return "checkpoint_restore"
|
||||
}
|
||||
return "unknown"
|
||||
}
|
||||
|
||||
// List returns list of all supported capabilities
|
||||
func List() []Cap {
|
||||
return []Cap{
|
||||
CAP_CHOWN,
|
||||
CAP_DAC_OVERRIDE,
|
||||
CAP_DAC_READ_SEARCH,
|
||||
CAP_FOWNER,
|
||||
CAP_FSETID,
|
||||
CAP_KILL,
|
||||
CAP_SETGID,
|
||||
CAP_SETUID,
|
||||
CAP_SETPCAP,
|
||||
CAP_LINUX_IMMUTABLE,
|
||||
CAP_NET_BIND_SERVICE,
|
||||
CAP_NET_BROADCAST,
|
||||
CAP_NET_ADMIN,
|
||||
CAP_NET_RAW,
|
||||
CAP_IPC_LOCK,
|
||||
CAP_IPC_OWNER,
|
||||
CAP_SYS_MODULE,
|
||||
CAP_SYS_RAWIO,
|
||||
CAP_SYS_CHROOT,
|
||||
CAP_SYS_PTRACE,
|
||||
CAP_SYS_PACCT,
|
||||
CAP_SYS_ADMIN,
|
||||
CAP_SYS_BOOT,
|
||||
CAP_SYS_NICE,
|
||||
CAP_SYS_RESOURCE,
|
||||
CAP_SYS_TIME,
|
||||
CAP_SYS_TTY_CONFIG,
|
||||
CAP_MKNOD,
|
||||
CAP_LEASE,
|
||||
CAP_AUDIT_WRITE,
|
||||
CAP_AUDIT_CONTROL,
|
||||
CAP_SETFCAP,
|
||||
CAP_MAC_OVERRIDE,
|
||||
CAP_MAC_ADMIN,
|
||||
CAP_SYSLOG,
|
||||
CAP_WAKE_ALARM,
|
||||
CAP_BLOCK_SUSPEND,
|
||||
CAP_AUDIT_READ,
|
||||
CAP_PERFMON,
|
||||
CAP_BPF,
|
||||
CAP_CHECKPOINT_RESTORE,
|
||||
}
|
||||
}
|
||||
154
vendor/github.com/syndtr/gocapability/capability/syscall_linux.go
generated
vendored
154
vendor/github.com/syndtr/gocapability/capability/syscall_linux.go
generated
vendored
@@ -1,154 +0,0 @@
|
||||
// Copyright (c) 2013, Suryandaru Triandana <syndtr@gmail.com>
|
||||
// All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
package capability
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
type capHeader struct {
|
||||
version uint32
|
||||
pid int32
|
||||
}
|
||||
|
||||
type capData struct {
|
||||
effective uint32
|
||||
permitted uint32
|
||||
inheritable uint32
|
||||
}
|
||||
|
||||
func capget(hdr *capHeader, data *capData) (err error) {
|
||||
_, _, e1 := syscall.Syscall(syscall.SYS_CAPGET, uintptr(unsafe.Pointer(hdr)), uintptr(unsafe.Pointer(data)), 0)
|
||||
if e1 != 0 {
|
||||
err = e1
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func capset(hdr *capHeader, data *capData) (err error) {
|
||||
_, _, e1 := syscall.Syscall(syscall.SYS_CAPSET, uintptr(unsafe.Pointer(hdr)), uintptr(unsafe.Pointer(data)), 0)
|
||||
if e1 != 0 {
|
||||
err = e1
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// not yet in syscall
|
||||
const (
|
||||
pr_CAP_AMBIENT = 47
|
||||
pr_CAP_AMBIENT_IS_SET = uintptr(1)
|
||||
pr_CAP_AMBIENT_RAISE = uintptr(2)
|
||||
pr_CAP_AMBIENT_LOWER = uintptr(3)
|
||||
pr_CAP_AMBIENT_CLEAR_ALL = uintptr(4)
|
||||
)
|
||||
|
||||
func prctl(option int, arg2, arg3, arg4, arg5 uintptr) (err error) {
|
||||
_, _, e1 := syscall.Syscall6(syscall.SYS_PRCTL, uintptr(option), arg2, arg3, arg4, arg5, 0)
|
||||
if e1 != 0 {
|
||||
err = e1
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
const (
|
||||
vfsXattrName = "security.capability"
|
||||
|
||||
vfsCapVerMask = 0xff000000
|
||||
vfsCapVer1 = 0x01000000
|
||||
vfsCapVer2 = 0x02000000
|
||||
|
||||
vfsCapFlagMask = ^vfsCapVerMask
|
||||
vfsCapFlageffective = 0x000001
|
||||
|
||||
vfscapDataSizeV1 = 4 * (1 + 2*1)
|
||||
vfscapDataSizeV2 = 4 * (1 + 2*2)
|
||||
)
|
||||
|
||||
type vfscapData struct {
|
||||
magic uint32
|
||||
data [2]struct {
|
||||
permitted uint32
|
||||
inheritable uint32
|
||||
}
|
||||
effective [2]uint32
|
||||
version int8
|
||||
}
|
||||
|
||||
var (
|
||||
_vfsXattrName *byte
|
||||
)
|
||||
|
||||
func init() {
|
||||
_vfsXattrName, _ = syscall.BytePtrFromString(vfsXattrName)
|
||||
}
|
||||
|
||||
func getVfsCap(path string, dest *vfscapData) (err error) {
|
||||
var _p0 *byte
|
||||
_p0, err = syscall.BytePtrFromString(path)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
r0, _, e1 := syscall.Syscall6(syscall.SYS_GETXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_vfsXattrName)), uintptr(unsafe.Pointer(dest)), vfscapDataSizeV2, 0, 0)
|
||||
if e1 != 0 {
|
||||
if e1 == syscall.ENODATA {
|
||||
dest.version = 2
|
||||
return
|
||||
}
|
||||
err = e1
|
||||
}
|
||||
switch dest.magic & vfsCapVerMask {
|
||||
case vfsCapVer1:
|
||||
dest.version = 1
|
||||
if r0 != vfscapDataSizeV1 {
|
||||
return syscall.EINVAL
|
||||
}
|
||||
dest.data[1].permitted = 0
|
||||
dest.data[1].inheritable = 0
|
||||
case vfsCapVer2:
|
||||
dest.version = 2
|
||||
if r0 != vfscapDataSizeV2 {
|
||||
return syscall.EINVAL
|
||||
}
|
||||
default:
|
||||
return syscall.EINVAL
|
||||
}
|
||||
if dest.magic&vfsCapFlageffective != 0 {
|
||||
dest.effective[0] = dest.data[0].permitted | dest.data[0].inheritable
|
||||
dest.effective[1] = dest.data[1].permitted | dest.data[1].inheritable
|
||||
} else {
|
||||
dest.effective[0] = 0
|
||||
dest.effective[1] = 0
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func setVfsCap(path string, data *vfscapData) (err error) {
|
||||
var _p0 *byte
|
||||
_p0, err = syscall.BytePtrFromString(path)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
var size uintptr
|
||||
if data.version == 1 {
|
||||
data.magic = vfsCapVer1
|
||||
size = vfscapDataSizeV1
|
||||
} else if data.version == 2 {
|
||||
data.magic = vfsCapVer2
|
||||
if data.effective[0] != 0 || data.effective[1] != 0 {
|
||||
data.magic |= vfsCapFlageffective
|
||||
}
|
||||
size = vfscapDataSizeV2
|
||||
} else {
|
||||
return syscall.EINVAL
|
||||
}
|
||||
_, _, e1 := syscall.Syscall6(syscall.SYS_SETXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_vfsXattrName)), uintptr(unsafe.Pointer(data)), size, 0, 0)
|
||||
if e1 != 0 {
|
||||
err = e1
|
||||
}
|
||||
return
|
||||
}
|
||||
41
vendor/golang.org/x/net/bpf/asm.go
generated
vendored
41
vendor/golang.org/x/net/bpf/asm.go
generated
vendored
@@ -1,41 +0,0 @@
|
||||
// Copyright 2016 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package bpf
|
||||
|
||||
import "fmt"
|
||||
|
||||
// Assemble converts insts into raw instructions suitable for loading
|
||||
// into a BPF virtual machine.
|
||||
//
|
||||
// Currently, no optimization is attempted, the assembled program flow
|
||||
// is exactly as provided.
|
||||
func Assemble(insts []Instruction) ([]RawInstruction, error) {
|
||||
ret := make([]RawInstruction, len(insts))
|
||||
var err error
|
||||
for i, inst := range insts {
|
||||
ret[i], err = inst.Assemble()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("assembling instruction %d: %s", i+1, err)
|
||||
}
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
// Disassemble attempts to parse raw back into
|
||||
// Instructions. Unrecognized RawInstructions are assumed to be an
|
||||
// extension not implemented by this package, and are passed through
|
||||
// unchanged to the output. The allDecoded value reports whether insts
|
||||
// contains no RawInstructions.
|
||||
func Disassemble(raw []RawInstruction) (insts []Instruction, allDecoded bool) {
|
||||
insts = make([]Instruction, len(raw))
|
||||
allDecoded = true
|
||||
for i, r := range raw {
|
||||
insts[i] = r.Disassemble()
|
||||
if _, ok := insts[i].(RawInstruction); ok {
|
||||
allDecoded = false
|
||||
}
|
||||
}
|
||||
return insts, allDecoded
|
||||
}
|
||||
222
vendor/golang.org/x/net/bpf/constants.go
generated
vendored
222
vendor/golang.org/x/net/bpf/constants.go
generated
vendored
@@ -1,222 +0,0 @@
|
||||
// Copyright 2016 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package bpf
|
||||
|
||||
// A Register is a register of the BPF virtual machine.
|
||||
type Register uint16
|
||||
|
||||
const (
|
||||
// RegA is the accumulator register. RegA is always the
|
||||
// destination register of ALU operations.
|
||||
RegA Register = iota
|
||||
// RegX is the indirection register, used by LoadIndirect
|
||||
// operations.
|
||||
RegX
|
||||
)
|
||||
|
||||
// An ALUOp is an arithmetic or logic operation.
|
||||
type ALUOp uint16
|
||||
|
||||
// ALU binary operation types.
|
||||
const (
|
||||
ALUOpAdd ALUOp = iota << 4
|
||||
ALUOpSub
|
||||
ALUOpMul
|
||||
ALUOpDiv
|
||||
ALUOpOr
|
||||
ALUOpAnd
|
||||
ALUOpShiftLeft
|
||||
ALUOpShiftRight
|
||||
aluOpNeg // Not exported because it's the only unary ALU operation, and gets its own instruction type.
|
||||
ALUOpMod
|
||||
ALUOpXor
|
||||
)
|
||||
|
||||
// A JumpTest is a comparison operator used in conditional jumps.
|
||||
type JumpTest uint16
|
||||
|
||||
// Supported operators for conditional jumps.
|
||||
// K can be RegX for JumpIfX
|
||||
const (
|
||||
// K == A
|
||||
JumpEqual JumpTest = iota
|
||||
// K != A
|
||||
JumpNotEqual
|
||||
// K > A
|
||||
JumpGreaterThan
|
||||
// K < A
|
||||
JumpLessThan
|
||||
// K >= A
|
||||
JumpGreaterOrEqual
|
||||
// K <= A
|
||||
JumpLessOrEqual
|
||||
// K & A != 0
|
||||
JumpBitsSet
|
||||
// K & A == 0
|
||||
JumpBitsNotSet
|
||||
)
|
||||
|
||||
// An Extension is a function call provided by the kernel that
|
||||
// performs advanced operations that are expensive or impossible
|
||||
// within the BPF virtual machine.
|
||||
//
|
||||
// Extensions are only implemented by the Linux kernel.
|
||||
//
|
||||
// TODO: should we prune this list? Some of these extensions seem
|
||||
// either broken or near-impossible to use correctly, whereas other
|
||||
// (len, random, ifindex) are quite useful.
|
||||
type Extension int
|
||||
|
||||
// Extension functions available in the Linux kernel.
|
||||
const (
|
||||
// extOffset is the negative maximum number of instructions used
|
||||
// to load instructions by overloading the K argument.
|
||||
extOffset = -0x1000
|
||||
// ExtLen returns the length of the packet.
|
||||
ExtLen Extension = 1
|
||||
// ExtProto returns the packet's L3 protocol type.
|
||||
ExtProto Extension = 0
|
||||
// ExtType returns the packet's type (skb->pkt_type in the kernel)
|
||||
//
|
||||
// TODO: better documentation. How nice an API do we want to
|
||||
// provide for these esoteric extensions?
|
||||
ExtType Extension = 4
|
||||
// ExtPayloadOffset returns the offset of the packet payload, or
|
||||
// the first protocol header that the kernel does not know how to
|
||||
// parse.
|
||||
ExtPayloadOffset Extension = 52
|
||||
// ExtInterfaceIndex returns the index of the interface on which
|
||||
// the packet was received.
|
||||
ExtInterfaceIndex Extension = 8
|
||||
// ExtNetlinkAttr returns the netlink attribute of type X at
|
||||
// offset A.
|
||||
ExtNetlinkAttr Extension = 12
|
||||
// ExtNetlinkAttrNested returns the nested netlink attribute of
|
||||
// type X at offset A.
|
||||
ExtNetlinkAttrNested Extension = 16
|
||||
// ExtMark returns the packet's mark value.
|
||||
ExtMark Extension = 20
|
||||
// ExtQueue returns the packet's assigned hardware queue.
|
||||
ExtQueue Extension = 24
|
||||
// ExtLinkLayerType returns the packet's hardware address type
|
||||
// (e.g. Ethernet, Infiniband).
|
||||
ExtLinkLayerType Extension = 28
|
||||
// ExtRXHash returns the packets receive hash.
|
||||
//
|
||||
// TODO: figure out what this rxhash actually is.
|
||||
ExtRXHash Extension = 32
|
||||
// ExtCPUID returns the ID of the CPU processing the current
|
||||
// packet.
|
||||
ExtCPUID Extension = 36
|
||||
// ExtVLANTag returns the packet's VLAN tag.
|
||||
ExtVLANTag Extension = 44
|
||||
// ExtVLANTagPresent returns non-zero if the packet has a VLAN
|
||||
// tag.
|
||||
//
|
||||
// TODO: I think this might be a lie: it reads bit 0x1000 of the
|
||||
// VLAN header, which changed meaning in recent revisions of the
|
||||
// spec - this extension may now return meaningless information.
|
||||
ExtVLANTagPresent Extension = 48
|
||||
// ExtVLANProto returns 0x8100 if the frame has a VLAN header,
|
||||
// 0x88a8 if the frame has a "Q-in-Q" double VLAN header, or some
|
||||
// other value if no VLAN information is present.
|
||||
ExtVLANProto Extension = 60
|
||||
// ExtRand returns a uniformly random uint32.
|
||||
ExtRand Extension = 56
|
||||
)
|
||||
|
||||
// The following gives names to various bit patterns used in opcode construction.
|
||||
|
||||
const (
|
||||
opMaskCls uint16 = 0x7
|
||||
// opClsLoad masks
|
||||
opMaskLoadDest = 0x01
|
||||
opMaskLoadWidth = 0x18
|
||||
opMaskLoadMode = 0xe0
|
||||
// opClsALU & opClsJump
|
||||
opMaskOperand = 0x08
|
||||
opMaskOperator = 0xf0
|
||||
)
|
||||
|
||||
const (
|
||||
// +---------------+-----------------+---+---+---+
|
||||
// | AddrMode (3b) | LoadWidth (2b) | 0 | 0 | 0 |
|
||||
// +---------------+-----------------+---+---+---+
|
||||
opClsLoadA uint16 = iota
|
||||
// +---------------+-----------------+---+---+---+
|
||||
// | AddrMode (3b) | LoadWidth (2b) | 0 | 0 | 1 |
|
||||
// +---------------+-----------------+---+---+---+
|
||||
opClsLoadX
|
||||
// +---+---+---+---+---+---+---+---+
|
||||
// | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 |
|
||||
// +---+---+---+---+---+---+---+---+
|
||||
opClsStoreA
|
||||
// +---+---+---+---+---+---+---+---+
|
||||
// | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 |
|
||||
// +---+---+---+---+---+---+---+---+
|
||||
opClsStoreX
|
||||
// +---------------+-----------------+---+---+---+
|
||||
// | Operator (4b) | OperandSrc (1b) | 1 | 0 | 0 |
|
||||
// +---------------+-----------------+---+---+---+
|
||||
opClsALU
|
||||
// +-----------------------------+---+---+---+---+
|
||||
// | TestOperator (4b) | 0 | 1 | 0 | 1 |
|
||||
// +-----------------------------+---+---+---+---+
|
||||
opClsJump
|
||||
// +---+-------------------------+---+---+---+---+
|
||||
// | 0 | 0 | 0 | RetSrc (1b) | 0 | 1 | 1 | 0 |
|
||||
// +---+-------------------------+---+---+---+---+
|
||||
opClsReturn
|
||||
// +---+-------------------------+---+---+---+---+
|
||||
// | 0 | 0 | 0 | TXAorTAX (1b) | 0 | 1 | 1 | 1 |
|
||||
// +---+-------------------------+---+---+---+---+
|
||||
opClsMisc
|
||||
)
|
||||
|
||||
const (
|
||||
opAddrModeImmediate uint16 = iota << 5
|
||||
opAddrModeAbsolute
|
||||
opAddrModeIndirect
|
||||
opAddrModeScratch
|
||||
opAddrModePacketLen // actually an extension, not an addressing mode.
|
||||
opAddrModeMemShift
|
||||
)
|
||||
|
||||
const (
|
||||
opLoadWidth4 uint16 = iota << 3
|
||||
opLoadWidth2
|
||||
opLoadWidth1
|
||||
)
|
||||
|
||||
// Operand for ALU and Jump instructions
|
||||
type opOperand uint16
|
||||
|
||||
// Supported operand sources.
|
||||
const (
|
||||
opOperandConstant opOperand = iota << 3
|
||||
opOperandX
|
||||
)
|
||||
|
||||
// An jumpOp is a conditional jump condition.
|
||||
type jumpOp uint16
|
||||
|
||||
// Supported jump conditions.
|
||||
const (
|
||||
opJumpAlways jumpOp = iota << 4
|
||||
opJumpEqual
|
||||
opJumpGT
|
||||
opJumpGE
|
||||
opJumpSet
|
||||
)
|
||||
|
||||
const (
|
||||
opRetSrcConstant uint16 = iota << 4
|
||||
opRetSrcA
|
||||
)
|
||||
|
||||
const (
|
||||
opMiscTAX = 0x00
|
||||
opMiscTXA = 0x80
|
||||
)
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user