From 7b6b630925963290012f13872288124b00a9d96b Mon Sep 17 00:00:00 2001 From: Tonis Tiigi Date: Mon, 10 Aug 2026 15:46:15 +0300 Subject: [PATCH 1/6] bake: enforce entitlements for rawjson progress Reject rawjson bake builds when required entitlements have not been granted. Signed-off-by: Tonis Tiigi (cherry picked from commit 8e78175d68ccc0d76c5294649527839b24e90510) --- bake/entitlements.go | 21 +++++++++++++-- bake/entitlements_test.go | 56 +++++++++++++++++++++++++++++++++++++++ commands/bake.go | 4 +-- tests/bake.go | 43 ++++++++++++++++++++++++++++++ 4 files changed, 120 insertions(+), 4 deletions(-) diff --git a/bake/entitlements.go b/bake/entitlements.go index b42ba1ab7bb9..c23cc85194aa 100644 --- a/bake/entitlements.go +++ b/bake/entitlements.go @@ -231,9 +231,19 @@ func (c EntitlementConf) check(bo build.Options, expected *EntitlementConf) erro } func (c EntitlementConf) Prompt(ctx context.Context, isRemote bool, out io.Writer) error { + return c.prompt(ctx, isRemote, out, true) +} + +func (c EntitlementConf) Check(isRemote bool) error { + return c.prompt(context.Background(), isRemote, io.Discard, false) +} + +func (c EntitlementConf) prompt(ctx context.Context, isRemote bool, out io.Writer, interactive bool) error { var term bool - if _, err := console.ConsoleFromFile(os.Stdin); err == nil { - term = true + if interactive { + if _, err := console.ConsoleFromFile(os.Stdin); err == nil { + term = true + } } var msgs []string @@ -365,6 +375,13 @@ func (c EntitlementConf) Prompt(ctx context.Context, isRemote bool, out io.Write if fsEntitlementsEnabled && !fsEntitlementsSet && len(msgsFS) != 0 { fmt.Fprintf(out, "To disable filesystem entitlements checks, you can set BUILDX_BAKE_ENTITLEMENTS_FS=0 .\n\n") } + if !interactive { + requiredFlags := flags + if fsEntitlementsEnabled { + requiredFlags = slices.Concat(requiredFlags, flagsFS) + } + return errors.Errorf("additional privileges requested: pass %q to grant requested privileges", strings.Join(requiredFlags, " ")) + } if term { fmt.Fprintf(out, "Do you want to grant requested privileges and continue? [y/N] ") diff --git a/bake/entitlements_test.go b/bake/entitlements_test.go index d1f67fe43362..11561547343f 100644 --- a/bake/entitlements_test.go +++ b/bake/entitlements_test.go @@ -7,6 +7,7 @@ import ( "os" "path/filepath" "slices" + "strings" "testing" "github.com/docker/buildx/build" @@ -441,6 +442,61 @@ func TestPromptLocalOutputDeleteCannotBeDisabledWithFSEntitlements(t *testing.T) require.Contains(t, out.String(), "--allow=buildx.local.delete") } +func TestCheckEntitlements(t *testing.T) { + t.Run("all entitlement types", func(t *testing.T) { + t.Setenv("BUILDX_BAKE_ENTITLEMENTS_FS", "1") + + err := EntitlementConf{ + NetworkHost: true, + SecurityInsecure: true, + Devices: &EntitlementsDevicesConf{ + Devices: map[string]struct{}{"vendor.com/device=foo": {}}, + }, + FSRead: []string{t.TempDir()}, + FSWrite: []string{t.TempDir()}, + SSH: true, + LocalOutputDelete: true, + }.Check(false) + require.Error(t, err) + require.True(t, strings.HasPrefix(err.Error(), `additional privileges requested: pass "`), err.Error()) + for _, flag := range []string{ + "--allow=network.host", + "--allow=security.insecure", + "--allow=device=vendor.com/device=foo", + "--allow=fs.read=", + "--allow=fs.write=", + "--allow=ssh", + "--allow=buildx.local.delete", + } { + require.ErrorContains(t, err, flag) + } + }) + + t.Run("filesystem checks disabled", func(t *testing.T) { + t.Setenv("BUILDX_BAKE_ENTITLEMENTS_FS", "0") + + err := EntitlementConf{ + FSRead: []string{t.TempDir()}, + FSWrite: []string{t.TempDir()}, + SSH: true, + }.Check(false) + require.NoError(t, err) + }) + + t.Run("filesystem setting does not disable other checks", func(t *testing.T) { + t.Setenv("BUILDX_BAKE_ENTITLEMENTS_FS", "0") + + err := EntitlementConf{ + NetworkHost: true, + FSRead: []string{t.TempDir()}, + SSH: true, + }.Check(false) + require.ErrorContains(t, err, "--allow=network.host") + require.NotContains(t, err.Error(), "--allow=fs.read=") + require.NotContains(t, err.Error(), "--allow=ssh") + }) +} + func TestGroupSamePaths(t *testing.T) { tests := []struct { name string diff --git a/commands/bake.go b/commands/bake.go index 2924177f24d0..ff03f4fd6b43 100644 --- a/commands/bake.go +++ b/commands/bake.go @@ -341,8 +341,8 @@ func runBake(ctx context.Context, dockerCli command.Cli, targets []string, in ba return err } if progressMode == progressui.RawJSONMode { - if exp.LocalOutputDelete { - return errors.Errorf("additional privileges requested: pass %q to grant requested privileges", "--allow="+string(bake.EntitlementKeyBuildxLocalDelete)) + if err := exp.Check(url != ""); err != nil { + return err } } else { if err := exp.Prompt(ctx, url != "", &syncWriter{w: dockerCli.Err(), wait: printer.Wait}); err != nil { diff --git a/tests/bake.go b/tests/bake.go index 279bc3c1143e..fab9f018a9cb 100644 --- a/tests/bake.go +++ b/tests/bake.go @@ -69,6 +69,7 @@ var bakeTests = []func(t *testing.T, sb integration.Sandbox){ testBakeDefinitionNotExistingSubdirNoParallel, testBakeDefinitionNotExistingOutsideNoParallel, testBakeDefinitionExistingOutsideNoParallel, + testBakeRawJSONEntitlementsNoParallel, testBakeDefinitionSymlinkOutsideNoParallel, testBakeDefinitionSymlinkOutsideGrantedNoParallel, testBakeSSHPathNoParallel, @@ -1853,6 +1854,48 @@ target "default" { } } +func testBakeRawJSONEntitlementsNoParallel(t *testing.T, sb integration.Sandbox) { + t.Setenv("BUILDX_BAKE_ENTITLEMENTS_FS", "1") + dockerfile := []byte(` +FROM scratch +COPY foo /foo + `) + dirSrc := tmpdir( + t, + fstest.CreateFile("Dockerfile", dockerfile, 0600), + fstest.CreateFile("foo", []byte("foo"), 0600), + ) + dirDest := t.TempDir() + bakefile := fmt.Appendf(nil, ` +target "default" { + context = %q + output = ["type=local,dest=%s"] +} +`, dirSrc, dirDest) + dirSpec := tmpdir( + t, + fstest.CreateFile("docker-bake.hcl", bakefile, 0600), + ) + + cmd := buildxCmd(sb, withDir(dirSpec), withArgs("bake", "--progress=rawjson")) + out, err := cmd.CombinedOutput() + require.Error(t, err, string(out)) + require.Contains(t, string(out), "additional privileges requested") + require.Contains(t, string(out), "--allow=fs.read=") + require.Contains(t, string(out), "--allow=fs.write=") + require.NoFileExists(t, filepath.Join(dirDest, "foo")) + + cmd = buildxCmd(sb, withDir(dirSpec), withArgs( + "bake", + "--progress=rawjson", + "--allow=fs.read="+dirSrc, + "--allow=fs.write="+dirDest, + )) + out, err = cmd.CombinedOutput() + require.NoError(t, err, string(out)) + require.FileExists(t, filepath.Join(dirDest, "foo")) +} + func testBakeDefinitionSymlinkOutsideNoParallel(t *testing.T, sb integration.Sandbox) { for _, ent := range []bool{true, false} { t.Run(fmt.Sprintf("ent=%v", ent), func(t *testing.T) { From 69a8e58c7dee280c07caafbed5ff838ec259dd55 Mon Sep 17 00:00:00 2001 From: Tonis Tiigi Date: Tue, 29 Sep 2026 23:06:33 -0700 Subject: [PATCH 2/6] bake: require fs.read for implicit secret files and oci-layout contexts A secret with only an id falls back to reading the file named by the id when no environment variable with that name exists, but the entitlement check only looked at an explicit src. Resolve the source the same way BuildKit does so the implicit file read needs fs.read permission. Named contexts using oci-layout:// were treated as relative paths and resolved under the working directory, so any layout directory was allowed. Parse the reference and check the actual layout path instead. Signed-off-by: Tonis Tiigi (cherry picked from commit f7979d8a5b2e363129ef9850950cce0c5c87c031) --- bake/bake.go | 12 +++++-- bake/entitlements.go | 11 +++--- bake/entitlements_test.go | 71 ++++++++++++++++++++++++++++++++++++++ util/buildflags/secrets.go | 15 ++++++++ 4 files changed, 103 insertions(+), 6 deletions(-) diff --git a/bake/bake.go b/bake/bake.go index 290e8670d590..30eac7bc72b6 100644 --- a/bake/bake.go +++ b/bake/bake.go @@ -23,6 +23,7 @@ import ( "github.com/docker/buildx/bake/hclparser" "github.com/docker/buildx/build" "github.com/docker/buildx/util/buildflags" + "github.com/docker/buildx/util/ocilayout" "github.com/docker/buildx/util/osutil" "github.com/docker/buildx/util/platformutil" "github.com/docker/buildx/util/progress" @@ -1614,7 +1615,7 @@ func remoteURLWithSubdir(remoteURL, subdir string) string { return base + "#" + ref + ":" + subdir } -func collectLocalPaths(t build.Inputs) []string { +func collectLocalPaths(t build.Inputs) ([]string, error) { var out []string if t.ContextState == nil { if v, ok := isLocalPath(t.ContextPath); ok { @@ -1630,11 +1631,18 @@ func collectLocalPaths(t build.Inputs) []string { if v.State != nil { continue } + if ref, ok, err := ocilayout.Parse(v.Path); ok { + if err != nil { + return nil, errors.Wrapf(err, "invalid OCI layout context %q", v.Path) + } + out = append(out, ref.Path) + continue + } if v, ok := isLocalPath(v.Path); ok { out = append(out, v) } } - return out + return out, nil } func isLocalPath(p string) (string, bool) { diff --git a/bake/entitlements.go b/bake/entitlements.go index c23cc85194aa..43ad6c82f84b 100644 --- a/bake/entitlements.go +++ b/bake/entitlements.go @@ -162,7 +162,11 @@ func (c EntitlementConf) check(bo build.Options, expected *EntitlementConf) erro rwPaths := map[string]struct{}{} roPaths := map[string]struct{}{} - for _, p := range collectLocalPaths(bo.Inputs) { + localPaths, err := collectLocalPaths(bo.Inputs) + if err != nil { + return err + } + for _, p := range localPaths { roPaths[p] = struct{}{} } @@ -200,8 +204,8 @@ func (c EntitlementConf) check(bo build.Options, expected *EntitlementConf) erro } for _, secret := range bo.SecretSpecs { - if secret.FilePath != "" { - roPaths[secret.FilePath] = struct{}{} + if filePath := secret.ResolveSource().FilePath; filePath != "" { + roPaths[filePath] = struct{}{} } } @@ -216,7 +220,6 @@ func (c EntitlementConf) check(bo build.Options, expected *EntitlementConf) erro } } - var err error expected.FSRead, err = findMissingPaths(c.FSRead, roPaths) if err != nil { return err diff --git a/bake/entitlements_test.go b/bake/entitlements_test.go index 11561547343f..c96795a98939 100644 --- a/bake/entitlements_test.go +++ b/bake/entitlements_test.go @@ -108,6 +108,13 @@ func TestValidateEntitlements(t *testing.T) { require.NoError(t, err) expWd, err := filepath.EvalSymlinks(wd) require.NoError(t, err) + credentialPath := filepath.Join(dir1, "credential") + require.NoError(t, os.WriteFile(credentialPath, []byte("test credential"), 0600)) + expCredentialPath, err := filepath.EvalSymlinks(credentialPath) + require.NoError(t, err) + layoutLink := filepath.Join(dir1, "layout-link") + require.NoError(t, os.Symlink(dir2, layoutLink)) + t.Setenv("BUILDX_TEST_SECRET_SOURCE", "test credential") tcases := []struct { name string @@ -224,6 +231,70 @@ func TestValidateEntitlements(t *testing.T) { FSRead: []string{wd, dir1}, }, }, + { + name: "secret-id-file-fallback-requires-read", + opt: build.Options{ + SecretSpecs: []*buildflags.Secret{{ID: credentialPath}}, + }, + conf: EntitlementConf{FSRead: []string{wd}}, + expected: EntitlementConf{ + FSRead: []string{expCredentialPath}, + }, + }, + { + name: "secret-id-file-fallback-allowed", + opt: build.Options{ + SecretSpecs: []*buildflags.Secret{{ID: credentialPath}}, + }, + conf: EntitlementConf{FSRead: []string{wd, dir1}}, + }, + { + name: "secret-id-env-fallback-needs-no-read", + opt: build.Options{ + SecretSpecs: []*buildflags.Secret{{ID: "BUILDX_TEST_SECRET_SOURCE"}}, + }, + conf: EntitlementConf{FSRead: []string{wd}}, + }, + { + name: "explicit-secret-env-needs-no-read", + opt: build.Options{ + SecretSpecs: []*buildflags.Secret{{ID: credentialPath, Env: "BUILDX_TEST_SECRET_SOURCE"}}, + }, + conf: EntitlementConf{FSRead: []string{wd}}, + }, + { + name: "oci-layout-named-context-requires-read", + opt: build.Options{ + Inputs: build.Inputs{NamedContexts: map[string]build.NamedContext{ + "layout": {Path: "oci-layout://" + dir1 + ":latest"}, + }}, + }, + conf: EntitlementConf{FSRead: []string{wd}}, + expected: EntitlementConf{ + FSRead: []string{expDir1}, + }, + }, + { + name: "oci-layout-named-context-allowed", + opt: build.Options{ + Inputs: build.Inputs{NamedContexts: map[string]build.NamedContext{ + "layout": {Path: "oci-layout://" + dir1 + ":latest"}, + }}, + }, + conf: EntitlementConf{FSRead: []string{wd, dir1}}, + }, + { + name: "oci-layout-named-context-symlink-requires-destination", + opt: build.Options{ + Inputs: build.Inputs{NamedContexts: map[string]build.NamedContext{ + "layout": {Path: "oci-layout://" + layoutLink + ":latest"}, + }}, + }, + conf: EntitlementConf{FSRead: []string{wd, dir1}}, + expected: EntitlementConf{ + FSRead: []string{expDir2}, + }, + }, { name: "SecretFromEscapeLink", opt: build.Options{ diff --git a/util/buildflags/secrets.go b/util/buildflags/secrets.go index 994fc416a129..4ce97e6d86dc 100644 --- a/util/buildflags/secrets.go +++ b/util/buildflags/secrets.go @@ -2,6 +2,7 @@ package buildflags import ( "encoding/json" + "os" "strings" "github.com/pkg/errors" @@ -35,6 +36,20 @@ type Secret struct { Env string `json:"env,omitempty"` } +// ResolveSource returns a copy with the source selected using BuildKit's +// default secret source rules. +func (s *Secret) ResolveSource() *Secret { + resolved := *s + if resolved.Env == "" && resolved.FilePath == "" { + if _, ok := os.LookupEnv(resolved.ID); ok { + resolved.Env = resolved.ID + } else { + resolved.FilePath = resolved.ID + } + } + return &resolved +} + func (s *Secret) Equal(other *Secret) bool { return s.ID == other.ID && s.FilePath == other.FilePath && s.Env == other.Env } From 8fc0a7371afc3d0bb137bd45f8bde1029d482e10 Mon Sep 17 00:00:00 2001 From: Sebastiaan van Stijn Date: Thu, 3 Sep 2026 01:55:01 +0200 Subject: [PATCH 3/6] vendor: golang.org/x/crypto v0.56.0 full diff: https://github.com/golang/crypto/compare/v0.55.0...v0.56.0 We have tagged version v0.56.0 of golang.org/x/crypto in order to address the following security issues: - ssh: prevent DoS on deadlocked established channel Previously, after a channel has been established, a malicious peer could send crafted messages that would deadlock the entire connection. Now, we handle all RFC 4254 channel messages; global requests are handled explicitly. Then, treat all other messages as a protocol error and tear the connection down instead of buffering and blocking. Thanks to Will Mortensen for reporting this issue. This is CVE-2026-56855 and Go issue https://go.dev/issue/81317. - ssh: prevent DoS on deadlocked undecided channel Previously, a channel registered in the mux's chanList is not usable until it is established. A malicious peer was able flood the channel's incomingRequests, deadlocking the entire connection. Now, we add an atomic established state, set when a channel becomes usable. Until such a time, handlePacket drops every packet other than the open confirmation/failure, without blocking and without tearing down the connection. Thanks to Will Mortensen for reporting this issue. This is CVE-2026-78662 and Go issue https://go.dev/issue/81316. Signed-off-by: Sebastiaan van Stijn (cherry picked from commit 9bc4fca69f50a29ce0b54d0023a10920d7e23161) --- go.mod | 2 +- go.sum | 4 +-- vendor/golang.org/x/crypto/ssh/certs.go | 38 +++++++++------------ vendor/golang.org/x/crypto/ssh/channel.go | 20 ++++++++++- vendor/golang.org/x/crypto/ssh/transport.go | 12 +++++-- vendor/modules.txt | 4 +-- 6 files changed, 50 insertions(+), 30 deletions(-) diff --git a/go.mod b/go.mod index 7f8aba175b44..15b4c8c43f28 100644 --- a/go.mod +++ b/go.mod @@ -60,7 +60,7 @@ require ( go.opentelemetry.io/otel/sdk v1.45.0 go.opentelemetry.io/otel/trace v1.45.0 go.yaml.in/yaml/v3 v3.0.5 - golang.org/x/crypto v0.55.0 + golang.org/x/crypto v0.56.0 golang.org/x/mod v0.40.0 golang.org/x/sync v0.22.0 golang.org/x/sys v0.47.0 diff --git a/go.sum b/go.sum index 6c3a5b710ff3..674ef2cf1710 100644 --- a/go.sum +++ b/go.sum @@ -634,8 +634,8 @@ go.yaml.in/yaml/v3 v3.0.5 h1:N6y/pJk8buWs9NY5ERU2HSMfm+IuD/OtfdAnq6kESPw= go.yaml.in/yaml/v3 v3.0.5/go.mod h1:HVTZu1O7/Vkt2N+BFy8Zza+lnLsABggaTM2ZpNIGuKg= go.yaml.in/yaml/v4 v4.0.0-rc.4 h1:UP4+v6fFrBIb1l934bDl//mmnoIZEDK0idg1+AIvX5U= go.yaml.in/yaml/v4 v4.0.0-rc.4/go.mod h1:aZqd9kCMsGL7AuUv/m/PvWLdg5sjJsZ4oHDEnfPPfY0= -golang.org/x/crypto v0.55.0 h1:+KWHjbgOaAQ66dh/YlkZKHlz9ZUlq61AFirAR9ntP8M= -golang.org/x/crypto v0.55.0/go.mod h1:uq0V9dE/fzQuJtbnL+2EhWOE63vo164FY8xqEnV9xis= +golang.org/x/crypto v0.56.0 h1:GUh5Ii4J5jtcseSMiRqr1jXCNHoxjeV9Fmekc2oLy6Y= +golang.org/x/crypto v0.56.0/go.mod h1:OMW5y6CY9l38uPLmxU6l6pwcXp1obtLo3e6gT7gQR2I= golang.org/x/mod v0.40.0 h1:hUv+3cXcdRHz08UmSiOob7sadHig73uo5bkXxQ/tvUs= golang.org/x/mod v0.40.0/go.mod h1:0/weTWkPWGBikyTWAX3dkjVztMmBA5hM0DH6BElSupE= golang.org/x/net v0.58.0 h1:ynWG7rqYi4ccpTEuPZ2QGWHktVEM9DMCj9yzDE0Q7To= diff --git a/vendor/golang.org/x/crypto/ssh/certs.go b/vendor/golang.org/x/crypto/ssh/certs.go index fa848f51a5f9..a3b802e4b8bf 100644 --- a/vendor/golang.org/x/crypto/ssh/certs.go +++ b/vendor/golang.org/x/crypto/ssh/certs.go @@ -10,6 +10,7 @@ import ( "fmt" "io" "net" + "slices" "sort" "time" ) @@ -305,8 +306,11 @@ const sourceAddressCriticalOption = "source-address" // minimally, the IsAuthority callback should be set. type CertChecker struct { // SupportedCriticalOptions lists the CriticalOptions that the - // server application layer understands. These are only used - // for user certificates. + // application layer understands. A certificate carrying a critical + // option that is not listed here is rejected. + // CertChecker.Authenticate additionally accepts the source-address + // option, which the server enforces on the Permissions that + // Authenticate returns. SupportedCriticalOptions []string // IsUserAuthority should return true if the key is recognized as an @@ -369,8 +373,9 @@ func (c *CertChecker) CheckHostKey(addr string, remote net.Addr, key PublicKey) return c.CheckCert(hostname, cert) } -// Authenticate checks a user certificate. Authenticate can be used as -// a value for ServerConfig.PublicKeyCallback. +// Authenticate checks a user certificate. Authenticate can be used as a value +// for ServerConfig.PublicKeyCallback. The source-address critical option is +// allowed, as it will be enforced by the server. func (c *CertChecker) Authenticate(conn ConnMetadata, pubKey PublicKey) (*Permissions, error) { cert, ok := pubKey.(*Certificate) if !ok { @@ -389,8 +394,11 @@ func (c *CertChecker) Authenticate(conn ConnMetadata, pubKey PublicKey) (*Permis if !c.IsUserAuthority(cert.SignatureKey) { return nil, fmt.Errorf("ssh: certificate signed by unrecognized authority") } - - if err := c.CheckCert(conn.User(), cert); err != nil { + // The source-address critical option is enforced by serverAuthenticate, + // so it is supported regardless of SupportedCriticalOptions + cc := *c + cc.SupportedCriticalOptions = append(slices.Clip(cc.SupportedCriticalOptions), sourceAddressCriticalOption) + if err := cc.CheckCert(conn.User(), cert); err != nil { return nil, err } @@ -398,27 +406,15 @@ func (c *CertChecker) Authenticate(conn ConnMetadata, pubKey PublicKey) (*Permis } // CheckCert checks CriticalOptions, ValidPrincipals, revocation, timestamp and -// the signature of the certificate. +// the signature of the certificate. Critical options that are not listed in +// SupportedCriticalOptions are rejected. func (c *CertChecker) CheckCert(principal string, cert *Certificate) error { if c.IsRevoked != nil && c.IsRevoked(cert) { return fmt.Errorf("ssh: certificate serial %d revoked", cert.Serial) } for opt := range cert.CriticalOptions { - // sourceAddressCriticalOption will be enforced by - // serverAuthenticate - if opt == sourceAddressCriticalOption { - continue - } - - found := false - for _, supp := range c.SupportedCriticalOptions { - if supp == opt { - found = true - break - } - } - if !found { + if !slices.Contains(c.SupportedCriticalOptions, opt) { return fmt.Errorf("ssh: unsupported critical option %q in certificate", opt) } } diff --git a/vendor/golang.org/x/crypto/ssh/channel.go b/vendor/golang.org/x/crypto/ssh/channel.go index ba3279e91d68..d6010fd77b99 100644 --- a/vendor/golang.org/x/crypto/ssh/channel.go +++ b/vendor/golang.org/x/crypto/ssh/channel.go @@ -173,6 +173,12 @@ type channel struct { // (for outbound channels) or received (for inbound channels). decided bool + // established is set to true once the channel is open and may carry normal + // channel traffic: for an outbound channel when the peer's open + // confirmation is received, for an inbound channel when the local side + // accepts it. It is set and read from different goroutines. + established atomic.Bool + // direction contains either channelOutbound, for channels created // locally, or channelInbound, for channels created by the peer. direction channelDirection @@ -434,10 +440,20 @@ func (ch *channel) responseMessageReceived() error { return errors.New("ssh: duplicate response received for channel") } ch.decided = true + ch.established.Store(true) return nil } func (ch *channel) handlePacket(packet []byte) error { + // Only the open response is expected before the channel is established. + if !ch.established.Load() { + switch packet[0] { + case msgChannelOpenConfirm, msgChannelOpenFailure: + default: + return nil + } + } + switch packet[0] { case msgChannelData, msgChannelExtendedData: return ch.handleData(packet) @@ -503,7 +519,8 @@ func (ch *channel) handlePacket(packet []byte) error { default: } default: - ch.msg <- msg + // No other message type is expected on an established channel. + return fmt.Errorf("ssh: unexpected message type %d on channel %d", packet[0], ch.localId) } return nil } @@ -554,6 +571,7 @@ func (ch *channel) Accept() (Channel, <-chan *Request, error) { MaxPacketSize: ch.maxIncomingPayload, } ch.decided = true + ch.established.Store(true) if err := ch.sendMessage(confirm); err != nil { return nil, nil, err } diff --git a/vendor/golang.org/x/crypto/ssh/transport.go b/vendor/golang.org/x/crypto/ssh/transport.go index fa3dd6a4299b..540865dfc823 100644 --- a/vendor/golang.org/x/crypto/ssh/transport.go +++ b/vendor/golang.org/x/crypto/ssh/transport.go @@ -331,13 +331,19 @@ func exchangeVersions(rw io.ReadWriter, versionLine []byte) (them []byte, err er // chars const maxVersionStringBytes = 255 +// maxPreVersionLines is the maximum number of lines sent by the peer +// before the version string. Each of these lines is limited to a maximum +// of maxVersionStringBytes chars. Lines sent before the version string +// are silently ignored. +const maxPreVersionLines = 1024 + // Read version string as specified by RFC 4253, section 4.2. func readVersion(r io.Reader) ([]byte, error) { versionString := make([]byte, 0, 64) var ok bool var buf [1]byte - for length := 0; length < maxVersionStringBytes; length++ { + for lines := 0; len(versionString) < maxVersionStringBytes && lines < maxPreVersionLines; { _, err := io.ReadFull(r, buf[:]) if err != nil { return nil, err @@ -347,9 +353,9 @@ func readVersion(r io.Reader) ([]byte, error) { if buf[0] == '\n' { if !bytes.HasPrefix(versionString, []byte("SSH-")) { // RFC 4253 says we need to ignore all version string lines - // except the one containing the SSH version (provided that - // all the lines do not exceed 255 bytes in total). + // except the one containing the SSH version. versionString = versionString[:0] + lines++ continue } ok = true diff --git a/vendor/modules.txt b/vendor/modules.txt index b17bfbeef39b..36eaff2f29d9 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -1273,8 +1273,8 @@ go.yaml.in/yaml/v3 ## explicit; go 1.18 go.yaml.in/yaml/v4 go.yaml.in/yaml/v4/internal/libyaml -# golang.org/x/crypto v0.55.0 -## explicit; go 1.25.0 +# golang.org/x/crypto v0.56.0 +## explicit; go 1.26.0 golang.org/x/crypto/argon2 golang.org/x/crypto/bcrypt golang.org/x/crypto/blake2b From a09052df64d07d1a8ff6391c367b9e2e0db6aa3c Mon Sep 17 00:00:00 2001 From: Sebastiaan van Stijn Date: Sat, 5 Sep 2026 02:27:42 +0200 Subject: [PATCH 4/6] vendor: github.com/containerd/containerd/v2 v2.3.5 full diff: https://github.com/containerd/containerd/compare/v2.3.4...v2.3.5 Security Updates - [**CVE-2026-53495**](https://github.com/containerd/containerd/security/advisories/GHSA-7jxh-36q5-gcqv) - [**GHSA-rp3h-jf77-q9p4**](https://github.com/containerd/containerd/security/advisories/GHSA-rp3h-jf77-q9p4) Image Distribution - Apply hardening to strip sensitive authentication headers when fetching descriptor URLs Runtime - Avoid hangs and data races when streaming container standard I/O in CRI - Fix missing error messages in OpenTelemetry trace attributes - Fix user and group lookup failures in container rootfs containing symlinked /etc/passwd or /etc/group - Fix configuration loading error when drop-in configuration files have a higher version than the root configuration - Avoid containerd startup hangs when loading shims - Add context to error when shim delete times out - Fix Windows Server 2022 container compatibility on host builds newer than the latest LTSC Snapshotters - Fix unpack failure for EROFS images containing the erofs OS feature Signed-off-by: Sebastiaan van Stijn (cherry picked from commit 86d1b72323fb1819f9ddc1154180835ed874af8b) --- go.mod | 2 +- go.sum | 4 +- .../v2/core/remotes/docker/fetcher.go | 38 ++++++++++++++++++- .../containerd/v2/pkg/tracing/helpers.go | 6 ++- .../containerd/v2/version/version.go | 2 +- vendor/modules.txt | 2 +- 6 files changed, 46 insertions(+), 8 deletions(-) diff --git a/go.mod b/go.mod index 15b4c8c43f28..2ed8005ab073 100644 --- a/go.mod +++ b/go.mod @@ -9,7 +9,7 @@ require ( github.com/aws/aws-sdk-go-v2/config v1.32.39 github.com/compose-spec/compose-go/v2 v2.14.0 github.com/containerd/console v1.0.5 - github.com/containerd/containerd/v2 v2.3.4 + github.com/containerd/containerd/v2 v2.3.5 github.com/containerd/continuity v0.5.0 github.com/containerd/errdefs v1.0.0 github.com/containerd/log v0.1.0 diff --git a/go.sum b/go.sum index 674ef2cf1710..e4b03368b3c0 100644 --- a/go.sum +++ b/go.sum @@ -118,8 +118,8 @@ github.com/containerd/console v1.0.5 h1:R0ymNeydRqH2DmakFNdmjR2k0t7UPuiOV/N/27/q github.com/containerd/console v1.0.5/go.mod h1:YynlIjWYF8myEu6sdkwKIvGQq+cOckRm6So2avqoYAk= github.com/containerd/containerd/api v1.11.1 h1:h8nfoDW9+fNsC/9TwiAHj8B1GzXKtR4eFtkhi/X5RLU= github.com/containerd/containerd/api v1.11.1/go.mod h1:CaQFRu+N1MtbgL6JDOJLUB1hCKESU1lD6MuTJhgtdlw= -github.com/containerd/containerd/v2 v2.3.4 h1:c2PJo/9UGVdiiw8SwrxuLxWGY+9b3jQ6Xp9zntneIvI= -github.com/containerd/containerd/v2 v2.3.4/go.mod h1:a30D8fWZJ1Uzx/2WpjLbLsxBkq9He41pe8ENW+QZ3LY= +github.com/containerd/containerd/v2 v2.3.5 h1:9MYlI81gUcOZ0WsCkSMtvOU7rTR3hqAoa2eCzhoLlkA= +github.com/containerd/containerd/v2 v2.3.5/go.mod h1:RXDyLPaI3zoO7dFdAW9/54W4cix+z3A6larieufC9mg= github.com/containerd/continuity v0.5.0 h1:7a85HZpCSs+1Zps0Ee3DPSuAWY+0SJM1JNM51nlEVDg= github.com/containerd/continuity v0.5.0/go.mod h1:/lNJvtJKUQStBzpVQ1+rasXO1LAWtUQssk28EZvJ3nE= github.com/containerd/errdefs v1.0.0 h1:tg5yIfIlQIrxYtu9ajqY42W3lpS19XqdxRQeEwYG8PI= diff --git a/vendor/github.com/containerd/containerd/v2/core/remotes/docker/fetcher.go b/vendor/github.com/containerd/containerd/v2/core/remotes/docker/fetcher.go index b5c29b1070c2..8b9961470076 100644 --- a/vendor/github.com/containerd/containerd/v2/core/remotes/docker/fetcher.go +++ b/vendor/github.com/containerd/containerd/v2/core/remotes/docker/fetcher.go @@ -218,6 +218,40 @@ type dockerFetcher struct { *dockerBase } +func stripSensitiveHeadersForExternalURLs(h http.Header) { + h.Del("Authorization") + h.Del("Proxy-Authorization") + h.Del("Cookie") + h.Del("Cookie2") +} + +func effectivePort(u *url.URL) string { + if port := u.Port(); port != "" { + return port + } + switch strings.ToLower(u.Scheme) { + case "http": + return "80" + case "https": + return "443" + default: + return "" + } +} + +func isRegistryOrigin(u *url.URL, hosts []RegistryHost) bool { + for _, host := range hosts { + if !strings.EqualFold(u.Scheme, host.Scheme) { + continue + } + hostURL := &url.URL{Scheme: host.Scheme, Host: host.Host} + if strings.EqualFold(u.Hostname(), hostURL.Hostname()) && effectivePort(u) == effectivePort(hostURL) { + return true + } + } + return false +} + func (r dockerFetcher) Fetch(ctx context.Context, desc ocispec.Descriptor) (io.ReadCloser, error) { ctx = log.WithLogger(ctx, log.G(ctx).WithField("digest", desc.Digest)) @@ -255,7 +289,9 @@ func (r dockerFetcher) Fetch(ctx context.Context, desc ocispec.Descriptor) (io.R Capabilities: HostCapabilityPull, } req := r.request(host, http.MethodGet) - // Strip namespace from base + if !isRegistryOrigin(u, hosts) { + stripSensitiveHeadersForExternalURLs(req.header) + } req.path = u.Path if u.RawQuery != "" { req.path = req.path + "?" + u.RawQuery diff --git a/vendor/github.com/containerd/containerd/v2/pkg/tracing/helpers.go b/vendor/github.com/containerd/containerd/v2/pkg/tracing/helpers.go index ab1278ef1fcf..4354e6c14b12 100644 --- a/vendor/github.com/containerd/containerd/v2/pkg/tracing/helpers.go +++ b/vendor/github.com/containerd/containerd/v2/pkg/tracing/helpers.go @@ -73,13 +73,15 @@ func keyValue(k string, v any) attribute.KeyValue { return attribute.String(k, typed) case []string: return attribute.StringSlice(k, typed) + case error: + return attribute.String(k, fmt.Sprint(typed)) } if stringer, ok := v.(fmt.Stringer); ok { - return attribute.String(k, stringer.String()) + return attribute.String(k, fmt.Sprint(stringer)) } if b, err := json.Marshal(v); b != nil && err == nil { return attribute.String(k, string(b)) } - return attribute.String(k, fmt.Sprintf("%v", v)) + return attribute.String(k, fmt.Sprint(v)) } diff --git a/vendor/github.com/containerd/containerd/v2/version/version.go b/vendor/github.com/containerd/containerd/v2/version/version.go index c256226281b0..a010e26e6c75 100644 --- a/vendor/github.com/containerd/containerd/v2/version/version.go +++ b/vendor/github.com/containerd/containerd/v2/version/version.go @@ -24,7 +24,7 @@ var ( Package = "github.com/containerd/containerd/v2" // Version holds the complete version number. Filled in at linking time. - Version = "2.3.4+unknown" + Version = "2.3.5+unknown" // Revision is filled with the VCS (e.g. git) revision being used to build // the program at linking time. diff --git a/vendor/modules.txt b/vendor/modules.txt index 36eaff2f29d9..3de18c8a4aaa 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -212,7 +212,7 @@ github.com/containerd/console # github.com/containerd/containerd/api v1.11.1 ## explicit; go 1.24.0 github.com/containerd/containerd/api/services/content/v1 -# github.com/containerd/containerd/v2 v2.3.4 +# github.com/containerd/containerd/v2 v2.3.5 ## explicit; go 1.26.3 github.com/containerd/containerd/v2/core/content github.com/containerd/containerd/v2/core/content/proxy From 7db01c24c44f2b3e1f027149ad0263f924eac467 Mon Sep 17 00:00:00 2001 From: CrazyMax <1951866+crazy-max@users.noreply.github.com> Date: Wed, 30 Sep 2026 12:26:14 +0200 Subject: [PATCH 5/6] vendor: github.com/containerd/containerd/v2 v2.3.6 full diff: https://github.com/containerd/containerd/compare/v2.3.5...v2.3.6 Signed-off-by: CrazyMax <1951866+crazy-max@users.noreply.github.com> (cherry picked from commit 78f48831b851688772e9bd1945e7e6d7cf052f40) --- go.mod | 4 +- go.sum | 4 +- .../containerd/v2/core/images/handlers.go | 122 +++++++++++++----- .../containerd/v2/version/version.go | 2 +- vendor/modules.txt | 4 +- 5 files changed, 100 insertions(+), 36 deletions(-) diff --git a/go.mod b/go.mod index 2ed8005ab073..ec274bbac9bd 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/docker/buildx -go 1.26.3 +go 1.26.8 require ( github.com/Masterminds/semver/v3 v3.4.0 @@ -9,7 +9,7 @@ require ( github.com/aws/aws-sdk-go-v2/config v1.32.39 github.com/compose-spec/compose-go/v2 v2.14.0 github.com/containerd/console v1.0.5 - github.com/containerd/containerd/v2 v2.3.5 + github.com/containerd/containerd/v2 v2.3.6 github.com/containerd/continuity v0.5.0 github.com/containerd/errdefs v1.0.0 github.com/containerd/log v0.1.0 diff --git a/go.sum b/go.sum index e4b03368b3c0..0a511f266ba2 100644 --- a/go.sum +++ b/go.sum @@ -118,8 +118,8 @@ github.com/containerd/console v1.0.5 h1:R0ymNeydRqH2DmakFNdmjR2k0t7UPuiOV/N/27/q github.com/containerd/console v1.0.5/go.mod h1:YynlIjWYF8myEu6sdkwKIvGQq+cOckRm6So2avqoYAk= github.com/containerd/containerd/api v1.11.1 h1:h8nfoDW9+fNsC/9TwiAHj8B1GzXKtR4eFtkhi/X5RLU= github.com/containerd/containerd/api v1.11.1/go.mod h1:CaQFRu+N1MtbgL6JDOJLUB1hCKESU1lD6MuTJhgtdlw= -github.com/containerd/containerd/v2 v2.3.5 h1:9MYlI81gUcOZ0WsCkSMtvOU7rTR3hqAoa2eCzhoLlkA= -github.com/containerd/containerd/v2 v2.3.5/go.mod h1:RXDyLPaI3zoO7dFdAW9/54W4cix+z3A6larieufC9mg= +github.com/containerd/containerd/v2 v2.3.6 h1:huoqZXaDW1x1kgPvFC4rMwxv92vUJnqgq7I5b1rSddM= +github.com/containerd/containerd/v2 v2.3.6/go.mod h1:qaUSWKk9EchqbudSbhv1MxI8dXKGYHLpZtMQdkEkVZ4= github.com/containerd/continuity v0.5.0 h1:7a85HZpCSs+1Zps0Ee3DPSuAWY+0SJM1JNM51nlEVDg= github.com/containerd/continuity v0.5.0/go.mod h1:/lNJvtJKUQStBzpVQ1+rasXO1LAWtUQssk28EZvJ3nE= github.com/containerd/errdefs v1.0.0 h1:tg5yIfIlQIrxYtu9ajqY42W3lpS19XqdxRQeEwYG8PI= diff --git a/vendor/github.com/containerd/containerd/v2/core/images/handlers.go b/vendor/github.com/containerd/containerd/v2/core/images/handlers.go index 245b9ac43c58..7d1ec35cb478 100644 --- a/vendor/github.com/containerd/containerd/v2/core/images/handlers.go +++ b/vendor/github.com/containerd/containerd/v2/core/images/handlers.go @@ -23,6 +23,7 @@ import ( "slices" "sort" "strings" + "sync" "github.com/containerd/containerd/v2/core/content" "github.com/containerd/errdefs" @@ -32,6 +33,16 @@ import ( "golang.org/x/sync/semaphore" ) +const ( + // defaultMaxConcurrency bounds the number of concurrent handler + // goroutines when Dispatch is called with a nil limiter. + defaultMaxConcurrency = 32 + + // maxReferences caps the references in a single Dispatch or Walk. + // Duplicate references count toward this limit. + maxReferences = 10_000 +) + var ( // ErrSkipDesc is used to skip processing of a descriptor and // its descendants. @@ -88,9 +99,26 @@ func Handlers(handlers ...Handler) HandlerFunc { // // This differs from dispatch in that each sibling resource is considered // synchronously. +// +// Each call is limited to 10,000 references, including duplicates. +// Exceeding this limit returns an error wrapping +// [errdefs.ErrResourceExhausted]. func Walk(ctx context.Context, handler Handler, descs ...ocispec.Descriptor) error { - for _, desc := range descs { + w := &walker{} + return w.walk(ctx, handler, descs...) +} + +type walker struct { + referenceCount int +} + +func (w *walker) walk(ctx context.Context, handler Handler, descs ...ocispec.Descriptor) error { + if w.referenceCount+len(descs) > maxReferences { + return fmt.Errorf("too many descriptors (limit %d): %w", maxReferences, errdefs.ErrResourceExhausted) + } + w.referenceCount += len(descs) + for _, desc := range descs { children, err := handler.Handle(ctx, desc) if err != nil { if errors.Is(err, ErrSkipDesc) { @@ -100,7 +128,7 @@ func Walk(ctx context.Context, handler Handler, descs ...ocispec.Descriptor) err } if len(children) > 0 { - if err := Walk(ctx, handler, children...); err != nil { + if err := w.walk(ctx, handler, children...); err != nil { return err } } @@ -146,45 +174,81 @@ func WalkNotEmpty(ctx context.Context, handler Handler, descs ...ocispec.Descrip // handler may return `ErrSkipDesc` to signal to the dispatcher to not traverse // any children. // -// A concurrency limiter can be passed in to limit the number of concurrent -// handlers running. When limiter is nil, there is no limit. +// The limiter bounds concurrent handlers. When limiter is nil, +// the limit is 32. // // Typically, this function will be used with `FetchHandler`, often composed // with other handlers. // // If any handler returns an error, the dispatch session will be canceled. +// +// Each call is limited to 10,000 references, including duplicates. +// Exceeding this limit returns an error wrapping +// [errdefs.ErrResourceExhausted]. func Dispatch(ctx context.Context, handler Handler, limiter *semaphore.Weighted, descs ...ocispec.Descriptor) error { - eg, ctx2 := errgroup.WithContext(ctx) - for _, desc := range descs { - if limiter != nil { - if err := limiter.Acquire(ctx, 1); err != nil { - return err - } + if len(descs) == 0 { + return nil + } + if err := ctx.Err(); err != nil { + return err + } + + if limiter == nil { + limiter = semaphore.NewWeighted(defaultMaxConcurrency) + } + + var ( + mu sync.Mutex + next []ocispec.Descriptor + referenceCount int + ) + + admit := func(descs []ocispec.Descriptor) error { + mu.Lock() + defer mu.Unlock() + if referenceCount+len(descs) > maxReferences { + return fmt.Errorf("too many descriptors (limit %d): %w", maxReferences, errdefs.ErrResourceExhausted) } + referenceCount += len(descs) + next = append(next, descs...) + return nil + } - eg.Go(func() error { - desc := desc + if err := admit(descs); err != nil { + return err + } - children, err := handler.Handle(ctx2, desc) - if limiter != nil { - limiter.Release(1) - } - if err != nil { - if errors.Is(err, ErrSkipDesc) { - return nil // don't traverse the children. - } - return err - } + for len(next) > 0 { + level := next + next = nil - if len(children) > 0 { - return Dispatch(ctx2, handler, limiter, children...) + eg, egCtx := errgroup.WithContext(ctx) + for _, desc := range level { + // Acquire here to bound the number of handler goroutines. + if err := limiter.Acquire(egCtx, 1); err != nil { + break } - - return nil - }) + eg.Go(func() error { + defer limiter.Release(1) + children, err := handler.Handle(egCtx, desc) + if err != nil { + if errors.Is(err, ErrSkipDesc) { + return nil // don't traverse the children. + } + return err + } + return admit(children) + }) + } + if err := eg.Wait(); err != nil { + return err + } + // Acquire can fail on cancellation even if every handler returns nil. + if err := ctx.Err(); err != nil { + return err + } } - - return eg.Wait() + return nil } // ChildrenHandler decodes well-known manifest types and returns their children. diff --git a/vendor/github.com/containerd/containerd/v2/version/version.go b/vendor/github.com/containerd/containerd/v2/version/version.go index a010e26e6c75..e5776233e7b1 100644 --- a/vendor/github.com/containerd/containerd/v2/version/version.go +++ b/vendor/github.com/containerd/containerd/v2/version/version.go @@ -24,7 +24,7 @@ var ( Package = "github.com/containerd/containerd/v2" // Version holds the complete version number. Filled in at linking time. - Version = "2.3.5+unknown" + Version = "2.3.6+unknown" // Revision is filled with the VCS (e.g. git) revision being used to build // the program at linking time. diff --git a/vendor/modules.txt b/vendor/modules.txt index 3de18c8a4aaa..03cec2fcc678 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -212,8 +212,8 @@ github.com/containerd/console # github.com/containerd/containerd/api v1.11.1 ## explicit; go 1.24.0 github.com/containerd/containerd/api/services/content/v1 -# github.com/containerd/containerd/v2 v2.3.5 -## explicit; go 1.26.3 +# github.com/containerd/containerd/v2 v2.3.6 +## explicit; go 1.26.8 github.com/containerd/containerd/v2/core/content github.com/containerd/containerd/v2/core/content/proxy github.com/containerd/containerd/v2/core/images From 33e13efcdb021d15d8585ed306b9edad7d61dacd Mon Sep 17 00:00:00 2001 From: CrazyMax <1951866+crazy-max@users.noreply.github.com> Date: Wed, 30 Sep 2026 17:55:03 +0200 Subject: [PATCH 6/6] vendor: github.com/moby/buildkit v0.33.1 Signed-off-by: CrazyMax <1951866+crazy-max@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 +- .../moby/buildkit/client/llb/definition.go | 9 ++++ .../github.com/moby/buildkit/client/solve.go | 6 ++- .../moby/buildkit/frontend/dockerui/config.go | 27 +++++----- .../buildkit/frontend/dockerui/context.go | 4 +- .../frontend/dockerui/namedcontext.go | 10 ++-- .../buildkit/frontend/dockerui/readfile.go | 52 +++++++++++++++++++ vendor/modules.txt | 4 +- 9 files changed, 91 insertions(+), 27 deletions(-) create mode 100644 vendor/github.com/moby/buildkit/frontend/dockerui/readfile.go diff --git a/go.mod b/go.mod index ec274bbac9bd..bc9cc9886e49 100644 --- a/go.mod +++ b/go.mod @@ -29,7 +29,7 @@ require ( github.com/hashicorp/hcl/v2 v2.24.0 github.com/in-toto/in-toto-golang v0.11.0 github.com/mitchellh/hashstructure/v2 v2.0.2 - github.com/moby/buildkit v0.33.0 + github.com/moby/buildkit v0.33.1 github.com/moby/moby/api v1.55.0 github.com/moby/moby/client v0.5.0 github.com/moby/policy-helpers v0.0.0-20260901104222-dd6c5499c491 diff --git a/go.sum b/go.sum index 0a511f266ba2..41cd1af81150 100644 --- a/go.sum +++ b/go.sum @@ -393,8 +393,8 @@ github.com/mitchellh/hashstructure/v2 v2.0.2 h1:vGKWl0YJqUNxE8d+h8f6NJLcCJrgbhC4 github.com/mitchellh/hashstructure/v2 v2.0.2/go.mod h1:MG3aRVU/N29oo/V/IhBX8GR/zz4kQkprJgF2EVszyDE= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= -github.com/moby/buildkit v0.33.0 h1:zBbt1FiMcTB/oFg1iCNcKa83k5Rn8MGcVjXFIcfYhuQ= -github.com/moby/buildkit v0.33.0/go.mod h1:uNKSZnfMk1aSa18JiCR5BT68M/3jIDGo6XuAByUK3ek= +github.com/moby/buildkit v0.33.1 h1:UUrdifmRdRadykO+f5l8BT1CseUXst2sJHV7AmkjjxE= +github.com/moby/buildkit v0.33.1/go.mod h1:584wW8T/WG4O+lpXUCoDaWEc5e+rTGC3iP+l9mNcX8E= github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= github.com/moby/go-archive v0.2.0 h1:zg5QDUM2mi0JIM9fdQZWC7U8+2ZfixfTYoHL7rWUcP8= diff --git a/vendor/github.com/moby/buildkit/client/llb/definition.go b/vendor/github.com/moby/buildkit/client/llb/definition.go index 33e996bea8ec..48ce487268d7 100644 --- a/vendor/github.com/moby/buildkit/client/llb/definition.go +++ b/vendor/github.com/moby/buildkit/client/llb/definition.go @@ -75,7 +75,13 @@ func NewDefinitionOp(def *pb.Definition) (*DefinitionOp, error) { } for dgst, locs := range def.Source.Locations { + if locs == nil { + return nil, errors.Errorf("invalid nil source locations for vertex %s", dgst) + } for _, loc := range locs.Locations { + if loc == nil { + return nil, errors.Errorf("invalid nil source location for vertex %s", dgst) + } if loc.SourceIndex < 0 || int(loc.SourceIndex) >= len(sourceMaps) { return nil, errors.Errorf("failed to find source map with index %d", loc.SourceIndex) } @@ -90,6 +96,9 @@ func NewDefinitionOp(def *pb.Definition) (*DefinitionOp, error) { var index pb.OutputIndex if dgst != "" { + if len(ops[dgst].Inputs) == 0 { + return nil, errors.New("invalid definition with no inputs on last vertex") + } index = pb.OutputIndex(ops[dgst].Inputs[0].Index) dgst = digest.Digest(ops[dgst].Inputs[0].Digest) } diff --git a/vendor/github.com/moby/buildkit/client/solve.go b/vendor/github.com/moby/buildkit/client/solve.go index 12d68b0c452c..863d87651b78 100644 --- a/vendor/github.com/moby/buildkit/client/solve.go +++ b/vendor/github.com/moby/buildkit/client/solve.go @@ -108,6 +108,8 @@ func (c *Client) solve(ctx context.Context, def *llb.Definition, runGateway runG if opt.Ref != "" { ref = opt.Ref } + + callerCtx := ctx eg, ctx := errgroup.WithContext(ctx) statusContext, cancelStatus := context.WithCancelCause(context.Background()) @@ -439,8 +441,8 @@ func (c *Client) solve(ctx context.Context, def *llb.Definition, runGateway runG } // Reset cache stores that have reset=true — delete unreferenced blobs for _, ref := range cacheOpt.storesToReset { - if err := resetCacheStore(ctx, ref.store, ref.path); err != nil { - bklog.G(ctx).WithError(err).Warn("failed to reset cache store") + if err := resetCacheStore(callerCtx, ref.store, ref.path); err != nil { + bklog.G(callerCtx).WithError(err).Warn("failed to reset cache store") } } return res, nil diff --git a/vendor/github.com/moby/buildkit/frontend/dockerui/config.go b/vendor/github.com/moby/buildkit/frontend/dockerui/config.go index fed608f4574e..09f8e51a4b4a 100644 --- a/vendor/github.com/moby/buildkit/frontend/dockerui/config.go +++ b/vendor/github.com/moby/buildkit/frontend/dockerui/config.go @@ -394,15 +394,11 @@ func (bc *Client) ReadEntrypoint(ctx context.Context, lang string, opts ...llb.L return nil, err } - dt, err := ref.ReadFile(ctx, client.ReadRequest{ - Filename: bctx.filename, - }) + dt, err := ReadFile(ctx, ref, bctx.filename) if err != nil { - if path.Base(bctx.filename) == DefaultDockerfileName { + if path.Base(bctx.filename) == DefaultDockerfileName && !isFileTooLarge(err) { var err1 error - dt, err1 = ref.ReadFile(ctx, client.ReadRequest{ - Filename: path.Join(path.Dir(bctx.filename), strings.ToLower(DefaultDockerfileName)), - }) + dt, err1 = ReadFile(ctx, ref, path.Join(path.Dir(bctx.filename), strings.ToLower(DefaultDockerfileName))) if err1 == nil { err = nil } @@ -414,12 +410,14 @@ func (bc *Client) ReadEntrypoint(ctx context.Context, lang string, opts ...llb.L smap := llb.NewSourceMap(src, bctx.filename, lang, dt) smap.Definition = def - dt, err = ref.ReadFile(ctx, client.ReadRequest{ - Filename: bctx.filename + ".dockerignore", - }) + // a missing ignore file is not an error, but an oversized one must not + // be silently skipped + dt, err = ReadFile(ctx, ref, bctx.filename+".dockerignore") if err == nil { bc.dockerignore = dt bc.dockerignoreName = bctx.filename + ".dockerignore" + } else if isFileTooLarge(err) { + return nil, err } return &Source{ @@ -563,9 +561,12 @@ func (bc *Client) dockerIgnorePatterns(ctx context.Context, bctx *buildContext) if err != nil { return nil, err } - dt, _ := ref.ReadFile(ctx, client.ReadRequest{ // ignore error - Filename: DefaultDockerignoreName, - }) + // a missing ignore file is not an error, but an oversized one must + // not be silently skipped + dt, err := ReadFile(ctx, ref, DefaultDockerignoreName) + if isFileTooLarge(err) { + return nil, err + } if dt == nil { dt = []byte{} } diff --git a/vendor/github.com/moby/buildkit/frontend/dockerui/context.go b/vendor/github.com/moby/buildkit/frontend/dockerui/context.go index 4848c04d41eb..9c556463072f 100644 --- a/vendor/github.com/moby/buildkit/frontend/dockerui/context.go +++ b/vendor/github.com/moby/buildkit/frontend/dockerui/context.go @@ -220,9 +220,7 @@ func archiveMaxTimeFromHTTPArchive(ctx context.Context, bctx *buildContext) (*ti if bctx.contextRef == nil || bctx.httpContextFilename == "" { return nil, nil } - dt, err := bctx.contextRef.ReadFile(ctx, client.ReadRequest{ - Filename: bctx.httpContextFilename, - }) + dt, err := ReadFile(ctx, bctx.contextRef, bctx.httpContextFilename) if err != nil { return nil, err } diff --git a/vendor/github.com/moby/buildkit/frontend/dockerui/namedcontext.go b/vendor/github.com/moby/buildkit/frontend/dockerui/namedcontext.go index 1d27ddcf488e..b125761880a4 100644 --- a/vendor/github.com/moby/buildkit/frontend/dockerui/namedcontext.go +++ b/vendor/github.com/moby/buildkit/frontend/dockerui/namedcontext.go @@ -252,10 +252,12 @@ func (nc *NamedContext) load(ctx context.Context, count int) (*llb.State, *docke } var excludes []string if !opt.NoDockerignore { - dt, _ := ref.ReadFile(ctx, client.ReadRequest{ - Filename: DefaultDockerignoreName, - }) // error ignored - + // a missing ignore file is not an error, but an oversized one + // must not be silently skipped + dt, err := ReadFile(ctx, ref, DefaultDockerignoreName) + if isFileTooLarge(err) { + return nil, nil, err + } if len(dt) != 0 { excludes, err = ignorefile.ReadAll(bytes.NewBuffer(dt)) if err != nil { diff --git a/vendor/github.com/moby/buildkit/frontend/dockerui/readfile.go b/vendor/github.com/moby/buildkit/frontend/dockerui/readfile.go new file mode 100644 index 000000000000..a22e8da73cfb --- /dev/null +++ b/vendor/github.com/moby/buildkit/frontend/dockerui/readfile.go @@ -0,0 +1,52 @@ +package dockerui + +import ( + "context" + "fmt" + + "github.com/containerd/containerd/v2/defaults" + "github.com/moby/buildkit/frontend/gateway/client" + "github.com/pkg/errors" +) + +// maxFileSize bounds files that the builtin frontend loads into daemon memory. +// A frontend running over the gateway cannot read more than one gRPC message in +// a single request anyway, so the builtin frontend is held to the same size. +const maxFileSize = defaults.DefaultMaxRecvMsgSize + +type fileTooLargeError struct { + filename string +} + +func (e *fileTooLargeError) Error() string { + return fmt.Sprintf("%s exceeds maximum allowed size of %d bytes", e.filename, maxFileSize) +} + +func isFileTooLarge(err error) bool { + var e *fileTooLargeError + return errors.As(err, &e) +} + +// ReadFile reads filename from ref, refusing files larger than maxFileSize. +// Oversized files are rejected on their reported size so that nothing is read +// from them, and the read itself carries a range so that no more than +// maxFileSize+1 bytes are ever loaded even when the size could not be checked. +func ReadFile(ctx context.Context, ref client.Reference, filename string) ([]byte, error) { + // stat failures are left to the read, which reports them properly + if st, err := ref.StatFile(ctx, client.StatRequest{Path: filename}); err == nil && st.Size > maxFileSize { + return nil, errors.WithStack(&fileTooLargeError{filename: filename}) + } + dt, err := ref.ReadFile(ctx, client.ReadRequest{ + Filename: filename, + Range: &client.FileRange{ + Length: maxFileSize + 1, + }, + }) + if err != nil { + return nil, err + } + if len(dt) > maxFileSize { + return nil, errors.WithStack(&fileTooLargeError{filename: filename}) + } + return dt, nil +} diff --git a/vendor/modules.txt b/vendor/modules.txt index 03cec2fcc678..73fbcb63c52a 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -644,8 +644,8 @@ github.com/mitchellh/go-wordwrap # github.com/mitchellh/hashstructure/v2 v2.0.2 ## explicit; go 1.14 github.com/mitchellh/hashstructure/v2 -# github.com/moby/buildkit v0.33.0 -## explicit; go 1.26.3 +# github.com/moby/buildkit v0.33.1 +## explicit; go 1.26.8 github.com/moby/buildkit/api/services/control github.com/moby/buildkit/api/types github.com/moby/buildkit/cache/remotecache/gha/ghatypes