Initialize module and dependencies

This commit is contained in:
dwrz
2026-01-04 20:57:40 +00:00
commit a3b390c008
514 changed files with 310495 additions and 0 deletions

349
vendor/golang.org/x/vuln/internal/goversion/asm.go generated vendored Normal file
View File

@@ -0,0 +1,349 @@
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package goversion
import (
"encoding/binary"
"fmt"
"os"
)
type matcher [][]uint32
const (
pWild uint32 = 0xff00
pAddr uint32 = 0x10000
pEnd uint32 = 0x20000
pRelAddr uint32 = 0x30000
opMaybe = 1 + iota
opMust
opDone
opAnchor = 0x100
opSub8 = 0x200
opFlags = opAnchor | opSub8
)
var amd64Matcher = matcher{
{opMaybe | opAnchor,
// __rt0_amd64_darwin:
// JMP __rt0_amd64
0xe9, pWild | pAddr, pWild, pWild, pWild | pEnd, 0xcc, 0xcc, 0xcc,
},
{opMaybe,
// _rt0_amd64_linux:
// lea 0x8(%rsp), %rsi
// mov (%rsp), %rdi
// lea ADDR(%rip), %rax # main
// jmpq *%rax
0x48, 0x8d, 0x74, 0x24, 0x08,
0x48, 0x8b, 0x3c, 0x24, 0x48,
0x8d, 0x05, pWild | pAddr, pWild, pWild, pWild | pEnd,
0xff, 0xe0,
},
{opMaybe,
// _rt0_amd64_linux:
// lea 0x8(%rsp), %rsi
// mov (%rsp), %rdi
// mov $ADDR, %eax # main
// jmpq *%rax
0x48, 0x8d, 0x74, 0x24, 0x08,
0x48, 0x8b, 0x3c, 0x24,
0xb8, pWild | pAddr, pWild, pWild, pWild,
0xff, 0xe0,
},
{opMaybe,
// __rt0_amd64:
// mov (%rsp), %rdi
// lea 8(%rsp), %rsi
// jmp runtime.rt0_g0
0x48, 0x8b, 0x3c, 0x24,
0x48, 0x8d, 0x74, 0x24, 0x08,
0xe9, pWild | pAddr, pWild, pWild, pWild | pEnd,
0xcc, 0xcc,
},
{opMaybe,
// _start (toward end)
// lea __libc_csu_fini(%rip), %r8
// lea __libc_csu_init(%rip), %rcx
// lea ADDR(%rip), %rdi # main
// callq *xxx(%rip)
0x4c, 0x8d, 0x05, pWild, pWild, pWild, pWild,
0x48, 0x8d, 0x0d, pWild, pWild, pWild, pWild,
0x48, 0x8d, 0x3d, pWild | pAddr, pWild, pWild, pWild | pEnd,
0xff, 0x15,
},
{opMaybe,
// _start (toward end)
// push %rsp (1)
// mov $__libc_csu_fini, %r8 (7)
// mov $__libc_csu_init, %rcx (7)
// mov $ADDR, %rdi # main (7)
// callq *xxx(%rip)
0x54,
0x49, 0xc7, 0xc0, pWild, pWild, pWild, pWild,
0x48, 0xc7, 0xc1, pWild, pWild, pWild, pWild,
0x48, 0xc7, 0xc7, pAddr | pWild, pWild, pWild, pWild,
},
{opMaybe | opAnchor,
// main:
// lea ADDR(%rip), %rax # rt0_go
// jmpq *%rax
0x48, 0x8d, 0x05, pWild | pAddr, pWild, pWild, pWild | pEnd,
0xff, 0xe0,
},
{opMaybe | opAnchor,
// main:
// mov $ADDR, %eax
// jmpq *%rax
0xb8, pWild | pAddr, pWild, pWild, pWild,
0xff, 0xe0,
},
{opMaybe | opAnchor,
// main:
// JMP runtime.rt0_go(SB)
0xe9, pWild | pAddr, pWild, pWild, pWild | pEnd, 0xcc, 0xcc, 0xcc,
},
{opMust | opAnchor,
// rt0_go:
// mov %rdi, %rax
// mov %rsi, %rbx
// sub %0x27, %rsp
// and $0xfffffffffffffff0,%rsp
// mov %rax,0x10(%rsp)
// mov %rbx,0x18(%rsp)
0x48, 0x89, 0xf8,
0x48, 0x89, 0xf3,
0x48, 0x83, 0xec, 0x27,
0x48, 0x83, 0xe4, 0xf0,
0x48, 0x89, 0x44, 0x24, 0x10,
0x48, 0x89, 0x5c, 0x24, 0x18,
},
{opMust,
// later in rt0_go:
// mov %eax, (%rsp)
// mov 0x18(%rsp), %rax
// mov %rax, 0x8(%rsp)
// callq runtime.args
// callq runtime.osinit
// callq runtime.schedinit (ADDR)
0x89, 0x04, 0x24,
0x48, 0x8b, 0x44, 0x24, 0x18,
0x48, 0x89, 0x44, 0x24, 0x08,
0xe8, pWild, pWild, pWild, pWild,
0xe8, pWild, pWild, pWild, pWild,
0xe8, pWild, pWild, pWild, pWild,
},
{opMaybe,
// later in rt0_go:
// mov %eax, (%rsp)
// mov 0x18(%rsp), %rax
// mov %rax, 0x8(%rsp)
// callq runtime.args
// callq runtime.osinit
// callq runtime.schedinit (ADDR)
// lea other(%rip), %rdi
0x89, 0x04, 0x24,
0x48, 0x8b, 0x44, 0x24, 0x18,
0x48, 0x89, 0x44, 0x24, 0x08,
0xe8, pWild, pWild, pWild, pWild,
0xe8, pWild, pWild, pWild, pWild,
0xe8, pWild | pAddr, pWild, pWild, pWild | pEnd,
0x48, 0x8d, 0x05,
},
{opMaybe,
// later in rt0_go:
// mov %eax, (%rsp)
// mov 0x18(%rsp), %rax
// mov %rax, 0x8(%rsp)
// callq runtime.args
// callq runtime.osinit
// callq runtime.hashinit
// callq runtime.schedinit (ADDR)
// pushq $main.main
0x89, 0x04, 0x24,
0x48, 0x8b, 0x44, 0x24, 0x18,
0x48, 0x89, 0x44, 0x24, 0x08,
0xe8, pWild, pWild, pWild, pWild,
0xe8, pWild, pWild, pWild, pWild,
0xe8, pWild, pWild, pWild, pWild,
0xe8, pWild | pAddr, pWild, pWild, pWild | pEnd,
0x68,
},
{opDone | opSub8,
// schedinit (toward end)
// mov ADDR(%rip), %rax
// test %rax, %rax
// jne <short>
// movq $0x7, ADDR(%rip)
//
0x48, 0x8b, 0x05, pWild, pWild, pWild, pWild,
0x48, 0x85, 0xc0,
0x75, pWild,
0x48, 0xc7, 0x05, pWild | pAddr, pWild, pWild, pWild, 0x07, 0x00, 0x00, 0x00 | pEnd,
},
{opDone | opSub8,
// schedinit (toward end)
// mov ADDR(%rip), %rbx
// cmp $0x0, %rbx
// jne <short>
// lea "unknown"(%rip), %rbx
// mov %rbx, ADDR(%rip)
// movq $7, (ADDR+8)(%rip)
0x48, 0x8b, 0x1d, pWild, pWild, pWild, pWild,
0x48, 0x83, 0xfb, 0x00,
0x75, pWild,
0x48, 0x8d, 0x1d, pWild, pWild, pWild, pWild,
0x48, 0x89, 0x1d, pWild, pWild, pWild, pWild,
0x48, 0xc7, 0x05, pWild | pAddr, pWild, pWild, pWild, 0x07, 0x00, 0x00, 0x00 | pEnd,
},
{opDone,
// schedinit (toward end)
// cmpq $0x0, ADDR(%rip)
// jne <short>
// lea "unknown"(%rip), %rax
// mov %rax, ADDR(%rip)
// lea ADDR(%rip), %rax
// movq $7, 8(%rax)
0x48, 0x83, 0x3d, pWild | pAddr, pWild, pWild, pWild, 0x00,
0x75, pWild,
0x48, 0x8d, 0x05, pWild, pWild, pWild, pWild,
0x48, 0x89, 0x05, pWild, pWild, pWild, pWild,
0x48, 0x8d, 0x05, pWild | pAddr, pWild, pWild, pWild | pEnd,
0x48, 0xc7, 0x40, 0x08, 0x07, 0x00, 0x00, 0x00,
},
{opDone,
// schedinit (toward end)
// cmpq $0x0, ADDR(%rip)
// jne <short>
// movq $0x7, ADDR(%rip)
0x48, 0x83, 0x3d, pWild | pAddr, pWild, pWild, pWild, 0x00,
0x75, pWild,
0x48, 0xc7, 0x05 | pEnd, pWild | pAddr, pWild, pWild, pWild, 0x07, 0x00, 0x00, 0x00,
},
{opDone,
// test %eax, %eax
// jne <later>
// lea "unknown"(RIP), %rax
// mov %rax, ADDR(%rip)
0x48, 0x85, 0xc0, 0x75, pWild, 0x48, 0x8d, 0x05, pWild, pWild, pWild, pWild, 0x48, 0x89, 0x05, pWild | pAddr, pWild, pWild, pWild | pEnd,
},
{opDone,
// schedinit (toward end)
// mov ADDR(%rip), %rcx
// test %rcx, %rcx
// jne <short>
// movq $0x7, ADDR(%rip)
//
0x48, 0x8b, 0x0d, pWild, pWild, pWild, pWild,
0x48, 0x85, 0xc9,
0x75, pWild,
0x48, 0xc7, 0x05 | pEnd, pWild | pAddr, pWild, pWild, pWild, 0x07, 0x00, 0x00, 0x00,
},
}
var DebugMatch bool
func (m matcher) match(f exe, addr uint64) (uint64, bool) {
data, err := f.ReadData(addr, 512)
if DebugMatch {
fmt.Fprintf(os.Stderr, "data @%#x: %x\n", addr, data[:16])
}
if err != nil {
if DebugMatch {
fmt.Fprintf(os.Stderr, "match: %v\n", err)
}
return 0, false
}
if DebugMatch {
fmt.Fprintf(os.Stderr, "data: %x\n", data[:32])
}
Matchers:
for pc, p := range m {
op := p[0]
p = p[1:]
Search:
for i := 0; i <= len(data)-len(p); i++ {
a := -1
e := -1
if i > 0 && op&opAnchor != 0 {
break
}
for j := 0; j < len(p); j++ {
b := byte(p[j])
m := byte(p[j] >> 8)
if data[i+j]&^m != b {
continue Search
}
if p[j]&pAddr != 0 {
a = j
}
if p[j]&pEnd != 0 {
e = j + 1
}
}
// matched
if DebugMatch {
fmt.Fprintf(os.Stderr, "match (%d) %#x+%d %x %x\n", pc, addr, i, p, data[i:i+len(p)])
}
if a != -1 {
val := uint64(int32(binary.LittleEndian.Uint32(data[i+a:])))
if e == -1 {
addr = val
} else {
addr += uint64(i+e) + val
}
if op&opSub8 != 0 {
addr -= 8
}
}
if op&^opFlags == opDone {
if DebugMatch {
fmt.Fprintf(os.Stderr, "done %x\n", addr)
}
return addr, true
}
if a != -1 {
// changed addr, so reload
data, err = f.ReadData(addr, 512)
if err != nil {
return 0, false
}
if DebugMatch {
fmt.Fprintf(os.Stderr, "reload @%#x: %x\n", addr, data[:32])
}
}
continue Matchers
}
// not matched
if DebugMatch {
fmt.Fprintf(os.Stderr, "no match (%d) %#x %x %x\n", pc, addr, p, data[:32])
}
if op&^opFlags == opMust {
return 0, false
}
}
// ran off end of matcher
return 0, false
}
func readBuildVersionX86Asm(f exe) (isGo bool, buildVersion string) {
entry := f.Entry()
if entry == 0 {
if DebugMatch {
fmt.Fprintf(os.Stderr, "missing entry!\n")
}
return
}
addr, ok := amd64Matcher.match(f, entry)
if !ok {
return
}
v, err := readBuildVersion(f, addr, 16)
if err != nil {
return
}
return true, v
}

