浏览代码

Check trust of the decompression DLLs + TrustFunc cleanup. Todo: check E32's and possible islzma*.exe. Also todo: add directive to disable.

Martijn Laan 3 月之前
父节点
当前提交
74b6ef8c9d

+ 1 - 1
Components/ScintInt.pas

@@ -1369,7 +1369,7 @@ uses
 procedure InitIsscintLibrary;
 begin
   var FileName := AddBackslash(PathExtractPath(ParamStr(0))) + IsscintDLL;
-  IsscintLibrary := LoadTrustedLibrary(PChar(FileName));
+  IsscintLibrary := LoadTrustedLibrary(PChar(FileName), []);
 end;
 
 end.

+ 31 - 31
Components/TrustFunc.pas

@@ -20,26 +20,44 @@ interface
 uses
   System.Classes;
 
-function CheckFileTrust(const FileName: String; const CheckExists: Boolean = True; const KeepOpen: Boolean = False): TFileStream;
-function LoadTrustedLibrary(const FileName: String; const TrustAllOnDebug: Boolean = False): HMODULE;
+type
+  TCheckFileTrustOption = (cftoKeepOpen);
+  TCheckFileTrustOptions = set of TCheckFileTrustOption;
+  TLoadTrustedLibraryOption = (ltloTrustAllOnDebug);
+  TLoadTrustedLibraryOptions = set of TLoadTrustedLibraryOption;
+
+function CheckFileTrust(const FileName: String; const Options: TCheckFileTrustOptions): TFileStream;
+function LoadTrustedLibrary(const FileName: String; const Options: TLoadTrustedLibraryOptions): HMODULE;
 
 implementation
 
 uses
   Winapi.Windows, System.SysUtils {$IFNDEF TRUSTALL}, ECDSA, SHA256, ISSigFunc {$ENDIF};
 
-function CheckFileTrust(const FileName: String; const CheckExists, KeepOpen: Boolean): TFileStream;
+function Win32ErrorString(ErrorCode: Integer): String;
+{ Like SysErrorMessage but also passes the FORMAT_MESSAGE_IGNORE_INSERTS flag
+  which allows the function to succeed on errors like 129 }
+var
+  Len: Integer;
+  Buffer: array[0..1023] of Char;
+begin
+  Len := FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM or
+    FORMAT_MESSAGE_IGNORE_INSERTS or FORMAT_MESSAGE_ARGUMENT_ARRAY, nil,
+    ErrorCode, 0, Buffer, SizeOf(Buffer) div SizeOf(Buffer[0]), nil);
+  while (Len > 0) and ((Buffer[Len-1] <= ' ') or (Buffer[Len-1] = '.')) do
+    Dec(Len);
+  SetString(Result, Buffer, Len);
+end;
+
+function CheckFileTrust(const FileName: String; const Options: TCheckFileTrustOptions): TFileStream;
 {$IFNDEF TRUSTALL}
 var
   AllowedKeys: array of TECDSAKey;
 {$ENDIF}
 begin
-  if CheckExists then begin
-    var Attr := GetFileAttributes(PChar(FileName));
-    if (Attr = INVALID_FILE_ATTRIBUTES) or (Attr and faDirectory <> 0) then
-      raise Exception.CreateFmt('File "%s" does not exist.',
-        [FileName]);
-  end;
+  var Attr := GetFileAttributes(PChar(FileName));
+  if (Attr = INVALID_FILE_ATTRIBUTES) or (Attr and faDirectory <> 0) then
+    raise Exception.Create(Win32ErrorString(ERROR_FILE_NOT_FOUND));
 {$IFNDEF TRUSTALL}
   var ExpectedFileSize: Int64;
   var ExpectedFileHash: TSHA256Digest;
@@ -96,7 +114,7 @@ begin
     FreeAndNil(F);
     raise;
   end;
-  if not KeepOpen then
+  if not (cftoKeepOpen in Options) then
     FreeAndNil(F);
 
   Result := F;
@@ -105,21 +123,6 @@ begin
 {$ENDIF}
 end;
 
