1
0
Fork 0
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:
AdamKorcz 2023-08-22 23:35:06 +01:00 committed by GitHub
parent 11ef5758e4
commit af33cd98c8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 495 additions and 23 deletions

View file

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

View 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"

View file

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