From 7da04797d036fff52fbdf57d6f71774aaaac98eb Mon Sep 17 00:00:00 2001 From: leizhongkai Date: Sun, 26 Sep 2021 11:56:02 +0800 Subject: [PATCH] fix CVE-2021-25735 and CVE-2021-25737 Signed-off-by: leizhongkai --- 0003-fix-CVE-2021-25735.patch | 394 ++++++++++++++++++++++++++++++++++ 0004-fix-CVE-2021-25737.patch | 209 ++++++++++++++++++ kubernetes.spec | 7 +- 3 files changed, 609 insertions(+), 1 deletion(-) create mode 100644 0003-fix-CVE-2021-25735.patch create mode 100644 0004-fix-CVE-2021-25737.patch diff --git a/0003-fix-CVE-2021-25735.patch b/0003-fix-CVE-2021-25735.patch new file mode 100644 index 0000000..98e3e40 --- /dev/null +++ b/0003-fix-CVE-2021-25735.patch @@ -0,0 +1,394 @@ +Reference: https://github.com/kubernetes/kubernetes/pull/100315/files + +diff --git a/pkg/apis/apps/validation/validation.go b/pkg/apis/apps/validation/validation.go +index e297c8a..ef784d6 100644 +--- a/pkg/apis/apps/validation/validation.go ++++ b/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 +diff --git a/pkg/apis/core/validation/BUILD b/pkg/apis/core/validation/BUILD +index 70d2bd7..d65041e 100644 +--- a/pkg/apis/core/validation/BUILD ++++ b/pkg/apis/core/validation/BUILD +@@ -41,7 +41,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/v2:go_default_library", + "//vendor/k8s.io/utils/net:go_default_library", + ], + ) +diff --git a/pkg/apis/core/validation/validation.go b/pkg/apis/core/validation/validation.go +index fd34771..af58e0e 100644 +--- a/pkg/apis/core/validation/validation.go ++++ b/pkg/apis/core/validation/validation.go +@@ -29,8 +29,6 @@ import ( + "unicode" + "unicode/utf8" + +- "k8s.io/klog/v2" +- + v1 "k8s.io/api/core/v1" + apiequality "k8s.io/apimachinery/pkg/api/equality" + "k8s.io/apimachinery/pkg/api/resource" +@@ -1944,13 +1942,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 + } + +@@ -2023,7 +2019,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, +@@ -2039,7 +2035,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"] +@@ -2096,7 +2092,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 + } + +@@ -2419,13 +2414,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 { +@@ -3089,10 +3084,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 + } +@@ -3970,37 +3966,44 @@ func ValidatePodUpdate(newPod, oldPod *core.Pod, opts PodValidationOptions) fiel + 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"))...) ++ ++ // 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 + +- // 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) { ++ 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))) + } + +@@ -4032,8 +4035,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) +@@ -4064,9 +4066,6 @@ func ValidatePodStatusUpdate(newPod, oldPod *core.Pod) field.ErrorList { + } + } + +- // For status update we ignore changes to pod spec. +- newPod.Spec = oldPod.Spec +- + return allErrs + } + +@@ -4754,11 +4753,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")) +@@ -4772,46 +4768,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 + } + +@@ -5224,10 +5209,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 newSecret.Immutable == nil || !*newSecret.Immutable { +@@ -5527,7 +5508,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"))...) +@@ -5546,12 +5526,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 { +@@ -5569,7 +5547,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 + } + +@@ -5602,19 +5579,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")) +@@ -5628,7 +5600,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")) + +@@ -5637,7 +5608,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 + } + +diff --git a/pkg/registry/core/secret/strategy.go b/pkg/registry/core/secret/strategy.go +index 0d5908d..aad0038 100644 +--- a/pkg/registry/core/secret/strategy.go ++++ b/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) + } + +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 e25dd1e..32ae5e9 100644 +--- 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 +@@ -1409,7 +1409,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) + diff --git a/0004-fix-CVE-2021-25737.patch b/0004-fix-CVE-2021-25737.patch new file mode 100644 index 0000000..73a1aba --- /dev/null +++ b/0004-fix-CVE-2021-25737.patch @@ -0,0 +1,209 @@ +From 9d22c94b7171a9a6ce0d167f6cb25abce2079941 Mon Sep 17 00:00:00 2001 +From: Rob Scott +Date: Fri, 9 Apr 2021 15:24:17 -0700 +Subject: [PATCH] Updating EndpointSlice validation to match Endpoints + validation + +(cherry picked from commit dd95bba6cd1dfec0985d3e1068c12713597cbe4a) +--- + pkg/apis/core/validation/validation.go | 18 +++++---- + pkg/apis/core/validation/validation_test.go | 40 +++++++++++++++++++ + pkg/apis/discovery/validation/validation.go | 2 + + pkg/apis/discovery/validation/validation_test.go | 51 ++++++++++++++++++++++-- + 4 files changed, 101 insertions(+), 10 deletions(-) + +diff --git a/pkg/apis/core/validation/validation.go b/pkg/apis/core/validation/validation.go +index af58e0e..d5e9037 100644 +--- a/pkg/apis/core/validation/validation.go ++++ b/pkg/apis/core/validation/validation.go +@@ -4238,7 +4238,7 @@ func ValidateService(service *core.Service) field.ErrorList { + allErrs = append(allErrs, field.Invalid(idxPath, ip, msgs[i])) + } + } else { +- allErrs = append(allErrs, validateNonSpecialIP(ip, idxPath)...) ++ allErrs = append(allErrs, ValidateNonSpecialIP(ip, idxPath)...) + } + } + +@@ -5673,15 +5673,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/core/validation/validation_test.go b/pkg/apis/core/validation/validation_test.go +index bfdb523..f379cd4 100644 +--- a/pkg/apis/core/validation/validation_test.go ++++ b/pkg/apis/core/validation/validation_test.go +@@ -16915,3 +16915,43 @@ func TestValidatePodTemplateSpecSeccomp(t *testing.T) { + asserttestify.Equal(t, test.expectedErr, err, "TestCase[%d]: %s", i, test.description) + } + } ++ ++func TestValidateNonSpecialIP(t *testing.T) { ++ fp := field.NewPath("ip") ++ ++ // Valid values. ++ for _, tc := range []struct { ++ desc string ++ ip string ++ }{ ++ {"ipv4", "10.1.2.3"}, ++ {"ipv6", "2000::1"}, ++ } { ++ t.Run(tc.desc, func(t *testing.T) { ++ errs := ValidateNonSpecialIP(tc.ip, fp) ++ if len(errs) != 0 { ++ t.Errorf("ValidateNonSpecialIP(%q, ...) = %v; want nil", tc.ip, errs) ++ } ++ }) ++ } ++ // Invalid cases ++ for _, tc := range []struct { ++ desc string ++ ip string ++ }{ ++ {"ipv4 unspecified", "0.0.0.0"}, ++ {"ipv6 unspecified", "::0"}, ++ {"ipv4 localhost", "127.0.0.0"}, ++ {"ipv4 localhost", "127.255.255.255"}, ++ {"ipv6 localhost", "::1"}, ++ {"ipv6 link local", "fe80::"}, ++ {"ipv6 local multicast", "ff02::"}, ++ } { ++ t.Run(tc.desc, func(t *testing.T) { ++ errs := ValidateNonSpecialIP(tc.ip, fp) ++ if len(errs) == 0 { ++ t.Errorf("ValidateNonSpecialIP(%q, ...) = nil; want non-nil (errors)", tc.ip) ++ } ++ }) ++ } ++} +diff --git a/pkg/apis/discovery/validation/validation.go b/pkg/apis/discovery/validation/validation.go +index 8499e7a..d1fa4c8 100644 +--- a/pkg/apis/discovery/validation/validation.go ++++ b/pkg/apis/discovery/validation/validation.go +@@ -96,8 +96,10 @@ func validateEndpoints(endpoints []discovery.Endpoint, addrType discovery.Addres + switch addrType { + 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 5c7d478..0d944b5 100644 +--- a/pkg/apis/discovery/validation/validation_test.go ++++ b/pkg/apis/discovery/validation/validation_test.go +@@ -52,6 +52,21 @@ func TestValidateEndpointSlice(t *testing.T) { + }}, + }, + }, ++ "good-ipv6": { ++ expectedErrors: 0, ++ endpointSlice: &discovery.EndpointSlice{ ++ ObjectMeta: standardMeta, ++ AddressType: discovery.AddressTypeIPv6, ++ Ports: []discovery.EndpointPort{{ ++ Name: utilpointer.StringPtr("http"), ++ Protocol: protocolPtr(api.ProtocolTCP), ++ }}, ++ Endpoints: []discovery.Endpoint{{ ++ Addresses: []string{"a00:100::4"}, ++ Hostname: utilpointer.StringPtr("valid-123"), ++ }}, ++ }, ++ }, + "good-fqdns": { + expectedErrors: 0, + endpointSlice: &discovery.EndpointSlice{ +@@ -375,7 +390,7 @@ func TestValidateEndpointSlice(t *testing.T) { + }, + }, + "bad-ip": { +- expectedErrors: 1, ++ expectedErrors: 2, + endpointSlice: &discovery.EndpointSlice{ + ObjectMeta: standardMeta, + AddressType: discovery.AddressTypeIPv4, +@@ -390,7 +405,7 @@ func TestValidateEndpointSlice(t *testing.T) { + }, + }, + "bad-ipv4": { +- expectedErrors: 2, ++ expectedErrors: 3, + endpointSlice: &discovery.EndpointSlice{ + ObjectMeta: standardMeta, + AddressType: discovery.AddressTypeIPv4, +@@ -405,7 +420,7 @@ func TestValidateEndpointSlice(t *testing.T) { + }, + }, + "bad-ipv6": { +- expectedErrors: 2, ++ expectedErrors: 4, + endpointSlice: &discovery.EndpointSlice{ + ObjectMeta: standardMeta, + AddressType: discovery.AddressTypeIPv6, +@@ -454,6 +469,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 { +-- +1.8.3.1 + diff --git a/kubernetes.spec b/kubernetes.spec index 9cbd329..aeb9be2 100644 --- a/kubernetes.spec +++ b/kubernetes.spec @@ -3,7 +3,7 @@ Name: kubernetes Version: 1.20.2 -Release: 4 +Release: 5 Summary: Container cluster management License: ASL 2.0 URL: https://k8s.io/kubernetes @@ -26,6 +26,8 @@ Source15: kubernetes.conf Patch6000: 0001-kubelet-support-exec-websocket-protocol.patch Patch6001: 0002-fix-compile-options.patch +Patch6002: 0003-fix-CVE-2021-25735.patch +Patch6003: 0004-fix-CVE-2021-25737.patch %description Container cluster management. @@ -257,6 +259,9 @@ getent passwd kube >/dev/null || useradd -r -g kube -d / -s /sbin/nologin \ %systemd_postun kubelet kube-proxy %changelog +* Fri Sep 24 2021 leizhongkai - 1.20.2-5 +- DESC: fix CVE-2021-25735 and CVE-2021-25737 + * The Mar 23 2021 wangfengtu - 1.20.2-4 - Fix compile options -- Gitee