Files
git.stella-ops.org/src/BinaryIndex/__Libraries/StellaOps.BinaryIndex.DeltaSig/Models.cs
2026-02-01 21:37:40 +02:00

464 lines
12 KiB
C#

// Copyright (c) StellaOps. All rights reserved.
// Licensed under BUSL-1.1. See LICENSE in the project root.
using StellaOps.BinaryIndex.Disassembly;
using System.Collections.Immutable;
namespace StellaOps.BinaryIndex.DeltaSig;
/// <summary>
/// Signature generation options.
/// </summary>
/// <param name="IncludeCfg">Include control flow graph metrics.</param>
/// <param name="IncludeChunks">Include rolling chunk hashes for resilience.</param>
/// <param name="ChunkSize">Size of rolling chunks in bytes (default 2KB).</param>
/// <param name="HashAlgorithm">Hash algorithm to use (default sha256).</param>
/// <param name="IncludeSemantic">Include IR-level semantic fingerprints for optimization-resilient matching.</param>
public sealed record SignatureOptions(
bool IncludeCfg = true,
bool IncludeChunks = true,
int ChunkSize = 2048,
string HashAlgorithm = "sha256",
bool IncludeSemantic = false);
/// <summary>
/// Request for generating delta signatures from a binary.
/// </summary>
public sealed record DeltaSignatureRequest
{
/// <summary>
/// CVE identifier (e.g., CVE-2024-1234).
/// </summary>
public required string Cve { get; init; }
/// <summary>
/// Package name.
/// </summary>
public required string Package { get; init; }
/// <summary>
/// Shared object name (e.g., libssl.so.1.1).
/// </summary>
public string? Soname { get; init; }
/// <summary>
/// Target architecture (e.g., x86_64, aarch64).
/// </summary>
public required string Arch { get; init; }
/// <summary>
/// ABI (e.g., gnu, musl, android).
/// </summary>
public string Abi { get; init; } = "gnu";
/// <summary>
/// Symbol names to generate signatures for.
/// </summary>
public required IReadOnlyList<string> TargetSymbols { get; init; }
/// <summary>
/// State of this signature: "vulnerable" or "patched".
/// </summary>
public required string SignatureState { get; init; }
/// <summary>
/// Signature generation options.
/// </summary>
public SignatureOptions? Options { get; init; }
}
/// <summary>
/// A complete delta signature for a binary.
/// </summary>
public sealed record DeltaSignature
{
/// <summary>
/// Unique identifier for this signature.
/// </summary>
public string SignatureId { get; init; } = Guid.NewGuid().ToString("N");
/// <summary>
/// Schema identifier for this signature format.
/// </summary>
public string Schema { get; init; } = "stellaops.deltasig.v1";
/// <summary>
/// Schema version.
/// </summary>
public string SchemaVersion { get; init; } = "1.0.0";
/// <summary>
/// CVE this signature is for.
/// </summary>
public required string Cve { get; init; }
/// <summary>
/// Package reference.
/// </summary>
public required PackageRef Package { get; init; }
/// <summary>
/// Target platform reference.
/// </summary>
public required TargetRef Target { get; init; }
/// <summary>
/// Normalization recipe used.
/// </summary>
public required NormalizationRef Normalization { get; init; }
/// <summary>
/// Signature state: "vulnerable" or "patched".
/// </summary>
public required string SignatureState { get; init; }
/// <summary>
/// Individual symbol signatures.
/// </summary>
public required ImmutableArray<SymbolSignature> Symbols { get; init; }
/// <summary>
/// When this signature was generated (UTC).
/// </summary>
public DateTimeOffset GeneratedAt { get; init; } = DateTimeOffset.UtcNow;
/// <summary>
/// Additional metadata.
/// </summary>
public IReadOnlyDictionary<string, object>? Metadata { get; init; }
}
/// <summary>
/// Package reference for a delta signature.
/// </summary>
/// <param name="Name">Package name.</param>
/// <param name="Soname">Shared object name.</param>
public sealed record PackageRef(string Name, string? Soname);
/// <summary>
/// Target platform reference.
/// </summary>
/// <param name="Arch">CPU architecture (x86_64, aarch64, etc.).</param>
/// <param name="Abi">ABI (gnu, musl, android, etc.).</param>
public sealed record TargetRef(string Arch, string Abi);
/// <summary>
/// Normalization recipe reference for reproducibility.
/// </summary>
/// <param name="RecipeId">Recipe identifier (e.g., elf.delta.norm.x64).</param>
/// <param name="RecipeVersion">Recipe version.</param>
/// <param name="Steps">List of normalization steps applied.</param>
public sealed record NormalizationRef(
string RecipeId,
string RecipeVersion,
ImmutableArray<string> Steps);
/// <summary>
/// Signature for a single symbol (function).
/// </summary>
public sealed record SymbolSignature
{
/// <summary>
/// Symbol name.
/// </summary>
public required string Name { get; init; }
/// <summary>
/// Section containing the symbol (e.g., .text).
/// </summary>
public string Scope { get; init; } = ".text";
/// <summary>
/// Hash algorithm used.
/// </summary>
public required string HashAlg { get; init; }
/// <summary>
/// Hash of the normalized function as hex string.
/// </summary>
public required string HashHex { get; init; }
/// <summary>
/// Size of the normalized function in bytes.
/// </summary>
public required int SizeBytes { get; init; }
/// <summary>
/// Number of basic blocks in the control flow graph.
/// </summary>
public int? CfgBbCount { get; init; }
/// <summary>
/// Hash of the CFG structure (edges).
/// </summary>
public string? CfgEdgeHash { get; init; }
/// <summary>
/// Rolling chunk hashes for resilience against small changes.
/// </summary>
public ImmutableArray<ChunkHash>? Chunks { get; init; }
/// <summary>
/// Semantic fingerprint hash based on IR-level analysis (hex string).
/// Provides resilience against compiler optimizations and instruction reordering.
/// </summary>
public string? SemanticHashHex { get; init; }
/// <summary>
/// API calls extracted from semantic analysis (for semantic anchoring).
/// </summary>
public ImmutableArray<string>? SemanticApiCalls { get; init; }
}
/// <summary>
/// Hash of a chunk within a function for resilience.
/// </summary>
/// <param name="Offset">Offset from function start.</param>
/// <param name="Size">Chunk size in bytes.</param>
/// <param name="HashHex">Hash of the chunk as hex string.</param>
public sealed record ChunkHash(int Offset, int Size, string HashHex);
/// <summary>
/// Result of matching a binary against delta signatures.
/// </summary>
public sealed record MatchResult
{
/// <summary>
/// Whether a match was found.
/// </summary>
public required bool Matched { get; init; }
/// <summary>
/// The CVE that matched.
/// </summary>
public string? Cve { get; init; }
/// <summary>
/// The signature state that matched (vulnerable/patched).
/// </summary>
public string? SignatureState { get; init; }
/// <summary>
/// Confidence score (0.0 - 1.0).
/// </summary>
public double Confidence { get; init; }
/// <summary>
/// Individual symbol match results.
/// </summary>
public ImmutableArray<SymbolMatchResult> SymbolMatches { get; init; } = [];
/// <summary>
/// Explanation of the match result.
/// </summary>
public string? Explanation { get; init; }
}
/// <summary>
/// Match result for a single symbol.
/// </summary>
public sealed record SymbolMatchResult
{
/// <summary>
/// Symbol name.
/// </summary>
public required string SymbolName { get; init; }
/// <summary>
/// Whether the symbol hash matched exactly.
/// </summary>
public required bool ExactMatch { get; init; }
/// <summary>
/// Number of chunk hashes that matched (partial match).
/// </summary>
public int ChunksMatched { get; init; }
/// <summary>
/// Total chunks in the signature.
/// </summary>
public int ChunksTotal { get; init; }
/// <summary>
/// Match confidence (0.0 - 1.0).
/// </summary>
public double Confidence { get; init; }
// ====== CHANGE TRACKING FIELDS ======
/// <summary>
/// Type of change detected.
/// </summary>
public SymbolChangeType ChangeType { get; init; } = SymbolChangeType.Unchanged;
/// <summary>
/// Size delta in bytes (positive = larger, negative = smaller).
/// </summary>
public int SizeDelta { get; init; }
/// <summary>
/// CFG basic block count delta (if available).
/// </summary>
public int? CfgBlockDelta { get; init; }
/// <summary>
/// Indices of chunks that matched (for partial match analysis).
/// </summary>
public ImmutableArray<int> MatchedChunkIndices { get; init; } = [];
/// <summary>
/// Human-readable explanation of the change.
/// </summary>
public string? ChangeExplanation { get; init; }
/// <summary>
/// Hash of the "from" version (before change).
/// </summary>
public string? FromHash { get; init; }
/// <summary>
/// Hash of the "to" version (after change).
/// </summary>
public string? ToHash { get; init; }
/// <summary>
/// Method used for matching (CFGHash, InstructionHash, SemanticHash, ChunkHash).
/// </summary>
public string? MatchMethod { get; init; }
}
/// <summary>
/// Type of symbol change detected.
/// </summary>
public enum SymbolChangeType
{
/// <summary>
/// No change detected.
/// </summary>
Unchanged,
/// <summary>
/// Symbol was added (not present in "from" version).
/// </summary>
Added,
/// <summary>
/// Symbol was removed (not present in "to" version).
/// </summary>
Removed,
/// <summary>
/// Symbol was modified (hash changed).
/// </summary>
Modified,
/// <summary>
/// Symbol was patched (security fix applied, verified).
/// </summary>
Patched
}
/// <summary>
/// Result of authoring signatures from vulnerable and patched binaries.
/// </summary>
public sealed record AuthoringResult
{
/// <summary>
/// Whether authoring succeeded.
/// </summary>
public required bool Success { get; init; }
/// <summary>
/// Signature for the vulnerable binary.
/// </summary>
public DeltaSignature? VulnerableSignature { get; init; }
/// <summary>
/// Signature for the patched binary.
/// </summary>
public DeltaSignature? PatchedSignature { get; init; }
/// <summary>
/// Symbols that differ between vulnerable and patched.
/// </summary>
public ImmutableArray<string> DifferingSymbols { get; init; } = [];
/// <summary>
/// Error message if authoring failed.
/// </summary>
public string? Error { get; init; }
}
/// <summary>
/// Result of comparing two delta signatures.
/// </summary>
public sealed record DeltaComparisonResult
{
/// <summary>
/// Identifier for the "from" signature.
/// </summary>
public required string FromSignatureId { get; init; }
/// <summary>
/// Identifier for the "to" signature.
/// </summary>
public required string ToSignatureId { get; init; }
/// <summary>
/// Individual symbol comparison results.
/// </summary>
public ImmutableArray<SymbolMatchResult> SymbolResults { get; init; } = [];
/// <summary>
/// Summary of the comparison.
/// </summary>
public required DeltaComparisonSummary Summary { get; init; }
}
/// <summary>
/// Summary of a delta comparison between two signatures.
/// </summary>
public sealed record DeltaComparisonSummary
{
/// <summary>
/// Total number of symbols compared.
/// </summary>
public int TotalSymbols { get; init; }
/// <summary>
/// Number of unchanged symbols.
/// </summary>
public int UnchangedSymbols { get; init; }
/// <summary>
/// Number of added symbols.
/// </summary>
public int AddedSymbols { get; init; }
/// <summary>
/// Number of removed symbols.
/// </summary>
public int RemovedSymbols { get; init; }
/// <summary>
/// Number of modified symbols.
/// </summary>
public int ModifiedSymbols { get; init; }
/// <summary>
/// Number of patched symbols (security fixes).
/// </summary>
public int PatchedSymbols { get; init; }
/// <summary>
/// Average confidence across all symbol comparisons.
/// </summary>
public double AverageConfidence { get; init; }
/// <summary>
/// Total size delta in bytes.
/// </summary>
public int TotalSizeDelta { get; init; }
}