github.com/google/syzkaller@v0.0.0-20240517125934-c0f1611a36d6/dashboard/app/kcidb.go (about)

     1  // Copyright 2020 syzkaller project authors. All rights reserved.
     2  // Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
     3  
     4  package main
     5  
     6  import (
     7  	"context"
     8  	"fmt"
     9  	"net/http"
    10  	"time"
    11  
    12  	"github.com/google/syzkaller/pkg/kcidb"
    13  	"google.golang.org/appengine/v2"
    14  	db "google.golang.org/appengine/v2/datastore"
    15  	"google.golang.org/appengine/v2/log"
    16  )
    17  
    18  func initKcidb() {
    19  	http.HandleFunc("/cron/kcidb_poll", handleKcidbPoll)
    20  }
    21  
    22  func handleKcidbPoll(w http.ResponseWriter, r *http.Request) {
    23  	c := appengine.NewContext(r)
    24  	for ns, cfg := range getConfig(c).Namespaces {
    25  		if cfg.Kcidb == nil {
    26  			continue
    27  		}
    28  		if err := handleKcidbNamespce(c, ns, cfg.Kcidb); err != nil {
    29  			log.Errorf(c, "kcidb: %v failed: %v", ns, err)
    30  		}
    31  	}
    32  }
    33  
    34  func handleKcidbNamespce(c context.Context, ns string, cfg *KcidbConfig) error {
    35  	client, err := kcidb.NewClient(c, cfg.Origin, cfg.Project, cfg.Topic, cfg.Credentials)
    36  	if err != nil {
    37  		return err
    38  	}
    39  	defer client.Close()
    40  
    41  	filter := func(query *db.Query) *db.Query {
    42  		return query.Filter("Namespace=", ns).
    43  			Filter("Status=", BugStatusOpen)
    44  	}
    45  	reported := 0
    46  	return foreachBug(c, filter, func(bug *Bug, bugKey *db.Key) error {
    47  		if reported >= 30 {
    48  			return nil
    49  		}
    50  		ok, err := publishKcidbBug(c, client, bug, bugKey)
    51  		if err != nil {
    52  			return err
    53  		}
    54  		if ok {
    55  			reported++
    56  		}
    57  		return nil
    58  	})
    59  }
    60  
    61  func publishKcidbBug(c context.Context, client *kcidb.Client, bug *Bug, bugKey *db.Key) (bool, error) {
    62  	if bug.KcidbStatus != 0 ||
    63  		bug.sanitizeAccess(c, AccessPublic) > AccessPublic ||
    64  		bug.Reporting[len(bug.Reporting)-1].Reported.IsZero() ||
    65  		bug.Status != BugStatusOpen && timeSince(c, bug.LastTime) > 7*24*time.Hour {
    66  		return false, nil
    67  	}
    68  	rep, err := loadBugReport(c, bug)
    69  	if err != nil {
    70  		return false, err
    71  	}
    72  	publish := true
    73  	if rep.KernelCommit == "" || len(rep.KernelConfig) == 0 {
    74  		// This should happen only for syzkaller build/test errors, which we don't want to publish.
    75  		// But if this ever happens for a kernel bug, then we also don't want to publish such bugs
    76  		// with missing critical info.
    77  		publish = false
    78  	}
    79  	if publish {
    80  		if err := client.Publish(rep); err != nil {
    81  			return false, err
    82  		}
    83  	}
    84  	tx := func(c context.Context) error {
    85  		bug := new(Bug)
    86  		if err := db.Get(c, bugKey, bug); err != nil {
    87  			return err
    88  		}
    89  		bug.KcidbStatus = 1
    90  		if !publish {
    91  			bug.KcidbStatus = 2
    92  		}
    93  		if _, err := db.Put(c, bugKey, bug); err != nil {
    94  			return fmt.Errorf("failed to put bug: %w", err)
    95  		}
    96  		return nil
    97  	}
    98  	if err := db.RunInTransaction(c, tx, nil); err != nil {
    99  		return false, err
   100  	}
   101  	log.Infof(c, "published bug to kcidb: %v:%v '%v'", bug.Namespace, bugKey.StringID(), bug.displayTitle())
   102  	return publish, nil
   103  }