Browse Source

* WASI: avoid using inner preopened dirs, that escape to the parent with '..',
in case there's an outer preopened dir

Nikolay Nikolov 5 months ago
parent
commit
6286ff38cc
1 changed files with 61 additions and 0 deletions
  1. 61 0
      rtl/wasi/system.pp

+ 61 - 0
rtl/wasi/system.pp

@@ -217,6 +217,65 @@ begin
   __wasi_proc_exit(ExitCode);
 End;
 
+function StripLeadingDirSep(const path: RawByteString): RawByteString;
+var
+  chridx: longint;
+begin
+  if path='' then
+  begin
+    Result:='';
+    exit;
+  end;
+
+  chridx:=1;
+  while (chridx<=Length(path)) and (path[chridx] in AllowDirectorySeparators) do
+    Inc(chridx);
+  Result:=Copy(path,chridx);
+end;
+
+function EscapesToParent(const relpath: RawByteString): Boolean;
+var
+  balance: longint;
+  item: RawByteString;
+
+  procedure FinishItem;
+  begin
+    case item of
+      '', '.':
+        {nothing};
+      '..':
+        Dec(balance);
+      else
+        Inc(balance);
+    end;
+  end;
+
+var
+  i: longint;
+begin
+  balance:=0;
+  item:='';
+  i:=1;
+  while i<=Length(relpath) do
+  begin
+    if relpath[i] in AllowDirectorySeparators then
+    begin
+      FinishItem;
+      if balance<0 then
+      begin
+        Result:=True;
+        exit;
+      end;
+      item:='';
+    end
+    else
+      item:=item+relpath[i];
+    Inc(i);
+  end;
+  FinishItem;
+  Result:=balance<0;
+end;
+
 function Do_ConvertToFdRelativePath(path: RawByteString; out fd: LongInt; out relfd_path: RawByteString): Word;
 var
   drive_nr,I,pdir_drive,longest_match,chridx: longint;
@@ -266,6 +325,8 @@ begin
     if ((Length(pdir)<>1) or ((Length(pdir)=1) and not (pdir[1] in AllowDirectorySeparators))) and
        ((chridx>Length(path)) or not (path[chridx] in AllowDirectorySeparators)) then
       continue;
+    if EscapesToParent(StripLeadingDirSep(Copy(path,chridx))) then
+      continue;
     if Length(pdir)>longest_match then
     begin
       longest_match:=Length(pdir);