From e9bfa5bf6a350d348db17571e029b4680140aba1 Mon Sep 17 00:00:00 2001
From: Anonymous Maarten <[EMAIL REDACTED]>
Date: Mon, 16 Sep 2024 16:51:38 +0200
Subject: [PATCH] Mitigate BatBadBut vulnerability
---
src/process/windows/SDL_windowsprocess.c | 46 +++++++++++++++++++++++-
1 file changed, 45 insertions(+), 1 deletion(-)
diff --git a/src/process/windows/SDL_windowsprocess.c b/src/process/windows/SDL_windowsprocess.c
index 6c816d0fdc9aa..989711a3152c1 100644
--- a/src/process/windows/SDL_windowsprocess.c
+++ b/src/process/windows/SDL_windowsprocess.c
@@ -76,12 +76,24 @@ static bool SetupRedirect(SDL_PropertiesID props, const char *property, HANDLE *
return true;
}
+static bool is_batch_file_path(const char *path) {
+ size_t len_path = SDL_strlen(path);
+ if (len_path < 4) {
+ return false;
+ }
+ if (SDL_strcasecmp(path + len_path - 4, ".bat") == 0 || SDL_strcasecmp(path + len_path - 4, ".cmd") == 0) {
+ return true;
+ }
+ return false;
+}
+
static bool join_arguments(const char * const *args, LPWSTR *args_out)
{
size_t len;
int i;
int i_out;
char *result;
+ bool batch_file = is_batch_file_path(args[0]);
len = 0;
for (i = 0; args[i]; i++) {
@@ -99,6 +111,18 @@ static bool join_arguments(const char * const *args, LPWSTR *args_out)
/* only escape backslashes that precede a double quote */
len += (a[1] == '"' || a[1] == '\0') ? 2 : 1;
break;
+ case ' ':
+ case '^':
+ case '&':
+ case '|':
+ case '<':
+ case '>':
+ if (batch_file) {
+ len += 2;
+ } else {
+ len += 1;
+ }
+ break;
default:
len += 1;
break;
@@ -122,7 +146,11 @@ static bool join_arguments(const char * const *args, LPWSTR *args_out)
for (; *a; a++) {
switch (*a) {
case '"':
- result[i_out++] = '\\';
+ if (batch_file) {
+ result[i_out++] = '"';
+ } else {
+ result[i_out++] = '\\';
+ }
result[i_out++] = *a;
break;
case '\\':
@@ -131,6 +159,22 @@ static bool join_arguments(const char * const *args, LPWSTR *args_out)
result[i_out++] = *a;
}
break;
+ case ' ':
+ if (batch_file) {
+ result[i_out++] = '^';
+ }
+ result[i_out++] = *a;
+ break;
+ case '^':
+ case '&':
+ case '|':
+ case '<':
+ case '>':
+ if (batch_file) {
+ result[i_out++] = '^';
+ }
+ result[i_out++] = *a;
+ break;
default:
result[i_out++] = *a;
break;