Add and use LoadTrustedLibrary function which protects the library from changes between the trust check and the load. Also fixes a typo and improves ISCmplr/isscint error messages on trust fail.

This commit is contained in:
Martijn Laan 2025-04-18 09:22:15 +02:00
parent aebff69e89
commit 84ccece758
No known key found for this signature in database
GPG Key ID: E2DD568CF6098F6A
7 changed files with 93 additions and 58 deletions

View File

@ -858,8 +858,8 @@ end;
procedure TScintEdit.CreateWnd;
begin
if IsscintLibary = 0 then
Error('CreateWnd: IsscintLibary is 0');
if IsscintLibrary = 0 then
Error('CreateWnd: IsscintLibrary is 0');
inherited;
FDirectPtr := Pointer(SendMessage(Handle, SCI_GETDIRECTPOINTER, 0, 0));
if FDirectPtr = nil then

View File

@ -1357,7 +1357,8 @@ const
IsscintDLL = 'isscint.dll';
var
IsscintLibary: HMODULE;
IsscintLibrary: HMODULE;
IsscintLibraryTrustFail: Boolean;
implementation
@ -1366,6 +1367,5 @@ uses
initialization
var FileName := AddBackslash(PathExtractPath(ParamStr(0))) + IsscintDLL;
if TrustedFileExists(FileName) then
IsscintLibary := LoadLibrary(PChar(FileName));
IsscintLibrary := LoadTrustedLibrary(PChar(FileName), IsscintLibraryTrustFail);
end.

View File

@ -13,17 +13,21 @@ unit TrustFunc;
interface
function TrustedFileExists(const FileName: String): Boolean;
function TrustedFileExists(const FileName: String; const CheckExists: Boolean = True): Boolean;
function LoadTrustedLibrary(const FileName: String; out TrustFail: Boolean; const TrustAllOnDebug: Boolean = False): HMODULE;
implementation
uses
Winapi.Windows, System.SysUtils {$IFNDEF TRUSTALL}, System.Classes, ECDSA, SHA256, ISSigFunc {$ENDIF};
function TrustedFileExists(const FileName: String): Boolean;
function TrustedFileExists(const FileName: String; const CheckExists: Boolean): Boolean;
begin
var Attr := GetFileAttributes(PChar(FileName));
Result := (Attr <> INVALID_FILE_ATTRIBUTES) and (Attr and faDirectory = 0);
if CheckExists then begin
var Attr := GetFileAttributes(PChar(FileName));
Result := (Attr <> INVALID_FILE_ATTRIBUTES) and (Attr and faDirectory = 0);
end else
Result := True;
{$IFNDEF TRUSTALL}
if Result then begin
try
@ -79,4 +83,32 @@ begin
{$ENDIF}
end;
function LoadTrustedLibrary(const FileName: String; out TrustFail: Boolean; const TrustAllOnDebug: Boolean): HMODULE;
begin
TrustFail := False;
{$IFDEF DEBUG}
if TrustAllOnDebug then begin
Result := SafeLoadLibrary(PChar(FileName), SEM_NOOPENFILEERRORBOX);
Exit;
end;
{$ENDIF}
try
{ 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);
try
if TrustedFileExists(FileName, False) then
Result := SafeLoadLibrary(PChar(FileName), SEM_NOOPENFILEERRORBOX)
else begin
TrustFail := True;
Result := 0;
end;
finally
F.Free;
end;
except
Result := 0;
end;
end;
end.

View File

