From: Vijay Anusuri <[email protected]>

Upstream-commit:
https://github.com/kubernetes/kubernetes/commit/e612ebfdff22e4bd27ad8345f7c82f074bfedf26
&
https://github.com/kubernetes/kubernetes/commit/d57f0641d60b73934ebc2cdf4b6a63182217d10c
& 
https://github.com/kubernetes/kubernetes/commit/901e8e07e1f031456ecd7fefce965aaa05916825

Signed-off-by: Vijay Anusuri <[email protected]>
---
 .../kubernetes/CVE-2021-25735-pre1.patch      | 613 ++++++++++++++++++
 .../kubernetes/CVE-2021-25735.patch           | 535 +++++++++++++++
 .../kubernetes/CVE-2021-25737.patch           | 128 ++++
 .../kubernetes/kubernetes_git.bb              |   3 +
 4 files changed, 1279 insertions(+)
 create mode 100644 
recipes-containers/kubernetes/kubernetes/CVE-2021-25735-pre1.patch
 create mode 100644 
recipes-containers/kubernetes/kubernetes/CVE-2021-25735.patch
 create mode 100644 
recipes-containers/kubernetes/kubernetes/CVE-2021-25737.patch

diff --git a/recipes-containers/kubernetes/kubernetes/CVE-2021-25735-pre1.patch 
b/recipes-containers/kubernetes/kubernetes/CVE-2021-25735-pre1.patch
new file mode 100644
index 00000000..2066188a
--- /dev/null
+++ b/recipes-containers/kubernetes/kubernetes/CVE-2021-25735-pre1.patch
@@ -0,0 +1,613 @@
+From e612ebfdff22e4bd27ad8345f7c82f074bfedf26 Mon Sep 17 00:00:00 2001
+From: wojtekt <[email protected]>
+Date: Tue, 26 Nov 2019 13:29:26 +0100
+Subject: [PATCH] Immutable field and validation
+
+Upstream-Status: Backport 
[https://github.com/kubernetes/kubernetes/commit/e612ebfdff22e4bd27ad8345f7c82f074bfedf26]
+CVE: CVE-2021-25735 #Dependency Patch1
+Signed-off-by: Vijay Anusuri <[email protected]>
+---
+ pkg/apis/core/types.go                        |  12 +
+ pkg/apis/core/validation/validation.go        |  24 +-
+ pkg/apis/core/validation/validation_test.go   | 209 ++++++++++++++++--
+ pkg/features/kube_features.go                 |   7 +
+ pkg/registry/core/configmap/strategy.go       |  28 ++-
+ pkg/registry/core/secret/strategy.go          |  17 ++
+ staging/src/k8s.io/api/core/v1/types.go       |  16 ++
+ .../k8sdeps/transformer/hash/hash.go          |  20 +-
+ .../k8sdeps/transformer/hash/hash_test.go     |   4 +-
+ .../src/k8s.io/kubectl/pkg/util/hash/hash.go  |  20 +-
+ .../k8s.io/kubectl/pkg/util/hash/hash_test.go |   4 +-
+ 11 files changed, 322 insertions(+), 39 deletions(-)
+
+diff --git a/pkg/apis/core/types.go b/pkg/apis/core/types.go
+index 74d22ae973e87..c5ada193effc4 100644
+--- a/src/import/pkg/apis/core/types.go
++++ b/src/import/pkg/apis/core/types.go
+@@ -4735,6 +4735,12 @@ type Secret struct {
+       // +optional
+       metav1.ObjectMeta
+ 
++      // Immutable field, if set, ensures that data stored in the Secret 
cannot
++      // be updated (only object metadata can be modified).
++      // This is an alpha field enabled by ImmutableEphemeralVolumes feature 
gate.
++      // +optional
++      Immutable *bool
++
+       // Data contains the secret data. Each key must consist of alphanumeric
+       // characters, '-', '_' or '.'. The serialized form of the secret data 
is a
+       // base64 encoded string, representing the arbitrary (possibly 
non-string)
+@@ -4857,6 +4863,12 @@ type ConfigMap struct {
+       // +optional
+       metav1.ObjectMeta
+ 
++      // Immutable field, if set, ensures that data stored in the ConfigMap 
cannot
++      // be updated (only object metadata can be modified).
++      // This is an alpha field enabled by ImmutableEphemeralVolumes feature 
gate.
++      // +optional
++      Immutable *bool
++
+       // Data contains the configuration data.
+       // Each key must consist of alphanumeric characters, '-', '_' or '.'.
+       // Values with non-UTF-8 byte sequences must use the BinaryData field.
+diff --git a/pkg/apis/core/validation/validation.go 
b/pkg/apis/core/validation/validation.go
+index 4ad241c745b7d..8e3cfd9d9e423 100644
+--- a/src/import/pkg/apis/core/validation/validation.go
++++ b/src/import/pkg/apis/core/validation/validation.go
+@@ -5005,6 +5005,16 @@ func ValidateSecretUpdate(newSecret, oldSecret 
*core.Secret) field.ErrorList {
+       }
+ 
+       allErrs = append(allErrs, ValidateImmutableField(newSecret.Type, 
oldSecret.Type, field.NewPath("type"))...)
++      if oldSecret.Immutable != nil && *oldSecret.Immutable {
++              if !reflect.DeepEqual(newSecret.Immutable, oldSecret.Immutable) 
{
++                      allErrs = append(allErrs, 
field.Forbidden(field.NewPath("immutable"), "field is immutable when 
`immutable` is set"))
++              }
++              if !reflect.DeepEqual(newSecret.Data, oldSecret.Data) {
++                      allErrs = append(allErrs, 
field.Forbidden(field.NewPath("data"), "field is immutable when `immutable` is 
set"))
++              }
++              // We don't validate StringData, as it was already converted 
back to Data
++              // before validation is happening.
++      }
+ 
+       allErrs = append(allErrs, ValidateSecret(newSecret)...)
+       return allErrs
+@@ -5051,8 +5061,20 @@ func ValidateConfigMap(cfg *core.ConfigMap) 
field.ErrorList {
+ func ValidateConfigMapUpdate(newCfg, oldCfg *core.ConfigMap) field.ErrorList {
+       allErrs := field.ErrorList{}
+       allErrs = append(allErrs, ValidateObjectMetaUpdate(&newCfg.ObjectMeta, 
&oldCfg.ObjectMeta, field.NewPath("metadata"))...)
+-      allErrs = append(allErrs, ValidateConfigMap(newCfg)...)
+ 
++      if oldCfg.Immutable != nil && *oldCfg.Immutable {
++              if !reflect.DeepEqual(newCfg.Immutable, oldCfg.Immutable) {
++                      allErrs = append(allErrs, 
field.Forbidden(field.NewPath("immutable"), "field is immutable when 
`immutable` is set"))
++              }
++              if !reflect.DeepEqual(newCfg.Data, oldCfg.Data) {
++                      allErrs = append(allErrs, 
field.Forbidden(field.NewPath("data"), "field is immutable when `immutable` is 
set"))
++              }
++              if !reflect.DeepEqual(newCfg.BinaryData, oldCfg.BinaryData) {
++                      allErrs = append(allErrs, 
field.Forbidden(field.NewPath("binaryData"), "field is immutable when 
`immutable` is set"))
++              }
++      }
++
++      allErrs = append(allErrs, ValidateConfigMap(newCfg)...)
+       return allErrs
+ }
+ 
+diff --git a/pkg/apis/core/validation/validation_test.go 
b/pkg/apis/core/validation/validation_test.go
+index 8ba68da00fe05..de8c1d49fc196 100644
+--- a/src/import/pkg/apis/core/validation/validation_test.go
++++ b/src/import/pkg/apis/core/validation/validation_test.go
+@@ -13117,6 +13117,104 @@ func TestValidateSecret(t *testing.T) {
+       }
+ }
+ 
++func TestValidateSecretUpdate(t *testing.T) {
++      validSecret := func() core.Secret {
++              return core.Secret{
++                      ObjectMeta: metav1.ObjectMeta{
++                              Name:            "foo",
++                              Namespace:       "bar",
++                              ResourceVersion: "20",
++                      },
++                      Data: map[string][]byte{
++                              "data-1": []byte("bar"),
++                      },
++              }
++      }
++
++      falseVal := false
++      trueVal := true
++
++      secret := validSecret()
++      immutableSecret := validSecret()
++      immutableSecret.Immutable = &trueVal
++      mutableSecret := validSecret()
++      mutableSecret.Immutable = &falseVal
++
++      secretWithData := validSecret()
++      secretWithData.Data["data-2"] = []byte("baz")
++      immutableSecretWithData := validSecret()
++      immutableSecretWithData.Immutable = &trueVal
++      immutableSecretWithData.Data["data-2"] = []byte("baz")
++
++      secretWithChangedData := validSecret()
++      secretWithChangedData.Data["data-1"] = []byte("foo")
++      immutableSecretWithChangedData := validSecret()
++      immutableSecretWithChangedData.Immutable = &trueVal
++      immutableSecretWithChangedData.Data["data-1"] = []byte("foo")
++
++      tests := []struct {
++              name      string
++              oldSecret core.Secret
++              newSecret core.Secret
++              valid     bool
++      }{
++              {
++                      name:      "mark secret immutable",
++                      oldSecret: secret,
++                      newSecret: immutableSecret,
++                      valid:     true,
++              },
++              {
++                      name:      "revert immutable secret",
++                      oldSecret: immutableSecret,
++                      newSecret: secret,
++                      valid:     false,
++              },
++              {
++                      name:      "makr immutable secret mutable",
++                      oldSecret: immutableSecret,
++                      newSecret: mutableSecret,
++                      valid:     false,
++              },
++              {
++                      name:      "add data in secret",
++                      oldSecret: secret,
++                      newSecret: secretWithData,
++                      valid:     true,
++              },
++              {
++                      name:      "add data in immutable secret",
++                      oldSecret: immutableSecret,
++                      newSecret: immutableSecretWithData,
++                      valid:     false,
++              },
++              {
++                      name:      "change data in secret",
++                      oldSecret: secret,
++                      newSecret: secretWithChangedData,
++                      valid:     true,
++              },
++              {
++                      name:      "change data in immutable secret",
++                      oldSecret: immutableSecret,
++                      newSecret: immutableSecretWithChangedData,
++                      valid:     false,
++              },
++      }
++
++      for _, tc := range tests {
++              t.Run(tc.name, func(t *testing.T) {
++                      errs := ValidateSecretUpdate(&tc.newSecret, 
&tc.oldSecret)
++                      if tc.valid && len(errs) > 0 {
++                              t.Errorf("Unexpected error: %v", errs)
++                      }
++                      if !tc.valid && len(errs) == 0 {
++                              t.Errorf("Unexpected lack of error")
++                      }
++              })
++      }
++}
++
+ func TestValidateDockerConfigSecret(t *testing.T) {
+       validDockerSecret := func() core.Secret {
+               return core.Secret{
+@@ -13731,40 +13829,105 @@ func TestValidateConfigMapUpdate(t *testing.T) {
+                       Data: data,
+               }
+       }
++      validConfigMap := func() core.ConfigMap {
++              return newConfigMap("1", "validname", "validdns", 
map[string]string{"key": "value"})
++      }
+ 
+-      var (
+-              validConfigMap = newConfigMap("1", "validname", "validns", 
map[string]string{"key": "value"})
+-              noVersion      = newConfigMap("", "validname", "validns", 
map[string]string{"key": "value"})
+-      )
++      falseVal := false
++      trueVal := true
++
++      configMap := validConfigMap()
++      immutableConfigMap := validConfigMap()
++      immutableConfigMap.Immutable = &trueVal
++      mutableConfigMap := validConfigMap()
++      mutableConfigMap.Immutable = &falseVal
++
++      configMapWithData := validConfigMap()
++      configMapWithData.Data["key-2"] = "value-2"
++      immutableConfigMapWithData := validConfigMap()
++      immutableConfigMapWithData.Immutable = &trueVal
++      immutableConfigMapWithData.Data["key-2"] = "value-2"
++
++      configMapWithChangedData := validConfigMap()
++      configMapWithChangedData.Data["key"] = "foo"
++      immutableConfigMapWithChangedData := validConfigMap()
++      immutableConfigMapWithChangedData.Immutable = &trueVal
++      immutableConfigMapWithChangedData.Data["key"] = "foo"
++
++      noVersion := newConfigMap("", "validname", "validns", 
map[string]string{"key": "value"})
+ 
+       cases := []struct {
+-              name    string
+-              newCfg  core.ConfigMap
+-              oldCfg  core.ConfigMap
+-              isValid bool
++              name   string
++              newCfg core.ConfigMap
++              oldCfg core.ConfigMap
++              valid  bool
+       }{
+               {
+-                      name:    "valid",
+-                      newCfg:  validConfigMap,
+-                      oldCfg:  validConfigMap,
+-                      isValid: true,
++                      name:   "valid",
++                      newCfg: configMap,
++                      oldCfg: configMap,
++                      valid:  true,
+               },
+               {
+-                      name:    "invalid",
+-                      newCfg:  noVersion,
+-                      oldCfg:  validConfigMap,
+-                      isValid: false,
++                      name:   "invalid",
++                      newCfg: noVersion,
++                      oldCfg: configMap,
++                      valid:  false,
++              },
++              {
++                      name:   "mark configmap immutable",
++                      oldCfg: configMap,
++                      newCfg: immutableConfigMap,
++                      valid:  true,
++              },
++              {
++                      name:   "revert immutable configmap",
++                      oldCfg: immutableConfigMap,
++                      newCfg: configMap,
++                      valid:  false,
++              },
++              {
++                      name:   "mark immutable configmap mutable",
++                      oldCfg: immutableConfigMap,
++                      newCfg: mutableConfigMap,
++                      valid:  false,
++              },
++              {
++                      name:   "add data in configmap",
++                      oldCfg: configMap,
++                      newCfg: configMapWithData,
++                      valid:  true,
++              },
++              {
++                      name:   "add data in immutable configmap",
++                      oldCfg: immutableConfigMap,
++                      newCfg: immutableConfigMapWithData,
++                      valid:  false,
++              },
++              {
++                      name:   "change data in configmap",
++                      oldCfg: configMap,
++                      newCfg: configMapWithChangedData,
++                      valid:  true,
++              },
++              {
++                      name:   "change data in immutable configmap",
++                      oldCfg: immutableConfigMap,
++                      newCfg: immutableConfigMapWithChangedData,
++                      valid:  false,
+               },
+       }
+ 
+       for _, tc := range cases {
+-              errs := ValidateConfigMapUpdate(&tc.newCfg, &tc.oldCfg)
+-              if tc.isValid && len(errs) > 0 {
+-                      t.Errorf("%v: unexpected error: %v", tc.name, errs)
+-              }
+-              if !tc.isValid && len(errs) == 0 {
+-                      t.Errorf("%v: unexpected non-error", tc.name)
+-              }
++              t.Run(tc.name, func(t *testing.T) {
++                      errs := ValidateConfigMapUpdate(&tc.newCfg, &tc.oldCfg)
++                      if tc.valid && len(errs) > 0 {
++                              t.Errorf("Unexpected error: %v", errs)
++                      }
++                      if !tc.valid && len(errs) == 0 {
++                              t.Errorf("Unexpected lack of error")
++                      }
++              })
+       }
+ }
+ 
+diff --git a/pkg/features/kube_features.go b/pkg/features/kube_features.go
+index 309dbb2955663..00da711112d71 100644
+--- a/src/import/pkg/features/kube_features.go
++++ b/src/import/pkg/features/kube_features.go
+@@ -548,6 +548,12 @@ const (
+       //
+       // Enables topology aware service routing
+       ServiceTopology featuregate.Feature = "ServiceTopology"
++
++      // owner: @wojtek-t
++      // alpha: v1.18
++      //
++      // Enables a feature to make secrets and configmaps data immutable.
++      ImmutableEphemeralVolumes featuregate.Feature = 
"ImmutableEphemeralVolumes"
+ )
+ 
+ func init() {
+@@ -634,6 +640,7 @@ var defaultKubernetesFeatureGates = 
map[featuregate.Feature]featuregate.FeatureS
+       AllowInsecureBackendProxy:                      {Default: true, 
PreRelease: featuregate.Beta},
+       PodDisruptionBudget:                            {Default: true, 
PreRelease: featuregate.Beta},
+       ServiceTopology:                                {Default: false, 
PreRelease: featuregate.Alpha},
++      ImmutableEphemeralVolumes:                      {Default: false, 
PreRelease: featuregate.Alpha},
+ 
+       // inherited features from generic apiserver, relisted here to get a 
conflict if it is changed
+       // unintentionally on either side:
+diff --git a/pkg/registry/core/configmap/strategy.go 
b/pkg/registry/core/configmap/strategy.go
+index 4f8bf42e3bd60..d592c181c0c2e 100644
+--- a/src/import/pkg/registry/core/configmap/strategy.go
++++ b/src/import/pkg/registry/core/configmap/strategy.go
+@@ -28,9 +28,11 @@ import (
+       "k8s.io/apiserver/pkg/registry/rest"
+       pkgstorage "k8s.io/apiserver/pkg/storage"
+       "k8s.io/apiserver/pkg/storage/names"
++      utilfeature "k8s.io/apiserver/pkg/util/feature"
+       "k8s.io/kubernetes/pkg/api/legacyscheme"
+       api "k8s.io/kubernetes/pkg/apis/core"
+       "k8s.io/kubernetes/pkg/apis/core/validation"
++      "k8s.io/kubernetes/pkg/features"
+ )
+ 
+ // strategy implements behavior for ConfigMap objects
+@@ -54,7 +56,8 @@ func (strategy) NamespaceScoped() bool {
+ }
+ 
+ func (strategy) PrepareForCreate(ctx context.Context, obj runtime.Object) {
+-      _ = obj.(*api.ConfigMap)
++      configMap := obj.(*api.ConfigMap)
++      dropDisabledFields(configMap, nil)
+ }
+ 
+ func (strategy) Validate(ctx context.Context, obj runtime.Object) 
field.ErrorList {
+@@ -72,12 +75,9 @@ func (strategy) AllowCreateOnUpdate() bool {
+ }
+ 
+ func (strategy) PrepareForUpdate(ctx context.Context, newObj, oldObj 
runtime.Object) {
+-      _ = oldObj.(*api.ConfigMap)
+-      _ = newObj.(*api.ConfigMap)
+-}
+-
+-func (strategy) AllowUnconditionalUpdate() bool {
+-      return true
++      oldConfigMap := oldObj.(*api.ConfigMap)
++      newConfigMap := newObj.(*api.ConfigMap)
++      dropDisabledFields(newConfigMap, oldConfigMap)
+ }
+ 
+ func (strategy) ValidateUpdate(ctx context.Context, newObj, oldObj 
runtime.Object) field.ErrorList {
+@@ -86,6 +86,20 @@ func (strategy) ValidateUpdate(ctx context.Context, newObj, 
oldObj runtime.Objec
+       return validation.ValidateConfigMapUpdate(newCfg, oldCfg)
+ }
+ 
++func isImmutableInUse(configMap *api.ConfigMap) bool {
++      return configMap != nil && configMap.Immutable != nil
++}
++
++func dropDisabledFields(configMap *api.ConfigMap, oldConfigMap 
*api.ConfigMap) {
++      if 
!utilfeature.DefaultFeatureGate.Enabled(features.ImmutableEphemeralVolumes) && 
!isImmutableInUse(oldConfigMap) {
++              configMap.Immutable = nil
++      }
++}
++
++func (strategy) AllowUnconditionalUpdate() bool {
++      return true
++}
++
+ // GetAttrs returns labels and fields of a given object for filtering 
purposes.
+ func GetAttrs(obj runtime.Object) (labels.Set, fields.Set, error) {
+       configMap, ok := obj.(*api.ConfigMap)
+diff --git a/pkg/registry/core/secret/strategy.go 
b/pkg/registry/core/secret/strategy.go
+index 1701805065e6c..0d5908d8975f1 100644
+--- a/src/import/pkg/registry/core/secret/strategy.go
++++ b/src/import/pkg/registry/core/secret/strategy.go
+@@ -29,9 +29,11 @@ import (
+       "k8s.io/apiserver/pkg/registry/rest"
+       pkgstorage "k8s.io/apiserver/pkg/storage"
+       "k8s.io/apiserver/pkg/storage/names"
++      utilfeature "k8s.io/apiserver/pkg/util/feature"
+       "k8s.io/kubernetes/pkg/api/legacyscheme"
+       api "k8s.io/kubernetes/pkg/apis/core"
+       "k8s.io/kubernetes/pkg/apis/core/validation"
++      "k8s.io/kubernetes/pkg/features"
+ )
+ 
+ // strategy implements behavior for Secret objects
+@@ -53,6 +55,8 @@ func (strategy) NamespaceScoped() bool {
+ }
+ 
+ func (strategy) PrepareForCreate(ctx context.Context, obj runtime.Object) {
++      secret := obj.(*api.Secret)
++      dropDisabledFields(secret, nil)
+ }
+ 
+ func (strategy) Validate(ctx context.Context, obj runtime.Object) 
field.ErrorList {
+@@ -67,12 +71,25 @@ func (strategy) AllowCreateOnUpdate() bool {
+ }
+ 
+ func (strategy) PrepareForUpdate(ctx context.Context, obj, old 
runtime.Object) {
++      newSecret := obj.(*api.Secret)
++      oldSecret := old.(*api.Secret)
++      dropDisabledFields(newSecret, oldSecret)
+ }
+ 
+ func (strategy) ValidateUpdate(ctx context.Context, obj, old runtime.Object) 
field.ErrorList {
+       return validation.ValidateSecretUpdate(obj.(*api.Secret), 
old.(*api.Secret))
+ }
+ 
++func isImmutableInUse(secret *api.Secret) bool {
++      return secret != nil && secret.Immutable != nil
++}
++
++func dropDisabledFields(secret *api.Secret, oldSecret *api.Secret) {
++      if 
!utilfeature.DefaultFeatureGate.Enabled(features.ImmutableEphemeralVolumes) && 
!isImmutableInUse(oldSecret) {
++              secret.Immutable = nil
++      }
++}
++
+ func (strategy) AllowUnconditionalUpdate() bool {
+       return true
+ }
+diff --git a/staging/src/k8s.io/api/core/v1/types.go 
b/staging/src/k8s.io/api/core/v1/types.go
+index a78372aeaffa7..1e3aa51730427 100644
+--- a/src/import/staging/src/k8s.io/api/core/v1/types.go
++++ b/src/import/staging/src/k8s.io/api/core/v1/types.go
+@@ -5424,6 +5424,14 @@ type Secret struct {
+       // +optional
+       metav1.ObjectMeta `json:"metadata,omitempty" 
protobuf:"bytes,1,opt,name=metadata"`
+ 
++      // Immutable, if set to true, ensures that data stored in the Secret 
cannot
++      // be updated (only object metadata can be modified).
++      // If not set to true, the field can be modified at any time.
++      // Defaulted to nil.
++      // This is an alpha field enabled by ImmutableEphemeralVolumes feature 
gate.
++      // +optional
++      Immutable *bool `json:"immutable,omitempty"`
++
+       // Data contains the secret data. Each key must consist of alphanumeric
+       // characters, '-', '_' or '.'. The serialized form of the secret data 
is a
+       // base64 encoded string, representing the arbitrary (possibly 
non-string)
+@@ -5557,6 +5565,14 @@ type ConfigMap struct {
+       // +optional
+       metav1.ObjectMeta `json:"metadata,omitempty" 
protobuf:"bytes,1,opt,name=metadata"`
+ 
++      // Immutable, if set to true, ensures that data stored in the ConfigMap 
cannot
++      // be updated (only object metadata can be modified).
++      // If not set to true, the field can be modified at any time.
++      // Defaulted to nil.
++      // This is an alpha field enabled by ImmutableEphemeralVolumes feature 
gate.
++      // +optional
++      Immutable *bool `json:"immutable,omitempty"`
++
+       // Data contains the configuration data.
+       // Each key must consist of alphanumeric characters, '-', '_' or '.'.
+       // Values with non-UTF-8 byte sequences must use the BinaryData field.
+diff --git 
a/staging/src/k8s.io/cli-runtime/pkg/kustomize/k8sdeps/transformer/hash/hash.go 
b/staging/src/k8s.io/cli-runtime/pkg/kustomize/k8sdeps/transformer/hash/hash.go
+index 17e24ff3e6443..85bf1e731c3fb 100644
+--- 
a/src/import/staging/src/k8s.io/cli-runtime/pkg/kustomize/k8sdeps/transformer/hash/hash.go
++++ 
b/src/import/staging/src/k8s.io/cli-runtime/pkg/kustomize/k8sdeps/transformer/hash/hash.go
+@@ -90,7 +90,14 @@ func SecretHash(sec *v1.Secret) (string, error) {
+ // Data, Kind, and Name are taken into account.
+ func encodeConfigMap(cm *v1.ConfigMap) (string, error) {
+       // json.Marshal sorts the keys in a stable order in the encoding
+-      m := map[string]interface{}{"kind": "ConfigMap", "name": cm.Name, 
"data": cm.Data}
++      m := map[string]interface{}{
++              "kind": "ConfigMap",
++              "name": cm.Name,
++              "data": cm.Data,
++      }
++      if cm.Immutable != nil {
++              m["immutable"] = *cm.Immutable
++      }
+       if len(cm.BinaryData) > 0 {
+               m["binaryData"] = cm.BinaryData
+       }
+@@ -105,7 +112,16 @@ func encodeConfigMap(cm *v1.ConfigMap) (string, error) {
+ // Data, Kind, Name, and Type are taken into account.
+ func encodeSecret(sec *v1.Secret) (string, error) {
+       // json.Marshal sorts the keys in a stable order in the encoding
+-      data, err := json.Marshal(map[string]interface{}{"kind": "Secret", 
"type": sec.Type, "name": sec.Name, "data": sec.Data})
++      m := map[string]interface{}{
++              "kind": "Secret",
++              "type": sec.Type,
++              "name": sec.Name,
++              "data": sec.Data,
++      }
++      if sec.Immutable != nil {
++              m["immutable"] = *sec.Immutable
++      }
++      data, err := json.Marshal(m)
+       if err != nil {
+               return "", err
+       }
+diff --git 
a/staging/src/k8s.io/cli-runtime/pkg/kustomize/k8sdeps/transformer/hash/hash_test.go
 
b/staging/src/k8s.io/cli-runtime/pkg/kustomize/k8sdeps/transformer/hash/hash_test.go
+index 2d336f35a824e..144fe444e4cac 100644
+--- 
a/src/import/staging/src/k8s.io/cli-runtime/pkg/kustomize/k8sdeps/transformer/hash/hash_test.go
++++ 
b/src/import/staging/src/k8s.io/cli-runtime/pkg/kustomize/k8sdeps/transformer/hash/hash_test.go
+@@ -178,8 +178,8 @@ not their metadata (e.g. the Data of a ConfigMap, but 
nothing in ObjectMeta).
+               obj      interface{}
+               expect   int
+       }{
+-              {"ConfigMap", v1.ConfigMap{}, 4},
+-              {"Secret", v1.Secret{}, 5},
++              {"ConfigMap", v1.ConfigMap{}, 5},
++              {"Secret", v1.Secret{}, 6},
+       }
+       for _, c := range cases {
+               val := reflect.ValueOf(c.obj)
+diff --git a/staging/src/k8s.io/kubectl/pkg/util/hash/hash.go 
b/staging/src/k8s.io/kubectl/pkg/util/hash/hash.go
+index de0036245d2f1..1b20f384b7098 100644
+--- a/src/import/staging/src/k8s.io/kubectl/pkg/util/hash/hash.go
++++ b/src/import/staging/src/k8s.io/kubectl/pkg/util/hash/hash.go
+@@ -56,7 +56,14 @@ func SecretHash(sec *v1.Secret) (string, error) {
+ // Data, Kind, and Name are taken into account.
+ func encodeConfigMap(cm *v1.ConfigMap) (string, error) {
+       // json.Marshal sorts the keys in a stable order in the encoding
+-      m := map[string]interface{}{"kind": "ConfigMap", "name": cm.Name, 
"data": cm.Data}
++      m := map[string]interface{}{
++              "kind": "ConfigMap",
++              "name": cm.Name,
++              "data": cm.Data,
++      }
++      if cm.Immutable != nil {
++              m["immutable"] = *cm.Immutable
++      }
+       if len(cm.BinaryData) > 0 {
+               m["binaryData"] = cm.BinaryData
+       }
+@@ -70,8 +77,17 @@ func encodeConfigMap(cm *v1.ConfigMap) (string, error) {
+ // encodeSecret encodes a Secret.
+ // Data, Kind, Name, and Type are taken into account.
+ func encodeSecret(sec *v1.Secret) (string, error) {
++      m := map[string]interface{}{
++              "kind": "Secret",
++              "type": sec.Type,
++              "name": sec.Name,
++              "data": sec.Data,
++      }
++      if sec.Immutable != nil {
++              m["immutable"] = *sec.Immutable
++      }
+       // json.Marshal sorts the keys in a stable order in the encoding
+-      data, err := json.Marshal(map[string]interface{}{"kind": "Secret", 
"type": sec.Type, "name": sec.Name, "data": sec.Data})
++      data, err := json.Marshal(m)
+       if err != nil {
+               return "", err
+       }
+diff --git a/staging/src/k8s.io/kubectl/pkg/util/hash/hash_test.go 
b/staging/src/k8s.io/kubectl/pkg/util/hash/hash_test.go
+index f527a98a2026c..455459c3b3df5 100644
+--- a/src/import/staging/src/k8s.io/kubectl/pkg/util/hash/hash_test.go
++++ b/src/import/staging/src/k8s.io/kubectl/pkg/util/hash/hash_test.go
+@@ -164,8 +164,8 @@ not their metadata (e.g. the Data of a ConfigMap, but 
nothing in ObjectMeta).
+               obj      interface{}
+               expect   int
+       }{
+-              {"ConfigMap", v1.ConfigMap{}, 4},
+-              {"Secret", v1.Secret{}, 5},
++              {"ConfigMap", v1.ConfigMap{}, 5},
++              {"Secret", v1.Secret{}, 6},
+       }
+       for _, c := range cases {
+               val := reflect.ValueOf(c.obj)
diff --git a/recipes-containers/kubernetes/kubernetes/CVE-2021-25735.patch 
b/recipes-containers/kubernetes/kubernetes/CVE-2021-25735.patch
new file mode 100644
index 00000000..dce50f3e
--- /dev/null
+++ b/recipes-containers/kubernetes/kubernetes/CVE-2021-25735.patch
@@ -0,0 +1,535 @@
+From 7d4efe7ad8cf06c0c1d6092cf1f77964edb8016f Mon Sep 17 00:00:00 2001
+From: David Eads <[email protected]>
+Date: Fri, 29 Jan 2021 13:47:31 -0500
+Subject: [PATCH 1/8] tweak validation to avoid mutation
+
+Upstream-Status: Backport 
[https://github.com/kubernetes/kubernetes/commit/d57f0641d60b73934ebc2cdf4b6a63182217d10c]
+CVE: CVE-2021-25735
+Signed-off-by: Vijay Anusuri <[email protected]>
+---
+ pkg/apis/core/validation/validation.go | 46 +++++++++-----------------
+ 1 file changed, 15 insertions(+), 31 deletions(-)
+
+diff --git a/pkg/apis/core/validation/validation.go 
b/pkg/apis/core/validation/validation.go
+index 8e3cfd9d9e4..89e5b5811c4 100644
+--- a/src/import/pkg/apis/core/validation/validation.go
++++ b/src/import/pkg/apis/core/validation/validation.go
+@@ -29,8 +29,6 @@ import (
+       "unicode"
+       "unicode/utf8"
+ 
+-      "k8s.io/klog"
+-
+       "k8s.io/api/core/v1"
+       apiequality "k8s.io/apimachinery/pkg/api/equality"
+       "k8s.io/apimachinery/pkg/api/resource"
+@@ -4530,11 +4528,8 @@ func ValidateNodeUpdate(node, oldNode *core.Node) 
field.ErrorList {
+               addresses[address] = true
+       }
+ 
+-      if len(oldNode.Spec.PodCIDRs) == 0 {
+-              // Allow the controller manager to assign a CIDR to a node if 
it doesn't have one.
+-              //this is a no op for a string slice.
+-              oldNode.Spec.PodCIDRs = node.Spec.PodCIDRs
+-      } else {
++      // Allow the controller manager to assign a CIDR to a node if it 
doesn't have one.
++      if len(oldNode.Spec.PodCIDRs) > 0 {
+               // compare the entire slice
+               if len(oldNode.Spec.PodCIDRs) != len(node.Spec.PodCIDRs) {
+                       allErrs = append(allErrs, 
field.Forbidden(field.NewPath("spec", "podCIDRs"), "node updates may not change 
podCIDR except from \"\" to valid"))
+@@ -4548,46 +4543,35 @@ func ValidateNodeUpdate(node, oldNode *core.Node) 
field.ErrorList {
+       }
+ 
+       // Allow controller manager updating provider ID when not set
+-      if len(oldNode.Spec.ProviderID) == 0 {
+-              oldNode.Spec.ProviderID = node.Spec.ProviderID
+-      } else {
+-              if oldNode.Spec.ProviderID != node.Spec.ProviderID {
+-                      allErrs = append(allErrs, 
field.Forbidden(field.NewPath("spec", "providerID"), "node updates may not 
change providerID except from \"\" to valid"))
+-              }
++      if len(oldNode.Spec.ProviderID) > 0 && oldNode.Spec.ProviderID != 
node.Spec.ProviderID {
++              allErrs = append(allErrs, field.Forbidden(field.NewPath("spec", 
"providerID"), "node updates may not change providerID except from \"\" to 
valid"))
+       }
+ 
+       if node.Spec.ConfigSource != nil {
+               allErrs = append(allErrs, 
validateNodeConfigSourceSpec(node.Spec.ConfigSource, field.NewPath("spec", 
"configSource"))...)
+       }
+-      oldNode.Spec.ConfigSource = node.Spec.ConfigSource
+       if node.Status.Config != nil {
+               allErrs = append(allErrs, 
validateNodeConfigStatus(node.Status.Config, field.NewPath("status", 
"config"))...)
+       }
+-      oldNode.Status.Config = node.Status.Config
+-
+-      // TODO: move reset function to its own location
+-      // Ignore metadata changes now that they have been tested
+-      oldNode.ObjectMeta = node.ObjectMeta
+-      // Allow users to update capacity
+-      oldNode.Status.Capacity = node.Status.Capacity
+-      // Allow users to unschedule node
+-      oldNode.Spec.Unschedulable = node.Spec.Unschedulable
+-      // Clear status
+-      oldNode.Status = node.Status
+ 
+       // update taints
+       if len(node.Spec.Taints) > 0 {
+               allErrs = append(allErrs, validateNodeTaints(node.Spec.Taints, 
fldPath.Child("taints"))...)
+       }
+-      oldNode.Spec.Taints = node.Spec.Taints
+ 
+-      // We made allowed changes to oldNode, and now we compare oldNode to 
node. Any remaining differences indicate changes to protected fields.
+-      // TODO: Add a 'real' error type for this error and provide print 
actual diffs.
+-      if !apiequality.Semantic.DeepEqual(oldNode, node) {
+-              klog.V(4).Infof("Update failed validation %#v vs %#v", oldNode, 
node)
+-              allErrs = append(allErrs, field.Forbidden(field.NewPath(""), 
"node updates may only change labels, taints, or capacity (or configSource, if 
the DynamicKubeletConfig feature gate is enabled)"))
++      if node.Spec.DoNotUseExternalID != oldNode.Spec.DoNotUseExternalID {
++              allErrs = append(allErrs, field.Forbidden(field.NewPath("spec", 
"externalID"), "may not be updated"))
+       }
+ 
++      // status and metadata are allowed change (barring restrictions above), 
so separately test spec field.
++      // spec only has a few fields, so check the ones we don't allow changing
++      //  1. PodCIDRs - immutable after first set - checked above
++      //  2. ProviderID - immutable after first set - checked above
++      //  3. Unschedulable - allowed to change
++      //  4. Taints - allowed to change
++      //  5. ConfigSource - allowed to change (and checked above)
++      //  6. DoNotUseExternalID - immutable - checked above
++
+       return allErrs
+ }
+ 
+-- 
+2.25.1
+
+
+From 0ef8605f4535713f17ede4bcf162ad513cbf6900 Mon Sep 17 00:00:00 2001
+From: David Eads <[email protected]>
+Date: Mon, 15 Feb 2021 16:21:42 -0500
+Subject: [PATCH 2/8] remove unnecessary mutations in validation
+
+These mutations are already done in the strategy
+---
+ pkg/apis/core/validation/validation.go | 22 ++--------------------
+ 1 file changed, 2 insertions(+), 20 deletions(-)
+
+diff --git a/pkg/apis/core/validation/validation.go 
b/pkg/apis/core/validation/validation.go
+index 89e5b5811c4..3381f2a37c2 100644
+--- a/src/import/pkg/apis/core/validation/validation.go
++++ b/src/import/pkg/apis/core/validation/validation.go
+@@ -1874,13 +1874,11 @@ func ValidatePersistentVolumeUpdate(newPv, oldPv 
*core.PersistentVolume) field.E
+ }
+ 
+ // ValidatePersistentVolumeStatusUpdate tests to see if the status update is 
legal for an end user to make.
+-// newPv is updated with fields that cannot be changed.
+ func ValidatePersistentVolumeStatusUpdate(newPv, oldPv 
*core.PersistentVolume) field.ErrorList {
+       allErrs := ValidateObjectMetaUpdate(&newPv.ObjectMeta, 
&oldPv.ObjectMeta, field.NewPath("metadata"))
+       if len(newPv.ResourceVersion) == 0 {
+               allErrs = append(allErrs, 
field.Required(field.NewPath("resourceVersion"), ""))
+       }
+-      newPv.Spec = oldPv.Spec
+       return allErrs
+ }
+ 
+@@ -2026,7 +2024,6 @@ func ValidatePersistentVolumeClaimStatusUpdate(newPvc, 
oldPvc *core.PersistentVo
+       for r, qty := range newPvc.Status.Capacity {
+               allErrs = append(allErrs, validateBasicResource(qty, 
capPath.Key(string(r)))...)
+       }
+-      newPvc.Spec = oldPvc.Spec
+       return allErrs
+ }
+ 
+@@ -3795,8 +3792,7 @@ func ValidateContainerStateTransition(newStatuses, 
oldStatuses []core.ContainerS
+       return allErrs
+ }
+ 
+-// ValidatePodStatusUpdate tests to see if the update is legal for an end 
user to make. newPod is updated with fields
+-// that cannot be changed.
++// ValidatePodStatusUpdate tests to see if the update is legal for an end 
user to make.
+ func ValidatePodStatusUpdate(newPod, oldPod *core.Pod) field.ErrorList {
+       fldPath := field.NewPath("metadata")
+       allErrs := ValidateObjectMetaUpdate(&newPod.ObjectMeta, 
&oldPod.ObjectMeta, fldPath)
+@@ -3819,9 +3815,6 @@ func ValidatePodStatusUpdate(newPod, oldPod *core.Pod) 
field.ErrorList {
+       allErrs = append(allErrs, 
ValidateContainerStateTransition(newPod.Status.ContainerStatuses, 
oldPod.Status.ContainerStatuses, fldPath.Child("containerStatuses"), 
oldPod.Spec.RestartPolicy)...)
+       allErrs = append(allErrs, 
ValidateContainerStateTransition(newPod.Status.InitContainerStatuses, 
oldPod.Status.InitContainerStatuses, fldPath.Child("initContainerStatuses"), 
oldPod.Spec.RestartPolicy)...)
+ 
+-      // For status update we ignore changes to pod spec.
+-      newPod.Spec = oldPod.Spec
+-
+       return allErrs
+ }
+ 
+@@ -5287,7 +5280,6 @@ func ValidateResourceQuantityValue(resource string, 
value resource.Quantity, fld
+ }
+ 
+ // ValidateResourceQuotaUpdate tests to see if the update is legal for an end 
user to make.
+-// newResourceQuota is updated with fields that cannot be changed.
+ func ValidateResourceQuotaUpdate(newResourceQuota, oldResourceQuota 
*core.ResourceQuota) field.ErrorList {
+       allErrs := ValidateObjectMetaUpdate(&newResourceQuota.ObjectMeta, 
&oldResourceQuota.ObjectMeta, field.NewPath("metadata"))
+       allErrs = append(allErrs, 
ValidateResourceQuotaSpec(&newResourceQuota.Spec, field.NewPath("spec"))...)
+@@ -5306,12 +5298,10 @@ func ValidateResourceQuotaUpdate(newResourceQuota, 
oldResourceQuota *core.Resour
+               allErrs = append(allErrs, field.Invalid(fldPath, 
newResourceQuota.Spec.Scopes, fieldImmutableErrorMsg))
+       }
+ 
+-      newResourceQuota.Status = oldResourceQuota.Status
+       return allErrs
+ }
+ 
+ // ValidateResourceQuotaStatusUpdate tests to see if the status update is 
legal for an end user to make.
+-// newResourceQuota is updated with fields that cannot be changed.
+ func ValidateResourceQuotaStatusUpdate(newResourceQuota, oldResourceQuota 
*core.ResourceQuota) field.ErrorList {
+       allErrs := ValidateObjectMetaUpdate(&newResourceQuota.ObjectMeta, 
&oldResourceQuota.ObjectMeta, field.NewPath("metadata"))
+       if len(newResourceQuota.ResourceVersion) == 0 {
+@@ -5329,7 +5319,6 @@ func ValidateResourceQuotaStatusUpdate(newResourceQuota, 
oldResourceQuota *core.
+               allErrs = append(allErrs, 
ValidateResourceQuotaResourceName(string(k), resPath)...)
+               allErrs = append(allErrs, 
ValidateResourceQuantityValue(string(k), v, resPath)...)
+       }
+-      newResourceQuota.Spec = oldResourceQuota.Spec
+       return allErrs
+ }
+ 
+@@ -5362,19 +5351,14 @@ func validateKubeFinalizerName(stringValue string, 
fldPath *field.Path) field.Er
+ }
+ 
+ // ValidateNamespaceUpdate tests to make sure a namespace update can be 
applied.
+-// newNamespace is updated with fields that cannot be changed
+ func ValidateNamespaceUpdate(newNamespace *core.Namespace, oldNamespace 
*core.Namespace) field.ErrorList {
+       allErrs := ValidateObjectMetaUpdate(&newNamespace.ObjectMeta, 
&oldNamespace.ObjectMeta, field.NewPath("metadata"))
+-      newNamespace.Spec.Finalizers = oldNamespace.Spec.Finalizers
+-      newNamespace.Status = oldNamespace.Status
+       return allErrs
+ }
+ 
+-// ValidateNamespaceStatusUpdate tests to see if the update is legal for an 
end user to make. newNamespace is updated with fields
+-// that cannot be changed.
++// ValidateNamespaceStatusUpdate tests to see if the update is legal for an 
end user to make.
+ func ValidateNamespaceStatusUpdate(newNamespace, oldNamespace 
*core.Namespace) field.ErrorList {
+       allErrs := ValidateObjectMetaUpdate(&newNamespace.ObjectMeta, 
&oldNamespace.ObjectMeta, field.NewPath("metadata"))
+-      newNamespace.Spec = oldNamespace.Spec
+       if newNamespace.DeletionTimestamp.IsZero() {
+               if newNamespace.Status.Phase != core.NamespaceActive {
+                       allErrs = append(allErrs, 
field.Invalid(field.NewPath("status", "Phase"), newNamespace.Status.Phase, "may 
only be 'Active' if `deletionTimestamp` is empty"))
+@@ -5388,7 +5372,6 @@ func ValidateNamespaceStatusUpdate(newNamespace, 
oldNamespace *core.Namespace) f
+ }
+ 
+ // ValidateNamespaceFinalizeUpdate tests to see if the update is legal for an 
end user to make.
+-// newNamespace is updated with fields that cannot be changed.
+ func ValidateNamespaceFinalizeUpdate(newNamespace, oldNamespace 
*core.Namespace) field.ErrorList {
+       allErrs := ValidateObjectMetaUpdate(&newNamespace.ObjectMeta, 
&oldNamespace.ObjectMeta, field.NewPath("metadata"))
+ 
+@@ -5397,7 +5380,6 @@ func ValidateNamespaceFinalizeUpdate(newNamespace, 
oldNamespace *core.Namespace)
+               idxPath := fldPath.Index(i)
+               allErrs = append(allErrs, 
validateFinalizerName(string(newNamespace.Spec.Finalizers[i]), idxPath)...)
+       }
+-      newNamespace.Status = oldNamespace.Status
+       return allErrs
+ }
+ 
+-- 
+2.25.1
+
+
+From 198ac41f97e11140b634274e34f0102e33806145 Mon Sep 17 00:00:00 2001
+From: David Eads <[email protected]>
+Date: Mon, 15 Feb 2021 16:55:41 -0500
+Subject: [PATCH 3/8] move secret mutation from validation to prepareforupdate
+
+---
+ pkg/apis/core/validation/validation.go | 4 ----
+ pkg/registry/core/secret/strategy.go   | 6 ++++++
+ 2 files changed, 6 insertions(+), 4 deletions(-)
+
+diff --git a/pkg/apis/core/validation/validation.go 
b/pkg/apis/core/validation/validation.go
+index 3381f2a37c2..9775b268e90 100644
+--- a/src/import/pkg/apis/core/validation/validation.go
++++ b/src/import/pkg/apis/core/validation/validation.go
+@@ -4977,10 +4977,6 @@ func ValidateSecret(secret *core.Secret) 
field.ErrorList {
+ func ValidateSecretUpdate(newSecret, oldSecret *core.Secret) field.ErrorList {
+       allErrs := ValidateObjectMetaUpdate(&newSecret.ObjectMeta, 
&oldSecret.ObjectMeta, field.NewPath("metadata"))
+ 
+-      if len(newSecret.Type) == 0 {
+-              newSecret.Type = oldSecret.Type
+-      }
+-
+       allErrs = append(allErrs, ValidateImmutableField(newSecret.Type, 
oldSecret.Type, field.NewPath("type"))...)
+       if oldSecret.Immutable != nil && *oldSecret.Immutable {
+               if !reflect.DeepEqual(newSecret.Immutable, oldSecret.Immutable) 
{
+diff --git a/pkg/registry/core/secret/strategy.go 
b/pkg/registry/core/secret/strategy.go
+index 0d5908d8975..aad00387ac1 100644
+--- a/src/import/pkg/registry/core/secret/strategy.go
++++ b/src/import/pkg/registry/core/secret/strategy.go
+@@ -73,6 +73,12 @@ func (strategy) AllowCreateOnUpdate() bool {
+ func (strategy) PrepareForUpdate(ctx context.Context, obj, old 
runtime.Object) {
+       newSecret := obj.(*api.Secret)
+       oldSecret := old.(*api.Secret)
++
++      // this is weird, but consistent with what the validatedUpdate function 
used to do.
++      if len(newSecret.Type) == 0 {
++              newSecret.Type = oldSecret.Type
++      }
++
+       dropDisabledFields(newSecret, oldSecret)
+ }
+ 
+-- 
+2.25.1
+
+
+From 7973d58ea8fe93c2be920a766c7c5d6a4a2529e6 Mon Sep 17 00:00:00 2001
+From: David Eads <[email protected]>
+Date: Mon, 15 Feb 2021 17:18:11 -0500
+Subject: [PATCH 4/8] add markers for inspected validation mutation hits
+
+---
+ pkg/apis/core/validation/validation.go                 | 10 +++++-----
+ .../pkg/apis/apiextensions/validation/validation.go    |  2 +-
+ 2 files changed, 6 insertions(+), 6 deletions(-)
+
+diff --git a/pkg/apis/core/validation/validation.go 
b/pkg/apis/core/validation/validation.go
+index 9775b268e90..6f634db468e 100644
+--- a/src/import/pkg/apis/core/validation/validation.go
++++ b/src/import/pkg/apis/core/validation/validation.go
+@@ -1953,7 +1953,7 @@ func ValidatePersistentVolumeClaimUpdate(newPvc, oldPvc 
*core.PersistentVolumeCl
+       // Claims are immutable in order to enforce quota, range limits, etc. 
without gaming the system.
+       if len(oldPvc.Spec.VolumeName) == 0 {
+               // volumeName changes are allowed once.
+-              oldPvcClone.Spec.VolumeName = newPvcClone.Spec.VolumeName
++              oldPvcClone.Spec.VolumeName = newPvcClone.Spec.VolumeName // 
+k8s:verify-mutation:reason=clone
+       }
+ 
+       if validateStorageClassUpgrade(oldPvcClone.Annotations, 
newPvcClone.Annotations,
+@@ -1969,7 +1969,7 @@ func ValidatePersistentVolumeClaimUpdate(newPvc, oldPvc 
*core.PersistentVolumeCl
+       if 
utilfeature.DefaultFeatureGate.Enabled(features.ExpandPersistentVolumes) {
+               // lets make sure storage values are same.
+               if newPvc.Status.Phase == core.ClaimBound && 
newPvcClone.Spec.Resources.Requests != nil {
+-                      newPvcClone.Spec.Resources.Requests["storage"] = 
oldPvc.Spec.Resources.Requests["storage"]
++                      newPvcClone.Spec.Resources.Requests["storage"] = 
oldPvc.Spec.Resources.Requests["storage"] // +k8s:verify-mutation:reason=clone
+               }
+ 
+               oldSize := oldPvc.Spec.Resources.Requests["storage"]
+@@ -2317,13 +2317,13 @@ func GetVolumeMountMap(mounts []core.VolumeMount) 
map[string]string {
+ }
+ 
+ func GetVolumeDeviceMap(devices []core.VolumeDevice) map[string]string {
+-      voldevices := make(map[string]string)
++      volDevices := make(map[string]string)
+ 
+       for _, dev := range devices {
+-              voldevices[dev.Name] = dev.DevicePath
++              volDevices[dev.Name] = dev.DevicePath
+       }
+ 
+-      return voldevices
++      return volDevices
+ }
+ 
+ func ValidateVolumeMounts(mounts []core.VolumeMount, voldevices 
map[string]string, volumes map[string]core.VolumeSource, container 
*core.Container, fldPath *field.Path) field.ErrorList {
+diff --git 
a/staging/src/k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/validation/validation.go
 
b/staging/src/k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/validation/validation.go
+index f570dd82a4b..2bc72643c85 100644
+--- 
a/src/import/staging/src/k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/validation/validation.go
++++ 
b/src/import/staging/src/k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/validation/validation.go
+@@ -1304,7 +1304,7 @@ func validateAPIApproval(newCRD, oldCRD 
*apiextensions.CustomResourceDefinition,
+       var oldApprovalState *apihelpers.APIApprovalState
+       if oldCRD != nil {
+               t, _ := apihelpers.GetAPIApprovalState(oldCRD.Annotations)
+-              oldApprovalState = &t
++              oldApprovalState = &t // +k8s:verify-mutation:reason=clone
+       }
+       newApprovalState, reason := 
apihelpers.GetAPIApprovalState(newCRD.Annotations)
+ 
+-- 
+2.25.1
+
+
+From 0b8dcbecdc093829aaccee7bf541ef8cae7f3848 Mon Sep 17 00:00:00 2001
+From: David Eads <[email protected]>
+Date: Mon, 15 Feb 2021 17:33:34 -0500
+Subject: [PATCH 5/8] remove pod toleration toleration seconds mutation
+
+---
+ pkg/apis/core/validation/validation.go | 16 ++++++++--------
+ 1 file changed, 8 insertions(+), 8 deletions(-)
+
+diff --git a/pkg/apis/core/validation/validation.go 
b/pkg/apis/core/validation/validation.go
+index 6f634db468e..4226047775b 100644
+--- a/src/import/pkg/apis/core/validation/validation.go
++++ b/src/import/pkg/apis/core/validation/validation.go
+@@ -2967,10 +2967,11 @@ func validateOnlyAddedTolerations(newTolerations 
[]core.Toleration, oldToleratio
+       allErrs := field.ErrorList{}
+       for _, old := range oldTolerations {
+               found := false
+-              old.TolerationSeconds = nil
+-              for _, new := range newTolerations {
+-                      new.TolerationSeconds = nil
+-                      if reflect.DeepEqual(old, new) {
++              oldTolerationClone := old.DeepCopy()
++              for _, newToleration := range newTolerations {
++                      // assign to our clone before doing a deep equal so we 
can allow tolerationseconds to change.
++                      oldTolerationClone.TolerationSeconds = 
newToleration.TolerationSeconds // +k8s:verify-mutation:reason=clone
++                      if reflect.DeepEqual(*oldTolerationClone, 
newToleration) {
+                               found = true
+                               break
+                       }
+@@ -3730,6 +3731,9 @@ func ValidatePodUpdate(newPod, oldPod *core.Pod) 
field.ErrorList {
+               allErrs = append(allErrs, 
field.Invalid(specPath.Child("activeDeadlineSeconds"), 
newPod.Spec.ActiveDeadlineSeconds, "must not update from a positive integer to 
nil value"))
+       }
+ 
++      // Allow only additions to tolerations updates.
++      allErrs = append(allErrs, 
validateOnlyAddedTolerations(newPod.Spec.Tolerations, oldPod.Spec.Tolerations, 
specPath.Child("tolerations"))...)
++
+       // handle updateable fields by munging those fields prior to deep equal 
comparison.
+       mungedPod := *newPod
+       // munge spec.containers[*].image
+@@ -3753,10 +3757,6 @@ func ValidatePodUpdate(newPod, oldPod *core.Pod) 
field.ErrorList {
+               mungedPod.Spec.ActiveDeadlineSeconds = &activeDeadlineSeconds
+       }
+ 
+-      // Allow only additions to tolerations updates.
+-      mungedPod.Spec.Tolerations = oldPod.Spec.Tolerations
+-      allErrs = append(allErrs, 
validateOnlyAddedTolerations(newPod.Spec.Tolerations, oldPod.Spec.Tolerations, 
specPath.Child("tolerations"))...)
+-
+       if !apiequality.Semantic.DeepEqual(mungedPod.Spec, oldPod.Spec) {
+               // This diff isn't perfect, but it's a helluva lot better an 
"I'm not going to tell you what the difference is".
+               //TODO: Pinpoint the specific field that causes the invalid 
error after we have strategic merge diff
+-- 
+2.25.1
+
+
+From db5696ebe654a487c0216bd0646ffb9872bac39a Mon Sep 17 00:00:00 2001
+From: David Eads <[email protected]>
+Date: Mon, 15 Feb 2021 17:43:57 -0500
+Subject: [PATCH 6/8] full deepcopy on munged pod spec
+
+---
+ pkg/apis/core/validation/validation.go | 30 ++++++++++++++++----------
+ 1 file changed, 19 insertions(+), 11 deletions(-)
+
+diff --git a/pkg/apis/core/validation/validation.go 
b/pkg/apis/core/validation/validation.go
+index 4226047775b..d6eb9fe56f4 100644
+--- a/src/import/pkg/apis/core/validation/validation.go
++++ b/src/import/pkg/apis/core/validation/validation.go
+@@ -3734,33 +3734,41 @@ func ValidatePodUpdate(newPod, oldPod *core.Pod) 
field.ErrorList {
+       // Allow only additions to tolerations updates.
+       allErrs = append(allErrs, 
validateOnlyAddedTolerations(newPod.Spec.Tolerations, oldPod.Spec.Tolerations, 
specPath.Child("tolerations"))...)
+ 
++      // the last thing to check is pod spec equality.  If the pod specs are 
equal, then we can simply return the errors we have
++      // so far and save the cost of a deep copy.
++      if apiequality.Semantic.DeepEqual(newPod.Spec, oldPod.Spec) {
++              return allErrs
++      }
++
+       // handle updateable fields by munging those fields prior to deep equal 
comparison.
+-      mungedPod := *newPod
++      mungedPodSpec := *newPod.Spec.DeepCopy()
+       // munge spec.containers[*].image
+       var newContainers []core.Container
+-      for ix, container := range mungedPod.Spec.Containers {
+-              container.Image = oldPod.Spec.Containers[ix].Image
++      for ix, container := range mungedPodSpec.Containers {
++              container.Image = oldPod.Spec.Containers[ix].Image // 
+k8s:verify-mutation:reason=clone
+               newContainers = append(newContainers, container)
+       }
+-      mungedPod.Spec.Containers = newContainers
++      mungedPodSpec.Containers = newContainers
+       // munge spec.initContainers[*].image
+       var newInitContainers []core.Container
+-      for ix, container := range mungedPod.Spec.InitContainers {
+-              container.Image = oldPod.Spec.InitContainers[ix].Image
++      for ix, container := range mungedPodSpec.InitContainers {
++              container.Image = oldPod.Spec.InitContainers[ix].Image // 
+k8s:verify-mutation:reason=clone
+               newInitContainers = append(newInitContainers, container)
+       }
+-      mungedPod.Spec.InitContainers = newInitContainers
++      mungedPodSpec.InitContainers = newInitContainers
+       // munge spec.activeDeadlineSeconds
+-      mungedPod.Spec.ActiveDeadlineSeconds = nil
++      mungedPodSpec.ActiveDeadlineSeconds = nil
+       if oldPod.Spec.ActiveDeadlineSeconds != nil {
+               activeDeadlineSeconds := *oldPod.Spec.ActiveDeadlineSeconds
+-              mungedPod.Spec.ActiveDeadlineSeconds = &activeDeadlineSeconds
++              mungedPodSpec.ActiveDeadlineSeconds = &activeDeadlineSeconds
+       }
++      // tolerations are checked before the deep copy, so munge those too
++      mungedPodSpec.Tolerations = oldPod.Spec.Tolerations // 
+k8s:verify-mutation:reason=clone
+ 
+-      if !apiequality.Semantic.DeepEqual(mungedPod.Spec, oldPod.Spec) {
++      if !apiequality.Semantic.DeepEqual(mungedPodSpec, oldPod.Spec) {
+               // This diff isn't perfect, but it's a helluva lot better an 
"I'm not going to tell you what the difference is".
+               //TODO: Pinpoint the specific field that causes the invalid 
error after we have strategic merge diff
+-              specDiff := diff.ObjectDiff(mungedPod.Spec, oldPod.Spec)
++              specDiff := diff.ObjectDiff(mungedPodSpec, oldPod.Spec)
+               allErrs = append(allErrs, field.Forbidden(specPath, 
fmt.Sprintf("pod updates may not change fields other than 
`spec.containers[*].image`, `spec.initContainers[*].image`, 
`spec.activeDeadlineSeconds` or `spec.tolerations` (only additions to existing 
tolerations)\n%v", specDiff)))
+       }
+ 
+-- 
+2.25.1
+
+
+From 888666d4d5b96328f7e9d96c0946e9d7c8222f81 Mon Sep 17 00:00:00 2001
+From: David Eads <[email protected]>
+Date: Wed, 17 Feb 2021 10:51:38 -0500
+Subject: [PATCH 7/8] deepcopy statefulsets
+
+---
+ pkg/apis/apps/validation/validation.go | 20 +++++++-------------
+ 1 file changed, 7 insertions(+), 13 deletions(-)
+
+diff --git a/pkg/apis/apps/validation/validation.go 
b/pkg/apis/apps/validation/validation.go
+index 6ac73cb6b7e..03e0d2024dd 100644
+--- a/src/import/pkg/apis/apps/validation/validation.go
++++ b/src/import/pkg/apis/apps/validation/validation.go
+@@ -144,21 +144,15 @@ func ValidateStatefulSet(statefulSet *apps.StatefulSet) 
field.ErrorList {
+ func ValidateStatefulSetUpdate(statefulSet, oldStatefulSet *apps.StatefulSet) 
field.ErrorList {
+       allErrs := 
apivalidation.ValidateObjectMetaUpdate(&statefulSet.ObjectMeta, 
&oldStatefulSet.ObjectMeta, field.NewPath("metadata"))
+ 
+-      restoreReplicas := statefulSet.Spec.Replicas
+-      statefulSet.Spec.Replicas = oldStatefulSet.Spec.Replicas
+-
+-      restoreTemplate := statefulSet.Spec.Template
+-      statefulSet.Spec.Template = oldStatefulSet.Spec.Template
+-
+-      restoreStrategy := statefulSet.Spec.UpdateStrategy
+-      statefulSet.Spec.UpdateStrategy = oldStatefulSet.Spec.UpdateStrategy
+-
+-      if !apiequality.Semantic.DeepEqual(statefulSet.Spec, 
oldStatefulSet.Spec) {
++      // statefulset updates aren't super common and general updates are 
likely to be touching spec, so we'll do this
++      // deep copy right away.  This avoids mutating our inputs
++      newStatefulSetClone := statefulSet.DeepCopy()
++      newStatefulSetClone.Spec.Replicas = oldStatefulSet.Spec.Replicas        
     // +k8s:verify-mutation:reason=clone
++      newStatefulSetClone.Spec.Template = oldStatefulSet.Spec.Template        
     // +k8s:verify-mutation:reason=clone
++      newStatefulSetClone.Spec.UpdateStrategy = 
oldStatefulSet.Spec.UpdateStrategy // +k8s:verify-mutation:reason=clone
++      if !apiequality.Semantic.DeepEqual(newStatefulSetClone.Spec, 
oldStatefulSet.Spec) {
+               allErrs = append(allErrs, 
field.Forbidden(field.NewPath("spec"), "updates to statefulset spec for fields 
other than 'replicas', 'template', and 'updateStrategy' are forbidden"))
+       }
+-      statefulSet.Spec.Replicas = restoreReplicas
+-      statefulSet.Spec.Template = restoreTemplate
+-      statefulSet.Spec.UpdateStrategy = restoreStrategy
+ 
+       allErrs = append(allErrs, 
apivalidation.ValidateNonnegativeField(int64(statefulSet.Spec.Replicas), 
field.NewPath("spec", "replicas"))...)
+       return allErrs
+-- 
+2.25.1
+
+
+From bfbe634654ae1ac86033b69703ed78ade5d605ea Mon Sep 17 00:00:00 2001
+From: David Eads <[email protected]>
+Date: Wed, 17 Mar 2021 09:12:42 -0400
+Subject: [PATCH 8/8] bazel
+
+---
+ pkg/apis/core/validation/BUILD | 1 -
+ 1 file changed, 1 deletion(-)
+
+diff --git a/pkg/apis/core/validation/BUILD b/pkg/apis/core/validation/BUILD
+index 2db631180e6..00649a3a52c 100644
+--- a/src/import/pkg/apis/core/validation/BUILD
++++ b/src/import/pkg/apis/core/validation/BUILD
+@@ -40,7 +40,6 @@ go_library(
+         
"//staging/src/k8s.io/apimachinery/pkg/util/validation:go_default_library",
+         
"//staging/src/k8s.io/apimachinery/pkg/util/validation/field:go_default_library",
+         "//staging/src/k8s.io/apiserver/pkg/util/feature:go_default_library",
+-        "//vendor/k8s.io/klog:go_default_library",
+         "//vendor/k8s.io/utils/net:go_default_library",
+     ],
+ )
+-- 
+2.25.1
+
diff --git a/recipes-containers/kubernetes/kubernetes/CVE-2021-25737.patch 
b/recipes-containers/kubernetes/kubernetes/CVE-2021-25737.patch
new file mode 100644
index 00000000..d1a97971
--- /dev/null
+++ b/recipes-containers/kubernetes/kubernetes/CVE-2021-25737.patch
@@ -0,0 +1,128 @@
+From 901e8e07e1f031456ecd7fefce965aaa05916825 Mon Sep 17 00:00:00 2001
+From: Rob Scott <[email protected]>
+Date: Fri, 9 Apr 2021 15:24:17 -0700
+Subject: [PATCH] Updating EndpointSlice validation to match Endpoints
+ validation
+
+Upstream-Status: Backport 
[https://github.com/kubernetes/kubernetes/commit/901e8e07e1f031456ecd7fefce965aaa05916825]
+CVE: CVE-2021-25737
+Signed-off-by: Vijay Anusuri <[email protected]>
+---
+ pkg/apis/core/validation/validation.go        | 18 ++++++----
+ pkg/apis/discovery/validation/validation.go   |  2 ++
+ .../discovery/validation/validation_test.go   | 34 +++++++++++++++++--
+ 3 files changed, 45 insertions(+), 9 deletions(-)
+
+diff --git a/pkg/apis/core/validation/validation.go 
b/pkg/apis/core/validation/validation.go
+index 3daeb139d590d..c65cdd40f9061 100644
+--- a/src/import/pkg/apis/core/validation/validation.go
++++ b/src/import/pkg/apis/core/validation/validation.go
+@@ -4014,7 +4014,7 @@ func ValidateService(service *core.Service, 
allowAppProtocol bool) field.ErrorLi
+                               allErrs = append(allErrs, 
field.Invalid(idxPath, ip, msgs[i]))
+                       }
+               } else {
+-                      allErrs = append(allErrs, validateNonSpecialIP(ip, 
idxPath)...)
++                      allErrs = append(allErrs, ValidateNonSpecialIP(ip, 
idxPath)...)
+               }
+       }
+ 
+@@ -5572,15 +5572,19 @@ func validateEndpointAddress(address 
*core.EndpointAddress, fldPath *field.Path)
+                       allErrs = append(allErrs, 
field.Invalid(fldPath.Child("nodeName"), *address.NodeName, msg))
+               }
+       }
+-      allErrs = append(allErrs, validateNonSpecialIP(address.IP, 
fldPath.Child("ip"))...)
++      allErrs = append(allErrs, ValidateNonSpecialIP(address.IP, 
fldPath.Child("ip"))...)
+       return allErrs
+ }
+ 
+-func validateNonSpecialIP(ipAddress string, fldPath *field.Path) 
field.ErrorList {
+-      // We disallow some IPs as endpoints or external-ips.  Specifically,
+-      // unspecified and loopback addresses are nonsensical and link-local
+-      // addresses tend to be used for node-centric purposes (e.g. metadata
+-      // service).
++// ValidateNonSpecialIP is used to validate Endpoints, EndpointSlices, and
++// external IPs. Specifically, this disallows unspecified and loopback 
addresses
++// are nonsensical and link-local addresses tend to be used for node-centric
++// purposes (e.g. metadata service).
++//
++// IPv6 references
++// - 
https://www.iana.org/assignments/iana-ipv6-special-registry/iana-ipv6-special-registry.xhtml
++// - 
https://www.iana.org/assignments/ipv6-multicast-addresses/ipv6-multicast-addresses.xhtml
++func ValidateNonSpecialIP(ipAddress string, fldPath *field.Path) 
field.ErrorList {
+       allErrs := field.ErrorList{}
+       ip := net.ParseIP(ipAddress)
+       if ip == nil {
+diff --git a/pkg/apis/discovery/validation/validation.go 
b/pkg/apis/discovery/validation/validation.go
+index 810f2ca124d57..3aa5128359d7f 100644
+--- a/src/import/pkg/apis/discovery/validation/validation.go
++++ b/src/import/pkg/apis/discovery/validation/validation.go
+@@ -103,8 +103,10 @@ func validateEndpoints(endpoints []discovery.Endpoint, 
addrType discovery.Addres
+                               }
+                       case discovery.AddressTypeIPv4:
+                               allErrs = append(allErrs, 
validation.IsValidIPv4Address(addressPath.Index(i), address)...)
++                              allErrs = append(allErrs, 
apivalidation.ValidateNonSpecialIP(address, addressPath.Index(i))...)
+                       case discovery.AddressTypeIPv6:
+                               allErrs = append(allErrs, 
validation.IsValidIPv6Address(addressPath.Index(i), address)...)
++                              allErrs = append(allErrs, 
apivalidation.ValidateNonSpecialIP(address, addressPath.Index(i))...)
+                       case discovery.AddressTypeFQDN:
+                               allErrs = append(allErrs, 
validation.IsFullyQualifiedDomainName(addressPath.Index(i), address)...)
+                       }
+diff --git a/pkg/apis/discovery/validation/validation_test.go 
b/pkg/apis/discovery/validation/validation_test.go
+index 060545f93ab31..3c8a5465128a9 100644
+--- a/src/import/pkg/apis/discovery/validation/validation_test.go
++++ b/src/import/pkg/apis/discovery/validation/validation_test.go
+@@ -390,7 +390,7 @@ func TestValidateEndpointSlice(t *testing.T) {
+                       },
+               },
+               "bad-ipv4": {
+-                      expectedErrors: 2,
++                      expectedErrors: 3,
+                       endpointSlice: &discovery.EndpointSlice{
+                               ObjectMeta:  standardMeta,
+                               AddressType: discovery.AddressTypeIPv4,
+@@ -405,7 +405,7 @@ func TestValidateEndpointSlice(t *testing.T) {
+                       },
+               },
+               "bad-ipv6": {
+-                      expectedErrors: 2,
++                      expectedErrors: 4,
+                       endpointSlice: &discovery.EndpointSlice{
+                               ObjectMeta:  standardMeta,
+                               AddressType: discovery.AddressTypeIPv6,
+@@ -454,6 +454,36 @@ func TestValidateEndpointSlice(t *testing.T) {
+                       expectedErrors: 3,
+                       endpointSlice:  &discovery.EndpointSlice{},
+               },
++              "special-ipv4": {
++                      expectedErrors: 1,
++                      endpointSlice: &discovery.EndpointSlice{
++                              ObjectMeta:  standardMeta,
++                              AddressType: discovery.AddressTypeIPv4,
++                              Ports: []discovery.EndpointPort{{
++                                      Name:     utilpointer.StringPtr("http"),
++                                      Protocol: protocolPtr(api.ProtocolTCP),
++                              }},
++                              Endpoints: []discovery.Endpoint{{
++                                      Addresses: []string{"127.0.0.1"},
++                                      Hostname:  
utilpointer.StringPtr("valid-123"),
++                              }},
++                      },
++              },
++              "special-ipv6": {
++                      expectedErrors: 1,
++                      endpointSlice: &discovery.EndpointSlice{
++                              ObjectMeta:  standardMeta,
++                              AddressType: discovery.AddressTypeIPv6,
++                              Ports: []discovery.EndpointPort{{
++                                      Name:     utilpointer.StringPtr("http"),
++                                      Protocol: protocolPtr(api.ProtocolTCP),
++                              }},
++                              Endpoints: []discovery.Endpoint{{
++                                      Addresses: 
[]string{"fe80::9656:d028:8652:66b6"},
++                                      Hostname:  
utilpointer.StringPtr("valid-123"),
++                              }},
++                      },
++              },
+       }
+ 
+       for name, testCase := range testCases {
diff --git a/recipes-containers/kubernetes/kubernetes_git.bb 
b/recipes-containers/kubernetes/kubernetes_git.bb
index 2b0bfb7a..be3d7dbe 100644
--- a/recipes-containers/kubernetes/kubernetes_git.bb
+++ b/recipes-containers/kubernetes/kubernetes_git.bb
@@ -14,6 +14,9 @@ SRC_URI = 
"git://github.com/kubernetes/kubernetes.git;branch=release-1.17;name=k
            file://CVE-2020-8564.patch \
            file://CVE-2020-8565.patch \
            file://CVE-2020-8566.patch \
+           file://CVE-2021-25735-pre1.patch \
+           file://CVE-2021-25735.patch \
+           file://CVE-2021-25737.patch \
           "
 
 DEPENDS += "rsync-native \
-- 
2.25.1

-=-=-=-=-=-=-=-=-=-=-=-
Links: You receive all messages sent to this group.
View/Reply Online (#8326): 
https://lists.yoctoproject.org/g/meta-virtualization/message/8326
Mute This Topic: https://lists.yoctoproject.org/mt/101614699/21656
Group Owner: [email protected]
Unsubscribe: https://lists.yoctoproject.org/g/meta-virtualization/unsub 
[[email protected]]
-=-=-=-=-=-=-=-=-=-=-=-

Reply via email to