-function Win32ErrorString(ErrorCode: Integer): String;
-{ Like SysErrorMessage but also passes the FORMAT_MESSAGE_IGNORE_INSERTS flag
-  which allows the function to succeed on errors like 129 }
-var
-  Len: Integer;
-  Buffer: array[0..1023] of Char;
-begin
-  Len := FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM or
-    FORMAT_MESSAGE_IGNORE_INSERTS or FORMAT_MESSAGE_ARGUMENT_ARRAY, nil,
-    ErrorCode, 0, Buffer, SizeOf(Buffer) div SizeOf(Buffer[0]), nil);
-  while (Len > 0) and ((Buffer[Len-1] <= ' ') or (Buffer[Len-1] = '.')) do
-    Dec(Len);
-  SetString(Result, Buffer, Len);
-end;
-
 function DoLoadLibrary(const FileName: String): HMODULE;
 begin
   Result := SafeLoadLibrary(PChar(FileName), SEM_NOOPENFILEERRORBOX);
@@ -127,19 +130,16 @@ begin
     raise Exception.Create(Win32ErrorString(GetLastError));
 end;
 
-function LoadTrustedLibrary(const FileName: String; const TrustAllOnDebug: Boolean): HMODULE;
+function LoadTrustedLibrary(const FileName: String; const Options: TLoadTrustedLibraryOptions): HMODULE;
 begin
 {$IFDEF DEBUG}
-  if TrustAllOnDebug then begin
+  if ltloTrustAllOnDebug in Options then begin
     Result := DoLoadLibrary(FileName);
     Exit;
   end;
 {$ENDIF}
-  { First open a temporary regular handle to the library to protect it from changes
-    between the trust check and the load }
-  const F = TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite);
+  const F = CheckFileTrust(FileName, [cftoKeepOpen]);
   try
-    CheckFileTrust(FileName, False);
     Result := DoLoadLibrary(FileName);
   finally
     F.Free;

+ 2 - 2
Projects/Bin/synch-isfiles.bat

@@ -9,9 +9,9 @@ copy ..\..\Files\ISPPBuiltins.iss
 copy ..\..\Files\is7z*.dll
 copy ..\..\Files\is7z*.dll.issig
 copy ..\..\Files\is*zip.dll
-copy ..\..\Files\isbzip.dll.issig
+copy ..\..\Files\is*zip.dll.issig
 copy ..\..\Files\is*zlib.dll
-copy ..\..\Files\iszlib.dll.issig
+copy ..\..\Files\is*zlib.dll.issig
 copy ..\..\Files\isscint.dll
 copy ..\..\Files\isscint.dll.issig
 copy ..\..\Files\islzma.dll

+ 21 - 12
Projects/Src/Compiler.HelperFunc.pas

