blob: 0a1ef97058676267d5e03de12a8a34218285c5db [file] [log] [blame]
// Copyright 2020 syzkaller project authors. All rights reserved.
// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
package main
import (
"context"
"fmt"
"net/http"
"time"
"github.com/google/syzkaller/pkg/kcidb"
"google.golang.org/appengine/v2"
db "google.golang.org/appengine/v2/datastore"
"google.golang.org/appengine/v2/log"
)
func initKcidb() {
http.HandleFunc("/cron/kcidb_poll", handleKcidbPoll)
}
func handleKcidbPoll(w http.ResponseWriter, r *http.Request) {
c := appengine.NewContext(r)
for ns, cfg := range getConfig(c).Namespaces {
if cfg.Kcidb == nil {
continue
}
if err := handleKcidbNamespce(c, ns, cfg.Kcidb); err != nil {
log.Errorf(c, "kcidb: %v failed: %v", ns, err)
}
}
}
func handleKcidbNamespce(c context.Context, ns string, cfg *KcidbConfig) error {
client, err := kcidb.NewClient(c, cfg.Origin, cfg.Project, cfg.Topic, cfg.Credentials)
if err != nil {
return err
}
defer client.Close()
filter := func(query *db.Query) *db.Query {
return query.Filter("Namespace=", ns).
Filter("Status=", BugStatusOpen)
}
reported := 0
return foreachBug(c, filter, func(bug *Bug, bugKey *db.Key) error {
if reported >= 30 {
return nil
}
ok, err := publishKcidbBug(c, client, bug, bugKey)
if err != nil {
return err
}
if ok {
reported++
}
return nil
})
}
func publishKcidbBug(c context.Context, client *kcidb.Client, bug *Bug, bugKey *db.Key) (bool, error) {
if bug.KcidbStatus != 0 ||
bug.sanitizeAccess(c, AccessPublic) > AccessPublic ||
bug.Reporting[len(bug.Reporting)-1].Reported.IsZero() ||
bug.Status != BugStatusOpen && timeSince(c, bug.LastTime) > 7*24*time.Hour {
return false, nil
}
rep, err := loadBugReport(c, bug)
if err != nil {
return false, err
}
publish := true
if rep.KernelCommit == "" || len(rep.KernelConfig) == 0 {
// This should happen only for syzkaller build/test errors, which we don't want to publish.
// But if this ever happens for a kernel bug, then we also don't want to publish such bugs
// with missing critical info.
publish = false
}
if publish {
if err := client.Publish(rep); err != nil {
return false, err
}
}
tx := func(c context.Context) error {
bug := new(Bug)
if err := db.Get(c, bugKey, bug); err != nil {
return err
}
bug.KcidbStatus = 1
if !publish {
bug.KcidbStatus = 2
}
if _, err := db.Put(c, bugKey, bug); err != nil {
return fmt.Errorf("failed to put bug: %w", err)
}
return nil
}
if err := db.RunInTransaction(c, tx, nil); err != nil {
return false, err
}
log.Infof(c, "published bug to kcidb: %v:%v '%v'", bug.Namespace, bugKey.StringID(), bug.displayTitle())
return publish, nil
}