From d4f72ec9b53ef773e69dff0306331616621d39f6 Mon Sep 17 00:00:00 2001 From: Wendi Onwuakpa Date: Wed, 18 Mar 2026 15:44:06 -0400 Subject: [PATCH 1/9] disable network iso --- build-1es-pipeline.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/build-1es-pipeline.yaml b/build-1es-pipeline.yaml index 7a586dd767..2d0ddde19f 100644 --- a/build-1es-pipeline.yaml +++ b/build-1es-pipeline.yaml @@ -61,6 +61,8 @@ extends: # For productions pipelines, use "Official". template: v1/1ES.Official.PipelineTemplate.yml@1esPipelines parameters: + featureFlags: + disableNetworkIsolation: true sdl: sourceAnalysisPool: name: azcopy-pool # Name of your hosted pool From 2ee49b771b13660f4401f00368adf99cd75ae69c Mon Sep 17 00:00:00 2001 From: Adele Reed Date: Mon, 23 Mar 2026 10:43:28 -0700 Subject: [PATCH 2/9] Update offending packages --- go.mod | 14 +++++++------- go.sum | 14 ++++++++++++++ 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/go.mod b/go.mod index 02d8e22425..c5fbc5349a 100644 --- a/go.mod +++ b/go.mod @@ -17,10 +17,10 @@ require ( github.com/rogpeppe/go-internal v1.14.1 // indirect github.com/spf13/cobra v1.8.1 github.com/wastore/keyctl v0.3.1 - golang.org/x/crypto v0.47.0 // indirect + golang.org/x/crypto v0.49.0 // indirect golang.org/x/oauth2 v0.34.0 - golang.org/x/sync v0.19.0 - golang.org/x/sys v0.40.0 + golang.org/x/sync v0.20.0 + golang.org/x/sys v0.42.0 google.golang.org/api v0.249.0 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c ) @@ -35,7 +35,7 @@ require ( github.com/Azure/go-autorest/autorest/date v0.3.0 github.com/keybase/go-keychain v0.0.1 github.com/spf13/pflag v1.0.5 - golang.org/x/net v0.49.0 + golang.org/x/net v0.52.0 ) require ( @@ -87,12 +87,12 @@ require ( go.opentelemetry.io/otel/sdk v1.40.0 // indirect go.opentelemetry.io/otel/sdk/metric v1.40.0 // indirect go.opentelemetry.io/otel/trace v1.40.0 // indirect - golang.org/x/text v0.33.0 // indirect + golang.org/x/text v0.35.0 // indirect golang.org/x/time v0.13.0 // indirect google.golang.org/genproto v0.0.0-20250922171735-9219d122eba9 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20251202230838-ff82c1b0f217 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20260128011058-8636f8732409 // indirect - google.golang.org/grpc v1.79.1 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20260319201613-d00831a3d3e7 // indirect + google.golang.org/grpc v1.79.3 // indirect google.golang.org/protobuf v1.36.11 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index cd4e4e9704..f7233c88c0 100644 --- a/go.sum +++ b/go.sum @@ -181,24 +181,34 @@ go.opentelemetry.io/otel/trace v1.40.0 h1:WA4etStDttCSYuhwvEa8OP8I5EWu24lkOzp+ZY go.opentelemetry.io/otel/trace v1.40.0/go.mod h1:zeAhriXecNGP/s2SEG3+Y8X9ujcJOTqQ5RgdEJcawiA= golang.org/x/crypto v0.47.0 h1:V6e3FRj+n4dbpw86FJ8Fv7XVOql7TEwpHapKoMJ/GO8= golang.org/x/crypto v0.47.0/go.mod h1:ff3Y9VzzKbwSSEzWqJsJVBnWmRwRSHt/6Op5n9bQc4A= +golang.org/x/crypto v0.49.0 h1:+Ng2ULVvLHnJ/ZFEq4KdcDd/cfjrrjjNSXNzxg0Y4U4= +golang.org/x/crypto v0.49.0/go.mod h1:ErX4dUh2UM+CFYiXZRTcMpEcN8b/1gxEuv3nODoYtCA= golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.49.0 h1:eeHFmOGUTtaaPSGNmjBKpbng9MulQsJURQUAfUwY++o= golang.org/x/net v0.49.0/go.mod h1:/ysNB2EvaqvesRkuLAyjI1ycPZlQHM3q01F02UY/MV8= +golang.org/x/net v0.52.0 h1:He/TN1l0e4mmR3QqHMT2Xab3Aj3L9qjbhRm78/6jrW0= +golang.org/x/net v0.52.0/go.mod h1:R1MAz7uMZxVMualyPXb+VaqGSa3LIaUqk0eEt3w36Sw= golang.org/x/oauth2 v0.34.0 h1:hqK/t4AKgbqWkdkcAeI8XLmbK+4m4G5YeQRrmiotGlw= golang.org/x/oauth2 v0.34.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA= golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= +golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4= +golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20220408201424-a24fb2fb8a0f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ= golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/sys v0.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo= +golang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.33.0 h1:B3njUFyqtHDUI5jMn1YIr5B0IE2U0qck04r6d4KPAxE= golang.org/x/text v0.33.0/go.mod h1:LuMebE6+rBincTi9+xWTY8TztLzKHc/9C1uBCG27+q8= +golang.org/x/text v0.35.0 h1:JOVx6vVDFokkpaq1AEptVzLTpDe9KGpj5tR4/X+ybL8= +golang.org/x/text v0.35.0/go.mod h1:khi/HExzZJ2pGnjenulevKNX1W67CUy0AsXcNubPGCA= golang.org/x/time v0.13.0 h1:eUlYslOIt32DgYD6utsuUeHs4d7AsEYLuIAdg7FlYgI= golang.org/x/time v0.13.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -212,8 +222,12 @@ google.golang.org/genproto/googleapis/api v0.0.0-20251202230838-ff82c1b0f217 h1: google.golang.org/genproto/googleapis/api v0.0.0-20251202230838-ff82c1b0f217/go.mod h1:+rXWjjaukWZun3mLfjmVnQi18E1AsFbDN9QdJ5YXLto= google.golang.org/genproto/googleapis/rpc v0.0.0-20260128011058-8636f8732409 h1:H86B94AW+VfJWDqFeEbBPhEtHzJwJfTbgE2lZa54ZAQ= google.golang.org/genproto/googleapis/rpc v0.0.0-20260128011058-8636f8732409/go.mod h1:j9x/tPzZkyxcgEFkiKEEGxfvyumM01BEtsW8xzOahRQ= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260319201613-d00831a3d3e7 h1:ndE4FoJqsIceKP2oYSnUZqhTdYufCYYkqwtFzfrhI7w= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260319201613-d00831a3d3e7/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8= google.golang.org/grpc v1.79.1 h1:zGhSi45ODB9/p3VAawt9a+O/MULLl9dpizzNNpq7flY= google.golang.org/grpc v1.79.1/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ= +google.golang.org/grpc v1.79.3 h1:sybAEdRIEtvcD68Gx7dmnwjZKlyfuc61Dyo9pGXXkKE= +google.golang.org/grpc v1.79.3/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ= google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= From 3c3aec830e5a35f09fb44e98d4f973d2d002fdb9 Mon Sep 17 00:00:00 2001 From: Adele Reed Date: Mon, 23 Mar 2026 12:11:46 -0700 Subject: [PATCH 3/9] Correct issues re: MSRC case #110341 --- sddl/sddlHelper_linux.go | 32 +++++++++++++++++++++++--------- 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/sddl/sddlHelper_linux.go b/sddl/sddlHelper_linux.go index 5d5384ee8f..f5c41c6227 100644 --- a/sddl/sddlHelper_linux.go +++ b/sddl/sddlHelper_linux.go @@ -26,6 +26,7 @@ package sddl import ( "encoding/binary" "fmt" + "math" "strconv" "unsafe" @@ -589,6 +590,14 @@ var domainRidShortcuts = map[string]uint32{ /****************************************************************************/ +// isRangeValid validates that offset+length does not overflow, and lies under descriptorLength +func isRangeValid(offset, length, descriptorLength uint32) bool { + u64RangeEnd := uint64(offset) + uint64(length) + + return u64RangeEnd < math.MaxUint32 && // the range is valid, provided we do not overflow + u64RangeEnd < uint64(descriptorLength) // and that we line up with the max length of the descriptor. +} + // Test whether sd refers to a valid Security Descriptor. // We do some basic validations of the SECURITY_DESCRIPTOR_RELATIVE header. // 'flags' is used to convey what all information does the caller want us to verify in the binary SD. @@ -605,6 +614,7 @@ func sdRelativeIsValid(sd []byte, flags SECURITY_INFORMATION) error { offsetGroup := binary.LittleEndian.Uint32(sd[8:12]) offsetSacl := binary.LittleEndian.Uint32(sd[12:16]) offsetDacl := binary.LittleEndian.Uint32(sd[16:20]) + sdLenU32 := uint32(len(sd)) // Now validate sanity of these fields. if revision != SDDL_REVISION { @@ -629,8 +639,9 @@ func sdRelativeIsValid(sd []byte, flags SECURITY_INFORMATION) error { // offsetDacl may be 0 which would mean "No ACLs" aka "allow all users". // If non-zero, OffsetDacl must point inside the relative Security Descriptor. - if offsetDacl != 0 && offsetDacl+uint32(unsafe.Sizeof(ACL{})) > uint32(len(sd)) { - return fmt.Errorf("DACL (offsetDacl=%d) must lie within sd (length=%d)", offsetDacl, len(sd)) + if offsetDacl != 0 && + !isRangeValid(offsetDacl, uint32(unsafe.Sizeof(ACL{})), sdLenU32) { + return fmt.Errorf("DACL (offsetDacl=%d) must lie within sd (length=%d)", uint64(offsetDacl)+uint64(unsafe.Sizeof(ACL{})), len(sd)) } } @@ -639,7 +650,7 @@ func sdRelativeIsValid(sd []byte, flags SECURITY_INFORMATION) error { // SE_SACL_PRESENT bit is optional. If not set it means there is no SACL present. if (control&SE_SACL_PRESENT) != 0 && offsetSacl != 0 { // OffsetSacl must point inside the relative Security Descriptor. - if offsetSacl+uint32(unsafe.Sizeof(ACL{})) > uint32(len(sd)) { + if !isRangeValid(offsetSacl, uint32(unsafe.Sizeof(ACL{})), sdLenU32) { return fmt.Errorf("SACL (offsetSacl=%d) must lie within sd (length=%d)", offsetSacl, len(sd)) } } @@ -652,7 +663,7 @@ func sdRelativeIsValid(sd []byte, flags SECURITY_INFORMATION) error { } // OffsetOwner must point inside the relative Security Descriptor. - if offsetOwner+uint32(unsafe.Sizeof(SID{})) > uint32(len(sd)) { + if !isRangeValid(offsetOwner, uint32(unsafe.Sizeof(SID{})), sdLenU32) { return fmt.Errorf("OwnerSID (offsetOwner=%d) must lie within sd (length=%d)", offsetOwner, len(sd)) } @@ -665,7 +676,7 @@ func sdRelativeIsValid(sd []byte, flags SECURITY_INFORMATION) error { } // OffsetGroup must point inside the relative Security Descriptor. - if offsetGroup+uint32(unsafe.Sizeof(SID{})) > uint32(len(sd)) { + if !isRangeValid(offsetGroup, uint32(unsafe.Sizeof(SID{})), sdLenU32) { return fmt.Errorf("GroupSID (offsetGroup=%d) must lie within sd (length=%d)", offsetGroup, len(sd)) } @@ -873,6 +884,7 @@ func aceRightsToString(aceRights uint32) string { // Does the aceType correspond to an object ACE? // We don't support object ACEs. +// //nolint:deadcode,unused func isObjectAce(aceType byte) bool { switch aceType { @@ -1017,6 +1029,7 @@ func getOwnerSidString(sd []byte) (string, error) { // SECURITY_DESCRIPTOR_RELATIVE.OffsetOwner. offsetOwner := binary.LittleEndian.Uint32(sd[4:8]) + // we don't care as much about validating the range here -- sidToString ensures there's at least 8 bytes after slicing. if offsetOwner >= uint32(len(sd)) { return "", fmt.Errorf("offsetOwner (%d) points outside Security Descriptor of size %d bytes!", offsetOwner, len(sd)) @@ -1044,6 +1057,7 @@ func getGroupSidString(sd []byte) (string, error) { // SECURITY_DESCRIPTOR_RELATIVE.OffsetGroup. offsetGroup := binary.LittleEndian.Uint32(sd[8:12]) + // we don't care as much about validating the range here -- sidToString ensures there's at least 8 bytes after slicing. if offsetGroup >= uint32(len(sd)) { return "", fmt.Errorf("offsetGroup (%d) points outside Security Descriptor of size %d bytes!", offsetGroup, len(sd)) @@ -1111,7 +1125,7 @@ func getDaclString(sd []byte) (string, error) { return daclString, nil } - if (dacloffset + 8) > uint32(len(sd)) { + if !isRangeValid(dacloffset, 8, uint32(len(sd))) { return "", fmt.Errorf("dacloffset (%d) points outside Security Descriptor of size %d bytes!", dacloffset+8, len(sd)) } @@ -1141,7 +1155,7 @@ func getDaclString(sd []byte) (string, error) { // If numAces is 0 it'll result in daclString to have only flags and no ACEs. // Such an ACL will mean "allow nobody". for i := 0; i < int(numAces); i++ { - if (offset + 4) > uint32(len(sd)) { + if !isRangeValid(offset, 4, uint32(len(sd))) { return "", fmt.Errorf("Short ACE (offset=%d), Security Descriptor size=%d bytes!", offset, len(sd)) } @@ -1149,8 +1163,8 @@ func getDaclString(sd []byte) (string, error) { // ACCESS_ALLOWED_ACE.Header.AceSize. ace_size := uint32(binary.LittleEndian.Uint16(sd[offset+2 : offset+4])) - if (offset + ace_size) > uint32(len(sd)) { - return "", fmt.Errorf("ACE (offset=%d, ace_size=%d) lies outside Security Descriptor of size %d bytes!", offset, ace_size, len(sd)) + if !isRangeValid(offset, ace_size, uint32(len(sd))) { + return "", fmt.Errorf("ACE (offset=%d, ace_size=%d) lies outside Security Descriptor of size %d bytes (or exceeds uint32 limits)!", offset, ace_size, len(sd)) } aceStr, err := aceToString(sd[offset : offset+ace_size]) From cf82e2e07fd8486050276588562b859b3277b932 Mon Sep 17 00:00:00 2001 From: Adele Reed Date: Mon, 23 Mar 2026 12:22:24 -0700 Subject: [PATCH 4/9] Alter intentional panics to return errors --- ste/sourceInfoProvider-Local_linux.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/ste/sourceInfoProvider-Local_linux.go b/ste/sourceInfoProvider-Local_linux.go index 1f5aada662..18789da44a 100644 --- a/ste/sourceInfoProvider-Local_linux.go +++ b/ste/sourceInfoProvider-Local_linux.go @@ -4,6 +4,7 @@ package ste import ( + "errors" "fmt" "os/user" "strconv" @@ -57,7 +58,7 @@ func (f localFileSourceInfoProvider) GetUNIXProperties() (common.UnixStatAdapter err = unix.Stat(f.transferInfo.Source, &stat) } if err != nil { - return nil, err + return nil, err } return StatTAdapter(stat), nil @@ -207,7 +208,7 @@ func (f localFileSourceInfoProvider) GetSDDL() (string, error) { sdStr, err := sddl.SecurityDescriptorToString(sd) if err != nil { // Panic, as it's unexpected and we would want to know. - panic(fmt.Errorf("Cannot parse binary Security Descriptor returned by QuerySecurityObject(%s, 0x%x): %v", f.jptm.Info().Source, securityInfoFlags, err)) + return "", fmt.Errorf("Cannot parse binary Security Descriptor returned by QuerySecurityObject(%s, 0x%x): %v", f.jptm.Info().Source, securityInfoFlags, err) } fSDDL, err := sddl.ParseSDDL(sdStr) @@ -216,7 +217,7 @@ func (f localFileSourceInfoProvider) GetSDDL() (string, error) { } if strings.TrimSpace(fSDDL.String()) != strings.TrimSpace(sdStr) { - panic("SDDL sanity check failed (parsed string output != original string)") + return "", errors.New("SDDL sanity check failed (parsed string output != original string)") } return fSDDL.PortableString(), nil From f314f115dc3307560f6fb08f25186ee656b40582 Mon Sep 17 00:00:00 2001 From: Adele Reed Date: Mon, 23 Mar 2026 12:22:33 -0700 Subject: [PATCH 5/9] Changelog --- ChangeLog.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/ChangeLog.md b/ChangeLog.md index 9f7e635d42..445b813918 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -1,6 +1,21 @@ # Change Log +## Version 10.32.3 + +### Dependency updates +1. golang.org/x/crypto v0.47.0 -> v0.49.0 +2. golang.org/x/sync v0.19.0 -> v0.20.0 +3. golang.org/x/sys v0.40.0 -> v0.42.0 +4. golang.org/x/net v0.49.0 -> v0.52.0 +5. golang.org/x/text v0.33.0 -> v0.35.0 +6. google.golang.org/genproto/googleapis/rpc v0.0.0-20260128011058-8636f8732409 -> v0.0.0-20260319201613-d00831a3d3e7 +7. google.golang.org/grpc v1.79.1 -> v1.79.3 + +### Vulnerability fixes +1. Fixed an issue where a maliciously crafted SDDL could crash AzCopy on Linux. + + ## Version 10.32.2 ### Dependency updates From 704718eb4b0442f0ca6343bc174a292538450444 Mon Sep 17 00:00:00 2001 From: Adele Reed Date: Mon, 23 Mar 2026 15:09:36 -0700 Subject: [PATCH 6/9] Add test to validate changes --- sddl/sddlHelper_linux_test.go | 103 ++++++++++++++++++++++++++++++++++ 1 file changed, 103 insertions(+) create mode 100644 sddl/sddlHelper_linux_test.go diff --git a/sddl/sddlHelper_linux_test.go b/sddl/sddlHelper_linux_test.go new file mode 100644 index 0000000000..706a0533c9 --- /dev/null +++ b/sddl/sddlHelper_linux_test.go @@ -0,0 +1,103 @@ +//go:build linux +// +build linux + +package sddl + +import ( + "math" + "testing" + "unsafe" + + "github.com/stretchr/testify/assert" +) + +func TestMaliciousRelativeSDDLCrashPrevented(t *testing.T) { + a := assert.New(t) + + craftedDescriptor := SECURITY_DESCRIPTOR_RELATIVE{ + Revision: SDDL_REVISION, + Sbz1: 0, // must be zero + Control: SE_SELF_RELATIVE, + Data: [0]BYTE{}, + } + + type testTargets struct { + testName string + offset *DWORD + offsetValue DWORD + controlFlag SECURITY_DESCRIPTOR_CONTROL + siFlags SECURITY_INFORMATION + } + + maliciousOffsetSID := DWORD(math.MaxUint32 - unsafe.Sizeof(SID{}) + 1) + maliciousOffsetACL := DWORD(math.MaxUint32 - unsafe.Sizeof(ACL{}) + 1) + + fieldsToTest := []testTargets{ + {"DACL", &craftedDescriptor.OffsetDacl, maliciousOffsetACL, SE_DACL_PRESENT | SE_SELF_RELATIVE, DACL_SECURITY_INFORMATION}, + {"SACL", &craftedDescriptor.OffsetSacl, maliciousOffsetACL, SE_SACL_PRESENT | SE_SELF_RELATIVE, SACL_SECURITY_INFORMATION}, + {"Owner", &craftedDescriptor.OffsetOwner, maliciousOffsetSID, SE_SELF_RELATIVE, OWNER_SECURITY_INFORMATION}, + {"Group", &craftedDescriptor.OffsetGroup, maliciousOffsetSID, SE_SELF_RELATIVE, GROUP_SECURITY_INFORMATION}, + } + + //sdRelativeIsValid() + for _, v := range fieldsToTest { + // take note of the original values of the fields we're updating. + originalOffset := *v.offset + originalControl := craftedDescriptor.Control + + // Update our offset and control bits. + *v.offset = v.offsetValue + craftedDescriptor.Control = v.controlFlag + + // Run sdRelativeIsValid inside a closure + // so that we can validate that it did not crash, and errored appropriately. + panicked, err := func() (panicked any, err error) { + defer func() { + panicked = recover() + }() + + // Goland thinks these byte typecasts are redundant. They are not! + //goland:noinspection GoRedundantConversion + descData := ([]byte)(unsafe.Slice((*byte)(unsafe.Pointer(&craftedDescriptor)), unsafe.Sizeof(craftedDescriptor))) + + err = sdRelativeIsValid(descData, v.siFlags) + + return + }() + + // reset our flags + *v.offset = originalOffset + craftedDescriptor.Control = originalControl + + // We should not have panicked, just errored cleanly. + a.Nil(panicked, v.testName, "panicked") + a.NotNil(err, v.testName, "should have returned an error") + a.Contains(err.Error(), "must lie within sd", v.testName, "error wasn't as expected") + } + + // let's test one more thing. getDaclString could cause issues in the past, let's set the malicious data for that and make sure we error. + craftedDescriptor = SECURITY_DESCRIPTOR_RELATIVE{ + Revision: SDDL_REVISION, + Sbz1: 0, // must be zero + Control: SE_SELF_RELATIVE | SE_DACL_PRESENT, + OffsetDacl: maliciousOffsetACL, + Data: [0]BYTE{}, + } + + panicked, err := func() (panicked any, err error) { + defer func() { + panicked = recover() + }() + + // Goland thinks these byte typecasts are redundant. They are not! + //goland:noinspection GoRedundantConversion + descData := ([]byte)(unsafe.Slice((*byte)(unsafe.Pointer(&craftedDescriptor)), unsafe.Sizeof(craftedDescriptor))) + + _, err = getDaclString(descData) + return + }() + + a.Nil(panicked, "getDaclString panicked") + a.NotNil(err, "getDaclString should error") + a.Contains(err.Error(), "points outside Security Descriptor of size", "getDaclString error wasn't what was expected") +} From 3d4ada981fbfa2f1e77aefe6b131dddf2e654a7d Mon Sep 17 00:00:00 2001 From: Adele Reed Date: Mon, 23 Mar 2026 15:21:55 -0700 Subject: [PATCH 7/9] Satiate the clanker --- sddl/sddlHelper_linux.go | 16 ++++++++-------- ste/sourceInfoProvider-Local_linux.go | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/sddl/sddlHelper_linux.go b/sddl/sddlHelper_linux.go index f5c41c6227..7832013ce9 100644 --- a/sddl/sddlHelper_linux.go +++ b/sddl/sddlHelper_linux.go @@ -594,8 +594,8 @@ var domainRidShortcuts = map[string]uint32{ func isRangeValid(offset, length, descriptorLength uint32) bool { u64RangeEnd := uint64(offset) + uint64(length) - return u64RangeEnd < math.MaxUint32 && // the range is valid, provided we do not overflow - u64RangeEnd < uint64(descriptorLength) // and that we line up with the max length of the descriptor. + return u64RangeEnd <= math.MaxUint32 && // the range is valid, provided we do not overflow + u64RangeEnd <= uint64(descriptorLength) // and that we line up with the max length of the descriptor. } // Test whether sd refers to a valid Security Descriptor. @@ -641,7 +641,7 @@ func sdRelativeIsValid(sd []byte, flags SECURITY_INFORMATION) error { // If non-zero, OffsetDacl must point inside the relative Security Descriptor. if offsetDacl != 0 && !isRangeValid(offsetDacl, uint32(unsafe.Sizeof(ACL{})), sdLenU32) { - return fmt.Errorf("DACL (offsetDacl=%d) must lie within sd (length=%d)", uint64(offsetDacl)+uint64(unsafe.Sizeof(ACL{})), len(sd)) + return fmt.Errorf("DACL (offsetDacl=%d, end=%d) must lie within sd (length=%d)", offsetDacl, uint64(offsetDacl)+uint64(unsafe.Sizeof(ACL{})), len(sd)) } } @@ -651,7 +651,7 @@ func sdRelativeIsValid(sd []byte, flags SECURITY_INFORMATION) error { if (control&SE_SACL_PRESENT) != 0 && offsetSacl != 0 { // OffsetSacl must point inside the relative Security Descriptor. if !isRangeValid(offsetSacl, uint32(unsafe.Sizeof(ACL{})), sdLenU32) { - return fmt.Errorf("SACL (offsetSacl=%d) must lie within sd (length=%d)", offsetSacl, len(sd)) + return fmt.Errorf("SACL (offsetSacl=%d, end=%d) must lie within sd (length=%d)", offsetSacl, uint64(offsetSacl)+uint64(unsafe.Sizeof(ACL{})), len(sd)) } } } @@ -664,8 +664,8 @@ func sdRelativeIsValid(sd []byte, flags SECURITY_INFORMATION) error { // OffsetOwner must point inside the relative Security Descriptor. if !isRangeValid(offsetOwner, uint32(unsafe.Sizeof(SID{})), sdLenU32) { - return fmt.Errorf("OwnerSID (offsetOwner=%d) must lie within sd (length=%d)", - offsetOwner, len(sd)) + return fmt.Errorf("OwnerSID (offsetOwner=%d, end=%d) must lie within sd (length=%d)", + offsetOwner, uint64(offsetOwner)+uint64(unsafe.Sizeof(SID{})), len(sd)) } } @@ -677,8 +677,8 @@ func sdRelativeIsValid(sd []byte, flags SECURITY_INFORMATION) error { // OffsetGroup must point inside the relative Security Descriptor. if !isRangeValid(offsetGroup, uint32(unsafe.Sizeof(SID{})), sdLenU32) { - return fmt.Errorf("GroupSID (offsetGroup=%d) must lie within sd (length=%d)", - offsetGroup, len(sd)) + return fmt.Errorf("GroupSID (offsetGroup=%d, end=%d) must lie within sd (length=%d)", + offsetGroup, uint64(offsetGroup)+uint64(unsafe.Sizeof(SID{})), len(sd)) } } diff --git a/ste/sourceInfoProvider-Local_linux.go b/ste/sourceInfoProvider-Local_linux.go index 18789da44a..77d401fd14 100644 --- a/ste/sourceInfoProvider-Local_linux.go +++ b/ste/sourceInfoProvider-Local_linux.go @@ -207,7 +207,7 @@ func (f localFileSourceInfoProvider) GetSDDL() (string, error) { // This is the Windows equivalent of ConvertSecurityDescriptorToStringSecurityDescriptorW(). sdStr, err := sddl.SecurityDescriptorToString(sd) if err != nil { - // Panic, as it's unexpected and we would want to know. + // No longer panic here. A malformed SD would prevent the entire job from running. return "", fmt.Errorf("Cannot parse binary Security Descriptor returned by QuerySecurityObject(%s, 0x%x): %v", f.jptm.Info().Source, securityInfoFlags, err) } From 5bd126e0c815198858c341656c911f51cb1cf9da Mon Sep 17 00:00:00 2001 From: Adele Reed Date: Mon, 23 Mar 2026 15:23:01 -0700 Subject: [PATCH 8/9] Error formatting --- ste/sourceInfoProvider-Local_linux.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ste/sourceInfoProvider-Local_linux.go b/ste/sourceInfoProvider-Local_linux.go index 77d401fd14..564b2ac808 100644 --- a/ste/sourceInfoProvider-Local_linux.go +++ b/ste/sourceInfoProvider-Local_linux.go @@ -208,7 +208,7 @@ func (f localFileSourceInfoProvider) GetSDDL() (string, error) { sdStr, err := sddl.SecurityDescriptorToString(sd) if err != nil { // No longer panic here. A malformed SD would prevent the entire job from running. - return "", fmt.Errorf("Cannot parse binary Security Descriptor returned by QuerySecurityObject(%s, 0x%x): %v", f.jptm.Info().Source, securityInfoFlags, err) + return "", fmt.Errorf("cannot parse binary Security Descriptor returned by QuerySecurityObject(%s, 0x%x): %w", f.jptm.Info().Source, securityInfoFlags, err) } fSDDL, err := sddl.ParseSDDL(sdStr) From e3c0e0ca2a2b9079c4c41f080fcada34ae83c251 Mon Sep 17 00:00:00 2001 From: Adele Reed Date: Tue, 24 Mar 2026 12:13:00 -0700 Subject: [PATCH 9/9] version.go --- common/version.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/version.go b/common/version.go index d974dc108a..b11bec15d1 100644 --- a/common/version.go +++ b/common/version.go @@ -1,6 +1,6 @@ package common -const AzcopyVersion = "10.32.2" +const AzcopyVersion = "10.32.3" const UserAgent = "AzCopy/" + AzcopyVersion const S3ImportUserAgent = "S3Import " + UserAgent const GCPImportUserAgent = "GCPImport " + UserAgent