On 2024-11-12 Lasse Collin wrote:
> On 2024-11-12 Pali Rohár wrote:
> > At least every character which is by best-fit mapped to double quote
> > has to be replaced.  
> 
> Yes, that seems mandatory.

This alone might not be enough because a double quote can be escaped
with a backslash. Thus unexpected backslashes would need to be
sanitized too. It's simpler to convert with WC_NO_BEST_FIT_CHARS.

I attached a version of _acmdln sanitization for discussion and
testing. I'm not suggesting to include this in MinGW-w64 for now. Let's
see first what Microsoft does.

The patch does nothing with UTF-8 code page because U+FFFD seems the
least bad replacement character for unpaired surrogates. With other code
pages, underscore is used as the replacement character. A question mark
is perhaps clearer for humans but if _dowildcard is enabled and the
sanitized string contained a filename, those question marks would
expand back to the problematic name.

A problem with underscore is that it's a valid char in filenames. If
_dowildcard is disabled and the app itself doesn't expand wildcards
either, then a question mark is better because it's invalid in
filenames. That is, a wrong file wouldn't be accidentally accessed. I
don't know what is the least bad choice.

If best-fit mapping from wildcard expansion was ignored, something like
this patch might perhaps be an OK compromise as the default behavior
(not completely safe but safer than the old behavior). Otherwise also
the wargv-to-argv code is needed. Even then, other best-fit issues can
exist in apps like FindFirstFileA().

On 2024-11-12 LIU Hao wrote:
> The security issue is actually about file names (path injection).

Filenames are a common case but it can also be a problem if an app needs
to escape special characters in an untrusted non-filename string before
using it as a command line argument to another program. Best-fit
mapping can introduce new characters that should have been escaped.

-- 
Lasse Collin
diff --git a/mingw-w64-crt/crt/crtexe.c b/mingw-w64-crt/crt/crtexe.c
index cdf5dcd25..45c264e0b 100644
--- a/mingw-w64-crt/crt/crtexe.c
+++ b/mingw-w64-crt/crt/crtexe.c
@@ -130,6 +130,29 @@ pre_cpp_init (void)
 #ifdef _UNICODE
   argret = __wgetmainargs(&argc,&argv,&envp,_dowildcard,&startinfo);
 #else
+  if (GetACP() != CP_UTF8 && _wcmdln != NULL) {
+    const char replacement_mbchar[] = "_";
+    BOOL conv_was_lossy = TRUE;
+    int acmdln_size = WideCharToMultiByte(
+        CP_ACP, WC_NO_BEST_FIT_CHARS,
+        _wcmdln, -1,
+        NULL, 0,
+        replacement_mbchar, &conv_was_lossy);
+
+    // If the above WideCharToMultiByte() failed, _acmdln isn't changed.
+    if (acmdln_size > 0 && conv_was_lossy) {
+      _acmdln = malloc(acmdln_size);
+      if (_acmdln == NULL)
+        _amsg_exit(8); // R6008 "not enough space for arguments" with MSVCRT
+
+      WideCharToMultiByte(
+          CP_ACP, WC_NO_BEST_FIT_CHARS,
+          _wcmdln, -1,
+          _acmdln, acmdln_size,
+          replacement_mbchar, NULL);
+    }
+  }
+
   argret = __getmainargs(&argc,&argv,&envp,_dowildcard,&startinfo);
 #endif
 }
_______________________________________________
Mingw-w64-public mailing list
Mingw-w64-public@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/mingw-w64-public

Reply via email to