analysis

package
v0.0.0-...-f44e450 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 11, 2023 License: BSD-3-Clause Imports: 31 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	// AutoRegisterTypes automatically registers new types in the
	// type registry on an attempt to get TypeID of an unregistered
	// sample.
	AutoRegisterTypes = false
)

Functions

func IsRegisteredType

func IsRegisteredType(sample any) bool

IsRegisteredType returns true if the type of the provided sample is already registered (and could be used in analyzer input/output).

func RegisterType

func RegisterType(sample any)

RegisterType registers the type of the provided sample into the registry. It allows to deserialize JSONs into typed values.

The sample may also be given as a (nil) pointer.

func SetValueCalculator

func SetValueCalculator[inputType, outputType any, T calculator[inputType, outputType]](dc *DataCalculator, calc T) error

SetValueCalculator verifies and sets a function "calc" which can compute the values of parameters used as inputs for analyzers.

Note: There could be only one calculator for one output type. Setting a calculator for a type where a calculator is already set will overwrite the calculator.

TODO: The UNIQUE KEY for calculators should be not the outputType, but inputType+outputType. For example

BIOSInfo could be calculated from different input types and it should be allowed.

For example: firmware parsing, fixing register's values. Input argument should be a function of format func(ctx context.Context, in InputStruct) (Output1, Output2, ..., OutputN, []Issue, error)

func TypeRegistry

func TypeRegistry() xjson.TypeIDHandler

TypeRegistry returns the TypeIDHandler for xjson package.

Types

type ActualBIOSInfo

type ActualBIOSInfo struct {
	dmidecode.BIOSInfo
}

ActualBIOSInfo represents data stored in the SMBIOS of the actual image.

func NewActualBIOSInfo

func NewActualBIOSInfo(biosInfo dmidecode.BIOSInfo) *ActualBIOSInfo

NewActualBIOSInfo creates a new instance of ActualBIOSInfo

type ActualFirmware

type ActualFirmware struct {
	Blob // contributes into cache key
	// contains filtered or unexported fields
}

ActualFirmware represents parsed actual firmware (the one we dump)

func NewActualFirmware

func NewActualFirmware(fw *uefi.UEFI, blob Blob) ActualFirmware

NewActualFirmware creates a new ActualFirmware object from firmware.

`blob` is optional, if not provided, then fw.Buf() is used instead.

func (ActualFirmware) UEFI

func (of ActualFirmware) UEFI() *uefi.UEFI

UEFI returns an UEFI object of ActualFirmware

type ActualFirmwareBlob

type ActualFirmwareBlob struct {
	Blob
}

ActualFirmwareBlob represents raw bytes of the actual firmware image (the one obtained from the host)

func NewActualFirmwareBlob

func NewActualFirmwareBlob(image Blob) ActualFirmwareBlob

NewActualFirmwareBlob creates a new ActualFirmwareBlob object

type ActualPCR0

type ActualPCR0 []byte

ActualPCR0 represents an actual PCR0 value of the host

type ActualPSPFirmware

type ActualPSPFirmware struct {
	Blob Blob // contributes to the cache key
	// contains filtered or unexported fields
}

ActualPSPFirmware represents parsed original AMD PSP firmware (the one we get from the orig firmware table and expect to be installed on the host)

func NewActualPSPFirmware

func NewActualPSPFirmware(amdFW *amd_manifest.AMDFirmware, blob Blob) ActualPSPFirmware

NewActualPSPFirmware creates a new ActualPSPFirmware object from firmware.

`blob` is optional, if not provided, then amdFW.Firmware().ImageBytes() is used instead.

func (ActualPSPFirmware) AMDFirmware

func (af ActualPSPFirmware) AMDFirmware() *amd_manifest.AMDFirmware

AMDFirmware returns an AMDFirmware object

type ActualRegisters

type ActualRegisters struct {
	Regs registers.Registers
	// contains filtered or unexported fields
}

ActualRegisters represents the actual registers (the one obtained from the host)

func NewActualRegisters

func NewActualRegisters(regs registers.Registers) (ActualRegisters, error)

NewActualRegisters creates new ActualRegisters object

func (ActualRegisters) CacheWrite

func (ar ActualRegisters) CacheWrite(b *objhash.Builder) error

CacheWrite is an implementation of objhash.Custom interface

func (ActualRegisters) GetRegisters

func (ar ActualRegisters) GetRegisters() registers.Registers

GetRegisters returns registers

type AlignedOriginalFirmware

type AlignedOriginalFirmware struct {
	Blob        Blob
	ImageOffset uint64
	// contains filtered or unexported fields
}

AlignedOriginalFirmware represents a part of the original image which is aligned with the DumpedFirmware image.

Often the only region we can dump from the target is BIOS region, while the original image usually consists of multiple regions (and the BIOS region is the last one). So the aligned image is a such image that has an offset (to start with the same thing as the dumped firmware) and the same length as the dumped firmware.

