@@ -2,6 +2,7 @@ package validation
2
2
3
3
import (
4
4
"fmt"
5
+ "regexp"
5
6
"strings"
6
7
7
8
"k8s.io/apimachinery/pkg/api/validation"
@@ -110,6 +111,98 @@ func ValidateSecurityContextConstraints(scc *securityapi.SecurityContextConstrai
110
111
}
111
112
}
112
113
114
+ allowedUnsafeSysctlsPath := field .NewPath ("allowedUnsafeSysctls" )
115
+ forbiddenSysctlsPath := field .NewPath ("forbiddenSysctls" )
116
+ allErrs = append (allErrs , validateSCCSysctls (allowedUnsafeSysctlsPath , scc .AllowedUnsafeSysctls )... )
117
+ allErrs = append (allErrs , validateSCCSysctls (forbiddenSysctlsPath , scc .ForbiddenSysctls )... )
118
+ allErrs = append (allErrs , validatePodSecurityPolicySysctlListsDoNotOverlap (allowedUnsafeSysctlsPath , forbiddenSysctlsPath , scc .AllowedUnsafeSysctls , scc .ForbiddenSysctls )... )
119
+
120
+ return allErrs
121
+ }
122
+
123
+ const sysctlPatternSegmentFmt string = "([a-z0-9][-_a-z0-9]*)?[a-z0-9*]"
124
+ const SysctlPatternFmt string = "(" + kapivalidation .SysctlSegmentFmt + "\\ .)*" + sysctlPatternSegmentFmt
125
+
126
+ var sysctlPatternRegexp = regexp .MustCompile ("^" + SysctlPatternFmt + "$" )
127
+
128
+ func IsValidSysctlPattern (name string ) bool {
129
+ if len (name ) > kapivalidation .SysctlMaxLength {
130
+ return false
131
+ }
132
+ return sysctlPatternRegexp .MatchString (name )
133
+ }
134
+
135
+ // validatePodSecurityPolicySysctlListsDoNotOverlap validates the values in forbiddenSysctls and allowedSysctls fields do not overlap.
136
+ func validatePodSecurityPolicySysctlListsDoNotOverlap (allowedSysctlsFldPath , forbiddenSysctlsFldPath * field.Path , allowedUnsafeSysctls , forbiddenSysctls []string ) field.ErrorList {
137
+ allErrs := field.ErrorList {}
138
+ for i , allowedSysctl := range allowedUnsafeSysctls {
139
+ isAllowedSysctlPattern := false
140
+ allowedSysctlPrefix := ""
141
+ if strings .HasSuffix (allowedSysctl , "*" ) {
142
+ isAllowedSysctlPattern = true
143
+ allowedSysctlPrefix = strings .TrimSuffix (allowedSysctl , "*" )
144
+ }
145
+ for j , forbiddenSysctl := range forbiddenSysctls {
146
+ isForbiddenSysctlPattern := false
147
+ forbiddenSysctlPrefix := ""
148
+ if strings .HasSuffix (forbiddenSysctl , "*" ) {
149
+ isForbiddenSysctlPattern = true
150
+ forbiddenSysctlPrefix = strings .TrimSuffix (forbiddenSysctl , "*" )
151
+ }
152
+ switch {
153
+ case isAllowedSysctlPattern && isForbiddenSysctlPattern :
154
+ if strings .HasPrefix (allowedSysctlPrefix , forbiddenSysctlPrefix ) {
155
+ allErrs = append (allErrs , field .Invalid (allowedSysctlsFldPath .Index (i ), allowedUnsafeSysctls [i ], fmt .Sprintf ("sysctl overlaps with %v" , forbiddenSysctl )))
156
+ } else if strings .HasPrefix (forbiddenSysctlPrefix , allowedSysctlPrefix ) {
157
+ allErrs = append (allErrs , field .Invalid (forbiddenSysctlsFldPath .Index (j ), forbiddenSysctls [j ], fmt .Sprintf ("sysctl overlaps with %v" , allowedSysctl )))
158
+ }
159
+ case isAllowedSysctlPattern :
160
+ if strings .HasPrefix (forbiddenSysctl , allowedSysctlPrefix ) {
161
+ allErrs = append (allErrs , field .Invalid (forbiddenSysctlsFldPath .Index (j ), forbiddenSysctls [j ], fmt .Sprintf ("sysctl overlaps with %v" , allowedSysctl )))
162
+ }
163
+ case isForbiddenSysctlPattern :
164
+ if strings .HasPrefix (allowedSysctl , forbiddenSysctlPrefix ) {
165
+ allErrs = append (allErrs , field .Invalid (allowedSysctlsFldPath .Index (i ), allowedUnsafeSysctls [i ], fmt .Sprintf ("sysctl overlaps with %v" , forbiddenSysctl )))
166
+ }
167
+ default :
168
+ if allowedSysctl == forbiddenSysctl {
169
+ allErrs = append (allErrs , field .Invalid (allowedSysctlsFldPath .Index (i ), allowedUnsafeSysctls [i ], fmt .Sprintf ("sysctl overlaps with %v" , forbiddenSysctl )))
170
+ }
171
+ }
172
+ }
173
+ }
174
+ return allErrs
175
+ }
176
+
177
+ // validatePodSecurityPolicySysctls validates the sysctls fields of PodSecurityPolicy.
178
+ func validateSCCSysctls (fldPath * field.Path , sysctls []string ) field.ErrorList {
179
+ allErrs := field.ErrorList {}
180
+
181
+ if len (sysctls ) == 0 {
182
+ return allErrs
183
+ }
184
+
185
+ coversAll := false
186
+ for i , s := range sysctls {
187
+ if len (s ) == 0 {
188
+ allErrs = append (allErrs , field .Invalid (fldPath .Index (i ), sysctls [i ], fmt .Sprintf ("empty sysctl not allowed" )))
189
+ } else if ! IsValidSysctlPattern (string (s )) {
190
+ allErrs = append (
191
+ allErrs ,
192
+ field .Invalid (fldPath .Index (i ), sysctls [i ], fmt .Sprintf ("must have at most %d characters and match regex %s" ,
193
+ kapivalidation .SysctlMaxLength ,
194
+ SysctlPatternFmt ,
195
+ )),
196
+ )
197
+ } else if s [0 ] == '*' {
198
+ coversAll = true
199
+ }
200
+ }
201
+
202
+ if coversAll && len (sysctls ) > 1 {
203
+ allErrs = append (allErrs , field .Forbidden (fldPath .Child ("items" ), fmt .Sprintf ("if '*' is present, must not specify other sysctls" )))
204
+ }
205
+
113
206
return allErrs
114
207
}
115
208
0 commit comments