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(...@@ -1786,6 +1786,9 @@ pub fn symLink(
1786 // when converting to an NT namespaced path. CreateSymbolicLink in1786 // when converting to an NT namespaced path. CreateSymbolicLink in
1787 // symLinkW will handle the necessary conversion.1787 // symLinkW will handle the necessary conversion.
1788 var target_path_w: windows.PathSpace = undefined;1788 var target_path_w: windows.PathSpace = undefined;
1789 if (try std.unicode.checkWtf8ToWtf16LeOverflow(target_path, &target_path_w.data)) {
1790 return error.NameTooLong;
1791 }
1789 target_path_w.len = try std.unicode.wtf8ToWtf16Le(&target_path_w.data, target_path);1792 target_path_w.len = try std.unicode.wtf8ToWtf16Le(&target_path_w.data, target_path);
1790 target_path_w.data[target_path_w.len] = 0;1793 target_path_w.data[target_path_w.len] = 0;
1791 // However, we need to canonicalize any path separators to `\`, since if1794 // 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 {...@@ -3111,8 +3111,10 @@ pub fn chdir(dir_path: []const u8) ChangeCurDirError!void {
3111 @compileError("WASI does not support os.chdir");3111 @compileError("WASI does not support os.chdir");
3112 } else if (native_os == .windows) {3112 } else if (native_os == .windows) {
3113 var wtf16_dir_path: [windows.PATH_MAX_WIDE]u16 = undefined;3113 var wtf16_dir_path: [windows.PATH_MAX_WIDE]u16 = undefined;
3114 const len = try std.unicode.wtf8ToWtf16Le(wtf16_dir_path[0..], dir_path);3114 if (try std.unicode.checkWtf8ToWtf16LeOverflow(dir_path, &wtf16_dir_path)) {
3115 if (len > wtf16_dir_path.len) return error.NameTooLong;3115 return error.NameTooLong;
3116 }
3117 const len = try std.unicode.wtf8ToWtf16Le(&wtf16_dir_path, dir_path);
3116 return chdirW(wtf16_dir_path[0..len]);3118 return chdirW(wtf16_dir_path[0..len]);
3117 } else {3119 } else {
3118 const dir_path_c = try toPosixPath(dir_path);3120 const dir_path_c = try toPosixPath(dir_path);
...@@ -3126,9 +3128,12 @@ pub fn chdir(dir_path: []const u8) ChangeCurDirError!void {...@@ -3126,9 +3128,12 @@ pub fn chdir(dir_path: []const u8) ChangeCurDirError!void {
3126/// On other platforms, `dir_path` is an opaque sequence of bytes with no particular encoding.3128/// On other platforms, `dir_path` is an opaque sequence of bytes with no particular encoding.
3127pub fn chdirZ(dir_path: [*:0]const u8) ChangeCurDirError!void {3129pub fn chdirZ(dir_path: [*:0]const u8) ChangeCurDirError!void {
3128 if (native_os == .windows) {3130 if (native_os == .windows) {
3131 const dir_path_span = mem.span(dir_path);
3129 var wtf16_dir_path: [windows.PATH_MAX_WIDE]u16 = undefined;3132 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));3133 if (try std.unicode.checkWtf8ToWtf16LeOverflow(dir_path_span, &wtf16_dir_path)) {
3131 if (len > wtf16_dir_path.len) return error.NameTooLong;3134 return error.NameTooLong;
3135 }
3136 const len = try std.unicode.wtf8ToWtf16Le(&wtf16_dir_path, dir_path_span);
3132 return chdirW(wtf16_dir_path[0..len]);3137 return chdirW(wtf16_dir_path[0..len]);
3133 } else if (native_os == .wasi and !builtin.link_libc) {3138 } else if (native_os == .wasi and !builtin.link_libc) {
3134 return chdir(mem.span(dir_path));3139 return chdir(mem.span(dir_path));
lib/std/posix/test.zig+9
...@@ -22,6 +22,15 @@ const tmpDir = std.testing.tmpDir;...@@ -22,6 +22,15 @@ const tmpDir = std.testing.tmpDir;
22const Dir = std.fs.Dir;22const Dir = std.fs.Dir;
23const ArenaAllocator = std.heap.ArenaAllocator;23const 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
25test "chdir smoke test" {34test "chdir smoke test" {
26 if (native_os == .wasi) return error.SkipZigTest;35 if (native_os == .wasi) return error.SkipZigTest;
2736