func NewAlignedOriginalFirmware

func NewAlignedOriginalFirmware(fw *uefi.UEFI, offset uint64, blob Blob) AlignedOriginalFirmware

NewAlignedOriginalFirmware creates new AlignedOriginalImage object

`blob` is optional, if not provided, then fw.Buf() is used instead.

func (AlignedOriginalFirmware) UEFI

func (ao AlignedOriginalFirmware) UEFI() *uefi.UEFI

UEFI returns an UEFI object of AlignedOriginalImage

type Analyzer

type Analyzer[inputType any] interface {
	ID() AnalyzerID
	Analyze(context.Context, inputType) (*Report, error)
}

Analyzer is an abstract interface that each analyzer should implement

type AnalyzerID

type AnalyzerID string

AnalyzerID is a unique ID of every analyzer

TODO: consider replacing unique indexes with reflect.TypeOf(input) to have a single source of truth

type AssetID

type AssetID int64

AssetID represents information about the asset id of the host that is being analyzed

type Blob

type Blob interface {
	Bytes() []byte
}

Blob is an interface of a huge blob. Semantically in this package it is just `[]byte`. But:

  1. Sometimes the consumers of this package may have constraints against passing large blobs directly as input. For example if we want analysis be storable and reproducible, in some infras it will store only an object ID in the input instead of the whole blob (and object itself will be stored in an object storage, like GitHub LFS or BlobStorage).
  2. Another reason to pass objectIDs instead of images themselves is to make cache more efficient, because calculated hashes for large objects might be too expensive.

WARNING! The object, implementing this interface should export enough data to uniquely identify the specific image. Internally package `analysis` hashes all the input to calculate the cache key. So if two different images exports exactly the same fields, then there will be INVALID DATA provided by the cache.

type BytesBlob

type BytesBlob []byte

BytesBlob is a simple implementation of a Blob, based on a simple []byte.

func (BytesBlob) Bytes

func (s BytesBlob) Bytes() []byte

Bytes implements Blob.

type CachedValue

type CachedValue struct {
	// TODO: consider replacing "reflect.Value" with just "any"
	Val    reflect.Value
	Issues []Issue
	Err    error
}

CachedValue represents a value stored in DataCache

type DataCache

type DataCache interface {
	// Get returns a cached object if found. inputHash could be nil, for cases when cache guarantees object uniqness for each type.
	// On of that cases is `uniqueTypeDataCache` that is used to store objects obtained for a single Analyser
	Get(t reflect.Type, inputHash *objhash.ObjHash) *CachedValue
	Set(t reflect.Type, inputHash objhash.ObjHash, val *CachedValue)
}

DataCache represents an interface for a cache used in analysis package

func NewDataCache

func NewDataCache() DataCache

NewDataCache creates a new multithreaded implementation of DataCache

type DataCalculator

type DataCalculator struct {
	// contains filtered or unexported fields
}

DataCalculator is a handler which resolves missing values for the analyzers using the given values

func NewDataCalculator

func NewDataCalculator(cacheSize int) (*DataCalculator, error)

NewDataCalculator creates a new DataCalculator object

func (*DataCalculator) Calculate

func (dc *DataCalculator) Calculate(
	ctx context.Context,
	t reflect.Type,
	in Input,
	cache DataCache,
) (reflect.Value, []Issue, error)

Calculate calculates value of type 't' based on input 'in' argument

type DataCalculatorInterface

type DataCalculatorInterface interface {
	Calculate(ctx context.Context, t reflect.Type, in Input, cache DataCache) (reflect.Value, []Issue, error)
}

DataCalculatorInterface calculates intermediate results that could be reused, like: measurements flow, fixed registers

type ErrAnalyze

type ErrAnalyze struct {
	Err error
}

ErrAnalyze means got an error from calling Analyze().

func (ErrAnalyze) Error

func (e ErrAnalyze) Error() string

Error implements interface "error".

func (ErrAnalyze) Unwrap

func (e ErrAnalyze) Unwrap() error

Unwrap is used by errors.Is and errors.As.

type ErrCalcNotSupported

type ErrCalcNotSupported struct {
	// contains filtered or unexported fields
}

ErrCalcNotSupported determines a situation when input data calculator doesn't support the type

func (ErrCalcNotSupported) Error

func (e ErrCalcNotSupported) Error() string

type ErrFailedCalcInput

type ErrFailedCalcInput struct {
	Input string
	Err   error
}

ErrFailedCalcInput determines a situation when input value should be calculated and that calculation failed

func (ErrFailedCalcInput) Error

func (e ErrFailedCalcInput) Error() string

func (ErrFailedCalcInput) Unwrap

func (e ErrFailedCalcInput) Unwrap() error

