diff --git a/go.mod b/go.mod index 39c70a5da85..76bcef96696 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,7 @@ require ( github.com/checkpoint-restore/go-criu/v6 v6.3.0 github.com/containerd/console v1.0.5 github.com/coreos/go-systemd/v22 v22.5.0 - github.com/cyphar/filepath-securejoin v0.6.0 + github.com/cyphar/filepath-securejoin v0.5.2 github.com/docker/go-units v0.5.0 github.com/godbus/dbus/v5 v5.1.0 github.com/moby/sys/capability v0.4.0 @@ -16,7 +16,7 @@ require ( github.com/mrunalp/fileutils v0.5.1 github.com/opencontainers/cgroups v0.0.4 github.com/opencontainers/runtime-spec v1.2.1 - github.com/opencontainers/selinux v1.13.0 + github.com/opencontainers/selinux v1.13.1 github.com/seccomp/libseccomp-golang v0.10.0 github.com/sirupsen/logrus v1.9.3 github.com/urfave/cli v1.22.16 @@ -27,7 +27,6 @@ require ( ) require ( - cyphar.com/go-pathrs v0.2.1 // indirect github.com/cilium/ebpf v0.17.3 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.5 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect diff --git a/go.sum b/go.sum index a609122fdcc..fbed7aab6f1 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,3 @@ -cyphar.com/go-pathrs v0.2.1 h1:9nx1vOgwVvX1mNBWDu93+vaceedpbsDqo+XuBGL40b8= -cyphar.com/go-pathrs v0.2.1/go.mod h1:y8f1EMG7r+hCuFf/rXsKqMJrJAUoADZGNh5/vZPKcGc= github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= github.com/checkpoint-restore/go-criu/v6 v6.3.0 h1:mIdrSO2cPNWQY1truPg6uHLXyKHk3Z5Odx4wjKOASzA= github.com/checkpoint-restore/go-criu/v6 v6.3.0/go.mod h1:rrRTN/uSwY2X+BPRl/gkulo9gsKOSAeVp9/K2tv7xZI= @@ -12,8 +10,8 @@ github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSV github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/cpuguy83/go-md2man/v2 v2.0.5 h1:ZtcqGrnekaHpVLArFSe4HK5DoKx1T0rq2DwVB0alcyc= github.com/cpuguy83/go-md2man/v2 v2.0.5/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= -github.com/cyphar/filepath-securejoin v0.6.0 h1:BtGB77njd6SVO6VztOHfPxKitJvd/VPT+OFBFMOi1Is= -github.com/cyphar/filepath-securejoin v0.6.0/go.mod h1:A8hd4EnAeyujCJRrICiOWqjS1AX0a9kM5XL+NwKoYSc= +github.com/cyphar/filepath-securejoin v0.5.2 h1:w/T2bhKr4pgwG0SUGjU4S/Is9+zUknLh5ROTJLzWX8E= +github.com/cyphar/filepath-securejoin v0.5.2/go.mod h1:Sdj7gXlvMcPZsbhwhQ33GguGLDGQL7h7bg04C/+u9jI= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -55,8 +53,8 @@ github.com/opencontainers/cgroups v0.0.4 h1:XVj8P/IHVms/j+7eh8ggdkTLAxjz84ZzuFyG github.com/opencontainers/cgroups v0.0.4/go.mod h1:s8lktyhlGUqM7OSRL5P7eAW6Wb+kWPNvt4qvVfzA5vs= github.com/opencontainers/runtime-spec v1.2.1 h1:S4k4ryNgEpxW1dzyqffOmhI1BHYcjzU8lpJfSlR0xww= github.com/opencontainers/runtime-spec v1.2.1/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= -github.com/opencontainers/selinux v1.13.0 h1:Zza88GWezyT7RLql12URvoxsbLfjFx988+LGaWfbL84= -github.com/opencontainers/selinux v1.13.0/go.mod h1:XxWTed+A/s5NNq4GmYScVy+9jzXhGBVEOAyucdRUY8s= +github.com/opencontainers/selinux v1.13.1 h1:A8nNeceYngH9Ow++M+VVEwJVpdFmrlxsN22F+ISDCJE= +github.com/opencontainers/selinux v1.13.1/go.mod h1:S10WXZ/osk2kWOYKy1x2f/eXF5ZHJoUs8UU/2caNRbg= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= @@ -77,9 +75,8 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= -github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= github.com/urfave/cli v1.22.16 h1:MH0k6uJxdwdeWQTwhSO42Pwr4YLrNLwBtg1MRgTqPdQ= github.com/urfave/cli v1.22.16/go.mod h1:EeJR6BKodywf4zciqrdw6hpCPk68JO9z5LazXZMn5Po= github.com/vishvananda/netlink v1.3.0 h1:X7l42GfcV4S6E4vHTsw48qbrV+9PVojNfIhZcwQdrZk= diff --git a/libcontainer/rootfs_linux.go b/libcontainer/rootfs_linux.go index 7476caa1620..31d0517484c 100644 --- a/libcontainer/rootfs_linux.go +++ b/libcontainer/rootfs_linux.go @@ -588,6 +588,12 @@ func (m *mountEntry) createOpenMountpoint(rootfs string) (Err error) { func mountToRootfs(c *mountConfig, m mountEntry) error { rootfs := c.root + defer func() { + if m.dstFile != nil { + _ = m.dstFile.Close() + m.dstFile = nil + } + }() // procfs and sysfs are special because we need to ensure they are actually // mounted on a specific path in a container without any funny business. @@ -628,12 +634,6 @@ func mountToRootfs(c *mountConfig, m mountEntry) error { if err := m.createOpenMountpoint(rootfs); err != nil { return fmt.Errorf("create mountpoint for %s mount: %w", m.Destination, err) } - defer func() { - if m.dstFile != nil { - _ = m.dstFile.Close() - m.dstFile = nil - } - }() switch m.Device { case "mqueue": @@ -998,6 +998,8 @@ func createDeviceNode(rootfs string, node *devices.Device, bind bool) error { if err != nil { return fmt.Errorf("mkdir parent of device inode %q: %w", node.Path, err) } + defer destDir.Close() + if bind { return bindMountDeviceNode(destDir, destName, node) } diff --git a/tests/integration/create.bats b/tests/integration/create.bats index f12291ca9d9..7c9110e7674 100644 --- a/tests/integration/create.bats +++ b/tests/integration/create.bats @@ -10,6 +10,70 @@ function teardown() { teardown_bundle } +# is_allowed_fdtarget checks whether the target of a file descriptor symlink +# conforms to the allowed whitelist. +# +# This whitelist reflects the set of file descriptors that runc legitimately +# opens during container lifecycle operations (e.g., exec, create, and run). +# If runc's internal behavior changes (e.g., new FD types are introduced), +# this function MUST be updated accordingly to avoid false positives. +# +is_allowed_fdtarget() { + local target="$1" + { + # pty devices for stdio + grep -Ex "/dev/pts/[0-9]+" <<<"$target" || + # eventfd, eventpoll, signalfd, etc. + grep -Ex "anon_inode:\[.+\]" <<<"$target" || + # procfs handle cache (pathrs-lite / libpathrs) + grep -Ex "/(proc)?" <<<"$target" || + # anonymous sockets used for IPC + grep -Ex "socket:\[[0-9]+\]" <<<"$target" || + # anonymous pipes used for I/O forwarding + grep -Ex "pipe:\[[0-9]+\]" <<<"$target" || + # "runc start" synchronisation barrier FIFO + grep -Ex ".*/exec\.fifo" <<<"$target" || + # temporary internal fd used in exec.fifo FIFO reopen (pathrs-lite / libpathrs) + grep -Ex "(/proc)?/1/task/1/fd" <<<"$target" || + # overlayfs binary reference (CVE-2019-5736) + grep -Ex "/runc" <<<"$target" || + # memfd cloned binary (CVE-2019-5736) + grep -Fx "/memfd:runc_cloned:/proc/self/exe (deleted)" <<<"$target" + } >/dev/null + return "$?" +} + +@test "runc create[detect fd leak as comprehensively as possible]" { + runc create --console-socket "$CONSOLE_SOCKET" test_busybox + [ "$status" -eq 0 ] + + testcontainer test_busybox created + + pid=$(__runc state test_busybox | jq '.pid') + violation_found=0 + + while IFS= read -rd '' link; do + fd_name=$(basename "$link") + # Skip . and .. + if [[ "$fd_name" == "." || "$fd_name" == ".." ]]; then + continue + fi + + # Resolve symlink target (use readlink) + target=$(readlink "$link" 2>/dev/null) + if [[ -z "$target" ]]; then + echo "Warning: Cannot read target of $link" + continue + fi + + if ! is_allowed_fdtarget "$target"; then + echo "Violation: FD $fd_name -> '$target'" + violation_found=1 + fi + done < <(find "/proc/$pid/fd" -type l -print0) + [ "$violation_found" -eq 0 ] +} + @test "runc create" { runc create --console-socket "$CONSOLE_SOCKET" test_busybox [ "$status" -eq 0 ] diff --git a/tests/integration/seccomp.bats b/tests/integration/seccomp.bats index 748dbd2bfca..db9571e0d67 100644 --- a/tests/integration/seccomp.bats +++ b/tests/integration/seccomp.bats @@ -185,3 +185,16 @@ function flags_value() { [[ "$output" == *"error running startContainer hook"* ]] [[ "$output" == *"bad system call"* ]] } + +@test "runc run [seccomp] (verify syscall compatibility after seccomp enforcement)" { + update_config ' .process.args = ["true"] + | .process.noNewPrivileges = false + | .linux.seccomp = { + "defaultAction":"SCMP_ACT_ALLOW", + "architectures":["SCMP_ARCH_X86","SCMP_ARCH_X32","SCMP_ARCH_X86_64","SCMP_ARCH_AARCH64","SCMP_ARCH_ARM"], + "syscalls":[{"names":["close_range", "fsopen", "fsconfig", "fspick", "openat2", "open_tree", "move_mount", "mount_setattr"], "action":"SCMP_ACT_ERRNO", "errnoRet": 38}] + }' + + runc run test_busybox + [ "$status" -eq 0 ] +} diff --git a/vendor/cyphar.com/go-pathrs/.golangci.yml b/vendor/cyphar.com/go-pathrs/.golangci.yml deleted file mode 100644 index 2778a3268ef..00000000000 --- a/vendor/cyphar.com/go-pathrs/.golangci.yml +++ /dev/null @@ -1,43 +0,0 @@ -# SPDX-License-Identifier: MPL-2.0 -# -# libpathrs: safe path resolution on Linux -# Copyright (C) 2019-2025 Aleksa Sarai -# Copyright (C) 2019-2025 SUSE LLC -# -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at https://mozilla.org/MPL/2.0/. - -version: "2" -linters: - enable: - - bidichk - - cyclop - - errname - - errorlint - - exhaustive - - goconst - - godot - - gomoddirectives - - gosec - - mirror - - misspell - - mnd - - nilerr - - nilnil - - perfsprint - - prealloc - - reassign - - revive - - unconvert - - unparam - - usestdlibvars - - wastedassign -formatters: - enable: - - gofumpt - - goimports - settings: - goimports: - local-prefixes: - - cyphar.com/go-pathrs diff --git a/vendor/cyphar.com/go-pathrs/COPYING b/vendor/cyphar.com/go-pathrs/COPYING deleted file mode 100644 index d0a1fa1482e..00000000000 --- a/vendor/cyphar.com/go-pathrs/COPYING +++ /dev/null @@ -1,373 +0,0 @@ -Mozilla Public License Version 2.0 -================================== - -1. Definitions --------------- - -1.1. "Contributor" - means each individual or legal entity that creates, contributes to - the creation of, or owns Covered Software. - -1.2. "Contributor Version" - means the combination of the Contributions of others (if any) used - by a Contributor and that particular Contributor's Contribution. - -1.3. "Contribution" - means Covered Software of a particular Contributor. - -1.4. "Covered Software" - means Source Code Form to which the initial Contributor has attached - the notice in Exhibit A, the Executable Form of such Source Code - Form, and Modifications of such Source Code Form, in each case - including portions thereof. - -1.5. "Incompatible With Secondary Licenses" - means - - (a) that the initial Contributor has attached the notice described - in Exhibit B to the Covered Software; or - - (b) that the Covered Software was made available under the terms of - version 1.1 or earlier of the License, but not also under the - terms of a Secondary License. - -1.6. "Executable Form" - means any form of the work other than Source Code Form. - -1.7. "Larger Work" - means a work that combines Covered Software with other material, in - a separate file or files, that is not Covered Software. - -1.8. "License" - means this document. - -1.9. "Licensable" - means having the right to grant, to the maximum extent possible, - whether at the time of the initial grant or subsequently, any and - all of the rights conveyed by this License. - -1.10. "Modifications" - means any of the following: - - (a) any file in Source Code Form that results from an addition to, - deletion from, or modification of the contents of Covered - Software; or - - (b) any new file in Source Code Form that contains any Covered - Software. - -1.11. "Patent Claims" of a Contributor - means any patent claim(s), including without limitation, method, - process, and apparatus claims, in any patent Licensable by such - Contributor that would be infringed, but for the grant of the - License, by the making, using, selling, offering for sale, having - made, import, or transfer of either its Contributions or its - Contributor Version. - -1.12. "Secondary License" - means either the GNU General Public License, Version 2.0, the GNU - Lesser General Public License, Version 2.1, the GNU Affero General - Public License, Version 3.0, or any later versions of those - licenses. - -1.13. "Source Code Form" - means the form of the work preferred for making modifications. - -1.14. "You" (or "Your") - means an individual or a legal entity exercising rights under this - License. For legal entities, "You" includes any entity that - controls, is controlled by, or is under common control with You. For - purposes of this definition, "control" means (a) the power, direct - or indirect, to cause the direction or management of such entity, - whether by contract or otherwise, or (b) ownership of more than - fifty percent (50%) of the outstanding shares or beneficial - ownership of such entity. - -2. License Grants and Conditions --------------------------------- - -2.1. Grants - -Each Contributor hereby grants You a world-wide, royalty-free, -non-exclusive license: - -(a) under intellectual property rights (other than patent or trademark) - Licensable by such Contributor to use, reproduce, make available, - modify, display, perform, distribute, and otherwise exploit its - Contributions, either on an unmodified basis, with Modifications, or - as part of a Larger Work; and - -(b) under Patent Claims of such Contributor to make, use, sell, offer - for sale, have made, import, and otherwise transfer either its - Contributions or its Contributor Version. - -2.2. Effective Date - -The licenses granted in Section 2.1 with respect to any Contribution -become effective for each Contribution on the date the Contributor first -distributes such Contribution. - -2.3. Limitations on Grant Scope - -The licenses granted in this Section 2 are the only rights granted under -this License. No additional rights or licenses will be implied from the -distribution or licensing of Covered Software under this License. -Notwithstanding Section 2.1(b) above, no patent license is granted by a -Contributor: - -(a) for any code that a Contributor has removed from Covered Software; - or - -(b) for infringements caused by: (i) Your and any other third party's - modifications of Covered Software, or (ii) the combination of its - Contributions with other software (except as part of its Contributor - Version); or - -(c) under Patent Claims infringed by Covered Software in the absence of - its Contributions. - -This License does not grant any rights in the trademarks, service marks, -or logos of any Contributor (except as may be necessary to comply with -the notice requirements in Section 3.4). - -2.4. Subsequent Licenses - -No Contributor makes additional grants as a result of Your choice to -distribute the Covered Software under a subsequent version of this -License (see Section 10.2) or under the terms of a Secondary License (if -permitted under the terms of Section 3.3). - -2.5. Representation - -Each Contributor represents that the Contributor believes its -Contributions are its original creation(s) or it has sufficient rights -to grant the rights to its Contributions conveyed by this License. - -2.6. Fair Use - -This License is not intended to limit any rights You have under -applicable copyright doctrines of fair use, fair dealing, or other -equivalents. - -2.7. Conditions - -Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted -in Section 2.1. - -3. Responsibilities -------------------- - -3.1. Distribution of Source Form - -All distribution of Covered Software in Source Code Form, including any -Modifications that You create or to which You contribute, must be under -the terms of this License. You must inform recipients that the Source -Code Form of the Covered Software is governed by the terms of this -License, and how they can obtain a copy of this License. You may not -attempt to alter or restrict the recipients' rights in the Source Code -Form. - -3.2. Distribution of Executable Form - -If You distribute Covered Software in Executable Form then: - -(a) such Covered Software must also be made available in Source Code - Form, as described in Section 3.1, and You must inform recipients of - the Executable Form how they can obtain a copy of such Source Code - Form by reasonable means in a timely manner, at a charge no more - than the cost of distribution to the recipient; and - -(b) You may distribute such Executable Form under the terms of this - License, or sublicense it under different terms, provided that the - license for the Executable Form does not attempt to limit or alter - the recipients' rights in the Source Code Form under this License. - -3.3. Distribution of a Larger Work - -You may create and distribute a Larger Work under terms of Your choice, -provided that You also comply with the requirements of this License for -the Covered Software. If the Larger Work is a combination of Covered -Software with a work governed by one or more Secondary Licenses, and the -Covered Software is not Incompatible With Secondary Licenses, this -License permits You to additionally distribute such Covered Software -under the terms of such Secondary License(s), so that the recipient of -the Larger Work may, at their option, further distribute the Covered -Software under the terms of either this License or such Secondary -License(s). - -3.4. Notices - -You may not remove or alter the substance of any license notices -(including copyright notices, patent notices, disclaimers of warranty, -or limitations of liability) contained within the Source Code Form of -the Covered Software, except that You may alter any license notices to -the extent required to remedy known factual inaccuracies. - -3.5. Application of Additional Terms - -You may choose to offer, and to charge a fee for, warranty, support, -indemnity or liability obligations to one or more recipients of Covered -Software. However, You may do so only on Your own behalf, and not on -behalf of any Contributor. You must make it absolutely clear that any -such warranty, support, indemnity, or liability obligation is offered by -You alone, and You hereby agree to indemnify every Contributor for any -liability incurred by such Contributor as a result of warranty, support, -indemnity or liability terms You offer. You may include additional -disclaimers of warranty and limitations of liability specific to any -jurisdiction. - -4. Inability to Comply Due to Statute or Regulation ---------------------------------------------------- - -If it is impossible for You to comply with any of the terms of this -License with respect to some or all of the Covered Software due to -statute, judicial order, or regulation then You must: (a) comply with -the terms of this License to the maximum extent possible; and (b) -describe the limitations and the code they affect. Such description must -be placed in a text file included with all distributions of the Covered -Software under this License. Except to the extent prohibited by statute -or regulation, such description must be sufficiently detailed for a -recipient of ordinary skill to be able to understand it. - -5. Termination --------------- - -5.1. The rights granted under this License will terminate automatically -if You fail to comply with any of its terms. However, if You become -compliant, then the rights granted under this License from a particular -Contributor are reinstated (a) provisionally, unless and until such -Contributor explicitly and finally terminates Your grants, and (b) on an -ongoing basis, if such Contributor fails to notify You of the -non-compliance by some reasonable means prior to 60 days after You have -come back into compliance. Moreover, Your grants from a particular -Contributor are reinstated on an ongoing basis if such Contributor -notifies You of the non-compliance by some reasonable means, this is the -first time You have received notice of non-compliance with this License -from such Contributor, and You become compliant prior to 30 days after -Your receipt of the notice. - -5.2. If You initiate litigation against any entity by asserting a patent -infringement claim (excluding declaratory judgment actions, -counter-claims, and cross-claims) alleging that a Contributor Version -directly or indirectly infringes any patent, then the rights granted to -You by any and all Contributors for the Covered Software under Section -2.1 of this License shall terminate. - -5.3. In the event of termination under Sections 5.1 or 5.2 above, all -end user license agreements (excluding distributors and resellers) which -have been validly granted by You or Your distributors under this License -prior to termination shall survive termination. - -************************************************************************ -* * -* 6. Disclaimer of Warranty * -* ------------------------- * -* * -* Covered Software is provided under this License on an "as is" * -* basis, without warranty of any kind, either expressed, implied, or * -* statutory, including, without limitation, warranties that the * -* Covered Software is free of defects, merchantable, fit for a * -* particular purpose or non-infringing. The entire risk as to the * -* quality and performance of the Covered Software is with You. * -* Should any Covered Software prove defective in any respect, You * -* (not any Contributor) assume the cost of any necessary servicing, * -* repair, or correction. This disclaimer of warranty constitutes an * -* essential part of this License. No use of any Covered Software is * -* authorized under this License except under this disclaimer. * -* * -************************************************************************ - -************************************************************************ -* * -* 7. Limitation of Liability * -* -------------------------- * -* * -* Under no circumstances and under no legal theory, whether tort * -* (including negligence), contract, or otherwise, shall any * -* Contributor, or anyone who distributes Covered Software as * -* permitted above, be liable to You for any direct, indirect, * -* special, incidental, or consequential damages of any character * -* including, without limitation, damages for lost profits, loss of * -* goodwill, work stoppage, computer failure or malfunction, or any * -* and all other commercial damages or losses, even if such party * -* shall have been informed of the possibility of such damages. This * -* limitation of liability shall not apply to liability for death or * -* personal injury resulting from such party's negligence to the * -* extent applicable law prohibits such limitation. Some * -* jurisdictions do not allow the exclusion or limitation of * -* incidental or consequential damages, so this exclusion and * -* limitation may not apply to You. * -* * -************************************************************************ - -8. Litigation -------------- - -Any litigation relating to this License may be brought only in the -courts of a jurisdiction where the defendant maintains its principal -place of business and such litigation shall be governed by laws of that -jurisdiction, without reference to its conflict-of-law provisions. -Nothing in this Section shall prevent a party's ability to bring -cross-claims or counter-claims. - -9. Miscellaneous ----------------- - -This License represents the complete agreement concerning the subject -matter hereof. If any provision of this License is held to be -unenforceable, such provision shall be reformed only to the extent -necessary to make it enforceable. Any law or regulation which provides -that the language of a contract shall be construed against the drafter -shall not be used to construe this License against a Contributor. - -10. Versions of the License ---------------------------- - -10.1. New Versions - -Mozilla Foundation is the license steward. Except as provided in Section -10.3, no one other than the license steward has the right to modify or -publish new versions of this License. Each version will be given a -distinguishing version number. - -10.2. Effect of New Versions - -You may distribute the Covered Software under the terms of the version -of the License under which You originally received the Covered Software, -or under the terms of any subsequent version published by the license -steward. - -10.3. Modified Versions - -If you create software not governed by this License, and you want to -create a new license for such software, you may create and use a -modified version of this License if you rename the license and remove -any references to the name of the license steward (except to note that -such modified license differs from this License). - -10.4. Distributing Source Code Form that is Incompatible With Secondary -Licenses - -If You choose to distribute Source Code Form that is Incompatible With -Secondary Licenses under the terms of this version of the License, the -notice described in Exhibit B of this License must be attached. - -Exhibit A - Source Code Form License Notice -------------------------------------------- - - This Source Code Form is subject to the terms of the Mozilla Public - License, v. 2.0. If a copy of the MPL was not distributed with this - file, You can obtain one at https://mozilla.org/MPL/2.0/. - -If it is not possible or desirable to put the notice in a particular -file, then You may include the notice in a location (such as a LICENSE -file in a relevant directory) where a recipient would be likely to look -for such a notice. - -You may add additional accurate notices of copyright ownership. - -Exhibit B - "Incompatible With Secondary Licenses" Notice ---------------------------------------------------------- - - This Source Code Form is "Incompatible With Secondary Licenses", as - defined by the Mozilla Public License, v. 2.0. diff --git a/vendor/cyphar.com/go-pathrs/doc.go b/vendor/cyphar.com/go-pathrs/doc.go deleted file mode 100644 index a7ee4bc487f..00000000000 --- a/vendor/cyphar.com/go-pathrs/doc.go +++ /dev/null @@ -1,14 +0,0 @@ -// SPDX-License-Identifier: MPL-2.0 -/* - * libpathrs: safe path resolution on Linux - * Copyright (C) 2019-2025 Aleksa Sarai - * Copyright (C) 2019-2025 SUSE LLC - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -// Package pathrs provides bindings for libpathrs, a library for safe path -// resolution on Linux. -package pathrs diff --git a/vendor/cyphar.com/go-pathrs/handle_linux.go b/vendor/cyphar.com/go-pathrs/handle_linux.go deleted file mode 100644 index 3221ef67389..00000000000 --- a/vendor/cyphar.com/go-pathrs/handle_linux.go +++ /dev/null @@ -1,114 +0,0 @@ -//go:build linux - -// SPDX-License-Identifier: MPL-2.0 -/* - * libpathrs: safe path resolution on Linux - * Copyright (C) 2019-2025 Aleksa Sarai - * Copyright (C) 2019-2025 SUSE LLC - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -package pathrs - -import ( - "fmt" - "os" - - "cyphar.com/go-pathrs/internal/fdutils" - "cyphar.com/go-pathrs/internal/libpathrs" -) - -// Handle is a handle for a path within a given [Root]. This handle references -// an already-resolved path which can be used for only one purpose -- to -// "re-open" the handle and get an actual [os.File] which can be used for -// ordinary operations. -// -// If you wish to open a file without having an intermediate [Handle] object, -// you can try to use [Root.Open] or [Root.OpenFile]. -// -// It is critical that perform all relevant operations through this [Handle] -// (rather than fetching the file descriptor yourself with [Handle.IntoRaw]), -// because the security properties of libpathrs depend on users doing all -// relevant filesystem operations through libpathrs. -// -// [os.File]: https://pkg.go.dev/os#File -type Handle struct { - inner *os.File -} - -// HandleFromFile creates a new [Handle] from an existing file handle. The -// handle will be copied by this method, so the original handle should still be -// freed by the caller. -// -// This is effectively the inverse operation of [Handle.IntoRaw], and is used -// for "deserialising" pathrs root handles. -func HandleFromFile(file *os.File) (*Handle, error) { - newFile, err := fdutils.DupFile(file) - if err != nil { - return nil, fmt.Errorf("duplicate handle fd: %w", err) - } - return &Handle{inner: newFile}, nil -} - -// Open creates an "upgraded" file handle to the file referenced by the -// [Handle]. Note that the original [Handle] is not consumed by this operation, -// and can be opened multiple times. -// -// The handle returned is only usable for reading, and this is method is -// shorthand for [Handle.OpenFile] with os.O_RDONLY. -// -// TODO: Rename these to "Reopen" or something. -func (h *Handle) Open() (*os.File, error) { - return h.OpenFile(os.O_RDONLY) -} - -// OpenFile creates an "upgraded" file handle to the file referenced by the -// [Handle]. Note that the original [Handle] is not consumed by this operation, -// and can be opened multiple times. -// -// The provided flags indicate which open(2) flags are used to create the new -// handle. -// -// TODO: Rename these to "Reopen" or something. -func (h *Handle) OpenFile(flags int) (*os.File, error) { - return fdutils.WithFileFd(h.inner, func(fd uintptr) (*os.File, error) { - newFd, err := libpathrs.Reopen(fd, flags) - if err != nil { - return nil, err - } - return os.NewFile(newFd, h.inner.Name()), nil - }) -} - -// IntoFile unwraps the [Handle] into its underlying [os.File]. -// -// You almost certainly want to use [Handle.OpenFile] to get a non-O_PATH -// version of this [Handle]. -// -// This operation returns the internal [os.File] of the [Handle] directly, so -// calling [Handle.Close] will also close any copies of the returned [os.File]. -// If you want to get an independent copy, use [Handle.Clone] followed by -// [Handle.IntoFile] on the cloned [Handle]. -// -// [os.File]: https://pkg.go.dev/os#File -func (h *Handle) IntoFile() *os.File { - // TODO: Figure out if we really don't want to make a copy. - // TODO: We almost certainly want to clear r.inner here, but we can't do - // that easily atomically (we could use atomic.Value but that'll make - // things quite a bit uglier). - return h.inner -} - -// Clone creates a copy of a [Handle], such that it has a separate lifetime to -// the original (while referring to the same underlying file). -func (h *Handle) Clone() (*Handle, error) { - return HandleFromFile(h.inner) -} - -// Close frees all of the resources used by the [Handle]. -func (h *Handle) Close() error { - return h.inner.Close() -} diff --git a/vendor/cyphar.com/go-pathrs/internal/fdutils/fd_linux.go b/vendor/cyphar.com/go-pathrs/internal/fdutils/fd_linux.go deleted file mode 100644 index 41aea3e4b3d..00000000000 --- a/vendor/cyphar.com/go-pathrs/internal/fdutils/fd_linux.go +++ /dev/null @@ -1,75 +0,0 @@ -//go:build linux - -// SPDX-License-Identifier: MPL-2.0 -/* - * libpathrs: safe path resolution on Linux - * Copyright (C) 2019-2025 Aleksa Sarai - * Copyright (C) 2019-2025 SUSE LLC - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -// Package fdutils contains a few helper methods when dealing with *os.File and -// file descriptors. -package fdutils - -import ( - "fmt" - "os" - - "golang.org/x/sys/unix" - - "cyphar.com/go-pathrs/internal/libpathrs" -) - -// DupFd makes a duplicate of the given fd. -func DupFd(fd uintptr, name string) (*os.File, error) { - newFd, err := unix.FcntlInt(fd, unix.F_DUPFD_CLOEXEC, 0) - if err != nil { - return nil, fmt.Errorf("fcntl(F_DUPFD_CLOEXEC): %w", err) - } - return os.NewFile(uintptr(newFd), name), nil -} - -// WithFileFd is a more ergonomic wrapper around file.SyscallConn().Control(). -func WithFileFd[T any](file *os.File, fn func(fd uintptr) (T, error)) (T, error) { - conn, err := file.SyscallConn() - if err != nil { - return *new(T), err - } - var ( - ret T - innerErr error - ) - if err := conn.Control(func(fd uintptr) { - ret, innerErr = fn(fd) - }); err != nil { - return *new(T), err - } - return ret, innerErr -} - -// DupFile makes a duplicate of the given file. -func DupFile(file *os.File) (*os.File, error) { - return WithFileFd(file, func(fd uintptr) (*os.File, error) { - return DupFd(fd, file.Name()) - }) -} - -// MkFile creates a new *os.File from the provided file descriptor. However, -// unlike os.NewFile, the file's Name is based on the real path (provided by -// /proc/self/fd/$n). -func MkFile(fd uintptr) (*os.File, error) { - fdPath := fmt.Sprintf("fd/%d", fd) - fdName, err := libpathrs.ProcReadlinkat(libpathrs.ProcDefaultRootFd, libpathrs.ProcThreadSelf, fdPath) - if err != nil { - _ = unix.Close(int(fd)) - return nil, fmt.Errorf("failed to fetch real name of fd %d: %w", fd, err) - } - // TODO: Maybe we should prefix this name with something to indicate to - // users that they must not use this path as a "safe" path. Something like - // "//pathrs-handle:/foo/bar"? - return os.NewFile(fd, fdName), nil -} diff --git a/vendor/cyphar.com/go-pathrs/internal/libpathrs/error_unix.go b/vendor/cyphar.com/go-pathrs/internal/libpathrs/error_unix.go deleted file mode 100644 index c9f416de01f..00000000000 --- a/vendor/cyphar.com/go-pathrs/internal/libpathrs/error_unix.go +++ /dev/null @@ -1,40 +0,0 @@ -//go:build linux - -// TODO: Use "go:build unix" once we bump the minimum Go version 1.19. - -// SPDX-License-Identifier: MPL-2.0 -/* - * libpathrs: safe path resolution on Linux - * Copyright (C) 2019-2025 Aleksa Sarai - * Copyright (C) 2019-2025 SUSE LLC - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -package libpathrs - -import ( - "syscall" -) - -// Error represents an underlying libpathrs error. -type Error struct { - description string - errno syscall.Errno -} - -// Error returns a textual description of the error. -func (err *Error) Error() string { - return err.description -} - -// Unwrap returns the underlying error which was wrapped by this error (if -// applicable). -func (err *Error) Unwrap() error { - if err.errno != 0 { - return err.errno - } - return nil -} diff --git a/vendor/cyphar.com/go-pathrs/internal/libpathrs/libpathrs_linux.go b/vendor/cyphar.com/go-pathrs/internal/libpathrs/libpathrs_linux.go deleted file mode 100644 index c07b80e3071..00000000000 --- a/vendor/cyphar.com/go-pathrs/internal/libpathrs/libpathrs_linux.go +++ /dev/null @@ -1,337 +0,0 @@ -//go:build linux - -// SPDX-License-Identifier: MPL-2.0 -/* - * libpathrs: safe path resolution on Linux - * Copyright (C) 2019-2025 Aleksa Sarai - * Copyright (C) 2019-2025 SUSE LLC - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -// Package libpathrs is an internal thin wrapper around the libpathrs C API. -package libpathrs - -import ( - "fmt" - "syscall" - "unsafe" -) - -/* -// TODO: Figure out if we need to add support for linking against libpathrs -// statically even if in dynamically linked builds in order to make -// packaging a bit easier (using "-Wl,-Bstatic -lpathrs -Wl,-Bdynamic" or -// "-l:pathrs.a"). -#cgo pkg-config: pathrs -#include - -// This is a workaround for unsafe.Pointer() not working for non-void pointers. -char *cast_ptr(void *ptr) { return ptr; } -*/ -import "C" - -func fetchError(errID C.int) error { - if errID >= C.__PATHRS_MAX_ERR_VALUE { - return nil - } - cErr := C.pathrs_errorinfo(errID) - defer C.pathrs_errorinfo_free(cErr) - - var err error - if cErr != nil { - err = &Error{ - errno: syscall.Errno(cErr.saved_errno), - description: C.GoString(cErr.description), - } - } - return err -} - -// OpenRoot wraps pathrs_open_root. -func OpenRoot(path string) (uintptr, error) { - cPath := C.CString(path) - defer C.free(unsafe.Pointer(cPath)) - - fd := C.pathrs_open_root(cPath) - return uintptr(fd), fetchError(fd) -} - -// Reopen wraps pathrs_reopen. -func Reopen(fd uintptr, flags int) (uintptr, error) { - newFd := C.pathrs_reopen(C.int(fd), C.int(flags)) - return uintptr(newFd), fetchError(newFd) -} - -// InRootResolve wraps pathrs_inroot_resolve. -func InRootResolve(rootFd uintptr, path string) (uintptr, error) { - cPath := C.CString(path) - defer C.free(unsafe.Pointer(cPath)) - - fd := C.pathrs_inroot_resolve(C.int(rootFd), cPath) - return uintptr(fd), fetchError(fd) -} - -// InRootResolveNoFollow wraps pathrs_inroot_resolve_nofollow. -func InRootResolveNoFollow(rootFd uintptr, path string) (uintptr, error) { - cPath := C.CString(path) - defer C.free(unsafe.Pointer(cPath)) - - fd := C.pathrs_inroot_resolve_nofollow(C.int(rootFd), cPath) - return uintptr(fd), fetchError(fd) -} - -// InRootOpen wraps pathrs_inroot_open. -func InRootOpen(rootFd uintptr, path string, flags int) (uintptr, error) { - cPath := C.CString(path) - defer C.free(unsafe.Pointer(cPath)) - - fd := C.pathrs_inroot_open(C.int(rootFd), cPath, C.int(flags)) - return uintptr(fd), fetchError(fd) -} - -// InRootReadlink wraps pathrs_inroot_readlink. -func InRootReadlink(rootFd uintptr, path string) (string, error) { - cPath := C.CString(path) - defer C.free(unsafe.Pointer(cPath)) - - size := 128 - for { - linkBuf := make([]byte, size) - n := C.pathrs_inroot_readlink(C.int(rootFd), cPath, C.cast_ptr(unsafe.Pointer(&linkBuf[0])), C.ulong(len(linkBuf))) - switch { - case int(n) < C.__PATHRS_MAX_ERR_VALUE: - return "", fetchError(n) - case int(n) <= len(linkBuf): - return string(linkBuf[:int(n)]), nil - default: - // The contents were truncated. Unlike readlinkat, pathrs returns - // the size of the link when it checked. So use the returned size - // as a basis for the reallocated size (but in order to avoid a DoS - // where a magic-link is growing by a single byte each iteration, - // make sure we are a fair bit larger). - size += int(n) - } - } -} - -// InRootRmdir wraps pathrs_inroot_rmdir. -func InRootRmdir(rootFd uintptr, path string) error { - cPath := C.CString(path) - defer C.free(unsafe.Pointer(cPath)) - - err := C.pathrs_inroot_rmdir(C.int(rootFd), cPath) - return fetchError(err) -} - -// InRootUnlink wraps pathrs_inroot_unlink. -func InRootUnlink(rootFd uintptr, path string) error { - cPath := C.CString(path) - defer C.free(unsafe.Pointer(cPath)) - - err := C.pathrs_inroot_unlink(C.int(rootFd), cPath) - return fetchError(err) -} - -// InRootRemoveAll wraps pathrs_inroot_remove_all. -func InRootRemoveAll(rootFd uintptr, path string) error { - cPath := C.CString(path) - defer C.free(unsafe.Pointer(cPath)) - - err := C.pathrs_inroot_remove_all(C.int(rootFd), cPath) - return fetchError(err) -} - -// InRootCreat wraps pathrs_inroot_creat. -func InRootCreat(rootFd uintptr, path string, flags int, mode uint32) (uintptr, error) { - cPath := C.CString(path) - defer C.free(unsafe.Pointer(cPath)) - - fd := C.pathrs_inroot_creat(C.int(rootFd), cPath, C.int(flags), C.uint(mode)) - return uintptr(fd), fetchError(fd) -} - -// InRootRename wraps pathrs_inroot_rename. -func InRootRename(rootFd uintptr, src, dst string, flags uint) error { - cSrc := C.CString(src) - defer C.free(unsafe.Pointer(cSrc)) - - cDst := C.CString(dst) - defer C.free(unsafe.Pointer(cDst)) - - err := C.pathrs_inroot_rename(C.int(rootFd), cSrc, cDst, C.uint(flags)) - return fetchError(err) -} - -// InRootMkdir wraps pathrs_inroot_mkdir. -func InRootMkdir(rootFd uintptr, path string, mode uint32) error { - cPath := C.CString(path) - defer C.free(unsafe.Pointer(cPath)) - - err := C.pathrs_inroot_mkdir(C.int(rootFd), cPath, C.uint(mode)) - return fetchError(err) -} - -// InRootMkdirAll wraps pathrs_inroot_mkdir_all. -func InRootMkdirAll(rootFd uintptr, path string, mode uint32) (uintptr, error) { - cPath := C.CString(path) - defer C.free(unsafe.Pointer(cPath)) - - fd := C.pathrs_inroot_mkdir_all(C.int(rootFd), cPath, C.uint(mode)) - return uintptr(fd), fetchError(fd) -} - -// InRootMknod wraps pathrs_inroot_mknod. -func InRootMknod(rootFd uintptr, path string, mode uint32, dev uint64) error { - cPath := C.CString(path) - defer C.free(unsafe.Pointer(cPath)) - - err := C.pathrs_inroot_mknod(C.int(rootFd), cPath, C.uint(mode), C.dev_t(dev)) - return fetchError(err) -} - -// InRootSymlink wraps pathrs_inroot_symlink. -func InRootSymlink(rootFd uintptr, path, target string) error { - cPath := C.CString(path) - defer C.free(unsafe.Pointer(cPath)) - - cTarget := C.CString(target) - defer C.free(unsafe.Pointer(cTarget)) - - err := C.pathrs_inroot_symlink(C.int(rootFd), cPath, cTarget) - return fetchError(err) -} - -// InRootHardlink wraps pathrs_inroot_hardlink. -func InRootHardlink(rootFd uintptr, path, target string) error { - cPath := C.CString(path) - defer C.free(unsafe.Pointer(cPath)) - - cTarget := C.CString(target) - defer C.free(unsafe.Pointer(cTarget)) - - err := C.pathrs_inroot_hardlink(C.int(rootFd), cPath, cTarget) - return fetchError(err) -} - -// ProcBase is pathrs_proc_base_t (uint64_t). -type ProcBase C.pathrs_proc_base_t - -// FIXME: We need to open-code the constants because CGo unfortunately will -// implicitly convert any non-literal constants (i.e. those resolved using gcc) -// to signed integers. See for some -// more information on the underlying issue (though. -const ( - // ProcRoot is PATHRS_PROC_ROOT. - ProcRoot ProcBase = 0xFFFF_FFFE_7072_6F63 // C.PATHRS_PROC_ROOT - // ProcSelf is PATHRS_PROC_SELF. - ProcSelf ProcBase = 0xFFFF_FFFE_091D_5E1F // C.PATHRS_PROC_SELF - // ProcThreadSelf is PATHRS_PROC_THREAD_SELF. - ProcThreadSelf ProcBase = 0xFFFF_FFFE_3EAD_5E1F // C.PATHRS_PROC_THREAD_SELF - - // ProcBaseTypeMask is __PATHRS_PROC_TYPE_MASK. - ProcBaseTypeMask ProcBase = 0xFFFF_FFFF_0000_0000 // C.__PATHRS_PROC_TYPE_MASK - // ProcBaseTypePid is __PATHRS_PROC_TYPE_PID. - ProcBaseTypePid ProcBase = 0x8000_0000_0000_0000 // C.__PATHRS_PROC_TYPE_PID - - // ProcDefaultRootFd is PATHRS_PROC_DEFAULT_ROOTFD. - ProcDefaultRootFd = -int(syscall.EBADF) // C.PATHRS_PROC_DEFAULT_ROOTFD -) - -func assertEqual[T comparable](a, b T, msg string) { - if a != b { - panic(fmt.Sprintf("%s ((%T) %#v != (%T) %#v)", msg, a, a, b, b)) - } -} - -// Verify that the values above match the actual C values. Unfortunately, Go -// only allows us to forcefully cast int64 to uint64 if you use a temporary -// variable, which means we cannot do it in a const context and thus need to do -// it at runtime (even though it is a check that fundamentally could be done at -// compile-time)... -func init() { - var ( - actualProcRoot int64 = C.PATHRS_PROC_ROOT - actualProcSelf int64 = C.PATHRS_PROC_SELF - actualProcThreadSelf int64 = C.PATHRS_PROC_THREAD_SELF - ) - - assertEqual(ProcRoot, ProcBase(actualProcRoot), "PATHRS_PROC_ROOT") - assertEqual(ProcSelf, ProcBase(actualProcSelf), "PATHRS_PROC_SELF") - assertEqual(ProcThreadSelf, ProcBase(actualProcThreadSelf), "PATHRS_PROC_THREAD_SELF") - - var ( - actualProcBaseTypeMask uint64 = C.__PATHRS_PROC_TYPE_MASK - actualProcBaseTypePid uint64 = C.__PATHRS_PROC_TYPE_PID - ) - - assertEqual(ProcBaseTypeMask, ProcBase(actualProcBaseTypeMask), "__PATHRS_PROC_TYPE_MASK") - assertEqual(ProcBaseTypePid, ProcBase(actualProcBaseTypePid), "__PATHRS_PROC_TYPE_PID") - - assertEqual(ProcDefaultRootFd, int(C.PATHRS_PROC_DEFAULT_ROOTFD), "PATHRS_PROC_DEFAULT_ROOTFD") -} - -// ProcPid reimplements the PROC_PID(x) conversion. -func ProcPid(pid uint32) ProcBase { return ProcBaseTypePid | ProcBase(pid) } - -// ProcOpenat wraps pathrs_proc_openat. -func ProcOpenat(procRootFd int, base ProcBase, path string, flags int) (uintptr, error) { - cBase := C.pathrs_proc_base_t(base) - - cPath := C.CString(path) - defer C.free(unsafe.Pointer(cPath)) - - fd := C.pathrs_proc_openat(C.int(procRootFd), cBase, cPath, C.int(flags)) - return uintptr(fd), fetchError(fd) -} - -// ProcReadlinkat wraps pathrs_proc_readlinkat. -func ProcReadlinkat(procRootFd int, base ProcBase, path string) (string, error) { - // TODO: See if we can unify this code with InRootReadlink. - - cBase := C.pathrs_proc_base_t(base) - - cPath := C.CString(path) - defer C.free(unsafe.Pointer(cPath)) - - size := 128 - for { - linkBuf := make([]byte, size) - n := C.pathrs_proc_readlinkat( - C.int(procRootFd), cBase, cPath, - C.cast_ptr(unsafe.Pointer(&linkBuf[0])), C.ulong(len(linkBuf))) - switch { - case int(n) < C.__PATHRS_MAX_ERR_VALUE: - return "", fetchError(n) - case int(n) <= len(linkBuf): - return string(linkBuf[:int(n)]), nil - default: - // The contents were truncated. Unlike readlinkat, pathrs returns - // the size of the link when it checked. So use the returned size - // as a basis for the reallocated size (but in order to avoid a DoS - // where a magic-link is growing by a single byte each iteration, - // make sure we are a fair bit larger). - size += int(n) - } - } -} - -// ProcfsOpenHow is pathrs_procfs_open_how (struct). -type ProcfsOpenHow C.pathrs_procfs_open_how - -const ( - // ProcfsNewUnmasked is PATHRS_PROCFS_NEW_UNMASKED. - ProcfsNewUnmasked = C.PATHRS_PROCFS_NEW_UNMASKED -) - -// Flags returns a pointer to the internal flags field to allow other packages -// to modify structure fields that are internal due to Go's visibility model. -func (how *ProcfsOpenHow) Flags() *C.uint64_t { return &how.flags } - -// ProcfsOpen is pathrs_procfs_open (sizeof(*how) is passed automatically). -func ProcfsOpen(how *ProcfsOpenHow) (uintptr, error) { - fd := C.pathrs_procfs_open((*C.pathrs_procfs_open_how)(how), C.size_t(unsafe.Sizeof(*how))) - return uintptr(fd), fetchError(fd) -} diff --git a/vendor/cyphar.com/go-pathrs/procfs/procfs_linux.go b/vendor/cyphar.com/go-pathrs/procfs/procfs_linux.go deleted file mode 100644 index 5533c427cb7..00000000000 --- a/vendor/cyphar.com/go-pathrs/procfs/procfs_linux.go +++ /dev/null @@ -1,246 +0,0 @@ -//go:build linux - -// SPDX-License-Identifier: MPL-2.0 -/* - * libpathrs: safe path resolution on Linux - * Copyright (C) 2019-2025 Aleksa Sarai - * Copyright (C) 2019-2025 SUSE LLC - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -// Package procfs provides a safe API for operating on /proc on Linux. -package procfs - -import ( - "os" - "runtime" - - "cyphar.com/go-pathrs/internal/fdutils" - "cyphar.com/go-pathrs/internal/libpathrs" -) - -// ProcBase is used with [ProcReadlink] and related functions to indicate what -// /proc subpath path operations should be done relative to. -type ProcBase struct { - inner libpathrs.ProcBase -} - -var ( - // ProcRoot indicates to use /proc. Note that this mode may be more - // expensive because we have to take steps to try to avoid leaking unmasked - // procfs handles, so you should use [ProcBaseSelf] if you can. - ProcRoot = ProcBase{inner: libpathrs.ProcRoot} - // ProcSelf indicates to use /proc/self. For most programs, this is the - // standard choice. - ProcSelf = ProcBase{inner: libpathrs.ProcSelf} - // ProcThreadSelf indicates to use /proc/thread-self. In multi-threaded - // programs where one thread has a different CLONE_FS, it is possible for - // /proc/self to point the wrong thread and so /proc/thread-self may be - // necessary. - ProcThreadSelf = ProcBase{inner: libpathrs.ProcThreadSelf} -) - -// ProcPid returns a ProcBase which indicates to use /proc/$pid for the given -// PID (or TID). Be aware that due to PID recycling, using this is generally -// not safe except in certain circumstances. Namely: -// -// - PID 1 (the init process), as that PID cannot ever get recycled. -// - Your current PID (though you should just use [ProcBaseSelf]). -// - Your current TID if you have used [runtime.LockOSThread] (though you -// should just use [ProcBaseThreadSelf]). -// - PIDs of child processes (as long as you are sure that no other part of -// your program incorrectly catches or ignores SIGCHLD, and that you do it -// *before* you call wait(2)or any equivalent method that could reap -// zombies). -func ProcPid(pid int) ProcBase { - if pid < 0 || pid >= 1<<31 { - panic("invalid ProcBasePid value") // TODO: should this be an error? - } - return ProcBase{inner: libpathrs.ProcPid(uint32(pid))} -} - -// ThreadCloser is a callback that needs to be called when you are done -// operating on an [os.File] fetched using [Handle.OpenThreadSelf]. -// -// [os.File]: https://pkg.go.dev/os#File -type ThreadCloser func() - -// Handle is a wrapper around an *os.File handle to "/proc", which can be -// used to do further procfs-related operations in a safe way. -type Handle struct { - inner *os.File -} - -// Close releases all internal resources for this [Handle]. -// -// Note that if the handle is actually the global cached handle, this operation -// is a no-op. -func (proc *Handle) Close() error { - var err error - if proc.inner != nil { - err = proc.inner.Close() - } - return err -} - -// OpenOption is a configuration function passed as an argument to [Open]. -type OpenOption func(*libpathrs.ProcfsOpenHow) error - -// UnmaskedProcRoot can be passed to [Open] to request an unmasked procfs -// handle be created. -// -// procfs, err := procfs.OpenRoot(procfs.UnmaskedProcRoot) -func UnmaskedProcRoot(how *libpathrs.ProcfsOpenHow) error { - *how.Flags() |= libpathrs.ProcfsNewUnmasked - return nil -} - -// Open creates a new [Handle] to a safe "/proc", based on the passed -// configuration options (in the form of a series of [OpenOption]s). -func Open(opts ...OpenOption) (*Handle, error) { - var how libpathrs.ProcfsOpenHow - for _, opt := range opts { - if err := opt(&how); err != nil { - return nil, err - } - } - fd, err := libpathrs.ProcfsOpen(&how) - if err != nil { - return nil, err - } - var procFile *os.File - if int(fd) >= 0 { - procFile = os.NewFile(fd, "/proc") - } - // TODO: Check that fd == PATHRS_PROC_DEFAULT_ROOTFD in the <0 case? - return &Handle{inner: procFile}, nil -} - -// TODO: Switch to something fdutils.WithFileFd-like. -func (proc *Handle) fd() int { - if proc.inner != nil { - return int(proc.inner.Fd()) - } - return libpathrs.ProcDefaultRootFd -} - -// TODO: Should we expose open? -func (proc *Handle) open(base ProcBase, path string, flags int) (_ *os.File, Closer ThreadCloser, Err error) { - var closer ThreadCloser - if base == ProcThreadSelf { - runtime.LockOSThread() - closer = runtime.UnlockOSThread - } - defer func() { - if closer != nil && Err != nil { - closer() - Closer = nil - } - }() - - fd, err := libpathrs.ProcOpenat(proc.fd(), base.inner, path, flags) - if err != nil { - return nil, nil, err - } - file, err := fdutils.MkFile(fd) - return file, closer, err -} - -// OpenRoot safely opens a given path from inside /proc/. -// -// This function must only be used for accessing global information from procfs -// (such as /proc/cpuinfo) or information about other processes (such as -// /proc/1). Accessing your own process information should be done using -// [Handle.OpenSelf] or [Handle.OpenThreadSelf]. -func (proc *Handle) OpenRoot(path string, flags int) (*os.File, error) { - file, closer, err := proc.open(ProcRoot, path, flags) - if closer != nil { - // should not happen - panic("non-zero closer returned from procOpen(ProcRoot)") - } - return file, err -} - -// OpenSelf safely opens a given path from inside /proc/self/. -// -// This method is recommend for getting process information about the current -// process for almost all Go processes *except* for cases where there are -// [runtime.LockOSThread] threads that have changed some aspect of their state -// (such as through unshare(CLONE_FS) or changing namespaces). -// -// For such non-heterogeneous processes, /proc/self may reference to a task -// that has different state from the current goroutine and so it may be -// preferable to use [Handle.OpenThreadSelf]. The same is true if a user -// really wants to inspect the current OS thread's information (such as -// /proc/thread-self/stack or /proc/thread-self/status which is always uniquely -// per-thread). -// -// Unlike [Handle.OpenThreadSelf], this method does not involve locking -// the goroutine to the current OS thread and so is simpler to use and -// theoretically has slightly less overhead. -// -// [runtime.LockOSThread]: https://pkg.go.dev/runtime#LockOSThread -func (proc *Handle) OpenSelf(path string, flags int) (*os.File, error) { - file, closer, err := proc.open(ProcSelf, path, flags) - if closer != nil { - // should not happen - panic("non-zero closer returned from procOpen(ProcSelf)") - } - return file, err -} - -// OpenPid safely opens a given path from inside /proc/$pid/, where pid can be -// either a PID or TID. -// -// This is effectively equivalent to calling [Handle.OpenRoot] with the -// pid prefixed to the subpath. -// -// Be aware that due to PID recycling, using this is generally not safe except -// in certain circumstances. See the documentation of [ProcPid] for more -// details. -func (proc *Handle) OpenPid(pid int, path string, flags int) (*os.File, error) { - file, closer, err := proc.open(ProcPid(pid), path, flags) - if closer != nil { - // should not happen - panic("non-zero closer returned from procOpen(ProcPidOpen)") - } - return file, err -} - -// OpenThreadSelf safely opens a given path from inside /proc/thread-self/. -// -// Most Go processes have heterogeneous threads (all threads have most of the -// same kernel state such as CLONE_FS) and so [Handle.OpenSelf] is -// preferable for most users. -// -// For non-heterogeneous threads, or users that actually want thread-specific -// information (such as /proc/thread-self/stack or /proc/thread-self/status), -// this method is necessary. -// -// Because Go can change the running OS thread of your goroutine without notice -// (and then subsequently kill the old thread), this method will lock the -// current goroutine to the OS thread (with [runtime.LockOSThread]) and the -// caller is responsible for unlocking the the OS thread with the -// [ThreadCloser] callback once they are done using the returned file. This -// callback MUST be called AFTER you have finished using the returned -// [os.File]. This callback is completely separate to [os.File.Close], so it -// must be called regardless of how you close the handle. -// -// [runtime.LockOSThread]: https://pkg.go.dev/runtime#LockOSThread -// [os.File]: https://pkg.go.dev/os#File -// [os.File.Close]: https://pkg.go.dev/os#File.Close -func (proc *Handle) OpenThreadSelf(path string, flags int) (*os.File, ThreadCloser, error) { - return proc.open(ProcThreadSelf, path, flags) -} - -// Readlink safely reads the contents of a symlink from the given procfs base. -// -// This is effectively equivalent to doing an Open*(O_PATH|O_NOFOLLOW) of the -// path and then doing unix.Readlinkat(fd, ""), but with the benefit that -// thread locking is not necessary for [ProcThreadSelf]. -func (proc *Handle) Readlink(base ProcBase, path string) (string, error) { - return libpathrs.ProcReadlinkat(proc.fd(), base.inner, path) -} diff --git a/vendor/cyphar.com/go-pathrs/root_linux.go b/vendor/cyphar.com/go-pathrs/root_linux.go deleted file mode 100644 index edc9e4c87f9..00000000000 --- a/vendor/cyphar.com/go-pathrs/root_linux.go +++ /dev/null @@ -1,367 +0,0 @@ -//go:build linux - -// SPDX-License-Identifier: MPL-2.0 -/* - * libpathrs: safe path resolution on Linux - * Copyright (C) 2019-2025 Aleksa Sarai - * Copyright (C) 2019-2025 SUSE LLC - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -package pathrs - -import ( - "errors" - "fmt" - "os" - "syscall" - - "cyphar.com/go-pathrs/internal/fdutils" - "cyphar.com/go-pathrs/internal/libpathrs" -) - -// Root is a handle to the root of a directory tree to resolve within. The only -// purpose of this "root handle" is to perform operations within the directory -// tree, or to get a [Handle] to inodes within the directory tree. -// -// At time of writing, it is considered a *VERY BAD IDEA* to open a [Root] -// inside a possibly-attacker-controlled directory tree. While we do have -// protections that should defend against it, it's far more dangerous than just -// opening a directory tree which is not inside a potentially-untrusted -// directory. -type Root struct { - inner *os.File -} - -// OpenRoot creates a new [Root] handle to the directory at the given path. -func OpenRoot(path string) (*Root, error) { - fd, err := libpathrs.OpenRoot(path) - if err != nil { - return nil, err - } - file, err := fdutils.MkFile(fd) - if err != nil { - return nil, err - } - return &Root{inner: file}, nil -} - -// RootFromFile creates a new [Root] handle from an [os.File] referencing a -// directory. The provided file will be duplicated, so the original file should -// still be closed by the caller. -// -// This is effectively the inverse operation of [Root.IntoFile]. -// -// [os.File]: https://pkg.go.dev/os#File -func RootFromFile(file *os.File) (*Root, error) { - newFile, err := fdutils.DupFile(file) - if err != nil { - return nil, fmt.Errorf("duplicate root fd: %w", err) - } - return &Root{inner: newFile}, nil -} - -// Resolve resolves the given path within the [Root]'s directory tree, and -// returns a [Handle] to the resolved path. The path must already exist, -// otherwise an error will occur. -// -// All symlinks (including trailing symlinks) are followed, but they are -// resolved within the rootfs. If you wish to open a handle to the symlink -// itself, use [ResolveNoFollow]. -func (r *Root) Resolve(path string) (*Handle, error) { - return fdutils.WithFileFd(r.inner, func(rootFd uintptr) (*Handle, error) { - handleFd, err := libpathrs.InRootResolve(rootFd, path) - if err != nil { - return nil, err - } - handleFile, err := fdutils.MkFile(handleFd) - if err != nil { - return nil, err - } - return &Handle{inner: handleFile}, nil - }) -} - -// ResolveNoFollow is effectively an O_NOFOLLOW version of [Resolve]. Their -// behaviour is identical, except that *trailing* symlinks will not be -// followed. If the final component is a trailing symlink, an O_PATH|O_NOFOLLOW -// handle to the symlink itself is returned. -func (r *Root) ResolveNoFollow(path string) (*Handle, error) { - return fdutils.WithFileFd(r.inner, func(rootFd uintptr) (*Handle, error) { - handleFd, err := libpathrs.InRootResolveNoFollow(rootFd, path) - if err != nil { - return nil, err - } - handleFile, err := fdutils.MkFile(handleFd) - if err != nil { - return nil, err - } - return &Handle{inner: handleFile}, nil - }) -} - -// Open is effectively shorthand for [Resolve] followed by [Handle.Open], but -// can be slightly more efficient (it reduces CGo overhead and the number of -// syscalls used when using the openat2-based resolver) and is arguably more -// ergonomic to use. -// -// This is effectively equivalent to [os.Open]. -// -// [os.Open]: https://pkg.go.dev/os#Open -func (r *Root) Open(path string) (*os.File, error) { - return r.OpenFile(path, os.O_RDONLY) -} - -// OpenFile is effectively shorthand for [Resolve] followed by -// [Handle.OpenFile], but can be slightly more efficient (it reduces CGo -// overhead and the number of syscalls used when using the openat2-based -// resolver) and is arguably more ergonomic to use. -// -// However, if flags contains os.O_NOFOLLOW and the path is a symlink, then -// OpenFile's behaviour will match that of openat2. In most cases an error will -// be returned, but if os.O_PATH is provided along with os.O_NOFOLLOW then a -// file equivalent to [ResolveNoFollow] will be returned instead. -// -// This is effectively equivalent to [os.OpenFile], except that os.O_CREAT is -// not supported. -// -// [os.OpenFile]: https://pkg.go.dev/os#OpenFile -func (r *Root) OpenFile(path string, flags int) (*os.File, error) { - return fdutils.WithFileFd(r.inner, func(rootFd uintptr) (*os.File, error) { - fd, err := libpathrs.InRootOpen(rootFd, path, flags) - if err != nil { - return nil, err - } - return fdutils.MkFile(fd) - }) -} - -// Create creates a file within the [Root]'s directory tree at the given path, -// and returns a handle to the file. The provided mode is used for the new file -// (the process's umask applies). -// -// Unlike [os.Create], if the file already exists an error is created rather -// than the file being opened and truncated. -// -// [os.Create]: https://pkg.go.dev/os#Create -func (r *Root) Create(path string, flags int, mode os.FileMode) (*os.File, error) { - unixMode, err := toUnixMode(mode, false) - if err != nil { - return nil, err - } - return fdutils.WithFileFd(r.inner, func(rootFd uintptr) (*os.File, error) { - handleFd, err := libpathrs.InRootCreat(rootFd, path, flags, unixMode) - if err != nil { - return nil, err - } - return fdutils.MkFile(handleFd) - }) -} - -// Rename two paths within a [Root]'s directory tree. The flags argument is -// identical to the RENAME_* flags to the renameat2(2) system call. -func (r *Root) Rename(src, dst string, flags uint) error { - _, err := fdutils.WithFileFd(r.inner, func(rootFd uintptr) (struct{}, error) { - err := libpathrs.InRootRename(rootFd, src, dst, flags) - return struct{}{}, err - }) - return err -} - -// RemoveDir removes the named empty directory within a [Root]'s directory -// tree. -func (r *Root) RemoveDir(path string) error { - _, err := fdutils.WithFileFd(r.inner, func(rootFd uintptr) (struct{}, error) { - err := libpathrs.InRootRmdir(rootFd, path) - return struct{}{}, err - }) - return err -} - -// RemoveFile removes the named file within a [Root]'s directory tree. -func (r *Root) RemoveFile(path string) error { - _, err := fdutils.WithFileFd(r.inner, func(rootFd uintptr) (struct{}, error) { - err := libpathrs.InRootUnlink(rootFd, path) - return struct{}{}, err - }) - return err -} - -// Remove removes the named file or (empty) directory within a [Root]'s -// directory tree. -// -// This is effectively equivalent to [os.Remove]. -// -// [os.Remove]: https://pkg.go.dev/os#Remove -func (r *Root) Remove(path string) error { - // In order to match os.Remove's implementation we need to also do both - // syscalls unconditionally and adjust the error based on whether - // pathrs_inroot_rmdir() returned ENOTDIR. - unlinkErr := r.RemoveFile(path) - if unlinkErr == nil { - return nil - } - rmdirErr := r.RemoveDir(path) - if rmdirErr == nil { - return nil - } - // Both failed, adjust the error in the same way that os.Remove does. - err := rmdirErr - if errors.Is(err, syscall.ENOTDIR) { - err = unlinkErr - } - return err -} - -// RemoveAll recursively deletes a path and all of its children. -// -// This is effectively equivalent to [os.RemoveAll]. -// -// [os.RemoveAll]: https://pkg.go.dev/os#RemoveAll -func (r *Root) RemoveAll(path string) error { - _, err := fdutils.WithFileFd(r.inner, func(rootFd uintptr) (struct{}, error) { - err := libpathrs.InRootRemoveAll(rootFd, path) - return struct{}{}, err - }) - return err -} - -// Mkdir creates a directory within a [Root]'s directory tree. The provided -// mode is used for the new directory (the process's umask applies). -// -// This is effectively equivalent to [os.Mkdir]. -// -// [os.Mkdir]: https://pkg.go.dev/os#Mkdir -func (r *Root) Mkdir(path string, mode os.FileMode) error { - unixMode, err := toUnixMode(mode, false) - if err != nil { - return err - } - - _, err = fdutils.WithFileFd(r.inner, func(rootFd uintptr) (struct{}, error) { - err := libpathrs.InRootMkdir(rootFd, path, unixMode) - return struct{}{}, err - }) - return err -} - -// MkdirAll creates a directory (and any parent path components if they don't -// exist) within a [Root]'s directory tree. The provided mode is used for any -// directories created by this function (the process's umask applies). -// -// This is effectively equivalent to [os.MkdirAll]. -// -// [os.MkdirAll]: https://pkg.go.dev/os#MkdirAll -func (r *Root) MkdirAll(path string, mode os.FileMode) (*Handle, error) { - unixMode, err := toUnixMode(mode, false) - if err != nil { - return nil, err - } - - return fdutils.WithFileFd(r.inner, func(rootFd uintptr) (*Handle, error) { - handleFd, err := libpathrs.InRootMkdirAll(rootFd, path, unixMode) - if err != nil { - return nil, err - } - handleFile, err := fdutils.MkFile(handleFd) - if err != nil { - return nil, err - } - return &Handle{inner: handleFile}, err - }) -} - -// Mknod creates a new device inode of the given type within a [Root]'s -// directory tree. The provided mode is used for the new directory (the -// process's umask applies). -// -// This is effectively equivalent to [unix.Mknod]. -// -// [unix.Mknod]: https://pkg.go.dev/golang.org/x/sys/unix#Mknod -func (r *Root) Mknod(path string, mode os.FileMode, dev uint64) error { - unixMode, err := toUnixMode(mode, true) - if err != nil { - return err - } - - _, err = fdutils.WithFileFd(r.inner, func(rootFd uintptr) (struct{}, error) { - err := libpathrs.InRootMknod(rootFd, path, unixMode, dev) - return struct{}{}, err - }) - return err -} - -// Symlink creates a symlink within a [Root]'s directory tree. The symlink is -// created at path and is a link to target. -// -// This is effectively equivalent to [os.Symlink]. -// -// [os.Symlink]: https://pkg.go.dev/os#Symlink -func (r *Root) Symlink(path, target string) error { - _, err := fdutils.WithFileFd(r.inner, func(rootFd uintptr) (struct{}, error) { - err := libpathrs.InRootSymlink(rootFd, path, target) - return struct{}{}, err - }) - return err -} - -// Hardlink creates a hardlink within a [Root]'s directory tree. The hardlink -// is created at path and is a link to target. Both paths are within the -// [Root]'s directory tree (you cannot hardlink to a different [Root] or the -// host). -// -// This is effectively equivalent to [os.Link]. -// -// [os.Link]: https://pkg.go.dev/os#Link -func (r *Root) Hardlink(path, target string) error { - _, err := fdutils.WithFileFd(r.inner, func(rootFd uintptr) (struct{}, error) { - err := libpathrs.InRootHardlink(rootFd, path, target) - return struct{}{}, err - }) - return err -} - -// Readlink returns the target of a symlink with a [Root]'s directory tree. -// -// This is effectively equivalent to [os.Readlink]. -// -// [os.Readlink]: https://pkg.go.dev/os#Readlink -func (r *Root) Readlink(path string) (string, error) { - return fdutils.WithFileFd(r.inner, func(rootFd uintptr) (string, error) { - return libpathrs.InRootReadlink(rootFd, path) - }) -} - -// IntoFile unwraps the [Root] into its underlying [os.File]. -// -// It is critical that you do not operate on this file descriptor yourself, -// because the security properties of libpathrs depend on users doing all -// relevant filesystem operations through libpathrs. -// -// This operation returns the internal [os.File] of the [Root] directly, so -// calling [Root.Close] will also close any copies of the returned [os.File]. -// If you want to get an independent copy, use [Root.Clone] followed by -// [Root.IntoFile] on the cloned [Root]. -// -// [os.File]: https://pkg.go.dev/os#File -func (r *Root) IntoFile() *os.File { - // TODO: Figure out if we really don't want to make a copy. - // TODO: We almost certainly want to clear r.inner here, but we can't do - // that easily atomically (we could use atomic.Value but that'll make - // things quite a bit uglier). - return r.inner -} - -// Clone creates a copy of a [Root] handle, such that it has a separate -// lifetime to the original (while referring to the same underlying directory). -func (r *Root) Clone() (*Root, error) { - return RootFromFile(r.inner) -} - -// Close frees all of the resources used by the [Root] handle. -func (r *Root) Close() error { - return r.inner.Close() -} diff --git a/vendor/cyphar.com/go-pathrs/utils_linux.go b/vendor/cyphar.com/go-pathrs/utils_linux.go deleted file mode 100644 index 2208d608f8d..00000000000 --- a/vendor/cyphar.com/go-pathrs/utils_linux.go +++ /dev/null @@ -1,56 +0,0 @@ -//go:build linux - -// SPDX-License-Identifier: MPL-2.0 -/* - * libpathrs: safe path resolution on Linux - * Copyright (C) 2019-2025 Aleksa Sarai - * Copyright (C) 2019-2025 SUSE LLC - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - */ - -package pathrs - -import ( - "fmt" - "os" - - "golang.org/x/sys/unix" -) - -//nolint:cyclop // this function needs to handle a lot of cases -func toUnixMode(mode os.FileMode, needsType bool) (uint32, error) { - sysMode := uint32(mode.Perm()) - switch mode & os.ModeType { //nolint:exhaustive // we only care about ModeType bits - case 0: - if needsType { - sysMode |= unix.S_IFREG - } - case os.ModeDir: - sysMode |= unix.S_IFDIR - case os.ModeSymlink: - sysMode |= unix.S_IFLNK - case os.ModeCharDevice | os.ModeDevice: - sysMode |= unix.S_IFCHR - case os.ModeDevice: - sysMode |= unix.S_IFBLK - case os.ModeNamedPipe: - sysMode |= unix.S_IFIFO - case os.ModeSocket: - sysMode |= unix.S_IFSOCK - default: - return 0, fmt.Errorf("invalid mode filetype %+o", mode) - } - if mode&os.ModeSetuid != 0 { - sysMode |= unix.S_ISUID - } - if mode&os.ModeSetgid != 0 { - sysMode |= unix.S_ISGID - } - if mode&os.ModeSticky != 0 { - sysMode |= unix.S_ISVTX - } - return sysMode, nil -} diff --git a/vendor/github.com/cyphar/filepath-securejoin/.golangci.yml b/vendor/github.com/cyphar/filepath-securejoin/.golangci.yml index 3e8dd99bd7f..e965034ed36 100644 --- a/vendor/github.com/cyphar/filepath-securejoin/.golangci.yml +++ b/vendor/github.com/cyphar/filepath-securejoin/.golangci.yml @@ -9,10 +9,6 @@ version: "2" -run: - build-tags: - - libpathrs - linters: enable: - asasalint diff --git a/vendor/github.com/cyphar/filepath-securejoin/CHANGELOG.md b/vendor/github.com/cyphar/filepath-securejoin/CHANGELOG.md index 734cf61e322..1fc7eeb0693 100644 --- a/vendor/github.com/cyphar/filepath-securejoin/CHANGELOG.md +++ b/vendor/github.com/cyphar/filepath-securejoin/CHANGELOG.md @@ -4,64 +4,22 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/). -## [Unreleased] ## - -## [0.6.0] - 2025-11-03 ## - -> By the Power of Greyskull! - -While quite small code-wise, this release marks a very key point in the -development of filepath-securejoin. - -filepath-securejoin was originally intended (back in 2017) to simply be a -single-purpose library that would take some common code used in container -runtimes (specifically, Docker's `FollowSymlinksInScope`) and make it more -general-purpose (with the eventual goals of it ending up in the Go stdlib). - -Of course, I quickly discovered that this problem was actually far more -complicated to solve when dealing with racing attackers, which lead to me -developing `openat2(2)` and [libpathrs][]. I had originally planned for -libpathrs to completely replace filepath-securejoin "once it was ready" but in -the interim we needed to fix several race attacks in runc as part of security -advisories. Obviously we couldn't require the usage of a pre-0.1 Rust library -in runc so it was necessary to port bits of libpathrs into filepath-securejoin. -(Ironically the first prototypes of libpathrs were originally written in Go and -then rewritten to Rust, so the code in filepath-securejoin is actually Go code -that was rewritten to Rust then re-rewritten to Go.) - -It then became clear that pure-Go libraries will likely not be willing to -require CGo for all of their builds, so it was necessary to accept that -filepath-securejoin will need to stay. As such, in v0.5.0 we provided more -pure-Go implementations of features from libpathrs but moved them into -`pathrs-lite` subpackage to clarify what purpose these helpers serve. - -This release finally closes the loop and makes it so that pathrs-lite can -transparently use libpathrs (via a `libpathrs` build-tag). This means that -upstream libraries can use the pure Go version if they prefer, but downstreams -(either downstream library users or even downstream distributions) are able to -migrate to libpathrs for all usages of pathrs-lite in an entire Go binary. - -I should make it clear that I do not plan to port the rest of libpathrs to Go, -as I do not wish to maintain two copies of the same codebase. pathrs-lite -already provides the core essentials necessary to operate on paths safely for -most modern systems. Users who want additional hardening or more ergonomic APIs -are free to use [`cyphar.com/go-pathrs`][go-pathrs] (libpathrs's Go bindings). +## [Unreleased 0.5.z] ## -[libpathrs]: https://github.com/cyphar/libpathrs -[go-pathrs]: https://cyphar.com/go-pathrs +## [0.5.2] - 2025-11-19 ## -### Breaking ### -- The deprecated `MkdirAll`, `MkdirAllHandle`, `OpenInRoot`, `OpenatInRoot` and - `Reopen` wrappers have been removed. Please switch to using `pathrs-lite` - directly. +> "Will you walk into my parlour?" said a spider to a fly. -### Added ### -- `pathrs-lite` now has support for using [libpathrs][libpathrs] as a backend. - This is opt-in and can be enabled at build time with the `libpathrs` build - tag. The intention is to allow for downstream libraries and other projects to - make use of the pure-Go `github.com/cyphar/filepath-securejoin/pathrs-lite` - package and distributors can then opt-in to using `libpathrs` for the entire - binary if they wish. +### Fixed ### +- Our logic for deciding whether to use `openat2(2)` or fallback to an `O_PATH` + resolver would cache the result to avoid doing needless test runs of + `openat2(2)`. However, this causes issues when `pathrs-lite` is being used by + a program that applies new seccomp-bpf filters onto itself -- if the filter + denies `openat2(2)` then we would return that error rather than falling back + to the `O_PATH` resolver. To resolve this issue, we no longer cache the + result if `openat2(2)` was successful, only if there was an error. +- A file descriptor leak in our `openat2` wrapper (when doing the necessary + `dup` for `RESOLVE_IN_ROOT`) has been removed. ## [0.5.1] - 2025-10-31 ## @@ -440,8 +398,7 @@ This is our first release of `github.com/cyphar/filepath-securejoin`, containing a full implementation with a coverage of 93.5% (the only missing cases are the error cases, which are hard to mocktest at the moment). -[Unreleased]: https://github.com/cyphar/filepath-securejoin/compare/v0.6.0...HEAD -[0.6.0]: https://github.com/cyphar/filepath-securejoin/compare/v0.5.1...v0.6.0 +[Unreleased 0.5.z]: https://github.com/cyphar/filepath-securejoin/compare/v0.5.1...release-0.5 [0.5.1]: https://github.com/cyphar/filepath-securejoin/compare/v0.5.0...v0.5.1 [0.5.0]: https://github.com/cyphar/filepath-securejoin/compare/v0.4.1...v0.5.0 [0.4.1]: https://github.com/cyphar/filepath-securejoin/compare/v0.4.0...v0.4.1 diff --git a/vendor/github.com/cyphar/filepath-securejoin/VERSION b/vendor/github.com/cyphar/filepath-securejoin/VERSION index a918a2aa18d..cb0c939a936 100644 --- a/vendor/github.com/cyphar/filepath-securejoin/VERSION +++ b/vendor/github.com/cyphar/filepath-securejoin/VERSION @@ -1 +1 @@ -0.6.0 +0.5.2 diff --git a/vendor/github.com/cyphar/filepath-securejoin/deprecated_linux.go b/vendor/github.com/cyphar/filepath-securejoin/deprecated_linux.go new file mode 100644 index 00000000000..3e427b16409 --- /dev/null +++ b/vendor/github.com/cyphar/filepath-securejoin/deprecated_linux.go @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: MPL-2.0 + +//go:build linux + +// Copyright (C) 2024-2025 Aleksa Sarai +// Copyright (C) 2024-2025 SUSE LLC +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at https://mozilla.org/MPL/2.0/. + +package securejoin + +import ( + "github.com/cyphar/filepath-securejoin/pathrs-lite" +) + +var ( + // MkdirAll is a wrapper around [pathrs.MkdirAll]. + // + // Deprecated: You should use [pathrs.MkdirAll] directly instead. This + // wrapper will be removed in filepath-securejoin v0.6. + MkdirAll = pathrs.MkdirAll + + // MkdirAllHandle is a wrapper around [pathrs.MkdirAllHandle]. + // + // Deprecated: You should use [pathrs.MkdirAllHandle] directly instead. + // This wrapper will be removed in filepath-securejoin v0.6. + MkdirAllHandle = pathrs.MkdirAllHandle + + // OpenInRoot is a wrapper around [pathrs.OpenInRoot]. + // + // Deprecated: You should use [pathrs.OpenInRoot] directly instead. This + // wrapper will be removed in filepath-securejoin v0.6. + OpenInRoot = pathrs.OpenInRoot + + // OpenatInRoot is a wrapper around [pathrs.OpenatInRoot]. + // + // Deprecated: You should use [pathrs.OpenatInRoot] directly instead. This + // wrapper will be removed in filepath-securejoin v0.6. + OpenatInRoot = pathrs.OpenatInRoot + + // Reopen is a wrapper around [pathrs.Reopen]. + // + // Deprecated: You should use [pathrs.Reopen] directly instead. This + // wrapper will be removed in filepath-securejoin v0.6. + Reopen = pathrs.Reopen +) diff --git a/vendor/github.com/cyphar/filepath-securejoin/pathrs-lite/README.md b/vendor/github.com/cyphar/filepath-securejoin/pathrs-lite/README.md index bb95b028c67..1be727e75b3 100644 --- a/vendor/github.com/cyphar/filepath-securejoin/pathrs-lite/README.md +++ b/vendor/github.com/cyphar/filepath-securejoin/pathrs-lite/README.md @@ -5,13 +5,11 @@ Go** implementation of the core bits of [libpathrs][]. This is not intended to be a complete replacement for libpathrs, instead it is mainly intended to be useful as a transition tool for existing Go projects. -`pathrs-lite` also provides a very easy way to switch to `libpathrs` (even for -downstreams where `pathrs-lite` is being used in a third-party package and is -not interested in using CGo). At build time, if you use the `libpathrs` build -tag then `pathrs-lite` will use `libpathrs` directly instead of the pure Go -implementation. The two backends are functionally equivalent (and we have -integration tests to verify this), so this migration should be very easy with -no user-visible impact. +The long-term plan for `pathrs-lite` is to provide a build tag that will cause +all `pathrs-lite` operations to call into libpathrs directly, thus removing +code duplication for projects that wish to make use of libpathrs (and providing +the ability for software packagers to opt-in to libpathrs support without +needing to patch upstream). [libpathrs]: https://github.com/cyphar/libpathrs diff --git a/vendor/github.com/cyphar/filepath-securejoin/pathrs-lite/doc.go b/vendor/github.com/cyphar/filepath-securejoin/pathrs-lite/doc.go index 61411da37af..d3d74517500 100644 --- a/vendor/github.com/cyphar/filepath-securejoin/pathrs-lite/doc.go +++ b/vendor/github.com/cyphar/filepath-securejoin/pathrs-lite/doc.go @@ -11,6 +11,4 @@ // Package pathrs (pathrs-lite) is a less complete pure Go implementation of // some of the APIs provided by [libpathrs]. -// -// [libpathrs]: https://github.com/cyphar/libpathrs package pathrs diff --git a/vendor/github.com/cyphar/filepath-securejoin/pathrs-lite/internal/fd/openat2_linux.go b/vendor/github.com/cyphar/filepath-securejoin/pathrs-lite/internal/fd/openat2_linux.go index 3e937fe3c16..63863647d5b 100644 --- a/vendor/github.com/cyphar/filepath-securejoin/pathrs-lite/internal/fd/openat2_linux.go +++ b/vendor/github.com/cyphar/filepath-securejoin/pathrs-lite/internal/fd/openat2_linux.go @@ -39,7 +39,9 @@ const scopedLookupMaxRetries = 128 // Openat2 is an [Fd]-based wrapper around unix.Openat2, but with some retry // logic in case of EAGAIN errors. -func Openat2(dir Fd, path string, how *unix.OpenHow) (*os.File, error) { +// +// NOTE: This is a variable so that the lookup tests can force openat2 to fail. +var Openat2 = func(dir Fd, path string, how *unix.OpenHow) (*os.File, error) { dirFd, fullPath := prepareAt(dir, path) // Make sure we always set O_CLOEXEC. how.Flags |= unix.O_CLOEXEC diff --git a/vendor/github.com/cyphar/filepath-securejoin/pathrs-lite/internal/gocompat/gocompat_atomic_go119.go b/vendor/github.com/cyphar/filepath-securejoin/pathrs-lite/internal/gocompat/gocompat_atomic_go119.go new file mode 100644 index 00000000000..ac93cb045e1 --- /dev/null +++ b/vendor/github.com/cyphar/filepath-securejoin/pathrs-lite/internal/gocompat/gocompat_atomic_go119.go @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: BSD-3-Clause + +//go:build linux && go1.19 + +// Copyright 2022 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 gocompat + +import ( + "sync/atomic" +) + +// A Bool is an atomic boolean value. +// The zero value is false. +// +// Bool must not be copied after first use. +type Bool = atomic.Bool diff --git a/vendor/github.com/cyphar/filepath-securejoin/pathrs-lite/internal/gocompat/gocompat_atomic_unsupported.go b/vendor/github.com/cyphar/filepath-securejoin/pathrs-lite/internal/gocompat/gocompat_atomic_unsupported.go new file mode 100644 index 00000000000..21b5b29ada9 --- /dev/null +++ b/vendor/github.com/cyphar/filepath-securejoin/pathrs-lite/internal/gocompat/gocompat_atomic_unsupported.go @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: BSD-3-Clause + +//go:build linux && !go1.19 + +// Copyright (C) 2024-2025 SUSE LLC. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package gocompat + +import ( + "sync/atomic" +) + +// noCopy may be added to structs which must not be copied +// after the first use. +// +// See https://golang.org/issues/8005#issuecomment-190753527 +// for details. +// +// Note that it must not be embedded, due to the Lock and Unlock methods. +type noCopy struct{} + +// Lock is a no-op used by -copylocks checker from `go vet`. +func (*noCopy) Lock() {} + +// b32 returns a uint32 0 or 1 representing b. +func b32(b bool) uint32 { + if b { + return 1 + } + return 0 +} + +// A Bool is an atomic boolean value. +// The zero value is false. +// +// Bool must not be copied after first use. +type Bool struct { + _ noCopy + v uint32 +} + +// Load atomically loads and returns the value stored in x. +func (x *Bool) Load() bool { return atomic.LoadUint32(&x.v) != 0 } + +// Store atomically stores val into x. +func (x *Bool) Store(val bool) { atomic.StoreUint32(&x.v, b32(val)) } diff --git a/vendor/github.com/cyphar/filepath-securejoin/pathrs-lite/internal/gopathrs/doc.go b/vendor/github.com/cyphar/filepath-securejoin/pathrs-lite/internal/gopathrs/doc.go deleted file mode 100644 index 2ddb71e8445..00000000000 --- a/vendor/github.com/cyphar/filepath-securejoin/pathrs-lite/internal/gopathrs/doc.go +++ /dev/null @@ -1,16 +0,0 @@ -// SPDX-License-Identifier: MPL-2.0 - -//go:build linux - -// Copyright (C) 2024-2025 Aleksa Sarai -// Copyright (C) 2024-2025 SUSE LLC -// -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this -// file, You can obtain one at https://mozilla.org/MPL/2.0/. - -// Package gopathrs is a less complete pure Go implementation of some of the -// APIs provided by [libpathrs]. -// -// [libpathrs]: https://github.com/cyphar/libpathrs -package gopathrs diff --git a/vendor/github.com/cyphar/filepath-securejoin/pathrs-lite/internal/gopathrs/open_linux.go b/vendor/github.com/cyphar/filepath-securejoin/pathrs-lite/internal/gopathrs/open_linux.go deleted file mode 100644 index cd9632a9588..00000000000 --- a/vendor/github.com/cyphar/filepath-securejoin/pathrs-lite/internal/gopathrs/open_linux.go +++ /dev/null @@ -1,26 +0,0 @@ -// SPDX-License-Identifier: MPL-2.0 - -//go:build linux - -// Copyright (C) 2024-2025 Aleksa Sarai -// Copyright (C) 2024-2025 SUSE LLC -// -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this -// file, You can obtain one at https://mozilla.org/MPL/2.0/. - -package gopathrs - -import ( - "os" -) - -// OpenatInRoot is equivalent to [OpenInRoot], except that the root is provided -// using an *[os.File] handle, to ensure that the correct root directory is used. -func OpenatInRoot(root *os.File, unsafePath string) (*os.File, error) { - handle, err := completeLookupInRoot(root, unsafePath) - if err != nil { - return nil, &os.PathError{Op: "securejoin.OpenInRoot", Path: unsafePath, Err: err} - } - return handle, nil -} diff --git a/vendor/github.com/cyphar/filepath-securejoin/pathrs-lite/internal/linux/openat2_linux.go b/vendor/github.com/cyphar/filepath-securejoin/pathrs-lite/internal/linux/openat2_linux.go index 399609dc361..dc5f65cef7f 100644 --- a/vendor/github.com/cyphar/filepath-securejoin/pathrs-lite/internal/linux/openat2_linux.go +++ b/vendor/github.com/cyphar/filepath-securejoin/pathrs-lite/internal/linux/openat2_linux.go @@ -17,15 +17,27 @@ import ( "github.com/cyphar/filepath-securejoin/pathrs-lite/internal/gocompat" ) +// sawOpenat2Error stores whether we have seen an error from HasOpenat2. This +// is a one-way toggle, so as soon as we see an error we "lock" into that mode. +// We cannot use sync.OnceValue to store the success/fail state once because it +// is possible for the program we are running in to apply a seccomp-bpf filter +// and thus disable openat2 during execution. +var sawOpenat2Error gocompat.Bool + // HasOpenat2 returns whether openat2(2) is supported on the running kernel. -var HasOpenat2 = gocompat.SyncOnceValue(func() bool { +var HasOpenat2 = func() bool { + if sawOpenat2Error.Load() { + return false + } + fd, err := unix.Openat2(unix.AT_FDCWD, ".", &unix.OpenHow{ Flags: unix.O_PATH | unix.O_CLOEXEC, Resolve: unix.RESOLVE_NO_SYMLINKS | unix.RESOLVE_IN_ROOT, }) if err != nil { + sawOpenat2Error.Store(true) // doesn't matter if we race here return false } _ = unix.Close(fd) return true -}) +} diff --git a/vendor/github.com/cyphar/filepath-securejoin/pathrs-lite/internal/gopathrs/lookup_linux.go b/vendor/github.com/cyphar/filepath-securejoin/pathrs-lite/lookup_linux.go similarity index 95% rename from vendor/github.com/cyphar/filepath-securejoin/pathrs-lite/internal/gopathrs/lookup_linux.go rename to vendor/github.com/cyphar/filepath-securejoin/pathrs-lite/lookup_linux.go index 56480f0cee1..05d7dbcc119 100644 --- a/vendor/github.com/cyphar/filepath-securejoin/pathrs-lite/internal/gopathrs/lookup_linux.go +++ b/vendor/github.com/cyphar/filepath-securejoin/pathrs-lite/lookup_linux.go @@ -9,7 +9,7 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at https://mozilla.org/MPL/2.0/. -package gopathrs +package pathrs import ( "errors" @@ -166,11 +166,11 @@ func (s *symlinkStack) PopTopSymlink() (*os.File, string, bool) { return tailEntry.dir, tailEntry.remainingPath, true } -// PartialLookupInRoot tries to lookup as much of the request path as possible +// partialLookupInRoot tries to lookup as much of the request path as possible // within the provided root (a-la RESOLVE_IN_ROOT) and opens the final existing // component of the requested path, returning a file handle to the final // existing component and a string containing the remaining path components. -func PartialLookupInRoot(root fd.Fd, unsafePath string) (*os.File, string, error) { +func partialLookupInRoot(root fd.Fd, unsafePath string) (*os.File, string, error) { return lookupInRoot(root, unsafePath, true) } @@ -193,8 +193,13 @@ func lookupInRoot(root fd.Fd, unsafePath string, partial bool) (Handle *os.File, // managed open, along with the remaining path components not opened. // Try to use openat2 if possible. - if linux.HasOpenat2() { - return lookupOpenat2(root, unsafePath, partial) + // + // NOTE: If openat2(2) works normally but fails for this lookup, it is + // probably not a good idea to fall-back to the O_PATH resolver. An + // attacker could find a bug in the O_PATH resolver and uncontionally + // falling back to the O_PATH resolver would form a downgrade attack. + if handle, remainingPath, err := lookupOpenat2(root, unsafePath, partial); err == nil || linux.HasOpenat2() { + return handle, remainingPath, err } // Get the "actual" root path from /proc/self/fd. This is necessary if the diff --git a/vendor/github.com/cyphar/filepath-securejoin/pathrs-lite/mkdir.go b/vendor/github.com/cyphar/filepath-securejoin/pathrs-lite/mkdir.go deleted file mode 100644 index b43169564af..00000000000 --- a/vendor/github.com/cyphar/filepath-securejoin/pathrs-lite/mkdir.go +++ /dev/null @@ -1,55 +0,0 @@ -// SPDX-License-Identifier: MPL-2.0 - -//go:build linux - -// Copyright (C) 2024-2025 Aleksa Sarai -// Copyright (C) 2024-2025 SUSE LLC -// -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this -// file, You can obtain one at https://mozilla.org/MPL/2.0/. - -package pathrs - -import ( - "os" - - "golang.org/x/sys/unix" -) - -// MkdirAll is a race-safe alternative to the [os.MkdirAll] function, -// where the new directory is guaranteed to be within the root directory (if an -// attacker can move directories from inside the root to outside the root, the -// created directory tree might be outside of the root but the key constraint -// is that at no point will we walk outside of the directory tree we are -// creating). -// -// Effectively, MkdirAll(root, unsafePath, mode) is equivalent to -// -// path, _ := securejoin.SecureJoin(root, unsafePath) -// err := os.MkdirAll(path, mode) -// -// But is much safer. The above implementation is unsafe because if an attacker -// can modify the filesystem tree between [SecureJoin] and [os.MkdirAll], it is -// possible for MkdirAll to resolve unsafe symlink components and create -// directories outside of the root. -// -// If you plan to open the directory after you have created it or want to use -// an open directory handle as the root, you should use [MkdirAllHandle] instead. -// This function is a wrapper around [MkdirAllHandle]. -// -// [SecureJoin]: https://pkg.go.dev/github.com/cyphar/filepath-securejoin#SecureJoin -func MkdirAll(root, unsafePath string, mode os.FileMode) error { - rootDir, err := os.OpenFile(root, unix.O_PATH|unix.O_DIRECTORY|unix.O_CLOEXEC, 0) - if err != nil { - return err - } - defer rootDir.Close() //nolint:errcheck // close failures aren't critical here - - f, err := MkdirAllHandle(rootDir, unsafePath, mode) - if err != nil { - return err - } - _ = f.Close() - return nil -} diff --git a/vendor/github.com/cyphar/filepath-securejoin/pathrs-lite/mkdir_libpathrs.go b/vendor/github.com/cyphar/filepath-securejoin/pathrs-lite/mkdir_libpathrs.go deleted file mode 100644 index f864dbc8f38..00000000000 --- a/vendor/github.com/cyphar/filepath-securejoin/pathrs-lite/mkdir_libpathrs.go +++ /dev/null @@ -1,52 +0,0 @@ -// SPDX-License-Identifier: MPL-2.0 - -//go:build libpathrs - -// Copyright (C) 2024-2025 Aleksa Sarai -// Copyright (C) 2024-2025 SUSE LLC -// -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this -// file, You can obtain one at https://mozilla.org/MPL/2.0/. - -package pathrs - -import ( - "os" - - "cyphar.com/go-pathrs" -) - -// MkdirAllHandle is equivalent to [MkdirAll], except that it is safer to use -// in two respects: -// -// - The caller provides the root directory as an *[os.File] (preferably O_PATH) -// handle. This means that the caller can be sure which root directory is -// being used. Note that this can be emulated by using /proc/self/fd/... as -// the root path with [os.MkdirAll]. -// -// - Once all of the directories have been created, an *[os.File] O_PATH handle -// to the directory at unsafePath is returned to the caller. This is done in -// an effectively-race-free way (an attacker would only be able to swap the -// final directory component), which is not possible to emulate with -// [MkdirAll]. -// -// In addition, the returned handle is obtained far more efficiently than doing -// a brand new lookup of unsafePath (such as with [SecureJoin] or openat2) after -// doing [MkdirAll]. If you intend to open the directory after creating it, you -// should use MkdirAllHandle. -// -// [SecureJoin]: https://pkg.go.dev/github.com/cyphar/filepath-securejoin#SecureJoin -func MkdirAllHandle(root *os.File, unsafePath string, mode os.FileMode) (*os.File, error) { - rootRef, err := pathrs.RootFromFile(root) - if err != nil { - return nil, err - } - defer rootRef.Close() //nolint:errcheck // close failures aren't critical here - - handle, err := rootRef.MkdirAll(unsafePath, mode) - if err != nil { - return nil, err - } - return handle.IntoFile(), nil -} diff --git a/vendor/github.com/cyphar/filepath-securejoin/pathrs-lite/internal/gopathrs/mkdir_linux.go b/vendor/github.com/cyphar/filepath-securejoin/pathrs-lite/mkdir_linux.go similarity index 81% rename from vendor/github.com/cyphar/filepath-securejoin/pathrs-lite/internal/gopathrs/mkdir_linux.go rename to vendor/github.com/cyphar/filepath-securejoin/pathrs-lite/mkdir_linux.go index 21a5593f44f..f3c62b0dac6 100644 --- a/vendor/github.com/cyphar/filepath-securejoin/pathrs-lite/internal/gopathrs/mkdir_linux.go +++ b/vendor/github.com/cyphar/filepath-securejoin/pathrs-lite/mkdir_linux.go @@ -9,7 +9,7 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at https://mozilla.org/MPL/2.0/. -package gopathrs +package pathrs import ( "errors" @@ -23,12 +23,9 @@ import ( "github.com/cyphar/filepath-securejoin/pathrs-lite/internal/fd" "github.com/cyphar/filepath-securejoin/pathrs-lite/internal/gocompat" "github.com/cyphar/filepath-securejoin/pathrs-lite/internal/linux" - "github.com/cyphar/filepath-securejoin/pathrs-lite/internal/procfs" ) -// ErrInvalidMode is returned from [MkdirAll] when the requested mode is -// invalid. -var ErrInvalidMode = errors.New("invalid permission mode") +var errInvalidMode = errors.New("invalid permission mode") // modePermExt is like os.ModePerm except that it also includes the set[ug]id // and sticky bits. @@ -48,11 +45,11 @@ func toUnixMode(mode os.FileMode) (uint32, error) { } // We don't allow file type bits. if mode&os.ModeType != 0 { - return 0, fmt.Errorf("%w %+.3o (%s): type bits not permitted", ErrInvalidMode, mode, mode) + return 0, fmt.Errorf("%w %+.3o (%s): type bits not permitted", errInvalidMode, mode, mode) } // We don't allow other unknown modes. if mode&^modePermExt != 0 || sysMode&unix.S_IFMT != 0 { - return 0, fmt.Errorf("%w %+.3o (%s): unknown mode bits", ErrInvalidMode, mode, mode) + return 0, fmt.Errorf("%w %+.3o (%s): unknown mode bits", errInvalidMode, mode, mode) } return sysMode, nil } @@ -87,11 +84,11 @@ func MkdirAllHandle(root *os.File, unsafePath string, mode os.FileMode) (_ *os.F // users it seems more prudent to return an error so users notice that // these bits will not be set. if unixMode&^0o1777 != 0 { - return nil, fmt.Errorf("%w for mkdir %+.3o: suid and sgid are ignored by mkdir", ErrInvalidMode, mode) + return nil, fmt.Errorf("%w for mkdir %+.3o: suid and sgid are ignored by mkdir", errInvalidMode, mode) } // Try to open as much of the path as possible. - currentDir, remainingPath, err := PartialLookupInRoot(root, unsafePath) + currentDir, remainingPath, err := partialLookupInRoot(root, unsafePath) defer func() { if Err != nil { _ = currentDir.Close() @@ -120,7 +117,7 @@ func MkdirAllHandle(root *os.File, unsafePath string, mode os.FileMode) (_ *os.F // Re-open the path to match the O_DIRECTORY reopen loop later (so that we // always return a non-O_PATH handle). We also check that we actually got a // directory. - if reopenDir, err := procfs.ReopenFd(currentDir, unix.O_DIRECTORY|unix.O_CLOEXEC); errors.Is(err, unix.ENOTDIR) { + if reopenDir, err := Reopen(currentDir, unix.O_DIRECTORY|unix.O_CLOEXEC); errors.Is(err, unix.ENOTDIR) { return nil, fmt.Errorf("cannot create subdirectories in %q: %w", currentDir.Name(), unix.ENOTDIR) } else if err != nil { return nil, fmt.Errorf("re-opening handle to %q: %w", currentDir.Name(), err) @@ -210,3 +207,40 @@ func MkdirAllHandle(root *os.File, unsafePath string, mode os.FileMode) (_ *os.F } return currentDir, nil } + +// MkdirAll is a race-safe alternative to the [os.MkdirAll] function, +// where the new directory is guaranteed to be within the root directory (if an +// attacker can move directories from inside the root to outside the root, the +// created directory tree might be outside of the root but the key constraint +// is that at no point will we walk outside of the directory tree we are +// creating). +// +// Effectively, MkdirAll(root, unsafePath, mode) is equivalent to +// +// path, _ := securejoin.SecureJoin(root, unsafePath) +// err := os.MkdirAll(path, mode) +// +// But is much safer. The above implementation is unsafe because if an attacker +// can modify the filesystem tree between [SecureJoin] and [os.MkdirAll], it is +// possible for MkdirAll to resolve unsafe symlink components and create +// directories outside of the root. +// +// If you plan to open the directory after you have created it or want to use +// an open directory handle as the root, you should use [MkdirAllHandle] instead. +// This function is a wrapper around [MkdirAllHandle]. +// +// [SecureJoin]: https://pkg.go.dev/github.com/cyphar/filepath-securejoin#SecureJoin +func MkdirAll(root, unsafePath string, mode os.FileMode) error { + rootDir, err := os.OpenFile(root, unix.O_PATH|unix.O_DIRECTORY|unix.O_CLOEXEC, 0) + if err != nil { + return err + } + defer rootDir.Close() //nolint:errcheck // close failures aren't critical here + + f, err := MkdirAllHandle(rootDir, unsafePath, mode) + if err != nil { + return err + } + _ = f.Close() + return nil +} diff --git a/vendor/github.com/cyphar/filepath-securejoin/pathrs-lite/mkdir_purego.go b/vendor/github.com/cyphar/filepath-securejoin/pathrs-lite/mkdir_purego.go deleted file mode 100644 index 0369dfe7e66..00000000000 --- a/vendor/github.com/cyphar/filepath-securejoin/pathrs-lite/mkdir_purego.go +++ /dev/null @@ -1,42 +0,0 @@ -// SPDX-License-Identifier: MPL-2.0 - -//go:build linux && !libpathrs - -// Copyright (C) 2024-2025 Aleksa Sarai -// Copyright (C) 2024-2025 SUSE LLC -// -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this -// file, You can obtain one at https://mozilla.org/MPL/2.0/. - -package pathrs - -import ( - "os" - - "github.com/cyphar/filepath-securejoin/pathrs-lite/internal/gopathrs" -) - -// MkdirAllHandle is equivalent to [MkdirAll], except that it is safer to use -// in two respects: -// -// - The caller provides the root directory as an *[os.File] (preferably O_PATH) -// handle. This means that the caller can be sure which root directory is -// being used. Note that this can be emulated by using /proc/self/fd/... as -// the root path with [os.MkdirAll]. -// -// - Once all of the directories have been created, an *[os.File] O_PATH handle -// to the directory at unsafePath is returned to the caller. This is done in -// an effectively-race-free way (an attacker would only be able to swap the -// final directory component), which is not possible to emulate with -// [MkdirAll]. -// -// In addition, the returned handle is obtained far more efficiently than doing -// a brand new lookup of unsafePath (such as with [SecureJoin] or openat2) after -// doing [MkdirAll]. If you intend to open the directory after creating it, you -// should use MkdirAllHandle. -// -// [SecureJoin]: https://pkg.go.dev/github.com/cyphar/filepath-securejoin#SecureJoin -func MkdirAllHandle(root *os.File, unsafePath string, mode os.FileMode) (*os.File, error) { - return gopathrs.MkdirAllHandle(root, unsafePath, mode) -} diff --git a/vendor/github.com/cyphar/filepath-securejoin/pathrs-lite/open_libpathrs.go b/vendor/github.com/cyphar/filepath-securejoin/pathrs-lite/open_libpathrs.go deleted file mode 100644 index 53352000e61..00000000000 --- a/vendor/github.com/cyphar/filepath-securejoin/pathrs-lite/open_libpathrs.go +++ /dev/null @@ -1,57 +0,0 @@ -// SPDX-License-Identifier: MPL-2.0 - -//go:build libpathrs - -// Copyright (C) 2024-2025 Aleksa Sarai -// Copyright (C) 2024-2025 SUSE LLC -// -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this -// file, You can obtain one at https://mozilla.org/MPL/2.0/. - -package pathrs - -import ( - "os" - - "cyphar.com/go-pathrs" -) - -// OpenatInRoot is equivalent to [OpenInRoot], except that the root is provided -// using an *[os.File] handle, to ensure that the correct root directory is used. -func OpenatInRoot(root *os.File, unsafePath string) (*os.File, error) { - rootRef, err := pathrs.RootFromFile(root) - if err != nil { - return nil, err - } - defer rootRef.Close() //nolint:errcheck // close failures aren't critical here - - handle, err := rootRef.Resolve(unsafePath) - if err != nil { - return nil, err - } - return handle.IntoFile(), nil -} - -// Reopen takes an *[os.File] handle and re-opens it through /proc/self/fd. -// Reopen(file, flags) is effectively equivalent to -// -// fdPath := fmt.Sprintf("/proc/self/fd/%d", file.Fd()) -// os.OpenFile(fdPath, flags|unix.O_CLOEXEC) -// -// But with some extra hardenings to ensure that we are not tricked by a -// maliciously-configured /proc mount. While this attack scenario is not -// common, in container runtimes it is possible for higher-level runtimes to be -// tricked into configuring an unsafe /proc that can be used to attack file -// operations. See [CVE-2019-19921] for more details. -// -// [CVE-2019-19921]: https://github.com/advisories/GHSA-fh74-hm69-rqjw -func Reopen(file *os.File, flags int) (*os.File, error) { - handle, err := pathrs.HandleFromFile(file) - if err != nil { - return nil, err - } - defer handle.Close() //nolint:errcheck // close failures aren't critical here - - return handle.OpenFile(flags) -} diff --git a/vendor/github.com/cyphar/filepath-securejoin/pathrs-lite/open.go b/vendor/github.com/cyphar/filepath-securejoin/pathrs-lite/open_linux.go similarity index 57% rename from vendor/github.com/cyphar/filepath-securejoin/pathrs-lite/open.go rename to vendor/github.com/cyphar/filepath-securejoin/pathrs-lite/open_linux.go index 41b628907e1..7492d8cfa06 100644 --- a/vendor/github.com/cyphar/filepath-securejoin/pathrs-lite/open.go +++ b/vendor/github.com/cyphar/filepath-securejoin/pathrs-lite/open_linux.go @@ -15,8 +15,20 @@ import ( "os" "golang.org/x/sys/unix" + + "github.com/cyphar/filepath-securejoin/pathrs-lite/internal/procfs" ) +// OpenatInRoot is equivalent to [OpenInRoot], except that the root is provided +// using an *[os.File] handle, to ensure that the correct root directory is used. +func OpenatInRoot(root *os.File, unsafePath string) (*os.File, error) { + handle, err := completeLookupInRoot(root, unsafePath) + if err != nil { + return nil, &os.PathError{Op: "securejoin.OpenInRoot", Path: unsafePath, Err: err} + } + return handle, nil +} + // OpenInRoot safely opens the provided unsafePath within the root. // Effectively, OpenInRoot(root, unsafePath) is equivalent to // @@ -43,3 +55,20 @@ func OpenInRoot(root, unsafePath string) (*os.File, error) { defer rootDir.Close() //nolint:errcheck // close failures aren't critical here return OpenatInRoot(rootDir, unsafePath) } + +// Reopen takes an *[os.File] handle and re-opens it through /proc/self/fd. +// Reopen(file, flags) is effectively equivalent to +// +// fdPath := fmt.Sprintf("/proc/self/fd/%d", file.Fd()) +// os.OpenFile(fdPath, flags|unix.O_CLOEXEC) +// +// But with some extra hardenings to ensure that we are not tricked by a +// maliciously-configured /proc mount. While this attack scenario is not +// common, in container runtimes it is possible for higher-level runtimes to be +// tricked into configuring an unsafe /proc that can be used to attack file +// operations. See [CVE-2019-19921] for more details. +// +// [CVE-2019-19921]: https://github.com/advisories/GHSA-fh74-hm69-rqjw +func Reopen(handle *os.File, flags int) (*os.File, error) { + return procfs.ReopenFd(handle, flags) +} diff --git a/vendor/github.com/cyphar/filepath-securejoin/pathrs-lite/open_purego.go b/vendor/github.com/cyphar/filepath-securejoin/pathrs-lite/open_purego.go deleted file mode 100644 index 6d1be12ce5d..00000000000 --- a/vendor/github.com/cyphar/filepath-securejoin/pathrs-lite/open_purego.go +++ /dev/null @@ -1,42 +0,0 @@ -// SPDX-License-Identifier: MPL-2.0 - -//go:build linux && !libpathrs - -// Copyright (C) 2024-2025 Aleksa Sarai -// Copyright (C) 2024-2025 SUSE LLC -// -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this -// file, You can obtain one at https://mozilla.org/MPL/2.0/. - -package pathrs - -import ( - "os" - - "github.com/cyphar/filepath-securejoin/pathrs-lite/internal/gopathrs" - "github.com/cyphar/filepath-securejoin/pathrs-lite/internal/procfs" -) - -// OpenatInRoot is equivalent to [OpenInRoot], except that the root is provided -// using an *[os.File] handle, to ensure that the correct root directory is used. -func OpenatInRoot(root *os.File, unsafePath string) (*os.File, error) { - return gopathrs.OpenatInRoot(root, unsafePath) -} - -// Reopen takes an *[os.File] handle and re-opens it through /proc/self/fd. -// Reopen(file, flags) is effectively equivalent to -// -// fdPath := fmt.Sprintf("/proc/self/fd/%d", file.Fd()) -// os.OpenFile(fdPath, flags|unix.O_CLOEXEC) -// -// But with some extra hardenings to ensure that we are not tricked by a -// maliciously-configured /proc mount. While this attack scenario is not -// common, in container runtimes it is possible for higher-level runtimes to be -// tricked into configuring an unsafe /proc that can be used to attack file -// operations. See [CVE-2019-19921] for more details. -// -// [CVE-2019-19921]: https://github.com/advisories/GHSA-fh74-hm69-rqjw -func Reopen(handle *os.File, flags int) (*os.File, error) { - return procfs.ReopenFd(handle, flags) -} diff --git a/vendor/github.com/cyphar/filepath-securejoin/pathrs-lite/internal/gopathrs/openat2_linux.go b/vendor/github.com/cyphar/filepath-securejoin/pathrs-lite/openat2_linux.go similarity index 98% rename from vendor/github.com/cyphar/filepath-securejoin/pathrs-lite/internal/gopathrs/openat2_linux.go rename to vendor/github.com/cyphar/filepath-securejoin/pathrs-lite/openat2_linux.go index b80ecd08953..dbbb88c23f6 100644 --- a/vendor/github.com/cyphar/filepath-securejoin/pathrs-lite/internal/gopathrs/openat2_linux.go +++ b/vendor/github.com/cyphar/filepath-securejoin/pathrs-lite/openat2_linux.go @@ -9,7 +9,7 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at https://mozilla.org/MPL/2.0/. -package gopathrs +package pathrs import ( "errors" @@ -41,6 +41,7 @@ func openat2(dir fd.Fd, path string, how *unix.OpenHow) (*os.File, error) { if err != nil { return nil, err } + _ = file.Close() file = newFile } } diff --git a/vendor/github.com/cyphar/filepath-securejoin/pathrs-lite/procfs/procfs_libpathrs.go b/vendor/github.com/cyphar/filepath-securejoin/pathrs-lite/procfs/procfs_libpathrs.go deleted file mode 100644 index 6c4df3763bb..00000000000 --- a/vendor/github.com/cyphar/filepath-securejoin/pathrs-lite/procfs/procfs_libpathrs.go +++ /dev/null @@ -1,161 +0,0 @@ -// SPDX-License-Identifier: MPL-2.0 - -//go:build libpathrs - -// Copyright (C) 2024-2025 Aleksa Sarai -// Copyright (C) 2024-2025 SUSE LLC -// -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this -// file, You can obtain one at https://mozilla.org/MPL/2.0/. - -// Package procfs provides a safe API for operating on /proc on Linux. -package procfs - -import ( - "os" - "strconv" - - "cyphar.com/go-pathrs/procfs" - "golang.org/x/sys/unix" -) - -// ProcThreadSelfCloser is a callback that needs to be called when you are done -// operating on an [os.File] fetched using [Handle.OpenThreadSelf]. -// -// [os.File]: https://pkg.go.dev/os#File -type ProcThreadSelfCloser = procfs.ThreadCloser - -// Handle is a wrapper around an *os.File handle to "/proc", which can be used -// to do further procfs-related operations in a safe way. -type Handle struct { - inner *procfs.Handle -} - -// Close close the resources associated with this [Handle]. Note that if this -// [Handle] was created with [OpenProcRoot], on some kernels the underlying -// procfs handle is cached and so this Close operation may be a no-op. However, -// you should always call Close on [Handle]s once you are done with them. -func (proc *Handle) Close() error { return proc.inner.Close() } - -// OpenProcRoot tries to open a "safer" handle to "/proc" (i.e., one with the -// "subset=pid" mount option applied, available from Linux 5.8). Unless you -// plan to do many [Handle.OpenRoot] operations, users should prefer to use -// this over [OpenUnsafeProcRoot] which is far more dangerous to keep open. -// -// If a safe handle cannot be opened, OpenProcRoot will fall back to opening a -// regular "/proc" handle. -// -// Note that using [Handle.OpenRoot] will still work with handles returned by -// this function. If a subpath cannot be operated on with a safe "/proc" -// handle, then [OpenUnsafeProcRoot] will be called internally and a temporary -// unsafe handle will be used. -func OpenProcRoot() (*Handle, error) { - proc, err := procfs.Open() - if err != nil { - return nil, err - } - return &Handle{inner: proc}, nil -} - -// OpenUnsafeProcRoot opens a handle to "/proc" without any overmounts or -// masked paths. You must be extremely careful to make sure this handle is -// never leaked to a container and that you program cannot be tricked into -// writing to arbitrary paths within it. -// -// This is not necessary if you just wish to use [Handle.OpenRoot], as handles -// returned by [OpenProcRoot] will fall back to using a *temporary* unsafe -// handle in that case. You should only really use this if you need to do many -// operations with [Handle.OpenRoot] and the performance overhead of making -// many procfs handles is an issue. If you do use OpenUnsafeProcRoot, you -// should make sure to close the handle as soon as possible to avoid -// known-fd-number attacks. -func OpenUnsafeProcRoot() (*Handle, error) { - proc, err := procfs.Open(procfs.UnmaskedProcRoot) - if err != nil { - return nil, err - } - return &Handle{inner: proc}, nil -} - -// OpenThreadSelf returns a handle to "/proc/thread-self/" (or an -// equivalent handle on older kernels where "/proc/thread-self" doesn't exist). -// Once finished with the handle, you must call the returned closer function -// ([runtime.UnlockOSThread]). You must not pass the returned *os.File to other -// Go threads or use the handle after calling the closer. -// -// [runtime.UnlockOSThread]: https://pkg.go.dev/runtime#UnlockOSThread -func (proc *Handle) OpenThreadSelf(subpath string) (*os.File, ProcThreadSelfCloser, error) { - return proc.inner.OpenThreadSelf(subpath, unix.O_PATH|unix.O_NOFOLLOW) -} - -// OpenSelf returns a handle to /proc/self/. -// -// Note that in Go programs with non-homogenous threads, this may result in -// spurious errors. If you are monkeying around with APIs that are -// thread-specific, you probably want to use [Handle.OpenThreadSelf] instead -// which will guarantee that the handle refers to the same thread as the caller -// is executing on. -func (proc *Handle) OpenSelf(subpath string) (*os.File, error) { - return proc.inner.OpenSelf(subpath, unix.O_PATH|unix.O_NOFOLLOW) -} - -// OpenRoot returns a handle to /proc/. -// -// You should only use this when you need to operate on global procfs files -// (such as sysctls in /proc/sys). Unlike [Handle.OpenThreadSelf], -// [Handle.OpenSelf], and [Handle.OpenPid], the procfs handle used internally -// for this operation will never use "subset=pid", which makes it a more juicy -// target for [CVE-2024-21626]-style attacks (and doing something like opening -// a directory with OpenRoot effectively leaks [OpenUnsafeProcRoot] as long as -// the file descriptor is open). -// -// [CVE-2024-21626]: https://github.com/opencontainers/runc/security/advisories/GHSA-xr7r-f8xq-vfvv -func (proc *Handle) OpenRoot(subpath string) (*os.File, error) { - return proc.inner.OpenRoot(subpath, unix.O_PATH|unix.O_NOFOLLOW) -} - -// OpenPid returns a handle to /proc/$pid/ (pid can be a pid or tid). -// This is mainly intended for usage when operating on other processes. -// -// You should not use this for the current thread, as special handling is -// needed for /proc/thread-self (or /proc/self/task/) when dealing with -// goroutine scheduling -- use [Handle.OpenThreadSelf] instead. -// -// To refer to the current thread-group, you should use prefer -// [Handle.OpenSelf] to passing os.Getpid as the pid argument. -func (proc *Handle) OpenPid(pid int, subpath string) (*os.File, error) { - return proc.inner.OpenPid(pid, subpath, unix.O_PATH|unix.O_NOFOLLOW) -} - -// ProcSelfFdReadlink gets the real path of the given file by looking at -// /proc/self/fd/ with [readlink]. It is effectively just shorthand for -// something along the lines of: -// -// proc, err := procfs.OpenProcRoot() -// if err != nil { -// return err -// } -// link, err := proc.OpenThreadSelf(fmt.Sprintf("fd/%d", f.Fd())) -// if err != nil { -// return err -// } -// defer link.Close() -// var buf [4096]byte -// n, err := unix.Readlinkat(int(link.Fd()), "", buf[:]) -// if err != nil { -// return err -// } -// pathname := buf[:n] -// -// [readlink]: https://pkg.go.dev/golang.org/x/sys/unix#Readlinkat -func ProcSelfFdReadlink(f *os.File) (string, error) { - proc, err := procfs.Open() - if err != nil { - return "", err - } - defer proc.Close() //nolint:errcheck // close failures aren't critical here - - fdPath := "fd/" + strconv.Itoa(int(f.Fd())) - return proc.Readlink(procfs.ProcThreadSelf, fdPath) -} diff --git a/vendor/github.com/cyphar/filepath-securejoin/pathrs-lite/procfs/procfs_purego.go b/vendor/github.com/cyphar/filepath-securejoin/pathrs-lite/procfs/procfs_linux.go similarity index 99% rename from vendor/github.com/cyphar/filepath-securejoin/pathrs-lite/procfs/procfs_purego.go rename to vendor/github.com/cyphar/filepath-securejoin/pathrs-lite/procfs/procfs_linux.go index 9383002f9a9..ec187a414c5 100644 --- a/vendor/github.com/cyphar/filepath-securejoin/pathrs-lite/procfs/procfs_purego.go +++ b/vendor/github.com/cyphar/filepath-securejoin/pathrs-lite/procfs/procfs_linux.go @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MPL-2.0 -//go:build linux && !libpathrs +//go:build linux // Copyright (C) 2024-2025 Aleksa Sarai // Copyright (C) 2024-2025 SUSE LLC diff --git a/vendor/modules.txt b/vendor/modules.txt index b3090c77d47..038856580a2 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -1,9 +1,3 @@ -# cyphar.com/go-pathrs v0.2.1 -## explicit; go 1.18 -cyphar.com/go-pathrs -cyphar.com/go-pathrs/internal/fdutils -cyphar.com/go-pathrs/internal/libpathrs -cyphar.com/go-pathrs/procfs # github.com/checkpoint-restore/go-criu/v6 v6.3.0 ## explicit; go 1.16 github.com/checkpoint-restore/go-criu/v6 @@ -33,7 +27,7 @@ github.com/coreos/go-systemd/v22/dbus # github.com/cpuguy83/go-md2man/v2 v2.0.5 ## explicit; go 1.11 github.com/cpuguy83/go-md2man/v2/md2man -# github.com/cyphar/filepath-securejoin v0.6.0 +# github.com/cyphar/filepath-securejoin v0.5.2 ## explicit; go 1.18 github.com/cyphar/filepath-securejoin github.com/cyphar/filepath-securejoin/internal/consts @@ -42,7 +36,6 @@ github.com/cyphar/filepath-securejoin/pathrs-lite/internal github.com/cyphar/filepath-securejoin/pathrs-lite/internal/assert github.com/cyphar/filepath-securejoin/pathrs-lite/internal/fd github.com/cyphar/filepath-securejoin/pathrs-lite/internal/gocompat -github.com/cyphar/filepath-securejoin/pathrs-lite/internal/gopathrs github.com/cyphar/filepath-securejoin/pathrs-lite/internal/kernelversion github.com/cyphar/filepath-securejoin/pathrs-lite/internal/linux github.com/cyphar/filepath-securejoin/pathrs-lite/internal/procfs @@ -83,7 +76,7 @@ github.com/opencontainers/cgroups/systemd ## explicit github.com/opencontainers/runtime-spec/specs-go github.com/opencontainers/runtime-spec/specs-go/features -# github.com/opencontainers/selinux v1.13.0 +# github.com/opencontainers/selinux v1.13.1 ## explicit; go 1.19 github.com/opencontainers/selinux/go-selinux github.com/opencontainers/selinux/go-selinux/label