|
| 1 | +From a6e3194c6cf3e2a683fe69db61cba50b6eabe754 Mon Sep 17 00:00:00 2001 |
| 2 | +From: Saul Paredes <saulparedes@microsoft.com> |
| 3 | +Date: Tue, 18 Jun 2024 10:38:52 -0700 |
| 4 | +Subject: [PATCH] fix CVE-2024-35255 |
| 5 | + |
| 6 | +This patch is a combination of 50774cd9709905523136fb05e8c85a50e8984499 |
| 7 | +and 48d39a82091b3aebe3df3505bd5372294b3461ed confirmed by the author |
| 8 | +that fix CVE-2024-35255. This was slighly adapted to be applied to |
| 9 | +current version (v1.4.0) This patch can be removed once azure-sdk-for-go |
| 10 | +vendored dependency version gets updated to >= v1.6.0 |
| 11 | + |
| 12 | +Signed-off-by: Saul Paredes <saulparedes@microsoft.com> |
| 13 | +--- |
| 14 | + .../sdk/azidentity/managed_identity_client.go | 70 ++++++++++++++----- |
| 15 | + 1 file changed, 51 insertions(+), 19 deletions(-) |
| 16 | + |
| 17 | +diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/managed_identity_client.go b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/managed_identity_client.go |
| 18 | +index fdc3c1f67..e5f24ffce 100644 |
| 19 | +--- a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/managed_identity_client.go |
| 20 | ++++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/managed_identity_client.go |
| 21 | +@@ -14,13 +14,15 @@ import ( |
| 22 | + "net/http" |
| 23 | + "net/url" |
| 24 | + "os" |
| 25 | ++ "path/filepath" |
| 26 | ++ "runtime" |
| 27 | + "strconv" |
| 28 | + "strings" |
| 29 | + "time" |
| 30 | + |
| 31 | + "github.com/Azure/azure-sdk-for-go/sdk/azcore" |
| 32 | + "github.com/Azure/azure-sdk-for-go/sdk/azcore/policy" |
| 33 | +- "github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime" |
| 34 | ++ azruntime "github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime" |
| 35 | + "github.com/Azure/azure-sdk-for-go/sdk/azcore/streaming" |
| 36 | + "github.com/Azure/azure-sdk-for-go/sdk/internal/log" |
| 37 | + "github.com/AzureAD/microsoft-authentication-library-for-go/apps/confidential" |
| 38 | +@@ -55,12 +57,28 @@ const ( |
| 39 | + // managedIdentityClient provides the base for authenticating in managed identity environments |
| 40 | + // This type includes an runtime.Pipeline and TokenCredentialOptions. |
| 41 | + type managedIdentityClient struct { |
| 42 | +- pipeline runtime.Pipeline |
| 43 | ++ pipeline azruntime.Pipeline |
| 44 | + msiType msiType |
| 45 | + endpoint string |
| 46 | + id ManagedIDKind |
| 47 | + } |
| 48 | + |
| 49 | ++// arcKeyDirectory returns the directory expected to contain Azure Arc keys |
| 50 | ++var arcKeyDirectory = func() (string, error) { |
| 51 | ++ switch runtime.GOOS { |
| 52 | ++ case "linux": |
| 53 | ++ return "/var/opt/azcmagent/tokens", nil |
| 54 | ++ case "windows": |
| 55 | ++ pd := os.Getenv("ProgramData") |
| 56 | ++ if pd == "" { |
| 57 | ++ return "", errors.New("environment variable ProgramData has no value") |
| 58 | ++ } |
| 59 | ++ return filepath.Join(pd, "AzureConnectedMachineAgent", "Tokens"), nil |
| 60 | ++ default: |
| 61 | ++ return "", fmt.Errorf("unsupported OS %q", runtime.GOOS) |
| 62 | ++ } |
| 63 | ++} |
| 64 | ++ |
| 65 | + type wrappedNumber json.Number |
| 66 | + |
| 67 | + func (n *wrappedNumber) UnmarshalJSON(b []byte) error { |
| 68 | +@@ -141,7 +159,7 @@ func newManagedIdentityClient(options *ManagedIdentityCredentialOptions) (*manag |
| 69 | + } else { |
| 70 | + setIMDSRetryOptionDefaults(&cp.Retry) |
| 71 | + } |
| 72 | +- c.pipeline = runtime.NewPipeline(component, version, runtime.PipelineOptions{}, &cp) |
| 73 | ++ c.pipeline = azruntime.NewPipeline(component, version, azruntime.PipelineOptions{}, &cp) |
| 74 | + |
| 75 | + if log.Should(EventAuthentication) { |
| 76 | + log.Writef(EventAuthentication, "Managed Identity Credential will use %s managed identity", env) |
| 77 | +@@ -173,7 +191,7 @@ func (c *managedIdentityClient) authenticate(ctx context.Context, id ManagedIDKi |
| 78 | + return azcore.AccessToken{}, newAuthenticationFailedError(credNameManagedIdentity, err.Error(), nil, err) |
| 79 | + } |
| 80 | + |
| 81 | +- if runtime.HasStatusCode(resp, http.StatusOK, http.StatusCreated) { |
| 82 | ++ if azruntime.HasStatusCode(resp, http.StatusOK, http.StatusCreated) { |
| 83 | + return c.createAccessToken(resp) |
| 84 | + } |
| 85 | + |
| 86 | +@@ -184,14 +202,14 @@ func (c *managedIdentityClient) authenticate(ctx context.Context, id ManagedIDKi |
| 87 | + return azcore.AccessToken{}, newAuthenticationFailedError(credNameManagedIdentity, "the requested identity isn't assigned to this resource", resp, nil) |
| 88 | + } |
| 89 | + msg := "failed to authenticate a system assigned identity" |
| 90 | +- if body, err := runtime.Payload(resp); err == nil && len(body) > 0 { |
| 91 | ++ if body, err := azruntime.Payload(resp); err == nil && len(body) > 0 { |
| 92 | + msg += fmt.Sprintf(". The endpoint responded with %s", body) |
| 93 | + } |
| 94 | + return azcore.AccessToken{}, newCredentialUnavailableError(credNameManagedIdentity, msg) |
| 95 | + case http.StatusForbidden: |
| 96 | + // Docker Desktop runs a proxy that responds 403 to IMDS token requests. If we get that response, |
| 97 | + // we return credentialUnavailableError so credential chains continue to their next credential |
| 98 | +- body, err := runtime.Payload(resp) |
| 99 | ++ body, err := azruntime.Payload(resp) |
| 100 | + if err == nil && strings.Contains(string(body), "A socket operation was attempted to an unreachable network") { |
| 101 | + return azcore.AccessToken{}, newCredentialUnavailableError(credNameManagedIdentity, fmt.Sprintf("unexpected response %q", string(body))) |
| 102 | + } |
| 103 | +@@ -209,7 +227,7 @@ func (c *managedIdentityClient) createAccessToken(res *http.Response) (azcore.Ac |
| 104 | + ExpiresIn wrappedNumber `json:"expires_in,omitempty"` // this field should always return the number of seconds for which a token is valid |
| 105 | + ExpiresOn interface{} `json:"expires_on,omitempty"` // the value returned in this field varies between a number and a date string |
| 106 | + }{} |
| 107 | +- if err := runtime.UnmarshalAsJSON(res, &value); err != nil { |
| 108 | ++ if err := azruntime.UnmarshalAsJSON(res, &value); err != nil { |
| 109 | + return azcore.AccessToken{}, fmt.Errorf("internal AccessToken: %v", err) |
| 110 | + } |
| 111 | + if value.ExpiresIn != "" { |
| 112 | +@@ -257,7 +275,7 @@ func (c *managedIdentityClient) createAuthRequest(ctx context.Context, id Manage |
| 113 | + } |
| 114 | + |
| 115 | + func (c *managedIdentityClient) createIMDSAuthRequest(ctx context.Context, id ManagedIDKind, scopes []string) (*policy.Request, error) { |
| 116 | +- request, err := runtime.NewRequest(ctx, http.MethodGet, c.endpoint) |
| 117 | ++ request, err := azruntime.NewRequest(ctx, http.MethodGet, c.endpoint) |
| 118 | + if err != nil { |
| 119 | + return nil, err |
| 120 | + } |
| 121 | +@@ -277,7 +295,7 @@ func (c *managedIdentityClient) createIMDSAuthRequest(ctx context.Context, id Ma |
| 122 | + } |
| 123 | + |
| 124 | + func (c *managedIdentityClient) createAppServiceAuthRequest(ctx context.Context, id ManagedIDKind, scopes []string) (*policy.Request, error) { |
| 125 | +- request, err := runtime.NewRequest(ctx, http.MethodGet, c.endpoint) |
| 126 | ++ request, err := azruntime.NewRequest(ctx, http.MethodGet, c.endpoint) |
| 127 | + if err != nil { |
| 128 | + return nil, err |
| 129 | + } |
| 130 | +@@ -297,7 +315,7 @@ func (c *managedIdentityClient) createAppServiceAuthRequest(ctx context.Context, |
| 131 | + } |
| 132 | + |
| 133 | + func (c *managedIdentityClient) createServiceFabricAuthRequest(ctx context.Context, id ManagedIDKind, scopes []string) (*policy.Request, error) { |
| 134 | +- request, err := runtime.NewRequest(ctx, http.MethodGet, c.endpoint) |
| 135 | ++ request, err := azruntime.NewRequest(ctx, http.MethodGet, c.endpoint) |
| 136 | + if err != nil { |
| 137 | + return nil, err |
| 138 | + } |
| 139 | +@@ -320,7 +338,7 @@ func (c *managedIdentityClient) createServiceFabricAuthRequest(ctx context.Conte |
| 140 | + |
| 141 | + func (c *managedIdentityClient) getAzureArcSecretKey(ctx context.Context, resources []string) (string, error) { |
| 142 | + // create the request to retreive the secret key challenge provided by the HIMDS service |
| 143 | +- request, err := runtime.NewRequest(ctx, http.MethodGet, c.endpoint) |
| 144 | ++ request, err := azruntime.NewRequest(ctx, http.MethodGet, c.endpoint) |
| 145 | + if err != nil { |
| 146 | + return "", err |
| 147 | + } |
| 148 | +@@ -342,22 +360,36 @@ func (c *managedIdentityClient) getAzureArcSecretKey(ctx context.Context, resour |
| 149 | + } |
| 150 | + header := response.Header.Get("WWW-Authenticate") |
| 151 | + if len(header) == 0 { |
| 152 | +- return "", errors.New("did not receive a value from WWW-Authenticate header") |
| 153 | ++ return "", newAuthenticationFailedError(credNameManagedIdentity, "HIMDS response has no WWW-Authenticate header", nil, nil) |
| 154 | + } |
| 155 | + // the WWW-Authenticate header is expected in the following format: Basic realm=/some/file/path.key |
| 156 | +- pos := strings.LastIndex(header, "=") |
| 157 | +- if pos == -1 { |
| 158 | +- return "", fmt.Errorf("did not receive a correct value from WWW-Authenticate header: %s", header) |
| 159 | ++ _, p, found := strings.Cut(header, "=") |
| 160 | ++ if !found { |
| 161 | ++ return "", newAuthenticationFailedError(credNameManagedIdentity, "unexpected WWW-Authenticate header from HIMDS: "+header, nil, nil) |
| 162 | ++ } |
| 163 | ++ expected, err := arcKeyDirectory() |
| 164 | ++ if err != nil { |
| 165 | ++ return "", err |
| 166 | ++ } |
| 167 | ++ if filepath.Dir(p) != expected || !strings.HasSuffix(p, ".key") { |
| 168 | ++ return "", newAuthenticationFailedError(credNameManagedIdentity, "unexpected file path from HIMDS service: "+p, nil, nil) |
| 169 | ++ } |
| 170 | ++ f, err := os.Stat(p) |
| 171 | ++ if err != nil { |
| 172 | ++ return "", newAuthenticationFailedError(credNameManagedIdentity, fmt.Sprintf("could not stat %q: %v", p, err), nil, nil) |
| 173 | ++ } |
| 174 | ++ if s := f.Size(); s > 4096 { |
| 175 | ++ return "", newAuthenticationFailedError(credNameManagedIdentity, fmt.Sprintf("key is too large (%d bytes)", s), nil, nil) |
| 176 | + } |
| 177 | +- key, err := os.ReadFile(header[pos+1:]) |
| 178 | ++ key, err := os.ReadFile(p) |
| 179 | + if err != nil { |
| 180 | +- return "", fmt.Errorf("could not read file (%s) contents: %v", header[pos+1:], err) |
| 181 | ++ return "", newAuthenticationFailedError(credNameManagedIdentity, fmt.Sprintf("could not read %q: %v", p, err), nil, nil) |
| 182 | + } |
| 183 | + return string(key), nil |
| 184 | + } |
| 185 | + |
| 186 | + func (c *managedIdentityClient) createAzureArcAuthRequest(ctx context.Context, id ManagedIDKind, resources []string, key string) (*policy.Request, error) { |
| 187 | +- request, err := runtime.NewRequest(ctx, http.MethodGet, c.endpoint) |
| 188 | ++ request, err := azruntime.NewRequest(ctx, http.MethodGet, c.endpoint) |
| 189 | + if err != nil { |
| 190 | + return nil, err |
| 191 | + } |
| 192 | +@@ -379,7 +411,7 @@ func (c *managedIdentityClient) createAzureArcAuthRequest(ctx context.Context, i |
| 193 | + } |
| 194 | + |
| 195 | + func (c *managedIdentityClient) createCloudShellAuthRequest(ctx context.Context, id ManagedIDKind, scopes []string) (*policy.Request, error) { |
| 196 | +- request, err := runtime.NewRequest(ctx, http.MethodPost, c.endpoint) |
| 197 | ++ request, err := azruntime.NewRequest(ctx, http.MethodPost, c.endpoint) |
| 198 | + if err != nil { |
| 199 | + return nil, err |
| 200 | + } |
| 201 | +-- |
| 202 | +2.25.1 |
| 203 | + |
0 commit comments