324
vendor/golang.org/x/vuln/internal/goversion/exe.go generated vendored Normal file
View File

@@ -0,0 +1,324 @@
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package goversion
import (
"bytes"
"debug/elf"
"debug/macho"
"debug/pe"
"encoding/binary"
"fmt"
"io"
"os"
)
type sym struct {
Name string
Addr uint64
Size uint64
}
type exe interface {
AddrSize() int // bytes
ReadData(addr, size uint64) ([]byte, error)
Symbols() ([]sym, error)
SectionNames() []string
Close() error
ByteOrder() binary.ByteOrder
Entry() uint64
TextRange() (uint64, uint64)
RODataRange() (uint64, uint64)
}
func openExe(file string) (exe, error) {
f, err := os.Open(file)
if err != nil {
return nil, err
}
data := make([]byte, 16)
if _, err := io.ReadFull(f, data); err != nil {
return nil, err
}
f.Seek(0, 0)
if bytes.HasPrefix(data, []byte("\x7FELF")) {
e, err := elf.NewFile(f)
if err != nil {
f.Close()
return nil, err
}
return &elfExe{f, e}, nil
}
if bytes.HasPrefix(data, []byte("MZ")) {
e, err := pe.NewFile(f)
if err != nil {
f.Close()
return nil, err
}
return &peExe{f, e}, nil
}
if bytes.HasPrefix(data, []byte("\xFE\xED\xFA")) || bytes.HasPrefix(data[1:], []byte("\xFA\xED\xFE")) {
e, err := macho.NewFile(f)
if err != nil {
f.Close()
return nil, err
}
return &machoExe{f, e}, nil
}
return nil, fmt.Errorf("unrecognized executable format")
}
type elfExe struct {
os *os.File
f *elf.File
}
func (x *elfExe) AddrSize() int { return 0 }
func (x *elfExe) ByteOrder() binary.ByteOrder { return x.f.ByteOrder }
func (x *elfExe) Close() error {
return x.os.Close()
}
func (x *elfExe) Entry() uint64 { return x.f.Entry }
func (x *elfExe) ReadData(addr, size uint64) ([]byte, error) {
for _, prog := range x.f.Progs {
// The following line was commented from the original code.
//fmt.Printf("%#x %#x %#x\n", addr, prog.Vaddr, prog.Vaddr+prog.Filesz)
if prog.Vaddr <= addr && addr <= prog.Vaddr+prog.Filesz-1 {
n := prog.Vaddr + prog.Filesz - addr
if n > size {
n = size
}
data := make([]byte, n)
_, err := prog.ReadAt(data, int64(addr-prog.Vaddr))
if err != nil {
return nil, err
}
return data, nil
}
}
return nil, fmt.Errorf("address not mapped")
}
func (x *elfExe) Symbols() ([]sym, error) {
syms, err := x.f.Symbols()
if err != nil {
return nil, err
}
var out []sym
for _, s := range syms {
out = append(out, sym{s.Name, s.Value, s.Size})
}
return out, nil
}
func (x *elfExe) SectionNames() []string {
var names []string
for _, sect := range x.f.Sections {
names = append(names, sect.Name)
}
return names
}
func (x *elfExe) TextRange() (uint64, uint64) {
for _, p := range x.f.Progs {
if p.Type == elf.PT_LOAD && p.Flags&elf.PF_X != 0 {
return p.Vaddr, p.Vaddr + p.Filesz
}
}
return 0, 0
}
func (x *elfExe) RODataRange() (uint64, uint64) {
for _, p := range x.f.Progs {
if p.Type == elf.PT_LOAD && p.Flags&(elf.PF_R|elf.PF_W|elf.PF_X) == elf.PF_R {
return p.Vaddr, p.Vaddr + p.Filesz
}
}
for _, p := range x.f.Progs {
if p.Type == elf.PT_LOAD && p.Flags&(elf.PF_R|elf.PF_W|elf.PF_X) == (elf.PF_R|elf.PF_X) {
return p.Vaddr, p.Vaddr + p.Filesz
}
}
return 0, 0
}
type peExe struct {
os *os.File
f *pe.File
}
func (x *peExe) imageBase() uint64 {
switch oh := x.f.OptionalHeader.(type) {
case *pe.OptionalHeader32:
return uint64(oh.ImageBase)
case *pe.OptionalHeader64:
return oh.ImageBase
}
return 0
}
func (x *peExe) AddrSize() int {
if x.f.Machine == pe.IMAGE_FILE_MACHINE_AMD64 {
return 8
}
return 4
}
func (x *peExe) ByteOrder() binary.ByteOrder { return binary.LittleEndian }
func (x *peExe) Close() error {
return x.os.Close()
}
func (x *peExe) Entry() uint64 {
switch oh := x.f.OptionalHeader.(type) {
case *pe.OptionalHeader32:
return uint64(oh.ImageBase + oh.AddressOfEntryPoint)
case *pe.OptionalHeader64:
return oh.ImageBase + uint64(oh.AddressOfEntryPoint)
}
return 0
}
func (x *peExe) ReadData(addr, size uint64) ([]byte, error) {
addr -= x.imageBase()
data := make([]byte, size)
for _, sect := range x.f.Sections {
if uint64(sect.VirtualAddress) <= addr && addr+size-1 <= uint64(sect.VirtualAddress+sect.Size-1) {
_, err := sect.ReadAt(data, int64(addr-uint64(sect.VirtualAddress)))
if err != nil {
return nil, err
}
return data, nil
}
}
return nil, fmt.Errorf("address not mapped")
}
func (x *peExe) Symbols() ([]sym, error) {
base := x.imageBase()
var out []sym
for _, s := range x.f.Symbols {
if s.SectionNumber <= 0 || int(s.SectionNumber) > len(x.f.Sections) {
continue
}
sect := x.f.Sections[s.SectionNumber-1]
out = append(out, sym{s.Name, uint64(s.Value) + base + uint64(sect.VirtualAddress), 0})
}
return out, nil
}
func (x *peExe) SectionNames() []string {
var names []string
for _, sect := range x.f.Sections {
names = append(names, sect.Name)
}
return names
}
func (x *peExe) TextRange() (uint64, uint64) {
// Assume text is first non-empty section.
for _, sect := range x.f.Sections {
if sect.VirtualAddress != 0 && sect.Size != 0 {
return uint64(sect.VirtualAddress) + x.imageBase(), uint64(sect.VirtualAddress+sect.Size) + x.imageBase()
}
}
return 0, 0
}
func (x *peExe) RODataRange() (uint64, uint64) {
return x.TextRange()
}
type machoExe struct {
os *os.File
f *macho.File
}
func (x *machoExe) AddrSize() int {
if x.f.Cpu&0x01000000 != 0 {
return 8
}
return 4
}
func (x *machoExe) ByteOrder() binary.ByteOrder { return x.f.ByteOrder }
func (x *machoExe) Close() error {
return x.os.Close()
}
func (x *machoExe) Entry() uint64 {
for _, load := range x.f.Loads {
b, ok := load.(macho.LoadBytes)
if !ok {
continue
}
// TODO: Other thread states.
bo := x.f.ByteOrder
const x86_THREAD_STATE64 = 4
cmd, siz := macho.LoadCmd(bo.Uint32(b[0:4])), bo.Uint32(b[4:8])
if cmd == macho.LoadCmdUnixThread && siz == 184 && bo.Uint32(b[8:12]) == x86_THREAD_STATE64 {
return bo.Uint64(b[144:])
}
}
return 0
}
func (x *machoExe) ReadData(addr, size uint64) ([]byte, error) {
data := make([]byte, size)
for _, load := range x.f.Loads {
seg, ok := load.(*macho.Segment)
if !ok {
continue
}
if seg.Addr <= addr && addr+size-1 <= seg.Addr+seg.Filesz-1 {
if seg.Name == "__PAGEZERO" {
continue
}
_, err := seg.ReadAt(data, int64(addr-seg.Addr))
if err != nil {
return nil, err
}
return data, nil
}
}
return nil, fmt.Errorf("address not mapped")
}
func (x *machoExe) Symbols() ([]sym, error) {
var out []sym
for _, s := range x.f.Symtab.Syms {
out = append(out, sym{s.Name, s.Value, 0})
}
return out, nil
}
func (x *machoExe) SectionNames() []string {
var names []string
for _, sect := range x.f.Sections {
names = append(names, sect.Name)
}
return names
}
func (x *machoExe) TextRange() (uint64, uint64) {
// Assume text is first non-empty segment.
for _, load := range x.f.Loads {
seg, ok := load.(*macho.Segment)
if ok && seg.Name != "__PAGEZERO" && seg.Addr != 0 && seg.Filesz != 0 {
return seg.Addr, seg.Addr + seg.Filesz
}
}
return 0, 0
}
func (x *machoExe) RODataRange() (uint64, uint64) {
return x.TextRange()
}

