mirror of
https://github.com/kyverno/kyverno.git
synced 2024-12-14 11:57:48 +00:00
chore: improve performance of engine fuzzers (#8090)
Signed-off-by: AdamKorcz <adam@adalogics.com> Co-authored-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com>
This commit is contained in:
parent
11ef5758e4
commit
af33cd98c8
3 changed files with 495 additions and 23 deletions
|
@ -1,7 +1,6 @@
|
|||
package engine
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
@ -28,9 +27,6 @@ import (
|
|||
fuzz "github.com/AdaLogics/go-fuzz-headers"
|
||||
)
|
||||
|
||||
/*
|
||||
VerifyAndPatchImage
|
||||
*/
|
||||
var (
|
||||
fuzzCfg = config.NewDefaultConfiguration(false)
|
||||
fuzzMetricsCfg = config.NewDefaultMetricsConfiguration()
|
||||
|
@ -49,16 +45,72 @@ var (
|
|||
nil,
|
||||
"",
|
||||
)
|
||||
k8sKinds = map[int]string{
|
||||
0: "Config",
|
||||
1: "ConfigMap",
|
||||
2: "CronJob",
|
||||
3: "DaemonSet",
|
||||
4: "Deployment",
|
||||
5: "EndpointSlice",
|
||||
6: "Ingress",
|
||||
7: "Job",
|
||||
8: "LimitRange",
|
||||
9: "List",
|
||||
10: "NetworkPolicy",
|
||||
11: "PersistentVolume",
|
||||
12: "PersistentVolumeClaim",
|
||||
13: "Pod",
|
||||
14: "ReplicaSet",
|
||||
15: "ReplicationController",
|
||||
16: "RuntimeClass",
|
||||
17: "Secret",
|
||||
18: "Service",
|
||||
19: "StorageClass",
|
||||
20: "VolumeSnapshot",
|
||||
21: "VolumeSnapshotClass",
|
||||
22: "VolumeSnapshotContent",
|
||||
}
|
||||
|
||||
kindToVersion = map[string]string{
|
||||
"Config": "v1",
|
||||
"ConfigMap": "v1",
|
||||
"CronJob": "batch/v1",
|
||||
"DaemonSet": "apps/v1",
|
||||
"Deployment": "apps/v1",
|
||||
"EndpointSlice": "discovery.k8s.io/v1",
|
||||
"Ingress": "networking.k8s.io/v1",
|
||||
"Job": "batch/v1",
|
||||
"LimitRange": "v1",
|
||||
"List": "v1",
|
||||
"NetworkPolicy": "networking.k8s.io/v1",
|
||||
"PersistentVolume": "v1",
|
||||
"PersistentVolumeClaim": "v1",
|
||||
"Pod": "v1",
|
||||
"ReplicaSet": "apps/v1",
|
||||
"ReplicationController": "v1",
|
||||
"RuntimeClass": "node.k8s.io/v1",
|
||||
"Secret": "v1",
|
||||
"Service": "v1",
|
||||
"StorageClass": "storage.k8s.io/v1",
|
||||
"VolumeSnapshot": "snapshot.storage.k8s.io/v1",
|
||||
"VolumeSnapshotClass": "snapshot.storage.k8s.io/v1",
|
||||
"VolumeSnapshotContent": "snapshot.storage.k8s.io/v1",
|
||||
}
|
||||
)
|
||||
|
||||
func buildFuzzContext(policy, resource, oldResource []byte) (*PolicyContext, error) {
|
||||
var cpol kyverno.ClusterPolicy
|
||||
err := json.Unmarshal([]byte(policy), &cpol)
|
||||
func buildFuzzContext(ff *fuzz.ConsumeFuzzer) (*PolicyContext, error) {
|
||||
cpSpec, err := createPolicySpec(ff)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cpol := &kyverno.ClusterPolicy{}
|
||||
cpol.Spec = cpSpec
|
||||
|
||||
resourceUnstructured, err := kubeutils.BytesToUnstructured(resource)
|
||||
if len(autogen.ComputeRules(cpol)) == 0 {
|
||||
return nil, fmt.Errorf("No rules created")
|
||||
}
|
||||
|
||||
resourceUnstructured, err := createUnstructuredObject(ff)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -75,15 +127,25 @@ func buildFuzzContext(policy, resource, oldResource []byte) (*PolicyContext, err
|
|||
}
|
||||
|
||||
policyContext = policyContext.
|
||||
WithPolicy(&cpol).
|
||||
WithPolicy(cpol).
|
||||
WithNewResource(*resourceUnstructured)
|
||||
|
||||
if !bytes.Equal(oldResource, []byte("")) {
|
||||
oldResourceUnstructured, err := kubeutils.BytesToUnstructured(oldResource)
|
||||
addOldResource, err := ff.GetBool()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if addOldResource {
|
||||
oldResourceUnstructured, err := createUnstructuredObject(ff)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
oldResource, err := json.Marshal(oldResourceUnstructured)
|
||||
if err != nil {
|
||||
return policyContext, nil
|
||||
}
|
||||
|
||||
err = enginecontext.AddOldResource(policyContext.JSONContext(), oldResource)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -95,9 +157,13 @@ func buildFuzzContext(policy, resource, oldResource []byte) (*PolicyContext, err
|
|||
return policyContext, nil
|
||||
}
|
||||
|
||||
/*
|
||||
VerifyAndPatchImage
|
||||
*/
|
||||
func FuzzVerifyImageAndPatchTest(f *testing.F) {
|
||||
f.Fuzz(func(t *testing.T, policy, resource, oldResource []byte) {
|
||||
pc, err := buildFuzzContext(policy, resource, oldResource)
|
||||
f.Fuzz(func(t *testing.T, data []byte) {
|
||||
ff := fuzz.NewConsumer(data)
|
||||
pc, err := buildFuzzContext(ff)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
@ -346,7 +412,6 @@ func createRule(f *fuzz.ConsumeFuzzer) (*kyverno.Rule, error) {
|
|||
func FuzzEngineValidateTest(f *testing.F) {
|
||||
f.Fuzz(func(t *testing.T, data []byte) {
|
||||
ff := fuzz.NewConsumer(data)
|
||||
//ff.GenerateStruct(policy)
|
||||
cpSpec, err := createPolicySpec(ff)
|
||||
if err != nil {
|
||||
return
|
||||
|
@ -375,11 +440,86 @@ func FuzzEngineValidateTest(f *testing.F) {
|
|||
})
|
||||
}
|
||||
|
||||
func GetK8sString(ff *fuzz.ConsumeFuzzer) (string, error) {
|
||||
allowedChars := []byte("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.")
|
||||
stringLength, err := ff.GetInt()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
var sb strings.Builder
|
||||
for i := 0; i < stringLength%63; i++ {
|
||||
charIndex, err := ff.GetInt()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
sb.WriteString(string(allowedChars[charIndex%len(allowedChars)]))
|
||||
}
|
||||
return sb.String(), nil
|
||||
}
|
||||
|
||||
func getVersionAndKind(ff *fuzz.ConsumeFuzzer) (string, error) {
|
||||
kindToCreate, err := ff.GetInt()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
k := k8sKinds[kindToCreate%len(k8sKinds)]
|
||||
v := kindToVersion[k]
|
||||
var sb strings.Builder
|
||||
sb.WriteString("\"apiVersion\": \"")
|
||||
sb.WriteString(v)
|
||||
sb.WriteString("\", \"kind\": \"")
|
||||
sb.WriteString(k)
|
||||
sb.WriteString("\"")
|
||||
return sb.String(), nil
|
||||
}
|
||||
|
||||
func createLabels(ff *fuzz.ConsumeFuzzer) (string, error) {
|
||||
var sb strings.Builder
|
||||
noOfLabels, err := ff.GetInt()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
for i := 0; i < noOfLabels%30; i++ {
|
||||
key, err := GetK8sString(ff)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
value, err := GetK8sString(ff)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
sb.WriteString("\"")
|
||||
sb.WriteString(key)
|
||||
sb.WriteString("\":")
|
||||
sb.WriteString("\"")
|
||||
sb.WriteString(value)
|
||||
sb.WriteString("\"")
|
||||
if i != (noOfLabels%30)-1 {
|
||||
sb.WriteString(", ")
|
||||
}
|
||||
}
|
||||
return sb.String(), nil
|
||||
}
|
||||
|
||||
// Creates an unstructured k8s object
|
||||
func createUnstructuredObject(f *fuzz.ConsumeFuzzer) (*unstructured.Unstructured, error) {
|
||||
labels, err := createLabels(f)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
versionAndKind, err := getVersionAndKind(f)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var sb strings.Builder
|
||||
|
||||
sb.WriteString("{ \"apiVersion\": \"apps/v1\", \"kind\": \"Deployment\", \"metadata\": { \"creationTimestamp\": \"2020-09-21T12:56:35Z\", \"name\": \"fuzz\", \"labels\": { \"test\": \"qos\" } }, \"spec\": { ")
|
||||
sb.WriteString("{ ")
|
||||
sb.WriteString(versionAndKind)
|
||||
sb.WriteString(", \"metadata\": { \"creationTimestamp\": \"2020-09-21T12:56:35Z\", \"name\": \"fuzz\", \"labels\": { ")
|
||||
sb.WriteString(labels)
|
||||
sb.WriteString(" } }, \"spec\": { ")
|
||||
|
||||
for i := 0; i < 1000; i++ {
|
||||
typeToAdd, err := f.GetInt()
|
||||
|
@ -422,14 +562,22 @@ func createUnstructuredObject(f *fuzz.ConsumeFuzzer) (*unstructured.Unstructured
|
|||
Mutate
|
||||
*/
|
||||
func FuzzMutateTest(f *testing.F) {
|
||||
f.Fuzz(func(t *testing.T, resourceRaw, policyRaw []byte) {
|
||||
var policy kyverno.ClusterPolicy
|
||||
err := json.Unmarshal(policyRaw, &policy)
|
||||
f.Fuzz(func(t *testing.T, data []byte) {
|
||||
|
||||
ff := fuzz.NewConsumer(data)
|
||||
//ff.GenerateStruct(policy)
|
||||
cpSpec, err := createPolicySpec(ff)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
var resource unstructured.Unstructured
|
||||
err = resource.UnmarshalJSON(resourceRaw)
|
||||
policy := &kyverno.ClusterPolicy{}
|
||||
policy.Spec = cpSpec
|
||||
|
||||
if len(autogen.ComputeRules(policy)) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
resource, err := createUnstructuredObject(ff)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
@ -437,7 +585,7 @@ func FuzzMutateTest(f *testing.F) {
|
|||
// create policy context
|
||||
pc, err := NewPolicyContext(
|
||||
fuzzJp,
|
||||
resource,
|
||||
*resource,
|
||||
kyverno.Create,
|
||||
nil,
|
||||
fuzzCfg,
|
||||
|
@ -458,8 +606,7 @@ func FuzzMutateTest(f *testing.F) {
|
|||
)
|
||||
e.Mutate(
|
||||
context.Background(),
|
||||
pc.WithPolicy(&policy),
|
||||
pc.WithPolicy(policy),
|
||||
)
|
||||
panic("Here")
|
||||
})
|
||||
}
|
||||
|
|
321
test/fuzz/dictionaries/fuzz.dict
Normal file
321
test/fuzz/dictionaries/fuzz.dict
Normal file
|
@ -0,0 +1,321 @@
|
|||
"metadata"
|
||||
"name"
|
||||
"generateName"
|
||||
"namespace"
|
||||
"selfLink"
|
||||
"uid"
|
||||
"resourceVersion"
|
||||
"generation"
|
||||
"creationTimestamp"
|
||||
"deletionTimestamp"
|
||||
"deletionGracePeriodSeconds"
|
||||
"labels"
|
||||
"annotations"
|
||||
"ownerReferences"
|
||||
"apiVersion"
|
||||
"kind"
|
||||
"controller"
|
||||
"blockOwnerDeletion"
|
||||
"finalizers"
|
||||
"managedFields"
|
||||
"manager"
|
||||
"operation"
|
||||
"time"
|
||||
"fieldsType"
|
||||
"fieldsV1"
|
||||
"subresource"
|
||||
"spec"
|
||||
"volumes"
|
||||
"initContainers"
|
||||
"image"
|
||||
"command"
|
||||
"args"
|
||||
"workingDir"
|
||||
"ports"
|
||||
"hostPort"
|
||||
"containerPort"
|
||||
"protocol"
|
||||
"hostIP"
|
||||
"envFrom"
|
||||
"prefix"
|
||||
"configMapRef"
|
||||
"optional"
|
||||
"secretRef"
|
||||
"env"
|
||||
"value"
|
||||
"valueFrom"
|
||||
"fieldRef"
|
||||
"fieldPath"
|
||||
"resourceFieldRef"
|
||||
"containerName"
|
||||
"resource"
|
||||
"divisor"
|
||||
"configMapKeyRef"
|
||||
"key"
|
||||
"secretKeyRef"
|
||||
"resources"
|
||||
"limits"
|
||||
"requests"
|
||||
"claims"
|
||||
"resizePolicy"
|
||||
"resourceName"
|
||||
"restartPolicy"
|
||||
"volumeMounts"
|
||||
"readOnly"
|
||||
"mountPath"
|
||||
"subPath"
|
||||
"mountPropagation"
|
||||
"subPathExpr"
|
||||
"volumeDevices"
|
||||
"devicePath"
|
||||
"livenessProbe"
|
||||
"initialDelaySeconds"
|
||||
"timeoutSeconds"
|
||||
"periodSeconds"
|
||||
"successThreshold"
|
||||
"failureThreshold"
|
||||
"terminationGracePeriodSeconds"
|
||||
"readinessProbe"
|
||||
"startupProbe"
|
||||
"lifecycle"
|
||||
"postStart"
|
||||
"exec"
|
||||
"httpGet"
|
||||
"path"
|
||||
"port"
|
||||
"host"
|
||||
"scheme"
|
||||
"httpHeaders"
|
||||
"tcpSocket"
|
||||
"preStop"
|
||||
"terminationMessagePath"
|
||||
"terminationMessagePolicy"
|
||||
"imagePullPolicy"
|
||||
"securityContext"
|
||||
"capabilities"
|
||||
"add"
|
||||
"drop"
|
||||
"privileged"
|
||||
"seLinuxOptions"
|
||||
"user"
|
||||
"role"
|
||||
"type"
|
||||
"level"
|
||||
"windowsOptions"
|
||||
"gmsaCredentialSpecName"
|
||||
"gmsaCredentialSpec"
|
||||
"runAsUserName"
|
||||
"hostProcess"
|
||||
"runAsUser"
|
||||
"runAsGroup"
|
||||
"runAsNonRoot"
|
||||
"readOnlyRootFilesystem"
|
||||
"allowPrivilegeEscalation"
|
||||
"procMount"
|
||||
"seccompProfile"
|
||||
"localhostProfile"
|
||||
"stdin"
|
||||
"stdinOnce"
|
||||
"tty"
|
||||
"containers"
|
||||
"ephemeralContainers"
|
||||
"targetContainerName"
|
||||
"activeDeadlineSeconds"
|
||||
"dnsPolicy"
|
||||
"nodeSelector"
|
||||
"serviceAccountName"
|
||||
"serviceAccount"
|
||||
"automountServiceAccountToken"
|
||||
"nodeName"
|
||||
"hostNetwork"
|
||||
"hostPID"
|
||||
"hostIPC"
|
||||
"shareProcessNamespace"
|
||||
"supplementalGroups"
|
||||
"fsGroup"
|
||||
"sysctls"
|
||||
"fsGroupChangePolicy"
|
||||
"imagePullSecrets"
|
||||
"hostname"
|
||||
"subdomain"
|
||||
"affinity"
|
||||
"nodeAffinity"
|
||||
"requiredDuringSchedulingIgnoredDuringExecution"
|
||||
"nodeSelectorTerms"
|
||||
"matchExpressions"
|
||||
"operator"
|
||||
"values"
|
||||
"matchFields"
|
||||
"preferredDuringSchedulingIgnoredDuringExecution"
|
||||
"weight"
|
||||
"preference"
|
||||
"podAffinity"
|
||||
"labelSelector"
|
||||
"matchLabels"
|
||||
"namespaces"
|
||||
"topologyKey"
|
||||
"namespaceSelector"
|
||||
"podAffinityTerm"
|
||||
"podAntiAffinity"
|
||||
"schedulerName"
|
||||
"tolerations"
|
||||
"effect"
|
||||
"tolerationSeconds"
|
||||
"hostAliases"
|
||||
"ip"
|
||||
"hostnames"
|
||||
"priorityClassName"
|
||||
"priority"
|
||||
"dnsConfig"
|
||||
"nameservers"
|
||||
"searches"
|
||||
"options"
|
||||
"readinessGates"
|
||||
"conditionType"
|
||||
"runtimeClassName"
|
||||
"enableServiceLinks"
|
||||
"preemptionPolicy"
|
||||
"overhead"
|
||||
"topologySpreadConstraints"
|
||||
"maxSkew"
|
||||
"whenUnsatisfiable"
|
||||
"minDomains"
|
||||
"nodeAffinityPolicy"
|
||||
"nodeTaintsPolicy"
|
||||
"matchLabelKeys"
|
||||
"setHostnameAsFQDN"
|
||||
"os"
|
||||
"hostUsers"
|
||||
"schedulingGates"
|
||||
"resourceClaims"
|
||||
"source"
|
||||
"resourceClaimName"
|
||||
"resourceClaimTemplateName"
|
||||
"status"
|
||||
"phase"
|
||||
"conditions"
|
||||
"lastProbeTime"
|
||||
"lastTransitionTime"
|
||||
"reason"
|
||||
"message"
|
||||
"nominatedNodeName"
|
||||
"hostIPs"
|
||||
"podIP"
|
||||
"podIPs"
|
||||
"startTime"
|
||||
"initContainerStatuses"
|
||||
"state"
|
||||
"waiting"
|
||||
"running"
|
||||
"startedAt"
|
||||
"terminated"
|
||||
"exitCode"
|
||||
"signal"
|
||||
"finishedAt"
|
||||
"containerID"
|
||||
"lastState"
|
||||
"ready"
|
||||
"restartCount"
|
||||
"imageID"
|
||||
"started"
|
||||
"allocatedResources"
|
||||
"containerStatuses"
|
||||
"qosClass"
|
||||
"ephemeralContainerStatuses"
|
||||
"resize"
|
||||
"resourceClaimStatuses"
|
||||
"immutable"
|
||||
"data"
|
||||
"stringData"
|
||||
"binaryData"
|
||||
"schedule"
|
||||
"timeZone"
|
||||
"startingDeadlineSeconds"
|
||||
"concurrencyPolicy"
|
||||
"suspend"
|
||||
"jobTemplate"
|
||||
"parallelism"
|
||||
"completions"
|
||||
"podFailurePolicy"
|
||||
"rules"
|
||||
"action"
|
||||
"onExitCodes"
|
||||
"onPodConditions"
|
||||
"backoffLimit"
|
||||
"backoffLimitPerIndex"
|
||||
"maxFailedIndexes"
|
||||
"selector"
|
||||
"manualSelector"
|
||||
"template"
|
||||
"ttlSecondsAfterFinished"
|
||||
"completionMode"
|
||||
"podReplacementPolicy"
|
||||
"successfulJobsHistoryLimit"
|
||||
"failedJobsHistoryLimit"
|
||||
"active"
|
||||
"lastScheduleTime"
|
||||
"lastSuccessfulTime"
|
||||
"updateStrategy"
|
||||
"rollingUpdate"
|
||||
"maxUnavailable"
|
||||
"maxSurge"
|
||||
"minReadySeconds"
|
||||
"revisionHistoryLimit"
|
||||
"currentNumberScheduled"
|
||||
"numberMisscheduled"
|
||||
"desiredNumberScheduled"
|
||||
"numberReady"
|
||||
"observedGeneration"
|
||||
"updatedNumberScheduled"
|
||||
"numberAvailable"
|
||||
"numberUnavailable"
|
||||
"collisionCount"
|
||||
"replicas"
|
||||
"strategy"
|
||||
"paused"
|
||||
"progressDeadlineSeconds"
|
||||
"updatedReplicas"
|
||||
"readyReplicas"
|
||||
"availableReplicas"
|
||||
"unavailableReplicas"
|
||||
"lastUpdateTime"
|
||||
"addressType"
|
||||
"endpoints"
|
||||
"addresses"
|
||||
"serving"
|
||||
"terminating"
|
||||
"targetRef"
|
||||
"deprecatedTopology"
|
||||
"zone"
|
||||
"hints"
|
||||
"forZones"
|
||||
"appProtocol"
|
||||
"ingressClassName"
|
||||
"defaultBackend"
|
||||
"service"
|
||||
"number"
|
||||
"apiGroup"
|
||||
"tls"
|
||||
"hosts"
|
||||
"secretName"
|
||||
"http"
|
||||
"paths"
|
||||
"pathType"
|
||||
"backend"
|
||||
"loadBalancer"
|
||||
"ingress"
|
||||
"error"
|
||||
"completionTime"
|
||||
"succeeded"
|
||||
"failed"
|
||||
"completedIndexes"
|
||||
"failedIndexes"
|
||||
"uncountedTerminatedPods"
|
||||
"max"
|
||||
"min"
|
||||
"default"
|
||||
"defaultRequest"
|
||||
"maxLimitRequestRatio"
|
||||
"continue"
|
||||
"remainingItemCount"
|
||||
"items"
|
|
@ -22,3 +22,7 @@ compile_native_go_fuzzer github.com/kyverno/kyverno/pkg/engine FuzzMutateTest Fu
|
|||
compile_native_go_fuzzer github.com/kyverno/kyverno/pkg/validation/policy FuzzValidatePolicy FuzzValidatePolicy
|
||||
compile_native_go_fuzzer github.com/kyverno/kyverno/pkg/engine/anchor FuzzAnchorParseTest FuzzAnchorParseTest
|
||||
compile_native_go_fuzzer github.com/kyverno/kyverno/pkg/engine/api FuzzEngineResponse FuzzEngineResponse
|
||||
|
||||
cp $SRC/kyverno/test/fuzz/dictionaries/fuzz.dict $OUT/FuzzEngineValidateTest.dict
|
||||
cp $SRC/kyverno/test/fuzz/dictionaries/fuzz.dict $OUT/FuzzMutateTest.dict
|
||||
cp $SRC/kyverno/test/fuzz/dictionaries/fuzz.dict $OUT/FuzzVerifyImageAndPatchTest.dict
|
||||
|
|
Loading…
Reference in a new issue