package engine import ( "context" "encoding/json" "fmt" "sync" "testing" kyvFuzz "github.com/kyverno/kyverno/pkg/utils/fuzz" corev1 "k8s.io/api/core/v1" fuzz "github.com/AdaLogics/go-fuzz-headers" kyverno "github.com/kyverno/kyverno/api/kyverno/v1" "github.com/kyverno/kyverno/pkg/autogen" "github.com/kyverno/kyverno/pkg/config" "github.com/kyverno/kyverno/pkg/engine/adapters" engineapi "github.com/kyverno/kyverno/pkg/engine/api" enginecontext "github.com/kyverno/kyverno/pkg/engine/context" "github.com/kyverno/kyverno/pkg/engine/factories" "github.com/kyverno/kyverno/pkg/engine/jmespath" "github.com/kyverno/kyverno/pkg/engine/policycontext" "github.com/kyverno/kyverno/pkg/imageverifycache" "github.com/kyverno/kyverno/pkg/registryclient" kubeutils "github.com/kyverno/kyverno/pkg/utils/kube" ) var ( fuzzCfg = config.NewDefaultConfiguration(false) fuzzMetricsCfg = config.NewDefaultMetricsConfiguration() fuzzJp = jmespath.New(fuzzCfg) validateContext = context.Background() regClient = registryclient.NewOrDie() validateEngine = NewEngine( fuzzCfg, config.NewDefaultMetricsConfiguration(), fuzzJp, nil, factories.DefaultRegistryClientFactory(adapters.RegistryClient(regClient), nil), imageverifycache.DisabledImageVerifyCache(), factories.DefaultContextLoaderFactory(nil), nil, nil, ) initter sync.Once ) func buildFuzzContext(ff *fuzz.ConsumeFuzzer) (*PolicyContext, error) { cpSpec, err := kyvFuzz.CreatePolicySpec(ff) if err != nil { return nil, err } cpol := &kyverno.ClusterPolicy{} cpol.Spec = cpSpec if len(autogen.Default.ComputeRules(cpol, "")) == 0 { return nil, fmt.Errorf("No rules created") } resourceUnstructured, err := kyvFuzz.CreateUnstructuredObject(ff, "") if err != nil { return nil, err } policyContext, err := policycontext.NewPolicyContext( fuzzJp, *resourceUnstructured, kyverno.Create, nil, fuzzCfg, ) if err != nil { return nil, err } policyContext = policyContext. WithPolicy(cpol). WithNewResource(*resourceUnstructured) addOldResource, err := ff.GetBool() if err != nil { return nil, err } if addOldResource { oldResourceUnstructured, err := kyvFuzz.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 } policyContext = policyContext.WithOldResource(*oldResourceUnstructured) } return policyContext, nil } /* VerifyAndPatchImage */ func FuzzVerifyImageAndPatchTest(f *testing.F) { f.Fuzz(func(t *testing.T, data []byte) { ff := fuzz.NewConsumer(data) pc, err := buildFuzzContext(ff) if err != nil { return } verifyImageAndPatchEngine := NewEngine( fuzzCfg, fuzzMetricsCfg, fuzzJp, nil, factories.DefaultRegistryClientFactory(adapters.RegistryClient(registryclient.NewOrDie()), nil), imageverifycache.DisabledImageVerifyCache(), factories.DefaultContextLoaderFactory(nil), nil, nil, ) _, _ = verifyImageAndPatchEngine.VerifyAndPatchImages( context.Background(), pc, ) }) } func FuzzEngineValidateTest(f *testing.F) { f.Fuzz(func(t *testing.T, data []byte) { ff := fuzz.NewConsumer(data) cpSpec, err := kyvFuzz.CreatePolicySpec(ff) if err != nil { return } policy := &kyverno.ClusterPolicy{} policy.Spec = cpSpec if len(autogen.Default.ComputeRules(policy, "")) == 0 { return } resourceUnstructured, err := kyvFuzz.CreateUnstructuredObject(ff, "") if err != nil { return } pc, err := NewPolicyContext(fuzzJp, *resourceUnstructured, kyverno.Create, nil, fuzzCfg) if err != nil { return } validateEngine.Validate( validateContext, pc.WithPolicy(policy), ) }) } func getPod(ff *fuzz.ConsumeFuzzer) (*corev1.Pod, error) { pod := &corev1.Pod{} err := ff.GenerateStruct(pod) pod.Kind = "Pod" pod.APIVersion = "v1" return pod, err } func FuzzPodBypass(f *testing.F) { f.Fuzz(func(t *testing.T, data []byte) { initter.Do(kyvFuzz.InitFuzz) ff := fuzz.NewConsumer(data) policyToCheck, err := ff.GetInt() if err != nil { return } testPolicy := kyvFuzz.Policies[policyToCheck%11] pod, err := getPod(ff) if err != nil { return } shouldBlock, err := testPolicy.ShouldBlock(pod) if err != nil { return } resource, err := json.MarshalIndent(pod, "", " ") if err != nil { return } resourceUnstructured, err := kubeutils.BytesToUnstructured(resource) if err != nil { return } pc, err := NewPolicyContext(fuzzJp, *resourceUnstructured, kyverno.Create, nil, fuzzCfg) if err != nil { return } er := validateEngine.Validate( validateContext, pc.WithPolicy(testPolicy.ClusterPolicy), ) blocked := blockRequest([]engineapi.EngineResponse{er}) if blocked != shouldBlock { panic(fmt.Sprintf("\nDid not block a resource that should be blocked:\n%s\n should have been blocked by \n%+v\n\nshouldBlock was %t\nblocked was %t\n", string(resource), testPolicy.ClusterPolicy, shouldBlock, blocked)) } }) } func blockRequest(engineResponses []engineapi.EngineResponse) bool { for _, er := range engineResponses { if er.IsFailed() { return true } } return false } func FuzzMutateTest(f *testing.F) { f.Fuzz(func(t *testing.T, data []byte) { ff := fuzz.NewConsumer(data) //ff.GenerateStruct(policy) cpSpec, err := kyvFuzz.CreatePolicySpec(ff) if err != nil { return } policy := &kyverno.ClusterPolicy{} policy.Spec = cpSpec if len(autogen.Default.ComputeRules(policy, "")) == 0 { return } resource, err := kyvFuzz.CreateUnstructuredObject(ff, "") if err != nil { return } // create policy context pc, err := NewPolicyContext( fuzzJp, *resource, kyverno.Create, nil, fuzzCfg, ) if err != nil { t.Skip() } fuzzInterface := kyvFuzz.FuzzInterface{FF: ff} e := NewEngine( fuzzCfg, config.NewDefaultMetricsConfiguration(), fuzzJp, adapters.Client(fuzzInterface), factories.DefaultRegistryClientFactory(adapters.RegistryClient(nil), nil), imageverifycache.DisabledImageVerifyCache(), factories.DefaultContextLoaderFactory(nil), nil, nil, ) e.Mutate( context.Background(), pc.WithPolicy(policy), ) }) }