diff --git a/lib/std/fs/Dir.zig b/lib/std/fs/Dir.zig index 9b8406d6b2..bb36d99455 100644 --- a/lib/std/fs/Dir.zig +++ b/lib/std/fs/Dir.zig @@ -1786,6 +1786,9 @@ pub fn symLink( // when converting to an NT namespaced path. CreateSymbolicLink in // symLinkW will handle the necessary conversion. var target_path_w: windows.PathSpace = undefined; + if (try std.unicode.checkWtf8ToWtf16LeOverflow(target_path, &target_path_w.data)) { + return error.NameTooLong; + } target_path_w.len = try std.unicode.wtf8ToWtf16Le(&target_path_w.data, target_path); target_path_w.data[target_path_w.len] = 0; // However, we need to canonicalize any path separators to `\`, since if diff --git a/lib/std/posix.zig b/lib/std/posix.zig index 167c945abf..b02852e96c 100644 --- a/lib/std/posix.zig +++ b/lib/std/posix.zig @@ -3111,8 +3111,10 @@ pub fn chdir(dir_path: []const u8) ChangeCurDirError!void { @compileError("WASI does not support os.chdir"); } else if (native_os == .windows) { var wtf16_dir_path: [windows.PATH_MAX_WIDE]u16 = undefined; - const len = try std.unicode.wtf8ToWtf16Le(wtf16_dir_path[0..], dir_path); - if (len > wtf16_dir_path.len) return error.NameTooLong; + if (try std.unicode.checkWtf8ToWtf16LeOverflow(dir_path, &wtf16_dir_path)) { + return error.NameTooLong; + } + const len = try std.unicode.wtf8ToWtf16Le(&wtf16_dir_path, dir_path); return chdirW(wtf16_dir_path[0..len]); } else { const dir_path_c = try toPosixPath(dir_path); @@ -3126,9 +3128,12 @@ pub fn chdir(dir_path: []const u8) ChangeCurDirError!void { /// On other platforms, `dir_path` is an opaque sequence of bytes with no particular encoding. pub fn chdirZ(dir_path: [*:0]const u8) ChangeCurDirError!void { if (native_os == .windows) { + const dir_path_span = mem.span(dir_path); var wtf16_dir_path: [windows.PATH_MAX_WIDE]u16 = undefined; - const len = try std.unicode.wtf8ToWtf16Le(wtf16_dir_path[0..], mem.span(dir_path)); - if (len > wtf16_dir_path.len) return error.NameTooLong; + if (try std.unicode.checkWtf8ToWtf16LeOverflow(dir_path_span, &wtf16_dir_path)) { + return error.NameTooLong; + } + const len = try std.unicode.wtf8ToWtf16Le(&wtf16_dir_path, dir_path_span); return chdirW(wtf16_dir_path[0..len]); } else if (native_os == .wasi and !builtin.link_libc) { return chdir(mem.span(dir_path)); diff --git a/lib/std/posix/test.zig b/lib/std/posix/test.zig index dfc1dce01e..f1995acc74 100644 --- a/lib/std/posix/test.zig +++ b/lib/std/posix/test.zig @@ -22,6 +22,15 @@ const tmpDir = std.testing.tmpDir; const Dir = std.fs.Dir; const ArenaAllocator = std.heap.ArenaAllocator; +// https://github.com/ziglang/zig/issues/20288 +test "WTF-8 to WTF-16 conversion buffer overflows" { + if (native_os != .windows) return error.SkipZigTest; + + const input_wtf8 = "\u{10FFFF}" ** 16385; + try expectError(error.NameTooLong, posix.chdir(input_wtf8)); + try expectError(error.NameTooLong, posix.chdirZ(input_wtf8)); +} + test "chdir smoke test" { if (native_os == .wasi) return error.SkipZigTest;