mirror of
				https://github.com/optim-enterprises-bv/kubernetes.git
				synced 2025-11-03 19:58:17 +00:00 
			
		
		
		
	Update to latest cadvisor
Signed-off-by: Davanum Srinivas <davanum@gmail.com>
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