skipped 114 lines 115 115 func getPackage(component nativeImageComponent) pkg.Package { 116 116 var cpes []cpe.CPE 117 117 for _, property := range component.Properties { 118 - cpe , err := cpe.New(property.Value) 118 + c , err := cpe.New(property.Value) 119 119 if err != nil { 120 120 log.Debugf("native-image cataloger: could not parse CPE: %v.", err) 121 121 continue 122 122 } 123 - cpes = append(cpes, cpe ) 123 + cpes = append(cpes, c ) 124 124 } 125 125 return pkg.Package{ 126 126 Name: component.Name, skipped 12 lines 139 139 } 140 140 141 141 // decompressSbom returns the packages given within a native image executable's SBOM. 142 - func decompressSbom(databuf []byte, sbomStart uint64, lengthStart uint64) ([]pkg.Package, error) { 142 + func decompressSbom(dataBuf []byte, sbomStart uint64, lengthStart uint64) ([]pkg.Package, error) { 143 143 var pkgs []pkg.Package 144 144 145 145 lengthEnd := lengthStart + 8 146 - buflen := len(databuf) 147 - if lengthEnd > uint64(buflen ) { 148 - return nil, errors.New("the sbom_length symbol overflows the binary") 146 + bufLen := len(dataBuf) 147 + if lengthEnd > uint64(bufLen ) { 148 + return nil, errors.New("the ' sbom_length' symbol overflows the binary") 149 149 } 150 150 151 - length := databuf [lengthStart:lengthEnd] 151 + length := dataBuf [lengthStart:lengthEnd] 152 152 p := bytes.NewBuffer(length) 153 153 var storedLength uint64 154 154 err := binary.Read(p, binary.LittleEndian, &storedLength) 155 155 if err != nil { 156 - log .Debugf ("native - image - cataloger : could not read from binary file. ") 157 - return nil, err 156 + return nil , fmt .Errorf ("could not read from binary file: % w ", err ) 158 157 } 159 - log.Tracef("native-image cataloger: found SBOM of length %d.", storedLength) 158 + 159 + log.WithFields("len", storedLength).Trace("native-image cataloger: found SBOM") 160 160 sbomEnd := sbomStart + storedLength 161 - if sbomEnd > uint64(buflen ) { 161 + if sbomEnd > uint64(bufLen ) { 162 162 return nil, errors.New("the sbom symbol overflows the binary") 163 163 } 164 - sbomCompressed := databuf[sbomStart:sbomEnd] 164 + 165 + sbomCompressed := dataBuf[sbomStart:sbomEnd] 165 166 p = bytes.NewBuffer(sbomCompressed) 166 167 gzreader, err := gzip.NewReader(p) 167 168 if err != nil { 168 - log.Debugf("native-image cataloger: could not decompress the SBOM.") 169 - return nil, err 169 + return nil, fmt.Errorf("could not decompress the native-image SBOM: %w", err) 170 170 } 171 + 171 172 output, err := io.ReadAll(gzreader) 172 173 if err != nil { 173 - log.Debugf("native-image cataloger: could not read the decompressed SBOM.") 174 - return nil, err 174 + return nil, fmt.Errorf("could not read the native-image SBOM: %w", err) 175 175 } 176 + 176 177 var sbomContent nativeImageCycloneDX 177 178 err = json.Unmarshal(output, &sbomContent) 178 179 if err != nil { 179 - log.Debugf("native-image cataloger: could not unmarshal JSON.") 180 - return nil, err 180 + return nil, fmt.Errorf("could not unmarshal the native-image SBOM: %w", err) 181 181 } 182 182 183 183 for _, component := range sbomContent.Components { 184 184 p := getPackage(component) 185 185 pkgs = append(pkgs, p) 186 186 } 187 + 187 188 return pkgs, nil 188 189 } 189 190 190 191 // fileError logs an error message when an executable cannot be read. 191 192 func fileError(filename string, err error) (nativeImage, error) { 192 193 // We could not read the file as a binary for the desired platform, but it may still be a native-image executable. 193 - log .Debugf ("native - image cataloger : unable to read executable (file=%q): %v . ", filename, err) 194 - return nil, err 194 + return nil , fmt .Errorf ("unable to read executable (file=%q): %w ", filename, err) 195 195 } 196 196 197 197 // newElf reads a Native Image from an ELF executable. skipped 40 lines 238 238 case *pe.OptionalHeader64: 239 239 exportSymbolsDataDirectory = h.DataDirectory[0] 240 240 default: 241 - return nil, fmt.Errorf("unable to get exportSymbolsDataDirectory from binary: %s", filename) 241 + return nil, fmt.Errorf("unable to get ' exportSymbolsDataDirectory' from binary: %s", filename) 242 242 } 243 243 // If we have no exported symbols it is not a Native Image 244 244 if exportSymbolsDataDirectory.Size == 0 { skipped 3 lines 248 248 exports := make([]byte, exportSymbolsDataDirectory.Size) 249 249 _, err = r.ReadAt(exports, int64(exportSymbolsOffset)) 250 250 if err != nil { 251 - log .Debugf ("native - image cataloger : could not read the exported symbols data directory: %v . ", err) 252 - return fileError(filename, err) 251 + return fileError ( filename , fmt .Errorf ("could not read the exported symbols data directory: %w ", err)) 253 252 } 254 253 return nativeImagePE{ 255 254 file: bi, skipped 17 lines 273 272 } 274 273 275 274 // fetchPkgs obtains the packages given in the binary. 276 - func (ni nativeImageElf) fetchPkgs() ([]pkg.Package, error) { 275 + func (ni nativeImageElf) fetchPkgs() (pkgs []pkg.Package, retErr error) { 276 + defer func() { 277 + if r := recover(); r != nil { 278 + // this can happen in cases where a malformed binary is passed in can be initially parsed, but not 279 + // used without error later down the line. 280 + retErr = fmt.Errorf("recovered from panic: %v", r) 281 + } 282 + }() 283 + 277 284 bi := ni.file 285 + if bi == nil { 286 + log.Debugf("native-image cataloger: file is nil") 287 + return nil, nil 288 + } 278 289 var sbom elf.Symbol 279 290 var sbomLength elf.Symbol 280 291 var svmVersion elf.Symbol 281 292 282 293 si, err := bi.Symbols() 283 294 if err != nil { 284 - log.Debugf("native-image cataloger: no symbols found.") 285 - return nil, err 295 + return nil, fmt.Errorf("no symbols found in binary: %w", err) 296 + } 297 + if si == nil { 298 + return nil, errors.New(nativeImageMissingSymbolsError) 286 299 } 287 300 for _, s := range si { 288 301 switch s.Name { skipped 6 lines 295 308 } 296 309 } 297 310 if sbom.Value == 0 || sbomLength.Value == 0 || svmVersion.Value == 0 { 298 - log.Debugf("native-image cataloger: %v", nativeImageMissingSymbolsError) 299 311 return nil, errors.New(nativeImageMissingSymbolsError) 300 312 } 301 313 dataSection := bi.Section(".data") 302 314 if dataSection == nil { 303 - log.Debugf("native-image cataloger: .data section missing from ELF file.") 304 - return nil, err 315 + return nil, fmt.Errorf("no .data section found in binary: %w", err) 305 316 } 306 317 dataSectionBase := dataSection.SectionHeader.Addr 307 318 data, err := dataSection.Data() 308 319 if err != nil { 309 - log .Debugf ("native - image cataloger : cannot read the .data section. ") 310 - return nil, err 320 + return nil , fmt .Errorf ("cannot read the .data section: % w ", err ) 311 321 } 312 322 sbomLocation := sbom.Value - dataSectionBase 313 323 lengthLocation := sbomLength.Value - dataSectionBase skipped 2 lines 316 326 } 317 327 318 328 // fetchPkgs obtains the packages from a Native Image given as a Mach O file. 319 - func (ni nativeImageMachO) fetchPkgs() ([]pkg.Package, error) { 329 + func (ni nativeImageMachO) fetchPkgs() (pkgs []pkg.Package, retErr error) { 330 + defer func() { 331 + if r := recover(); r != nil { 332 + // this can happen in cases where a malformed binary is passed in can be initially parsed, but not 333 + // used without error later down the line. 334 + retErr = fmt.Errorf("recovered from panic: %v", r) 335 + } 336 + }() 337 + 320 338 var sbom macho.Symbol 321 339 var sbomLength macho.Symbol 322 340 var svmVersion macho.Symbol 323 341 324 342 bi := ni.file 343 + if bi == nil { 344 + log.Debugf("native-image cataloger: file is nil") 345 + return nil, nil 346 + } 347 + if bi.Symtab == nil { 348 + return nil, errors.New(nativeImageMissingSymbolsError) 349 + } 325 350 for _, s := range bi.Symtab.Syms { 326 351 switch s.Name { 327 352 case "_" + nativeImageSbomSymbol: skipped 5 lines 333 358 } 334 359 } 335 360 if sbom.Value == 0 || sbomLength.Value == 0 || svmVersion.Value == 0 { 336 - log.Debugf("native-image cataloger: %v.", nativeImageMissingSymbolsError) 337 361 return nil, errors.New(nativeImageMissingSymbolsError) 338 362 } 339 363 skipped 1 lines 341 365 if dataSegment == nil { 342 366 return nil, nil 343 367 } 344 - databuf , err := dataSegment.Data() 368 + dataBuf , err := dataSegment.Data() 345 369 if err != nil { 346 370 log.Debugf("native-image cataloger: cannot obtain buffer from data segment.") 347 371 return nil, nil skipped 1 lines 349 373 sbomLocation := sbom.Value - dataSegment.Addr 350 374 lengthLocation := sbomLength.Value - dataSegment.Addr 351 375 352 - return decompressSbom(databuf , sbomLocation, lengthLocation) 376 + return decompressSbom(dataBuf , sbomLocation, lengthLocation) 353 377 } 354 378 355 379 // fetchExportAttribute obtains an attribute from the exported symbols directory entry. skipped 40 lines 396 420 var err error 397 421 content.numberOfFunctions, err = ni.fetchExportAttribute(0) 398 422 if err != nil { 399 - log .Debugf ("native - image cataloger : could not find the number of exported functions attribute: %v ", err) 400 - return nil, err 423 + return nil , fmt .Errorf ("could not find the number of exported ' number of functions' attribute: %w ", err) 401 424 } 402 425 content.numberOfNames, err = ni.fetchExportAttribute(1) 403 426 if err != nil { 404 - log .Debugf ("native - image cataloger : could not find the number of exported names attribute: %v ", err) 405 - return nil, err 427 + return nil , fmt .Errorf ("could not find the number of exported ' number of names' attribute: %w ", err) 406 428 } 407 429 content.addressOfFunctions, err = ni.fetchExportAttribute(2) 408 430 if err != nil { 409 - log .Debugf ("native - image cataloger : could not find the exported functions attribute: %v ", err) 410 - return nil, err 431 + return nil , fmt .Errorf ("could not find the exported ' address of functions' attribute: %w ", err) 411 432 } 412 433 content.addressOfNames, err = ni.fetchExportAttribute(3) 413 434 if err != nil { 414 - log .Debugf ("native - image cataloger : could not find the exported names attribute: %v ", err) 415 - return nil, err 435 + return nil , fmt .Errorf ("could not find the exported ' address of names' attribute: %w ", err) 416 436 } 417 437 return content, nil 418 438 } skipped 41 lines 460 480 } 461 481 462 482 // fetchPkgs obtains the packages from a Native Image given as a PE file. 463 - func (ni nativeImagePE) fetchPkgs() ([]pkg.Package, error) { 483 + func (ni nativeImagePE) fetchPkgs() (pkgs []pkg.Package, retErr error) { 484 + defer func() { 485 + if r := recover(); r != nil { 486 + // this can happen in cases where a malformed binary is passed in can be initially parsed, but not 487 + // used without error later down the line. 488 + retErr = fmt.Errorf("recovered from panic: %v", r) 489 + } 490 + }() 491 + 464 492 content, err := ni.fetchExportContent() 465 493 if err != nil { 466 494 log.Debugf("native-image cataloger: could not fetch the content of the export directory entry: %v.", err) skipped 1 lines 468 496 } 469 497 ni.fetchSbomSymbols(content) 470 498 if content.addressOfSbom == uint32(0) || content.addressOfSbomLength == uint32(0) || content.addressOfSvmVersion == uint32(0) { 471 - log.Debugf("native-image cataloger: %v.", nativeImageMissingSymbolsError) 472 499 return nil, errors.New(nativeImageMissingSymbolsError) 473 500 } 474 501 functionsBase := content.addressOfFunctions - ni.exportSymbols.VirtualAddress 475 502 sbomOffset := content.addressOfSbom 476 503 sbomAddress, err := ni.fetchExportFunctionPointer(functionsBase, sbomOffset) 477 504 if err != nil { 478 - log .Debugf ("native - image cataloger : cannot fetch SBOM pointer from exported functions: %v . ", err) 479 - return nil, err 505 + return nil , fmt .Errorf ("could not fetch SBOM pointer from exported functions: %w ", err) 480 506 } 481 507 sbomLengthOffset := content.addressOfSbomLength 482 508 sbomLengthAddress, err := ni.fetchExportFunctionPointer(functionsBase, sbomLengthOffset) 483 509 if err != nil { 484 - log .Debugf ("native - image cataloger : cannot fetch SBOM length pointer from exported functions: %v . ", err) 485 - return nil, err 510 + return nil , fmt .Errorf ("could not fetch SBOM length pointer from exported functions: %w ", err) 486 511 } 487 512 bi := ni.file 488 513 dataSection := bi.Section(".data") 489 514 if dataSection == nil { 490 515 return nil, nil 491 516 } 492 - databuf , err := dataSection.Data() 517 + dataBuf , err := dataSection.Data() 493 518 if err != nil { 494 519 log.Debugf("native-image cataloger: cannot obtain buffer from .data section.") 495 520 return nil, nil skipped 1 lines 497 522 sbomLocation := sbomAddress - dataSection.VirtualAddress 498 523 lengthLocation := sbomLengthAddress - dataSection.VirtualAddress 499 524 500 - return decompressSbom(databuf , uint64(sbomLocation), uint64(lengthLocation)) 525 + return decompressSbom(dataBuf , uint64(sbomLocation), uint64(lengthLocation)) 501 526 } 502 527 503 528 // fetchPkgs provides the packages available in a UnionReader. skipped 55 lines