@@ -598,7 +598,7 @@ func validateGitRepoVolumeSource(gitRepo *api.GitRepoVolumeSource, fldPath *fiel
598
598
allErrs = append (allErrs , field .Required (fldPath .Child ("repository" ), "" ))
599
599
}
600
600
601
- pathErrs := validateVolumeSourcePath (gitRepo .Directory , fldPath .Child ("directory" ))
601
+ pathErrs := validateLocalDescendingPath (gitRepo .Directory , fldPath .Child ("directory" ))
602
602
allErrs = append (allErrs , pathErrs ... )
603
603
return allErrs
604
604
}
@@ -660,6 +660,11 @@ func validateSecretVolumeSource(secretSource *api.SecretVolumeSource, fldPath *f
660
660
if len (secretSource .SecretName ) == 0 {
661
661
allErrs = append (allErrs , field .Required (fldPath .Child ("secretName" ), "" ))
662
662
}
663
+ itemsPath := fldPath .Child ("items" )
664
+ for i , kp := range secretSource .Items {
665
+ itemPath := itemsPath .Index (i )
666
+ allErrs = append (allErrs , validateKeyToPath (& kp , itemPath )... )
667
+ }
663
668
return allErrs
664
669
}
665
670
@@ -668,6 +673,23 @@ func validateConfigMapVolumeSource(configMapSource *api.ConfigMapVolumeSource, f
668
673
if len (configMapSource .Name ) == 0 {
669
674
allErrs = append (allErrs , field .Required (fldPath .Child ("name" ), "" ))
670
675
}
676
+ itemsPath := fldPath .Child ("items" )
677
+ for i , kp := range configMapSource .Items {
678
+ itemPath := itemsPath .Index (i )
679
+ allErrs = append (allErrs , validateKeyToPath (& kp , itemPath )... )
680
+ }
681
+ return allErrs
682
+ }
683
+
684
+ func validateKeyToPath (kp * api.KeyToPath , fldPath * field.Path ) field.ErrorList {
685
+ allErrs := field.ErrorList {}
686
+ if len (kp .Key ) == 0 {
687
+ allErrs = append (allErrs , field .Required (fldPath .Child ("key" ), "" ))
688
+ }
689
+ if len (kp .Path ) == 0 {
690
+ allErrs = append (allErrs , field .Required (fldPath .Child ("path" ), "" ))
691
+ }
692
+ allErrs = append (allErrs , validateLocalNonReservedPath (kp .Path , fldPath .Child ("path" ))... )
671
693
return allErrs
672
694
}
673
695
@@ -715,22 +737,26 @@ func validateFlockerVolumeSource(flocker *api.FlockerVolumeSource, fldPath *fiel
715
737
return allErrs
716
738
}
717
739
718
- var validDownwardAPIFieldPathExpressions = sets .NewString ("metadata.name" , "metadata.namespace" , "metadata.labels" , "metadata.annotations" )
740
+ var validDownwardAPIFieldPathExpressions = sets .NewString (
741
+ "metadata.name" ,
742
+ "metadata.namespace" ,
743
+ "metadata.labels" ,
744
+ "metadata.annotations" )
719
745
720
746
func validateDownwardAPIVolumeSource (downwardAPIVolume * api.DownwardAPIVolumeSource , fldPath * field.Path ) field.ErrorList {
721
747
allErrs := field.ErrorList {}
722
- for _ , downwardAPIVolumeFile := range downwardAPIVolume .Items {
723
- if len (downwardAPIVolumeFile .Path ) == 0 {
748
+ for _ , file := range downwardAPIVolume .Items {
749
+ if len (file .Path ) == 0 {
724
750
allErrs = append (allErrs , field .Required (fldPath .Child ("path" ), "" ))
725
751
}
726
- allErrs = append (allErrs , validateVolumeSourcePath ( downwardAPIVolumeFile .Path , fldPath .Child ("path" ))... )
727
- if downwardAPIVolumeFile .FieldRef != nil {
728
- allErrs = append (allErrs , validateObjectFieldSelector (downwardAPIVolumeFile .FieldRef , & validDownwardAPIFieldPathExpressions , fldPath .Child ("fieldRef" ))... )
729
- if downwardAPIVolumeFile .ResourceFieldRef != nil {
752
+ allErrs = append (allErrs , validateLocalNonReservedPath ( file .Path , fldPath .Child ("path" ))... )
753
+ if file .FieldRef != nil {
754
+ allErrs = append (allErrs , validateObjectFieldSelector (file .FieldRef , & validDownwardAPIFieldPathExpressions , fldPath .Child ("fieldRef" ))... )
755
+ if file .ResourceFieldRef != nil {
730
756
allErrs = append (allErrs , field .Invalid (fldPath , "resource" , "fieldRef and resourceFieldRef can not be specified simultaneously" ))
731
757
}
732
- } else if downwardAPIVolumeFile .ResourceFieldRef != nil {
733
- allErrs = append (allErrs , validateContainerResourceFieldSelector (downwardAPIVolumeFile .ResourceFieldRef , & validContainerResourceFieldPathExpressions , fldPath .Child ("resourceFieldRef" ), true )... )
758
+ } else if file .ResourceFieldRef != nil {
759
+ allErrs = append (allErrs , validateContainerResourceFieldSelector (file .ResourceFieldRef , & validContainerResourceFieldPathExpressions , fldPath .Child ("resourceFieldRef" ), true )... )
734
760
} else {
735
761
allErrs = append (allErrs , field .Required (fldPath , "one of fieldRef and resourceFieldRef is required" ))
736
762
}
@@ -740,44 +766,33 @@ func validateDownwardAPIVolumeSource(downwardAPIVolume *api.DownwardAPIVolumeSou
740
766
741
767
// This validate will make sure targetPath:
742
768
// 1. is not abs path
743
- // 2. does not start with '../'
744
- // 3. does not contain '/../'
745
- // 4. does not end with '/..'
746
- func validateSubPath (targetPath string , fldPath * field.Path ) field.ErrorList {
769
+ // 2. does not have any element which is ".."
770
+ func validateLocalDescendingPath (targetPath string , fldPath * field.Path ) field.ErrorList {
747
771
allErrs := field.ErrorList {}
748
772
if path .IsAbs (targetPath ) {
749
773
allErrs = append (allErrs , field .Invalid (fldPath , targetPath , "must be a relative path" ))
750
774
}
751
- if strings . HasPrefix ( targetPath , "../" ) {
752
- allErrs = append ( allErrs , field . Invalid ( fldPath , targetPath , "must not start with '../'" ))
753
- }
754
- if strings . Contains ( targetPath , "/../" ) {
755
- allErrs = append ( allErrs , field . Invalid ( fldPath , targetPath , "must not contain '/../'" ))
756
- }
757
- if strings . HasSuffix ( targetPath , " /.." ) {
758
- allErrs = append ( allErrs , field . Invalid ( fldPath , targetPath , "must not end with '/..'" ))
775
+
776
+ // TODO: this assumes the OS of apiserver & nodes are the same
777
+ parts := strings . Split ( targetPath , string ( os . PathSeparator ))
778
+ for _ , item := range parts {
779
+ if item == ".." {
780
+ allErrs = append ( allErrs , field . Invalid ( fldPath , targetPath , "must not contain '..'" ))
781
+ break // even for `.. /../..`, one error is sufficient to make the point
782
+ }
759
783
}
760
784
return allErrs
761
785
}
762
786
763
787
// This validate will make sure targetPath:
764
788
// 1. is not abs path
765
- // 2. does not contain '..'
789
+ // 2. does not contain any '..' elements
766
790
// 3. does not start with '..'
767
- func validateVolumeSourcePath (targetPath string , fldPath * field.Path ) field.ErrorList {
791
+ func validateLocalNonReservedPath (targetPath string , fldPath * field.Path ) field.ErrorList {
768
792
allErrs := field.ErrorList {}
769
- if path .IsAbs (targetPath ) {
770
- allErrs = append (allErrs , field .Invalid (fldPath , targetPath , "must be a relative path" ))
771
- }
772
- // TODO assume OS of api server & nodes are the same for now
773
- items := strings .Split (targetPath , string (os .PathSeparator ))
774
-
775
- for _ , item := range items {
776
- if item == ".." {
777
- allErrs = append (allErrs , field .Invalid (fldPath , targetPath , "must not contain '..'" ))
778
- }
779
- }
780
- if strings .HasPrefix (items [0 ], ".." ) && len (items [0 ]) > 2 {
793
+ allErrs = append (allErrs , validateLocalDescendingPath (targetPath , fldPath )... )
794
+ // Don't report this error if the check for .. elements already caught it.
795
+ if strings .HasPrefix (targetPath , ".." ) && ! strings .HasPrefix (targetPath , "../" ) {
781
796
allErrs = append (allErrs , field .Invalid (fldPath , targetPath , "must not start with '..'" ))
782
797
}
783
798
return allErrs
@@ -1262,7 +1277,7 @@ func validateVolumeMounts(mounts []api.VolumeMount, volumes sets.String, fldPath
1262
1277
}
1263
1278
mountpoints .Insert (mnt .MountPath )
1264
1279
if len (mnt .SubPath ) > 0 {
1265
- allErrs = append (allErrs , validateSubPath (mnt .SubPath , fldPath .Child ("subPath" ))... )
1280
+ allErrs = append (allErrs , validateLocalDescendingPath (mnt .SubPath , fldPath .Child ("subPath" ))... )
1266
1281
}
1267
1282
}
1268
1283
return allErrs
@@ -1918,7 +1933,7 @@ func validateSeccompProfile(p string, fldPath *field.Path) field.ErrorList {
1918
1933
return nil
1919
1934
}
1920
1935
if strings .HasPrefix (p , "localhost/" ) {
1921
- return validateSubPath (strings .TrimPrefix (p , "localhost/" ), fldPath )
1936
+ return validateLocalDescendingPath (strings .TrimPrefix (p , "localhost/" ), fldPath )
1922
1937
}
1923
1938
return field.ErrorList {field .Invalid (fldPath , p , "must be a valid seccomp profile" )}
1924
1939
}
0 commit comments