Skip to content

Commit 0b35080

Browse files
committed
std: fix buffer overflows from improper WTF encoding
Closes #20288
1 parent 5692979 commit 0b35080

File tree

3 files changed

+21
-4
lines changed

3 files changed

+21
-4
lines changed

lib/std/fs/Dir.zig

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -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.
31273129
pub 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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,15 @@ const tmpDir = std.testing.tmpDir;
2222
const Dir = std.fs.Dir;
2323
const ArenaAllocator = std.heap.ArenaAllocator;
2424

25+
// https://github.com/ziglang/zig/issues/20288
26+
test "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+
2534
test "chdir smoke test" {
2635
if (native_os == .wasi) return error.SkipZigTest;
2736

0 commit comments

Comments
 (0)