Skip to content

Commit

Permalink
Add PathHasInvalidCharacters function
Browse files Browse the repository at this point in the history
  • Loading branch information
jordanrussell authored Nov 26, 2024
1 parent 880b9ee commit 0adec08
Showing 1 changed file with 65 additions and 0 deletions.
65 changes: 65 additions & 0 deletions Projects/Src/Setup.InstFunc.pas
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,8 @@ function IsProtectedSystemFile(const DisableFsRedir: Boolean;
const Filename: String): Boolean;
function MakePendingFileRenameOperationsChecksum: TSHA256Digest;
function ModifyPifFile(const Filename: String; const CloseOnExit: Boolean): Boolean;
function PathHasInvalidCharacters(const S: String;
const AllowDriveLetterColon: Boolean): Boolean;
procedure RaiseFunctionFailedError(const FunctionName: String);
procedure RaiseOleError(const FunctionName: String; const ResultCode: HRESULT);
procedure RefreshEnvironment;
Expand Down Expand Up @@ -1063,6 +1065,69 @@ function ForceDirectories(const DisableFsRedir: Boolean; Dir: String): Boolean;
CreateDirectoryRedir(DisableFsRedir, Dir);
end;

function PathHasInvalidCharacters(const S: String;
const AllowDriveLetterColon: Boolean): Boolean;
{ Checks the specified path for characters that are never allowed in paths,
or characters and path components that are accepted by the system but might
present a security problem (such as '..' and sometimes ':').
Specifically, True is returned if S includes any of the following:
- Control characters (0-31)
- One of these characters: /*?"<>|
(This means forward slashes and the prefixes '\\?\' and '\??\' are never
allowed.)
- Colons (':'), except when AllowDriveLetterColon=True and the string's
first character is a letter and the second character is the only colon.
(This blocks NTFS alternate data stream names.)
- A component with a trailing dot or space
Due to the last rule above, '.' and '..' components are never allowed, nor
are components like these:
'file '
'file.'
'file. . .'
'file . . '
When expanding paths (with no '\\?\' prefix used), Windows 11 23H2 silently
removes all trailing dots and spaces from the end of the string. Therefore,
if used at the end of a path, all of the above cases yield just 'file'.
On preceding components of the path, nothing is done with spaces; if there
is exactly one dot at the end, it is removed (e.g., 'dir.\file' becomes
'dir\file'), while multiple dots are left untouched ('dir..\file' doesn't
change).
By rejecting trailing dots and spaces up front, we avoid all that weirdness
and the problems that could arise from it.
Since ':' is considered invalid (except in the one case noted above), it's
not possible to sneak in disallowed dots/spaces by including an NTFS
alternate data stream name. The function will return True in these cases:
'..:streamname'
'file :streamname'
}
begin
Result := True;
for var I := Low(S) to High(S) do begin
var C := S[I];
if Ord(C) < 32 then
Exit;
case C of
#32, '.':
begin
if (I = High(S)) or PathCharIsSlash(S[I+1]) then
Exit;
end;
':':
begin
{ The A-Z check ensures that '.:streamname', ' :streamname', and
'\:streamname' are disallowed. }
if not AllowDriveLetterColon or (I <> Low(S)+1) or
not CharInSet(S[Low(S)], ['A'..'Z', 'a'..'z']) then
Exit;
end;
'/', '*', '?', '"', '<', '>', '|': Exit;
end;
end;
Result := False;
end;

{ TSimpleStringList }

procedure TSimpleStringList.Add(const S: String);
Expand Down

0 comments on commit 0adec08

Please sign in to comment.