138 lines
4.0 KiB
C#
138 lines
4.0 KiB
C#
// SPDX-License-Identifier: BUSL-1.1
|
|
// Copyright (c) StellaOps
|
|
|
|
using System.Collections.Immutable;
|
|
using StellaOps.Scanner.Reachability.Stack;
|
|
|
|
namespace StellaOps.Scanner.Reachability.Layer1;
|
|
|
|
/// <summary>
|
|
/// Layer 1 analyzer: Static call graph reachability.
|
|
/// Determines if vulnerable symbols are reachable from application entrypoints
|
|
/// via static code analysis.
|
|
/// </summary>
|
|
public interface ILayer1Analyzer
|
|
{
|
|
/// <summary>
|
|
/// Analyzes static reachability of a vulnerable symbol.
|
|
/// </summary>
|
|
/// <param name="symbol">The vulnerable symbol to check</param>
|
|
/// <param name="graph">The call graph to analyze</param>
|
|
/// <param name="entrypoints">Known application entrypoints</param>
|
|
/// <param name="ct">Cancellation token</param>
|
|
/// <returns>Layer 1 reachability analysis result</returns>
|
|
Task<ReachabilityLayer1> AnalyzeAsync(
|
|
VulnerableSymbol symbol,
|
|
CallGraph graph,
|
|
ImmutableArray<Entrypoint> entrypoints,
|
|
CancellationToken ct = default);
|
|
}
|
|
|
|
/// <summary>
|
|
/// A call graph representing method/function calls in the application.
|
|
/// </summary>
|
|
public sealed record CallGraph
|
|
{
|
|
/// <summary>Unique identifier for this call graph</summary>
|
|
public required string Id { get; init; }
|
|
|
|
/// <summary>When this call graph was generated</summary>
|
|
public required DateTimeOffset GeneratedAt { get; init; }
|
|
|
|
/// <summary>All nodes in the graph</summary>
|
|
public ImmutableArray<CallGraphNode> Nodes { get; init; } = [];
|
|
|
|
/// <summary>All edges (calls) in the graph</summary>
|
|
public ImmutableArray<CallGraphEdge> Edges { get; init; } = [];
|
|
|
|
/// <summary>Source of this call graph</summary>
|
|
public required CallGraphSource Source { get; init; }
|
|
|
|
/// <summary>Language/platform this graph represents</summary>
|
|
public required string Language { get; init; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// A node in the call graph (method/function).
|
|
/// </summary>
|
|
public sealed record CallGraphNode(
|
|
string Id,
|
|
string Name,
|
|
string? ClassName,
|
|
string? Namespace,
|
|
string? FileName,
|
|
int? LineNumber,
|
|
bool IsEntrypoint,
|
|
bool IsExternal
|
|
);
|
|
|
|
/// <summary>
|
|
/// An edge in the call graph (call from one method to another).
|
|
/// </summary>
|
|
public sealed record CallGraphEdge(
|
|
string FromNodeId,
|
|
string ToNodeId,
|
|
CallSiteType CallType,
|
|
int? LineNumber,
|
|
bool IsConditional
|
|
);
|
|
|
|
/// <summary>
|
|
/// Source of a call graph.
|
|
/// </summary>
|
|
public enum CallGraphSource
|
|
{
|
|
/// <summary>Roslyn/ILSpy analysis for .NET</summary>
|
|
DotNetAnalysis,
|
|
|
|
/// <summary>TypeScript/JavaScript AST analysis</summary>
|
|
NodeAnalysis,
|
|
|
|
/// <summary>javap/ASM analysis for Java</summary>
|
|
JavaAnalysis,
|
|
|
|
/// <summary>go/analysis for Go</summary>
|
|
GoAnalysis,
|
|
|
|
/// <summary>Python AST analysis</summary>
|
|
PythonAnalysis,
|
|
|
|
/// <summary>Binary disassembly</summary>
|
|
BinaryAnalysis,
|
|
|
|
/// <summary>Combined from multiple sources</summary>
|
|
Composite
|
|
}
|
|
|
|
/// <summary>
|
|
/// Input for Layer 1 analysis.
|
|
/// </summary>
|
|
public sealed record Layer1AnalysisInput
|
|
{
|
|
public required VulnerableSymbol Symbol { get; init; }
|
|
public required CallGraph Graph { get; init; }
|
|
public ImmutableArray<Entrypoint> Entrypoints { get; init; } = [];
|
|
public Layer1AnalysisOptions? Options { get; init; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Options for Layer 1 analysis.
|
|
/// </summary>
|
|
public sealed record Layer1AnalysisOptions
|
|
{
|
|
/// <summary>Maximum call path depth to explore</summary>
|
|
public int MaxPathDepth { get; init; } = 100;
|
|
|
|
/// <summary>Maximum number of paths to return</summary>
|
|
public int MaxPaths { get; init; } = 10;
|
|
|
|
/// <summary>Include paths through external libraries</summary>
|
|
public bool IncludeExternalPaths { get; init; } = true;
|
|
|
|
/// <summary>Consider reflection calls as potential paths</summary>
|
|
public bool ConsiderReflection { get; init; } = true;
|
|
|
|
/// <summary>Consider dynamic dispatch as potential paths</summary>
|
|
public bool ConsiderDynamicDispatch { get; init; } = true;
|
|
}
|