type ErrMissingInput

type ErrMissingInput struct {
	// contains filtered or unexported fields
}

ErrMissingInput determines situation when input needed by analyzer is missing

func (ErrMissingInput) Error

func (e ErrMissingInput) Error() string

type ErrNotApplicable

type ErrNotApplicable struct {
	Description string
}

ErrNotApplicable should be returned by analyzer to tell that it is not applicable for given input

func NewErrNotApplicable

func NewErrNotApplicable(description string) ErrNotApplicable

NewErrNotApplicable creates a new ErrNotApplicable object

func (ErrNotApplicable) Error

func (e ErrNotApplicable) Error() string

type ErrResolveInput

type ErrResolveInput struct {
	Err error
}

ErrResolveInput means it was unable to resolve input, required by the analyzer.

func (ErrResolveInput) Error

func (e ErrResolveInput) Error() string

Error implements interface "error".

func (ErrResolveInput) Unwrap

func (e ErrResolveInput) Unwrap() error

Unwrap is used by errors.Is and errors.As.

type ErrResolveValue

type ErrResolveValue struct {
	FieldName string
	TypeName  string
	Err       error
}

ErrResolveValue means it was unable to resolve a value, required by the analyzer.

func (ErrResolveValue) Error

func (e ErrResolveValue) Error() string

Error implements interface "error".

func (ErrResolveValue) Unwrap

func (e ErrResolveValue) Unwrap() error

Unwrap is used by errors.Is and errors.As.

type ErrTypeIDNotRegistered

type ErrTypeIDNotRegistered struct {
	TypeID TypeID
}

ErrTypeIDNotRegistered means there was an attempt to serialize/deserialize a value of a type, not registered in the type register (see also function `RegisterType`).

func (ErrTypeIDNotRegistered) Error

func (e ErrTypeIDNotRegistered) Error() string

Error implements interface "error".

type FixedRegisters

type FixedRegisters struct {
	Regs registers.Registers
	// contains filtered or unexported fields
}

FixedRegisters represents registers that have been fixed in accordance with other information obtained from the host

func NewFixedRegisters

func NewFixedRegisters(regs registers.Registers) (FixedRegisters, error)

NewFixedRegisters creates new ActualRegisters object

func (FixedRegisters) CacheWrite

func (fr FixedRegisters) CacheWrite(b *objhash.Builder) error

CacheWrite is an implementation of objhash.Custom interface

func (FixedRegisters) GetRegisters

func (fr FixedRegisters) GetRegisters() registers.Registers

GetRegisters returns registers

type Input

type Input map[TypeID]any

Input specifies input data for analysis

func NewInput

func NewInput() Input

NewInput creates a new Inout object

func (Input) AddActualBIOSInfo

func (in Input) AddActualBIOSInfo(biosInfo ActualBIOSInfo) Input

AddActualBIOSInfo adds SMBIOS info about the actual BIOS firmware.

func (Input) AddActualFirmware

func (in Input) AddActualFirmware(image Blob) Input

AddActualFirmware adds the actual firmware image

func (Input) AddActualPCR0

func (in Input) AddActualPCR0(pcr []byte) Input

AddActualPCR0 adds information about existing PCR0 value on a host

func (Input) AddActualRegisters

func (in Input) AddActualRegisters(regs ActualRegisters) Input

AddActualRegisters adds the actual registers

func (Input) AddAssetID

func (in Input) AddAssetID(assetID int64) Input

AddAssetID adds information about asset id of a host

func (Input) AddCustomValue

func (in Input) AddCustomValue(v any) Input

AddCustomValue adds a custom value as some plugins take unique values

Note: register custom values through RegisterInputType, to make them

deserializable.

func (Input) AddOriginalBIOSInfo

func (in Input) AddOriginalBIOSInfo(biosInfo OriginalBIOSInfo) Input

AddOriginalBIOSInfo adds SMBIOS info about the original BIOS firmware.

func (Input) AddOriginalFirmware

func (in Input) AddOriginalFirmware(image Blob) Input

AddOriginalFirmware adds the original firmware image

func (Input) AddTPMDevice

func (in Input) AddTPMDevice(tpm tpmdetection.Type) Input

AddTPMDevice adds inormation about the TPM device

func (Input) AddTPMEventLog

func (in Input) AddTPMEventLog(eventLog *tpmeventlog.TPMEventLog) Input

AddTPMEventLog adds information about the TPM event log

func (Input) ForceBootFlow

func (in Input) ForceBootFlow(_flow bootflowtypes.Flow) Input

ForceBootFlow adds information about the bootflow

func (Input) GoString

func (in Input) GoString() string

GoString implements fmt.GoStringer

func (Input) MarshalJSON

func (in Input) MarshalJSON() ([]byte, error)

MarshalJSON implements json.Marshaler

func (*Input) Scan