@@ -2,7 +2,7 @@ unit Compiler.HelperFunc;
 
 {
   Inno Setup
-  Copyright (C) 1997-2024 Jordan Russell
+  Copyright (C) 1997-2025 Jordan Russell
   Portions by Martijn Laan
   For conditions of distribution and use, see LICENSE.TXT.
 
@@ -68,7 +68,7 @@ const
 function IdentToColor(const Ident: string; var Color: Longint): Boolean;
 function StringToColor(const S: string): TColor;
 function IsRelativePath(const Filename: String): Boolean;
-function CreateMemoryStreamFromFile(const Filename: String): TMemoryStream;
+function CreateMemoryStreamFromFile(const Filename: String; const CheckTrust: Boolean = False): TMemoryStream;
 function FileSizeAndCRCIs(const Filename: String; const Size: Cardinal;
   const CRC: Longint): Boolean;
 function IsX86OrX64Executable(const F: TFile): Boolean;
@@ -82,7 +82,7 @@ procedure GenerateRandomBytes(var Buffer; Bytes: Cardinal);
 implementation
 
 uses
-  SysUtils, Shared.CommonFunc, Shared.Int64Em,
+  SysUtils, TrustFunc, Shared.CommonFunc, Shared.Int64Em,
   Compression.Base, Compiler.Messages;
 
 type
@@ -167,7 +167,7 @@ begin
     Result := False;
 end;
 
-function CreateMemoryStreamFromFile(const Filename: String): TMemoryStream;
+function CreateMemoryStreamFromFile(const Filename: String; const CheckTrust: Boolean): TMemoryStream;
 { Creates a TMemoryStream and loads the contents of the specified file into it }
 var
   F: TFile;
@@ -175,16 +175,25 @@ var
 begin
   Result := TMemoryStream.Create;
   try
-    { Why not use TMemoryStream.LoadFromFile here?
-      1. On Delphi 2 it opens files for exclusive access (not good).
-      2. It doesn't give specific error messages. }
-    F := TFile.Create(Filename, fdOpenExisting, faRead, fsRead);
+    var FS: TFileStream;
+    if CheckTrust then
+      FS := CheckFileTrust(Filename, [cftoKeepOpen])
+    else
+      FS := nil;
     try
-      SizeOfFile := F.CappedSize;
-      Result.SetSize(SizeOfFile);
-      F.ReadBuffer(Result.Memory^, SizeOfFile);
+      { Why not use TMemoryStream.LoadFromFile here?
+        1. On Delphi 2 it opens files for exclusive access (not good).
+        2. It doesn't give specific error messages. }
+      F := TFile.Create(Filename, fdOpenExisting, faRead, fsRead);
+      try
+        SizeOfFile := F.CappedSize;
+        Result.SetSize(SizeOfFile);
+        F.ReadBuffer(Result.Memory^, SizeOfFile);
+      finally
+        F.Free;
+      end;
     finally
-      F.Free;
+      FS.Free;
     end;
   except
     Result.Free;

+ 9 - 9
Projects/Src/Compiler.SetupCompiler.pas

@@ -539,10 +539,10 @@ begin
   end;
 end;
 
-function LoadCompilerDLL(const Filename: String; const TrustAllOnDebug: Boolean = False): HMODULE;
+function LoadCompilerDLL(const Filename: String; const Options: TLoadTrustedLibraryOptions): HMODULE;
 begin
   try
-    Result := LoadTrustedLibrary(FileName, TrustAllOnDebug);
+    Result := LoadTrustedLibrary(FileName, Options);
   except
     begin
       TSetupCompiler.AbortCompileFmt('Failed to load %s: %s', [PathExtractName(Filename), GetExceptMessage]);
@@ -558,7 +558,7 @@ begin
 {$IFNDEF STATICPREPROC}
   var Filename := CompilerDir + 'ISPP.dll';
   if NewFileExists(Filename) then begin
-    var M := LoadCompilerDLL(Filename, True);
+    var M := LoadCompilerDLL(Filename, [ltloTrustAllOnDebug]);
     PreprocessScriptProc := GetProcAddress(M, 'ISPreprocessScriptW');
     if not Assigned(PreprocessScriptProc) then
       AbortCompile('Failed to get address of functions in ISPP.dll');
@@ -574,7 +574,7 @@ begin
   if ZipInitialized then
     Exit;
   var Filename := CompilerDir + 'iszlib.dll';
-  var M := LoadCompilerDLL(Filename);
+  var M := LoadCompilerDLL(Filename, []);
   if not ZlibInitCompressFunctions(M) then
     AbortCompile('Failed to get address of functions in iszlib.dll');
   ZipInitialized := True;
@@ -585,7 +585,7 @@ begin
   if BzipInitialized then
     Exit;
   var Filename := CompilerDir + 'isbzip.dll';
-  var M := LoadCompilerDLL(Filename);
+  var M := LoadCompilerDLL(Filename, []);
   if not BZInitCompressFunctions(M) then
     AbortCompile('Failed to get address of functions in isbzip.dll');
   BzipInitialized := True;
@@ -596,7 +596,7 @@ begin
   if LZMAInitialized then
     Exit;
   var Filename := CompilerDir + 'islzma.dll';
-  var M := LoadCompilerDLL(Filename);
+  var M := LoadCompilerDLL(Filename, []);
   if not LZMAInitCompressFunctions(M) then
     AbortCompile('Failed to get address of functions in islzma.dll');
   LZMAInitialized := True;
@@ -8044,11 +8044,11 @@ begin
     case SetupHeader.CompressMethod of
       cmZip: begin
           AddStatus(Format(SCompilerStatusReadingFile, ['isunzlib.dll']));
-          DecompressorDLL := CreateMemoryStreamFromFile(CompilerDir + 'isunzlib.dll');
+          DecompressorDLL := CreateMemoryStreamFromFile(CompilerDir + 'isunzlib.dll', True);
         end;
       cmBzip: begin
           AddStatus(Format(SCompilerStatusReadingFile, ['isbunzip.dll']));
-          DecompressorDLL := CreateMemoryStreamFromFile(CompilerDir + 'isbunzip.dll');
+          DecompressorDLL := CreateMemoryStreamFromFile(CompilerDir + 'isbunzip.dll', True);
         end;
     end;
 
@@ -8056,7 +8056,7 @@ begin
       SetupHeader.SevenZipLibraryName isn't set until then }
     if SetupHeader.SevenZipLibraryName <> '' then begin
       AddStatus(Format(SCompilerStatusReadingFile, [SetupHeader.SevenZipLibraryName]));
-      SevenZipDLL := CreateMemoryStreamFromFile(CompilerDir + SetupHeader.SevenZipLibraryName);
+      SevenZipDLL := CreateMemoryStreamFromFile(CompilerDir + SetupHeader.SevenZipLibraryName, True);
     end;
 
     { Add default types if necessary }

+ 1 - 1
Projects/Src/Shared.CompilerInt.pas

@@ -41,7 +41,7 @@ uses
 procedure InitISCmplrLibrary;
 begin
   var FileName := AddBackslash(PathExtractPath(ParamStr(0))) + ISCmplrDLL;
-  ISCmplrLibrary := LoadTrustedLibrary(FileName, True);
+  ISCmplrLibrary := LoadTrustedLibrary(FileName, [ltloTrustAllOnDebug]);
   if ISCmplrLibrary <> 0 then begin
     ISDllCompileScript := GetProcAddress(ISCmplrLibrary, 'ISDllCompileScriptW');
     ISDllGetVersion := GetProcAddress(ISCmplrLibrary, 'ISDllGetVersion');

+ 5 - 0
setup.iss

@@ -140,14 +140,19 @@ Source: "files\WizClassicImage-IS.bmp"; DestDir: "{app}"; Flags: ignoreversion t
 Source: "files\WizClassicSmallImage.bmp"; DestDir: "{app}"; Flags: ignoreversion touch
 Source: "files\WizClassicSmallImage-IS.bmp"; DestDir: "{app}"; Flags: ignoreversion touch
 Source: "files\is7z.dll"; DestDir: "{app}"; Flags: ignoreversion issigverify signcheck touch
+Source: "files\is7z.dll.issig"; DestDir: "{app}"; Flags: ignoreversion issigverify signcheck touch
 Source: "files\is7zxa.dll"; DestDir: "{app}"; Flags: ignoreversion issigverify signcheck touch
+Source: "files\is7zxa.dll.issig"; DestDir: "{app}"; Flags: ignoreversion issigverify signcheck touch
 Source: "files\is7zxr.dll"; DestDir: "{app}"; Flags: ignoreversion issigverify signcheck touch
+Source: "files\is7zxr.dll.issig"; DestDir: "{app}"; Flags: ignoreversion issigverify signcheck touch
 Source: "files\iszlib.dll"; DestDir: "{app}"; Flags: ignoreversion issigverify signcheck touch
 Source: "files\iszlib.dll.issig"; DestDir: "{app}"; Flags: ignoreversion touch
 Source: "files\isunzlib.dll"; DestDir: "{app}"; Flags: ignoreversion issigverify signcheck touch
+Source: "files\isunzlib.dll.issig"; DestDir: "{app}"; Flags: ignoreversion issigverify signcheck touch
 Source: "files\isbzip.dll"; DestDir: "{app}"; Flags: ignoreversion issigverify signcheck touch
 Source: "files\isbzip.dll.issig"; DestDir: "{app}"; Flags: ignoreversion touch
 Source: "files\isbunzip.dll"; DestDir: "{app}"; Flags: ignoreversion issigverify signcheck touch
+Source: "files\isbunzip.dll.issig"; DestDir: "{app}"; Flags: ignoreversion issigverify signcheck touch
 Source: "files\islzma.dll"; DestDir: "{app}"; Flags: ignoreversion issigverify signcheck touch
 Source: "files\islzma.dll.issig"; DestDir: "{app}"; Flags: ignoreversion touch
 Source: "files\islzma32.exe"; DestDir: "{app}"; Flags: ignoreversion issigverify signcheck touch