github.com/google/osv-scalibr@v0.4.1/annotator/osduplicate/cos/cos.go (about) 1 // Copyright 2025 Google LLC 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 // Package cos implements an annotator for language packages that have already been found in 16 // COS OS packages. 17 package cos 18 19 import ( 20 "context" 21 "errors" 22 "fmt" 23 "io/fs" 24 "slices" 25 "strings" 26 27 "github.com/google/osv-scalibr/annotator" 28 "github.com/google/osv-scalibr/extractor/filesystem/os/cos" 29 "github.com/google/osv-scalibr/inventory" 30 "github.com/google/osv-scalibr/inventory/vex" 31 "github.com/google/osv-scalibr/plugin" 32 ) 33 34 const ( 35 // Name of the Annotator. 36 Name = "vex/os-duplicate/cos" 37 // The dir in which all OS-installed COS packages are stored. 38 cosPkgDir = "mnt/stateful_partition/var_overlay/db/pkg/" 39 // The only mutable path inside COS filesystems. 40 mutableDir = "mnt/stateful_partition" 41 42 // The COS package info file. 43 cosPackageInfoFile = "etc/cos-package-info.json" 44 ) 45 46 // Annotator adds annotations to language packages that have already been found in COS OS packages. 47 type Annotator struct{} 48 49 // New returns a new Annotator. 50 func New() annotator.Annotator { return &Annotator{} } 51 52 // Name of the annotator. 53 func (Annotator) Name() string { return Name } 54 55 // Version of the annotator. 56 func (Annotator) Version() int { return 0 } 57 58 // Requirements of the annotator. 59 func (Annotator) Requirements() *plugin.Capabilities { 60 return &plugin.Capabilities{OS: plugin.OSLinux} 61 } 62 63 // Annotate adds annotations to language packages that have already been found in COS OS packages. 64 func (a *Annotator) Annotate(ctx context.Context, input *annotator.ScanInput, results *inventory.Inventory) error { 65 if input == nil || input.ScanRoot == nil || input.ScanRoot.FS == nil { 66 return errors.New("input is nil") 67 } 68 69 if _, err := input.ScanRoot.FS.Stat(cosPackageInfoFile); err != nil { 70 if errors.Is(err, fs.ErrNotExist) { 71 // Nothing to annotate if we're not running on COS. 72 return nil 73 } 74 return fmt.Errorf("failed to stat %s: %w", cosPackageInfoFile, err) 75 } 76 77 for _, pkg := range results.Packages { 78 // Return if canceled or exceeding deadline. 79 if err := ctx.Err(); err != nil { 80 return fmt.Errorf("%s halted at %q because of context error: %w", a.Name(), input.ScanRoot.Path, err) 81 } 82 83 // Packages handled by the OS should always be scanned. 84 if slices.Contains(pkg.Plugins, cos.Name) { 85 continue 86 } 87 88 if len(pkg.Locations) == 0 { 89 continue 90 } 91 loc := pkg.Locations[0] 92 // Annotate non-OS (e.g. language) packages as OS duplicates if: 93 // They're in the OS package installation directory 94 if strings.HasPrefix(loc, cosPkgDir) || 95 // Or if they're outside of the user-writable path (only OS-installed packages can live there). 96 !strings.HasPrefix(loc, mutableDir) { 97 pkg.ExploitabilitySignals = append(pkg.ExploitabilitySignals, &vex.PackageExploitabilitySignal{ 98 Plugin: Name, 99 Justification: vex.ComponentNotPresent, 100 MatchesAllVulns: true, 101 }) 102 } 103 } 104 return nil 105 }