@ -13,6 +13,7 @@ uses
SafeDLLPath in '..\Components\SafeDLLPath.pas',
Windows,
SysUtils,
StrUtils,
Forms,
PathFunc in '..\Components\PathFunc.pas',
TrustFunc in '..\Components\TrustFunc.pas',
@ -207,13 +208,15 @@ end;
begin
{$IFNDEF STATICCOMPILER}
if ISCmplrLibrary = 0 then begin
MessageBox(0, PChar(Format('Could not load %s.', [ISCmplrDLL])), nil, MB_OK or MB_ICONSTOP);
MessageBox(0, PChar(Format('Could not load %s%s.',
[ISCmplrDLL, IfThen(ISCmplrLibraryTrustFail, ' (not trusted)', '')])), nil, MB_OK or MB_ICONSTOP);
Halt(3);
end;
{$ENDIF}
if IsscintLibary = 0 then begin
MessageBox(0, PChar(Format('Could not load %s.' {$IFDEF DEBUG} + #13#10#13#10'Did you run Projects\Bin\synch-isfiles.bat as instructed in README.md?' {$ENDIF} , [IsscintDLL])), nil, MB_OK or MB_ICONSTOP);
if IsscintLibrary = 0 then begin
MessageBox(0, PChar(Format('Could not load %s%s.' {$IFDEF DEBUG} + #13#10#13#10'Did you run Projects\Bin\synch-isfiles.bat as instructed in README.md?' {$ENDIF} ,
[IsscintDLL, IfThen(IsscintLibraryTrustFail, ' (not trusted)', '')])), nil, MB_OK or MB_ICONSTOP);
Halt(4);
end;

View File

@ -20,6 +20,7 @@ uses
SafeDLLPath in '..\Components\SafeDLLPath.pas',
Windows,
SysUtils,
StrUtils,
Classes,
{$IFDEF STATICCOMPILER} Compiler.Compile, {$ENDIF}
PathFunc in '..\Components\PathFunc.pas',
@ -566,7 +567,7 @@ begin
{$IFNDEF STATICCOMPILER}
if ISCmplrLibrary = 0 then begin
WriteStdErr(Format('Could not load %s.', [ISCmplrDLL]), True);
WriteStdErr(Format('Could not load %s%s.', [ISCmplrDLL, IfThen(ISCmplrLibraryTrustFail, ' (not trusted)', '')]), True);
Halt(1);
end;
Ver := ISDllGetVersion;

View File

@ -512,15 +512,15 @@ begin
{$IFNDEF STATICPREPROC}
var Filename := CompilerDir + 'ISPP.dll';
if NewFileExists(Filename) then begin
if {$IFNDEF DEBUG} TrustedFileExists(Filename) {$ELSE} True {$ENDIF} then begin
var M := SafeLoadLibrary(Filename, SEM_NOOPENFILEERRORBOX);
if M = 0 then
AbortCompileFmt('Failed to load ISPP.dll (%d)', [GetLastError]);
PreprocessScriptProc := GetProcAddress(M, 'ISPreprocessScriptW');
if not Assigned(PreprocessScriptProc) then
AbortCompile('Failed to get address of functions in ISPP.dll');
end else
AbortCompile('Failed to load ISPP.dll (not trusted)');
var TrustFail: Boolean;
var M := LoadTrustedLibrary(Filename, TrustFail, True);
if TrustFail then
AbortCompile('Failed to load ISPP.dll (not trusted)')
else if M = 0 then
AbortCompileFmt('Failed to load ISPP.dll (%d)', [GetLastError]);
PreprocessScriptProc := GetProcAddress(M, 'ISPreprocessScriptW');
if not Assigned(PreprocessScriptProc) then
AbortCompile('Failed to get address of functions in ISPP.dll');
end; { else ISPP unavailable; fall back to built-in preprocessor }
{$ELSE}
PreprocessScriptProc := ISPreprocessScript;
@ -533,14 +533,14 @@ begin
if ZipInitialized then
Exit;
var Filename := CompilerDir + 'iszlib.dll';
if TrustedFileExists(Filename) then begin
var M := SafeLoadLibrary(Filename, SEM_NOOPENFILEERRORBOX);
if M = 0 then
AbortCompileFmt('Failed to load iszlib.dll (%d)', [GetLastError]);
if not ZlibInitCompressFunctions(M) then
AbortCompile('Failed to get address of functions in iszlib.dll');
end else
AbortCompile('Failed to load iszlib.dll (not trusted)');
var TrustFail: Boolean;
var M := LoadTrustedLibrary(Filename, TrustFail);
if TrustFail then
AbortCompile('Failed to load iszlib.dll (not trusted)')
else if M = 0 then
AbortCompileFmt('Failed to load iszlib.dll (%d)', [GetLastError]);
if not ZlibInitCompressFunctions(M) then
AbortCompile('Failed to get address of functions in iszlib.dll');
ZipInitialized := True;
end;
@ -549,14 +549,14 @@ begin
if BzipInitialized then
Exit;
var Filename := CompilerDir + 'isbzip.dll';
if TrustedFileExists(Filename) then begin
var M := SafeLoadLibrary(Filename, SEM_NOOPENFILEERRORBOX);
if M = 0 then
AbortCompileFmt('Failed to load isbzip.dll (%d)', [GetLastError]);
if not BZInitCompressFunctions(M) then
AbortCompile('Failed to get address of functions in isbzip.dll');
end else
AbortCompile('Failed to load isbzip.dll (not trusted)');
var TrustFail: Boolean;
var M := LoadTrustedLibrary(Filename, TrustFail);
if TrustFail then
AbortCompile('Failed to load isbzip.dll (not trusted)')
else if M = 0 then
AbortCompileFmt('Failed to load isbzip.dll (%d)', [GetLastError]);
if not BZInitCompressFunctions(M) then
AbortCompile('Failed to get address of functions in isbzip.dll');
BzipInitialized := True;
end;
@ -565,14 +565,14 @@ begin
if LZMAInitialized then
Exit;
var Filename := CompilerDir + 'islzma.dll';
if TrustedFileExists(Filename) then begin
var M := SafeLoadLibrary(Filename, SEM_NOOPENFILEERRORBOX);
if M = 0 then
AbortCompileFmt('Failed to load islzma.dll (%d)', [GetLastError]);
if not LZMAInitCompressFunctions(M) then
AbortCompile('Failed to get address of functions in islzma.dll');
end else
AbortCompile('Failed to load islzma.dll (not trusted)');
var TrustFail: Boolean;
var M := LoadTrustedLibrary(Filename, TrustFail);
if TrustFail then
AbortCompile('Failed to load islzma.dll (not trusted)')
else if M = 0 then
AbortCompileFmt('Failed to load islzma.dll (%d)', [GetLastError]);
if not LZMAInitCompressFunctions(M) then
AbortCompile('Failed to get address of functions in islzma.dll');
LZMAInitialized := True;
end;

View File

@ -19,6 +19,7 @@ const
var
ISCmplrLibrary: HMODULE;
ISCmplrLibraryTrustFail: Boolean;
{ The ISDllCompileScript function begins compilation of a script. See the above
description of the TCompileScriptParams record. Return value is one of the
@ -34,21 +35,19 @@ implementation
uses
Windows,
SysUtils,
PathFunc {$IFNDEF DEBUG}, TrustFunc{$ENDIF};
PathFunc, TrustFunc;
initialization
var FileName := AddBackslash(PathExtractPath(ParamStr(0))) + ISCmplrDLL;
if {$IFNDEF DEBUG} TrustedFileExists(FileName) {$ELSE} True {$ENDIF} then begin
ISCmplrLibrary := SafeLoadLibrary(PChar(FileName), SEM_NOOPENFILEERRORBOX);
if ISCmplrLibrary <> 0 then begin
ISDllCompileScript := GetProcAddress(ISCmplrLibrary, 'ISDllCompileScriptW');
ISDllGetVersion := GetProcAddress(ISCmplrLibrary, 'ISDllGetVersion');
if not Assigned(ISDllCompileScript) or not Assigned(ISDllGetVersion) then begin
FreeLibrary(ISCmplrLibrary);
ISCmplrLibrary := 0;
ISDllCompileScript := nil;
ISDllGetVersion := nil;
end;
ISCmplrLibrary := LoadTrustedLibrary(FileName, ISCmplrLibraryTrustFail, True);
if ISCmplrLibrary <> 0 then begin
ISDllCompileScript := GetProcAddress(ISCmplrLibrary, 'ISDllCompileScriptW');
ISDllGetVersion := GetProcAddress(ISCmplrLibrary, 'ISDllGetVersion');
if not Assigned(ISDllCompileScript) or not Assigned(ISDllGetVersion) then begin
FreeLibrary(ISCmplrLibrary);
ISCmplrLibrary := 0;
ISDllCompileScript := nil;
ISDllGetVersion := nil;
end;
end;
end.