authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-05-26 16:05:38-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-05-27 20:56:48-07:00
log52ed54d1e7a396f4508829af45c6953f1a827a1c
tree3b2756974b8ed75be3cf1b79fb45476599fe1632
parent807b613f71bf97d8169b6ce3ed7ad0c0dc8bb402

std.Progress: truncate IPC data exceeding preallocated buffers

This accomplishes 2 things simultaneously: 1. Don't trust child process data; if the data is outside the expected range, ignore the data. 2. If there is too much data to fit in the preallocated buffers, drop the data.

1 files changed, 27 insertions(+), 18 deletions(-)

lib/std/Progress.zig+27-18
...@@ -593,9 +593,9 @@ var ipc_metadata_len: u16 = 0;...@@ -593,9 +593,9 @@ var ipc_metadata_len: u16 = 0;
593593
594const SavedMetadata = struct {594const SavedMetadata = struct {
595 ipc_fd: u16,595 ipc_fd: u16,
596 main_index: u16,596 main_index: u8,
597 start_index: u16,597 start_index: u8,
598 nodes_len: u16,598 nodes_len: u8,
599599
600 fn getIpcFd(metadata: SavedMetadata) posix.fd_t {600 fn getIpcFd(metadata: SavedMetadata) posix.fd_t {
601 return if (builtin.os.tag == .windows)601 return if (builtin.os.tag == .windows)
...@@ -677,11 +677,13 @@ fn serializeIpc(start_serialized_len: usize, serialized_buffer: *Serialized.Buff...@@ -677,11 +677,13 @@ fn serializeIpc(start_serialized_len: usize, serialized_buffer: *Serialized.Buff
677 };677 };
678 };678 };
679679
680 const nodes_len: u8 = @intCast(@min(parents.len - 1, serialized_buffer.storage.len - serialized_len));
681
680 // Remember in case the pipe is empty on next update.682 // Remember in case the pipe is empty on next update.
681 ipc_metadata[ipc_metadata_len] = .{683 ipc_metadata[ipc_metadata_len] = .{
682 .ipc_fd = SavedMetadata.setIpcFd(fd),684 .ipc_fd = SavedMetadata.setIpcFd(fd),
683 .start_index = @intCast(serialized_len),685 .start_index = @intCast(serialized_len),
684 .nodes_len = @intCast(parents.len),686 .nodes_len = nodes_len,
685 .main_index = @intCast(main_index),687 .main_index = @intCast(main_index),
686 };688 };
687 ipc_metadata_len += 1;689 ipc_metadata_len += 1;
...@@ -690,24 +692,26 @@ fn serializeIpc(start_serialized_len: usize, serialized_buffer: *Serialized.Buff...@@ -690,24 +692,26 @@ fn serializeIpc(start_serialized_len: usize, serialized_buffer: *Serialized.Buff
690 copyRoot(main_storage, &storage[0]);692 copyRoot(main_storage, &storage[0]);
691693
692 // Copy the rest of the tree to the end.694 // Copy the rest of the tree to the end.
693 @memcpy(serialized_buffer.storage[serialized_len..][0 .. storage.len - 1], storage[1..]);695 @memcpy(serialized_buffer.storage[serialized_len..][0..nodes_len], storage[1..][0..nodes_len]);
694696
695 // Patch up parent pointers taking into account how the subtree is mounted.697 // Patch up parent pointers taking into account how the subtree is mounted.
696 serialized_buffer.parents[serialized_len] = .none;698 for (serialized_buffer.parents[serialized_len..][0..nodes_len], parents[1..][0..nodes_len]) |*dest, p| {
697
698 for (serialized_buffer.parents[serialized_len..][0 .. parents.len - 1], parents[1..]) |*dest, p| {
699 dest.* = switch (p) {699 dest.* = switch (p) {
700 // Fix bad data so the rest of the code does not see `unused`.700 // Fix bad data so the rest of the code does not see `unused`.
701 .none, .unused => .none,701 .none, .unused => .none,
702 // Root node is being mounted here.702 // Root node is being mounted here.
703 @as(Node.Parent, @enumFromInt(0)) => @enumFromInt(main_index),703 @as(Node.Parent, @enumFromInt(0)) => @enumFromInt(main_index),
704 // Other nodes mounted at the end.704 // Other nodes mounted at the end.
705 // TODO check for bad data pointing outside the expected range705 // Don't trust child data; if the data is outside the expected range, ignore the data.
706 _ => |off| @enumFromInt(serialized_len + @intFromEnum(off) - 1),706 // This also handles the case when data was truncated.
707 _ => |off| if (@intFromEnum(off) > nodes_len)
708 .none
709 else
710 @enumFromInt(serialized_len + @intFromEnum(off) - 1),
707 };711 };
708 }712 }
709713
710 serialized_len += storage.len - 1;714 serialized_len += nodes_len;
711 }715 }
712716
713 // Save a copy in case any pipes are empty on the next update.717 // Save a copy in case any pipes are empty on the next update.
...@@ -753,7 +757,7 @@ fn useSavedIpcData(...@@ -753,7 +757,7 @@ fn useSavedIpcData(
753 };757 };
754758
755 const start_index = saved_metadata.start_index;759 const start_index = saved_metadata.start_index;
756 const nodes_len = saved_metadata.nodes_len;760 const nodes_len = @min(saved_metadata.nodes_len, serialized_buffer.storage.len - start_serialized_len);
757 const old_main_index = saved_metadata.main_index;761 const old_main_index = saved_metadata.main_index;
758762
759 ipc_metadata[ipc_metadata_len] = .{763 ipc_metadata[ipc_metadata_len] = .{
...@@ -764,8 +768,8 @@ fn useSavedIpcData(...@@ -764,8 +768,8 @@ fn useSavedIpcData(
764 };768 };
765 ipc_metadata_len += 1;769 ipc_metadata_len += 1;
766770
767 const parents = parents_copy[start_index..][0 .. nodes_len - 1];771 const parents = parents_copy[start_index..][0..nodes_len];
768 const storage = storage_copy[start_index..][0 .. nodes_len - 1];772 const storage = storage_copy[start_index..][0..nodes_len];
769773
770 copyRoot(main_storage, &storage_copy[old_main_index]);774 copyRoot(main_storage, &storage_copy[old_main_index]);
771775
...@@ -774,10 +778,15 @@ fn useSavedIpcData(...@@ -774,10 +778,15 @@ fn useSavedIpcData(
774 for (serialized_buffer.parents[start_serialized_len..][0..parents.len], parents) |*dest, p| {778 for (serialized_buffer.parents[start_serialized_len..][0..parents.len], parents) |*dest, p| {
775 dest.* = switch (p) {779 dest.* = switch (p) {
776 .none, .unused => .none,780 .none, .unused => .none,
777 _ => |prev| @enumFromInt(if (@intFromEnum(prev) == old_main_index)781 _ => |prev| d: {
778 main_index782 if (@intFromEnum(prev) == old_main_index) {
779 else783 break :d @enumFromInt(main_index);
780 @intFromEnum(prev) - start_index + start_serialized_len),784 } else if (@intFromEnum(prev) > nodes_len) {
785 break :d .none;
786 } else {
787 break :d @enumFromInt(@intFromEnum(prev) - start_index + start_serialized_len);
788 }
789 },
781 };790 };
782 }791 }
783792