diff --git a/pkg/wuffs/src/error.zig b/pkg/wuffs/src/error.zig index c75188718..0be55cf4e 100644 --- a/pkg/wuffs/src/error.zig +++ b/pkg/wuffs/src/error.zig @@ -2,7 +2,7 @@ const std = @import("std"); const c = @import("c.zig").c; -pub const Error = std.mem.Allocator.Error || error{WuffsError}; +pub const Error = std.mem.Allocator.Error || error{ WuffsError, Overflow }; pub fn check(log: anytype, status: *const c.struct_wuffs_base__status__struct) error{WuffsError}!void { if (!c.wuffs_base__status__is_ok(status)) { diff --git a/pkg/wuffs/src/jpeg.zig b/pkg/wuffs/src/jpeg.zig index 700ba01b9..69d91c8a9 100644 --- a/pkg/wuffs/src/jpeg.zig +++ b/pkg/wuffs/src/jpeg.zig @@ -4,6 +4,8 @@ const c = @import("c.zig").c; const Error = @import("error.zig").Error; const check = @import("error.zig").check; const ImageData = @import("main.zig").ImageData; +const maximum_image_size = @import("main.zig").maximum_image_size; +const mul = std.math.mul; const log = std.log.scoped(.wuffs_jpeg); @@ -61,9 +63,20 @@ pub fn decode(alloc: Allocator, data: []const u8) Error!ImageData { height, ); + const size: usize = try mul( + usize, + try mul(usize, width, height), + @sizeOf(c.wuffs_base__color_u32_argb_premul), + ); + + if (size > maximum_image_size) { + log.warn("image size {d} is larger than the maximum allowed ({d})", .{ size, maximum_image_size }); + return error.Overflow; + } + const destination = try alloc.alloc( u8, - width * height * @sizeOf(c.wuffs_base__color_u32_argb_premul), + size, ); errdefer alloc.free(destination); @@ -131,3 +144,8 @@ test "jpeg_decode_FFFFFF" { try std.testing.expectEqual(1, data.height); try std.testing.expectEqualSlices(u8, &.{ 255, 255, 255, 255 }, data.data); } + +test "jpeg: too big" { + const data = decode(std.testing.allocator, @embedFile("too_big.jpg")); + try std.testing.expectError(error.Overflow, data); +} diff --git a/pkg/wuffs/src/main.zig b/pkg/wuffs/src/main.zig index 89f3c008c..207d83f9a 100644 --- a/pkg/wuffs/src/main.zig +++ b/pkg/wuffs/src/main.zig @@ -5,6 +5,10 @@ pub const jpeg = @import("jpeg.zig"); pub const swizzle = @import("swizzle.zig"); pub const Error = @import("error.zig").Error; +/// The maximum image size, based on the 4G limit of Ghostty's +/// `image-storage-limit` config. +pub const maximum_image_size = 4 * 1024 * 1024 * 1024; + pub const ImageData = struct { width: u32, height: u32, diff --git a/pkg/wuffs/src/png.zig b/pkg/wuffs/src/png.zig index d79ae5b56..57a0e63bb 100644 --- a/pkg/wuffs/src/png.zig +++ b/pkg/wuffs/src/png.zig @@ -4,6 +4,8 @@ const c = @import("c.zig").c; const Error = @import("error.zig").Error; const check = @import("error.zig").check; const ImageData = @import("main.zig").ImageData; +const maximum_image_size = @import("main.zig").maximum_image_size; +const mul = std.math.mul; const log = std.log.scoped(.wuffs_png); @@ -61,9 +63,20 @@ pub fn decode(alloc: Allocator, data: []const u8) Error!ImageData { height, ); + const size: usize = try mul( + usize, + try mul(usize, width, height), + @sizeOf(c.wuffs_base__color_u32_argb_premul), + ); + + if (size > maximum_image_size) { + log.warn("image size {d} is larger than the maximum allowed ({d})", .{ size, maximum_image_size }); + return error.Overflow; + } + const destination = try alloc.alloc( u8, - width * height * @sizeOf(c.wuffs_base__color_u32_argb_premul), + size, ); errdefer alloc.free(destination); @@ -131,3 +144,8 @@ test "png_decode_FFFFFF" { try std.testing.expectEqual(1, data.height); try std.testing.expectEqualSlices(u8, &.{ 255, 255, 255, 255 }, data.data); } + +test "png: too big" { + const data = decode(std.testing.allocator, @embedFile("too_big.png")); + try std.testing.expectError(error.Overflow, data); +} diff --git a/pkg/wuffs/src/too_big.jpg b/pkg/wuffs/src/too_big.jpg new file mode 100644 index 000000000..d7ebf7dbb Binary files /dev/null and b/pkg/wuffs/src/too_big.jpg differ diff --git a/pkg/wuffs/src/too_big.png b/pkg/wuffs/src/too_big.png new file mode 100644 index 000000000..86b134a0d Binary files /dev/null and b/pkg/wuffs/src/too_big.png differ diff --git a/src/terminal/kitty/graphics_image.zig b/src/terminal/kitty/graphics_image.zig index 268f71601..f485e0161 100644 --- a/src/terminal/kitty/graphics_image.zig +++ b/src/terminal/kitty/graphics_image.zig @@ -433,6 +433,7 @@ pub const LoadingImage = struct { ) catch |err| switch (err) { error.WuffsError => return error.InvalidData, error.OutOfMemory => return error.OutOfMemory, + error.Overflow => return error.InvalidData, }; defer alloc.free(result.data);