246
vendor/golang.org/x/vuln/internal/goversion/read.go generated vendored Normal file
View File

@@ -0,0 +1,246 @@
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package goversion reports the Go version used to build program executables.
//
// This is a copy of rsc.io/goversion/version. We renamed the package to goversion
// to differentiate between version package in standard library that we also use.
package goversion
import (
"bytes"
"encoding/hex"
"errors"
"fmt"
"regexp"
"strings"
)
// Version is the information reported by ReadExe.
type Version struct {
Release string // Go version (runtime.Version in the program)
ModuleInfo string // program's module information
BoringCrypto bool // program uses BoringCrypto
StandardCrypto bool // program uses standard crypto (replaced by BoringCrypto)
FIPSOnly bool // program imports "crypto/tls/fipsonly"
}
// ReadExe reports information about the Go version used to build
// the program executable named by file.
func ReadExe(file string) (Version, error) {
var v Version
f, err := openExe(file)
if err != nil {
return v, err
}
defer f.Close()
isGo := false
for _, name := range f.SectionNames() {
if name == ".note.go.buildid" {
isGo = true
}
}
syms, symsErr := f.Symbols()
isGccgo := false
for _, sym := range syms {
name := sym.Name
if name == "runtime.main" || name == "main.main" {
isGo = true
}
if strings.HasPrefix(name, "runtime.") && strings.HasSuffix(name, "$descriptor") {
isGccgo = true
}
if name == "runtime.buildVersion" {
isGo = true
release, err := readBuildVersion(f, sym.Addr, sym.Size)
if err != nil {
return v, err
}
v.Release = release
}
// Note: Using strings.HasPrefix because Go 1.17+ adds ".abi0" to many of these symbols.
if strings.Contains(name, "_Cfunc__goboringcrypto_") || strings.HasPrefix(name, "crypto/internal/boring/sig.BoringCrypto") {
v.BoringCrypto = true
}
if strings.HasPrefix(name, "crypto/internal/boring/sig.FIPSOnly") {
v.FIPSOnly = true
}
for _, re := range standardCryptoNames {
if re.MatchString(name) {
v.StandardCrypto = true
}
}
if strings.HasPrefix(name, "crypto/internal/boring/sig.StandardCrypto") {
v.StandardCrypto = true
}
}
if DebugMatch {
v.Release = ""
}
if err := findModuleInfo(&v, f); err != nil {
return v, err
}
if v.Release == "" {
g, release := readBuildVersionX86Asm(f)
if g {
isGo = true
v.Release = release
if err := findCryptoSigs(&v, f); err != nil {
return v, err
}
}
}
if isGccgo && v.Release == "" {
isGo = true
v.Release = "gccgo (version unknown)"
}
if !isGo && symsErr != nil {
return v, symsErr
}
if !isGo {
return v, errors.New("not a Go executable")
}
if v.Release == "" {
v.Release = "unknown Go version"
}
return v, nil
}
var re = regexp.MustCompile
var standardCryptoNames = []*regexp.Regexp{
re(`^crypto/sha1\.\(\*digest\)`),
re(`^crypto/sha256\.\(\*digest\)`),
re(`^crypto/rand\.\(\*devReader\)`),
re(`^crypto/rsa\.encrypt(\.abi.)?$`),
re(`^crypto/rsa\.decrypt(\.abi.)?$`),
}
func readBuildVersion(f exe, addr, size uint64) (string, error) {
if size == 0 {
size = uint64(f.AddrSize() * 2)
}
if size != 8 && size != 16 {
return "", fmt.Errorf("invalid size for runtime.buildVersion")
}
data, err := f.ReadData(addr, size)
if err != nil {
return "", fmt.Errorf("reading runtime.buildVersion: %v", err)
}
if size == 8 {
addr = uint64(f.ByteOrder().Uint32(data))
size = uint64(f.ByteOrder().Uint32(data[4:]))
} else {
addr = f.ByteOrder().Uint64(data)
size = f.ByteOrder().Uint64(data[8:])
}
if size > 1000 {
return "", fmt.Errorf("implausible string size %d for runtime.buildVersion", size)
}
data, err = f.ReadData(addr, size)
if err != nil {
return "", fmt.Errorf("reading runtime.buildVersion string data: %v", err)
}
return string(data), nil
}
// Code signatures that indicate BoringCrypto or crypto/internal/fipsonly.
// These are not byte literals in order to avoid the actual
// byte signatures appearing in the goversion binary,
// because on some systems you can't tell rodata from text.
var (
sigBoringCrypto, _ = hex.DecodeString("EB1DF448F44BF4B332F52813A3B450D441CC2485F001454E92101B1D2F1950C3")
sigStandardCrypto, _ = hex.DecodeString("EB1DF448F44BF4BAEE4DFA9851CA56A91145E83E99C59CF911CB8E80DAF12FC3")
sigFIPSOnly, _ = hex.DecodeString("EB1DF448F44BF4363CB9CE9D68047D31F28D325D5CA5873F5D80CAF6D6151BC3")
)
func findCryptoSigs(v *Version, f exe) error {
const maxSigLen = 1 << 10
start, end := f.TextRange()
for addr := start; addr < end; {
size := uint64(1 << 20)
if end-addr < size {
size = end - addr
}
data, err := f.ReadData(addr, size)
if err != nil {
return fmt.Errorf("reading text: %v", err)
}
if haveSig(data, sigBoringCrypto) {
v.BoringCrypto = true
}
if haveSig(data, sigFIPSOnly) {
v.FIPSOnly = true
}
if haveSig(data, sigStandardCrypto) {
v.StandardCrypto = true
}
if addr+size < end {
size -= maxSigLen
}
addr += size
}
return nil
}
func haveSig(data, sig []byte) bool {
const align = 16
for {
i := bytes.Index(data, sig)
if i < 0 {
return false
}
if i&(align-1) == 0 {
return true
}
// Found unaligned match; unexpected but
// skip to next aligned boundary and keep searching.
data = data[(i+align-1)&^(align-1):]
}
}
func findModuleInfo(v *Version, f exe) error {
const maxModInfo = 128 << 10
start, end := f.RODataRange()
for addr := start; addr < end; {
size := uint64(4 << 20)
if end-addr < size {
size = end - addr
}
data, err := f.ReadData(addr, size)
if err != nil {
return fmt.Errorf("reading text: %v", err)
}
if haveModuleInfo(data, v) {
return nil
}
if addr+size < end {
size -= maxModInfo
}
addr += size
}
return nil
}
var (
infoStart, _ = hex.DecodeString("3077af0c9274080241e1c107e6d618e6")
infoEnd, _ = hex.DecodeString("f932433186182072008242104116d8f2")
)
func haveModuleInfo(data []byte, v *Version) bool {
i := bytes.Index(data, infoStart)
if i < 0 {
return false
}
j := bytes.Index(data[i:], infoEnd)
if j < 0 {
return false
}
v.ModuleInfo = string(data[i+len(infoStart) : i+j])
return true
}