!21 fix CVE-2021-25735 and CVE-2021-25737

From: @leizhongkai
Reviewed-by: @duguhaotian,@caihaomin
Signed-off-by: @caihaomin
This commit is contained in:
openeuler-ci-bot 2021-09-26 06:48:41 +00:00 committed by Gitee
commit a1cee7934d
3 changed files with 609 additions and 1 deletions

View File

@ -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)

View File

@ -0,0 +1,209 @@
From 9d22c94b7171a9a6ce0d167f6cb25abce2079941 Mon Sep 17 00:00:00 2001
From: Rob Scott <robertjscott@google.com>
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

View File

@ -3,7 +3,7 @@
Name: kubernetes
Version: 1.20.2
Release: 5
Release: 6
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<leizhongkai@huawei.com> - 1.20.2-6
- DESC: fix CVE-2021-25735 and CVE-2021-25737
* Fri Jul 30 2021 chenyanpanHW <chenyanpan@huawei.com> - 1.20.2-5
- DESC: delete -Sgit from %autosetup