github.com/google/syzkaller@v0.0.0-20251211124644-a066d2bc4b02/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.RestURI, cfg.Token)
    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 == false happens only for syzkaller build/test errors.
    73  	// But if this ever happens for a kernel bug, then we also don't want to publish such bugs
    74  	// with missing critical info.
    75  	publish := rep.KernelCommit != "" && len(rep.KernelConfig) != 0
    76  
    77  	if publish {
    78  		if err := client.Publish(rep); err != nil {
    79  			return false, err
    80  		}
    81  	}
    82  	tx := func(c context.Context) error {
    83  		bug := new(Bug)
    84  		if err := db.Get(c, bugKey, bug); err != nil {
    85  			return err
    86  		}
    87  		bug.KcidbStatus = 1
    88  		if !publish {
    89  			bug.KcidbStatus = 2
    90  		}
    91  		if _, err := db.Put(c, bugKey, bug); err != nil {
    92  			return fmt.Errorf("failed to put bug: %w", err)
    93  		}
    94  		return nil
    95  	}
    96  	if err := runInTransaction(c, tx, nil); err != nil {
    97  		return false, err
    98  	}
    99  	log.Infof(c, "published bug to kcidb: %v:%v '%v'", bug.Namespace, bugKey.StringID(), bug.displayTitle())
   100  	return publish, nil
   101  }