| ... | @@ -73,6 +73,31 @@ pub fn main() anyerror!void { | ... | @@ -73,6 +73,31 @@ pub fn main() anyerror!void { |
| 73 | try testExec(allocator, &.{ "\"hello^\"world\"", "hello &echo oh no >file.txt" }, null); | 73 | try testExec(allocator, &.{ "\"hello^\"world\"", "hello &echo oh no >file.txt" }, null); |
| 74 | try testExec(allocator, &.{"&whoami.exe"}, null); | 74 | try testExec(allocator, &.{"&whoami.exe"}, null); |
| 75 | | 75 | |
| | 76 | // Ensure that trailing space and . characters can't lead to unexpected bat/cmd script execution. |
| | 77 | // In many Windows APIs (including CreateProcess), trailing space and . characters are stripped |
| | 78 | // from paths, so if a path with trailing . and space character(s) is passed directly to |
| | 79 | // CreateProcess, then it could end up executing a batch/cmd script that naive extension detection |
| | 80 | // would not flag as .bat/.cmd. |
| | 81 | // |
| | 82 | // Note that we expect an error here, though, which *is* a valid mitigation, but also an implementation detail. |
| | 83 | // This error is caused by the use of a wildcard with NtQueryDirectoryFile to optimize PATHEXT searching. That is, |
| | 84 | // the trailing characters in the app name will lead to a FileNotFound error as the wildcard-appended path will not |
| | 85 | // match any real paths on the filesystem (e.g. `foo.bat .. *` will not match `foo.bat`; only `foo.bat*` will). |
| | 86 | // |
| | 87 | // This being an error matches the behavior of running a command via the command line of cmd.exe, too: |
| | 88 | // |
| | 89 | // > "args1.bat .. " |
| | 90 | // '"args1.bat .. "' is not recognized as an internal or external command, |
| | 91 | // operable program or batch file. |
| | 92 | try std.testing.expectError(error.FileNotFound, testExecBat(allocator, "args1.bat .. ", &.{"abc"}, null)); |
| | 93 | const absolute_with_trailing = blk: { |
| | 94 | const absolute_path = try std.fs.realpathAlloc(allocator, "args1.bat"); |
| | 95 | defer allocator.free(absolute_path); |
| | 96 | break :blk try std.mem.concat(allocator, u8, &.{ absolute_path, " .. " }); |
| | 97 | }; |
| | 98 | defer allocator.free(absolute_with_trailing); |
| | 99 | try std.testing.expectError(error.FileNotFound, testExecBat(allocator, absolute_with_trailing, &.{"abc"}, null)); |
| | 100 | |
| 76 | var env = env: { | 101 | var env = env: { |
| 77 | var env = try std.process.getEnvMap(allocator); | 102 | var env = try std.process.getEnvMap(allocator); |
| 78 | errdefer env.deinit(); | 103 | errdefer env.deinit(); |