std: fix buffer overflows from improper WTF encoding

Closes #20288
This commit is contained in:
Carter Snook 2024-06-14 15:41:43 -05:00
parent 56929795a8
commit 0b3508073c
3 changed files with 21 additions and 4 deletions

View file

@ -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

View file

@ -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));

View file

@ -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;