func (in *Input) Scan(src any) error

Scan implements database/sql.Scanner TODO: remove this from this package. Package `analysis` should be agnostic of this stuff.

func (*Input) UnmarshalJSON

func (in *Input) UnmarshalJSON(b []byte) error

UnmarshalJSON implements json.Unmarshaler

func (Input) Value

func (in Input) Value() (driver.Value, error)

Value implements database/sql/driver.Valuer TODO: remove this from this package. Package `analysis` should be agnostic of this stuff.

type Issue

type Issue struct {
	// Custom is a custom information provided for issue description. Should be serialisable
	Custom any

	// Severity tells how important is found issue
	Severity Severity

	// Description is a text description of a found problem
	Description string
}

Issue describes a single found problem in firmware

type OriginalBIOSInfo

type OriginalBIOSInfo struct {
	dmidecode.BIOSInfo
}

OriginalBIOSInfo represents data stored in the SMBIOS of the original image.

func NewOriginalBIOSInfo

func NewOriginalBIOSInfo(biosInfo dmidecode.BIOSInfo) *OriginalBIOSInfo

NewOriginalBIOSInfo creates a new instance of OriginalBIOSInfo

type OriginalFirmware

type OriginalFirmware struct {
	Blob // contributes into cache key
	// contains filtered or unexported fields
}

OriginalFirmware represents parsed original firmware (the one we get from the orig firmware table and expect to be installed on the host)

func NewOriginalFirmware

func NewOriginalFirmware(fw *uefi.UEFI, blob Blob) OriginalFirmware

NewOriginalFirmware creates a new OriginalFirmware object from firmware.

`blob` is optional, if not provided, then fw.Buf() is used instead.

func (OriginalFirmware) UEFI

func (of OriginalFirmware) UEFI() *uefi.UEFI

UEFI returns an UEFI object of OriginalFirmware

type OriginalFirmwareBlob

type OriginalFirmwareBlob struct {
	Blob
}

OriginalFirmwareBlob represents raw bytes of the original firmware image

func NewOriginalFirmwareBlob

func NewOriginalFirmwareBlob(image Blob) OriginalFirmwareBlob

NewOriginalFirmwareBlob creates a new OriginalFirmwareBlob object

type ReferenceFirmware

type ReferenceFirmware struct {
	Blob        Blob
	ImageOffset uint64
	// contains filtered or unexported fields
}

ReferenceFirmware is a firmware used as the reference. It is the aligned original firmware if it is available, or just the actual firmware otherwise.

func NewReferenceFirmware

func NewReferenceFirmware(ctx context.Context, alignedOriginalFirmware *AlignedOriginalFirmware, actualFirmware *ActualFirmware) (*ReferenceFirmware, error)

NewReferenceFirmware creates new ReferenceFirmware object.

If alignedOriginalFirmware is nil then actualFirmware will be used as the reference firmware.

func (ReferenceFirmware) UEFI

func (rf ReferenceFirmware) UEFI() *uefi.UEFI

UEFI returns an UEFI object of AlignedOriginalImage

type Report

type Report struct {
	// Custom is a custom information provided for report description. Should be serialisable
	Custom any

	// Errors is the list of errors.
	Issues []Issue

	// Comments is the list of additional messages, which are not considered errors.
	Comments []string
}

Report is an outcome of every firmware analysis algorithm

TODO: consider using Go generics to specify the `Custom` field.

func ExecuteAnalyzer

func ExecuteAnalyzer[analyzerInputType any](
	ctx context.Context,
	dataCalculator DataCalculatorInterface,
	analyzer Analyzer[analyzerInputType],
	in Input,
	cache DataCache,
) (retReport *Report, retErr error)

ExecuteAnalyzer invokes analysis of a single given Analyzer

func (Report) MarshalJSON

func (r Report) MarshalJSON() ([]byte, error)

MarshalJSON implements json.Marshaler

func (*Report) Scan

func (r *Report) Scan(src any) error

Scan implements database/sql.Scanner TODO: remove this from this package. Package `analysis` should be agnostic of this stuff.

func (*Report) UnmarshalJSON

func (r *Report) UnmarshalJSON(b []byte) error

UnmarshalJSON implements json.Unmarshaler

func (*Report) Value

func (r *Report) Value() (driver.Value, error)

Value implements database/sql/driver.Valuer TODO: remove this from this package. Package `analysis` should be agnostic of this stuff.

type Severity

type Severity uint32

Severity represents severity of an issue

const (
	// SeverityInfo tells that the issue is not important
	SeverityInfo Severity = iota

	// SeverityWarning tells that the issue has a medium priority
	SeverityWarning

	// SeverityCritical tells that the issue has a high priority
	SeverityCritical
)

type TypeID

type TypeID = xjson.TypeID

TypeID as an unique string of a named type.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL