authorgravatar for cartersnook04@gmail.comCarter Snook <cartersnook04@gmail.com> 2024-06-14 15:41:43-05:00
committergravatar for cartersnook04@gmail.comCarter Snook <cartersnook04@gmail.com> 2024-06-14 15:42:17-05:00
log0b3508073c25f9412740b5f98a6a6f235f6dc3d1
tree518252a230b46f93170ae4744784ff791818f197
parent56929795a8ce13792322486aa28de50c96865773

std: fix buffer overflows from improper WTF encoding

Closes #20288

3 files changed, 21 insertions(+), 4 deletions(-)

lib/std/fs/Dir.zig+3
......@@ -1786,6 +1786,9 @@ pub fn symLink(
17861786 // when converting to an NT namespaced path. CreateSymbolicLink in
17871787 // symLinkW will handle the necessary conversion.
17881788 var target_path_w: windows.PathSpace = undefined;
1789 if (try std.unicode.checkWtf8ToWtf16LeOverflow(target_path, &target_path_w.data)) {
1790 return error.NameTooLong;
1791 }
17891792 target_path_w.len = try std.unicode.wtf8ToWtf16Le(&target_path_w.data, target_path);
17901793 target_path_w.data[target_path_w.len] = 0;
17911794 // However, we need to canonicalize any path separators to `\`, since if
lib/std/posix.zig+9-4
......@@ -3111,8 +3111,10 @@ pub fn chdir(dir_path: []const u8) ChangeCurDirError!void {
31113111 @compileError("WASI does not support os.chdir");
31123112 } else if (native_os == .windows) {
31133113 var wtf16_dir_path: [windows.PATH_MAX_WIDE]u16 = undefined;
3114 const len = try std.unicode.wtf8ToWtf16Le(wtf16_dir_path[0..], dir_path);
3115 if (len > wtf16_dir_path.len) return error.NameTooLong;
3114 if (try std.unicode.checkWtf8ToWtf16LeOverflow(dir_path, &wtf16_dir_path)) {
3115 return error.NameTooLong;
3116 }
3117 const len = try std.unicode.wtf8ToWtf16Le(&wtf16_dir_path, dir_path);
31163118 return chdirW(wtf16_dir_path[0..len]);
31173119 } else {
31183120 const dir_path_c = try toPosixPath(dir_path);
......@@ -3126,9 +3128,12 @@ pub fn chdir(dir_path: []const u8) ChangeCurDirError!void {
31263128/// On other platforms, `dir_path` is an opaque sequence of bytes with no particular encoding.
31273129pub fn chdirZ(dir_path: [*:0]const u8) ChangeCurDirError!void {
31283130 if (native_os == .windows) {
3131 const dir_path_span = mem.span(dir_path);
31293132 var wtf16_dir_path: [windows.PATH_MAX_WIDE]u16 = undefined;
3130 const len = try std.unicode.wtf8ToWtf16Le(wtf16_dir_path[0..], mem.span(dir_path));
3131 if (len > wtf16_dir_path.len) return error.NameTooLong;
3133 if (try std.unicode.checkWtf8ToWtf16LeOverflow(dir_path_span, &wtf16_dir_path)) {
3134 return error.NameTooLong;
3135 }
3136 const len = try std.unicode.wtf8ToWtf16Le(&wtf16_dir_path, dir_path_span);
31323137 return chdirW(wtf16_dir_path[0..len]);
31333138 } else if (native_os == .wasi and !builtin.link_libc) {
31343139 return chdir(mem.span(dir_path));
lib/std/posix/test.zig+9
......@@ -22,6 +22,15 @@ const tmpDir = std.testing.tmpDir;
2222const Dir = std.fs.Dir;
2323const ArenaAllocator = std.heap.ArenaAllocator;
2424
25// https://github.com/ziglang/zig/issues/20288
26test "WTF-8 to WTF-16 conversion buffer overflows" {
27 if (native_os != .windows) return error.SkipZigTest;
28
29 const input_wtf8 = "\u{10FFFF}" ** 16385;
30 try expectError(error.NameTooLong, posix.chdir(input_wtf8));
31 try expectError(error.NameTooLong, posix.chdirZ(input_wtf8));
32}
33
2534test "chdir smoke test" {
2635 if (native_os == .wasi) return error.SkipZigTest;
2736