github.com/khulnasoft-lab/tunnel-db@v0.0.0-20231117205118-74e1113bd007/pkg/vulnsrc/ubuntu/ubuntu.go (about) 1 package ubuntu 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "io" 7 "log" 8 "path/filepath" 9 10 bolt "go.etcd.io/bbolt" 11 "golang.org/x/xerrors" 12 13 "github.com/khulnasoft-lab/tunnel-db/pkg/db" 14 "github.com/khulnasoft-lab/tunnel-db/pkg/types" 15 "github.com/khulnasoft-lab/tunnel-db/pkg/utils" 16 "github.com/khulnasoft-lab/tunnel-db/pkg/utils/strings" 17 "github.com/khulnasoft-lab/tunnel-db/pkg/vulnsrc/vulnerability" 18 ) 19 20 const ( 21 ubuntuDir = "ubuntu" 22 platformFormat = "ubuntu %s" 23 ) 24 25 var ( 26 targetStatuses = []string{"needed", "deferred", "released"} 27 UbuntuReleasesMapping = map[string]string{ 28 "precise": "12.04", 29 "quantal": "12.10", 30 "raring": "13.04", 31 "saucy": "13.10", 32 "trusty": "14.04", 33 "utopic": "14.10", 34 "vivid": "15.04", 35 "wily": "15.10", 36 "xenial": "16.04", 37 "yakkety": "16.10", 38 "zesty": "17.04", 39 "artful": "17.10", 40 "bionic": "18.04", 41 "cosmic": "18.10", 42 "disco": "19.04", 43 "eoan": "19.10", 44 "focal": "20.04", 45 "groovy": "20.10", 46 "hirsute": "21.04", 47 "impish": "21.10", 48 "jammy": "22.04", 49 "kinetic": "22.10", 50 "lunar": "23.04", 51 "mantic": "23.10", 52 // ESM versions: 53 "precise/esm": "12.04-ESM", 54 "trusty/esm": "14.04-ESM", 55 "esm-infra/xenial": "16.04-ESM", 56 } 57 58 source = types.DataSource{ 59 ID: vulnerability.Ubuntu, 60 Name: "Ubuntu CVE Tracker", 61 URL: "https://git.launchpad.net/ubuntu-cve-tracker", 62 } 63 ) 64 65 type Option func(src *VulnSrc) 66 67 func WithCustomPut(put db.CustomPut) Option { 68 return func(src *VulnSrc) { 69 src.put = put 70 } 71 } 72 73 type VulnSrc struct { 74 put db.CustomPut 75 dbc db.Operation 76 } 77 78 func NewVulnSrc(opts ...Option) VulnSrc { 79 src := VulnSrc{ 80 put: defaultPut, 81 dbc: db.Config{}, 82 } 83 84 for _, o := range opts { 85 o(&src) 86 } 87 88 return src 89 } 90 91 func (vs VulnSrc) Name() types.SourceID { 92 return source.ID 93 } 94 95 func (vs VulnSrc) Update(dir string) error { 96 rootDir := filepath.Join(dir, "vuln-list", ubuntuDir) 97 var cves []UbuntuCVE 98 err := utils.FileWalk(rootDir, func(r io.Reader, path string) error { 99 var cve UbuntuCVE 100 if err := json.NewDecoder(r).Decode(&cve); err != nil { 101 return xerrors.Errorf("failed to decode Ubuntu JSON: %w", err) 102 } 103 cves = append(cves, cve) 104 return nil 105 }) 106 if err != nil { 107 return xerrors.Errorf("error in Ubuntu walk: %w", err) 108 } 109 110 if err = vs.save(cves); err != nil { 111 return xerrors.Errorf("error in Ubuntu save: %w", err) 112 } 113 114 return nil 115 } 116 117 func (vs VulnSrc) save(cves []UbuntuCVE) error { 118 log.Println("Saving Ubuntu DB") 119 err := vs.dbc.BatchUpdate(func(tx *bolt.Tx) error { 120 err := vs.commit(tx, cves) 121 if err != nil { 122 return err 123 } 124 return nil 125 }) 126 if err != nil { 127 return xerrors.Errorf("error in batch update: %w", err) 128 } 129 return nil 130 } 131 132 func (vs VulnSrc) commit(tx *bolt.Tx, cves []UbuntuCVE) error { 133 for _, cve := range cves { 134 if err := vs.put(vs.dbc, tx, cve); err != nil { 135 return xerrors.Errorf("put error: %w", err) 136 } 137 } 138 return nil 139 } 140 141 func (vs VulnSrc) Get(release string, pkgName string) ([]types.Advisory, error) { 142 bucket := fmt.Sprintf(platformFormat, release) 143 advisories, err := vs.dbc.GetAdvisories(bucket, pkgName) 144 if err != nil { 145 return nil, xerrors.Errorf("failed to get Ubuntu advisories: %w", err) 146 } 147 return advisories, nil 148 } 149 150 func defaultPut(dbc db.Operation, tx *bolt.Tx, advisory interface{}) error { 151 cve, ok := advisory.(UbuntuCVE) 152 if !ok { 153 return xerrors.New("unknown type") 154 } 155 156 for packageName, patch := range cve.Patches { 157 pkgName := string(packageName) 158 for release, status := range patch { 159 if !strings.InSlice(status.Status, targetStatuses) { 160 continue 161 } 162 osVersion, ok := UbuntuReleasesMapping[string(release)] 163 if !ok { 164 continue 165 } 166 platformName := fmt.Sprintf(platformFormat, osVersion) 167 if err := dbc.PutDataSource(tx, platformName, source); err != nil { 168 return xerrors.Errorf("failed to put data source: %w", err) 169 } 170 171 adv := types.Advisory{} 172 if status.Status == "released" { 173 adv.FixedVersion = status.Note 174 } 175 if err := dbc.PutAdvisoryDetail(tx, cve.Candidate, pkgName, []string{platformName}, adv); err != nil { 176 return xerrors.Errorf("failed to save Ubuntu advisory: %w", err) 177 } 178 179 vuln := types.VulnerabilityDetail{ 180 Severity: SeverityFromPriority(cve.Priority), 181 References: cve.References, 182 Description: cve.Description, 183 } 184 if err := dbc.PutVulnerabilityDetail(tx, cve.Candidate, source.ID, vuln); err != nil { 185 return xerrors.Errorf("failed to save Ubuntu vulnerability: %w", err) 186 } 187 188 // for optimization 189 if err := dbc.PutVulnerabilityID(tx, cve.Candidate); err != nil { 190 return xerrors.Errorf("failed to save the vulnerability ID: %w", err) 191 } 192 } 193 } 194 195 return nil 196 } 197 198 // SeverityFromPriority converts Ubuntu priority into Tunnel severity 199 func SeverityFromPriority(priority string) types.Severity { 200 switch priority { 201 case "untriaged": 202 return types.SeverityUnknown 203 case "negligible", "low": 204 return types.SeverityLow 205 case "medium": 206 return types.SeverityMedium 207 case "high": 208 return types.SeverityHigh 209 case "critical": 210 return types.SeverityCritical 211 default: 212 return types.SeverityUnknown 213 } 214 }