Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix #93: Invalidate the plugin cache if the version hash mismatches #94

Merged
merged 1 commit into from
Dec 28, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 40 additions & 6 deletions src/Dotx64Managed/Plugins.Builder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ internal partial class Plugins
System.Threading.AutoResetEvent WorkerWakeup = new(false);
System.Threading.CancellationTokenSource BuildCancellation = new();

const UInt32 PluginCacheMagic = 0x58746F44; // DotX.
const UInt32 PluginCacheVersion = 0x00000002;

bool RebuildInProgress = false;
bool SkipRebuilding = false;

Expand Down Expand Up @@ -204,11 +207,13 @@ void CachePluginBuild(Plugin plugin, string cacheFilePath)
using System.IO.Compression.ZipArchive zipArchive = new(fs, System.IO.Compression.ZipArchiveMode.Create);
var entry = zipArchive.CreateEntry(nameof(Plugin));
using BinaryWriter bw = new(entry.Open());
bw.Write((uint)0x4D5A); // ZM magic number ;)
bw.Write(PluginCacheMagic);
bw.Write(PluginCacheVersion);
bw.Write(Utils.GetVersionHash());
bw.Write(ComputePluginSourcesHash(plugin)); // uint32 hash
bw.Write(plugin.AssemblyPath);
bw.Write(plugin.BuildOutputPath);
bw.Write((uint)0x4D5A);
bw.Write(PluginCacheMagic);
}

bool InitializePluginFromCache(Plugin plugin, string cacheFilePath)
Expand All @@ -222,20 +227,46 @@ bool InitializePluginFromCache(Plugin plugin, string cacheFilePath)

using BinaryReader br = new(entry.Open());

if (br.ReadUInt32() != 0x4D5A) // Check magic
if (br.ReadUInt32() != PluginCacheMagic)
{
Utils.DebugPrintLine($"Invalid cache for plugin '{plugin.Path}'");
return false;
}

var cacheVersion = br.ReadUInt32();
if (cacheVersion < PluginCacheVersion)
{
Utils.DebugPrintLine($"Cache version mismatch for plugin '{plugin.Path}': {cacheVersion} < {PluginCacheVersion}");
return false;
}

var versionHash = br.ReadUInt32();
if (versionHash != Utils.GetVersionHash())
{
Utils.DebugPrintLine($"Version hash mismatch for plugin '{plugin.Path}': {versionHash} != {Utils.GetVersionHash()}");
return false;
}

uint hash = br.ReadUInt32();
if (hash != ComputePluginSourcesHash(plugin)) // Modified source files
if (hash != ComputePluginSourcesHash(plugin))
{
Utils.DebugPrintLine($"Source hash mismatch for plugin '{plugin.Path}': {hash} != {ComputePluginSourcesHash(plugin)}");
return false;
}

string assemblyPath = br.ReadString();
if (!File.Exists(assemblyPath)) // Invalid cache
if (!File.Exists(assemblyPath))
{
Utils.DebugPrintLine($"Assembly '{assemblyPath}' does not exist for plugin '{plugin.Path}'");
return false;
}
string buildOutputPath = br.ReadString();

if (br.ReadUInt32() != 0x4D5A) // Check magic
if (br.ReadUInt32() != PluginCacheMagic)
{
Utils.DebugPrintLine($"Invalid cache for plugin '{plugin.Path}'");
return false;
}

plugin.AssemblyPath = assemblyPath;
plugin.BuildOutputPath = buildOutputPath;
Expand All @@ -245,7 +276,10 @@ bool InitializePluginFromCache(Plugin plugin, string cacheFilePath)
catch (Exception ex)
{
if (ex is FormatException || ex is EndOfStreamException || ex is InvalidDataException)
{
Utils.DebugPrintLine($"Failed to read cache for plugin '{plugin.Path}': {ex.Message}");
return false;
}
throw;
}
}
Expand Down
25 changes: 25 additions & 0 deletions src/Dotx64Managed/Utils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,31 @@ namespace Dotx64Dbg
{
public static class Utils
{
public static UInt32 VersionHash = 0x00000000;

public static UInt32 GetVersionHash()
{
if (VersionHash != 0)
return VersionHash;

// Get the hash of the executing assembly
var assembly = System.Reflection.Assembly.GetExecutingAssembly();
var assemblyPath = assembly.Location;
var fileData = File.ReadAllBytes(assemblyPath);

// Create a simple hash of all the bytes in the assembly.
UInt32 hash = UInt32.MaxValue;
foreach (var b in fileData)
{
// Rotate and xor.
hash = (hash << 1) | (hash >> 31);
hash ^= b;
}

VersionHash = hash;
return VersionHash;
}

public static string GetRootPath()
{
var process = System.Diagnostics.Process.GetCurrentProcess();
Expand Down