Merge pull request #729 from truemedian/fuzz

resolve simple crashes
This commit is contained in:
Mitchell Hashimoto
2023-10-26 10:02:48 -07:00
committed by GitHub
5 changed files with 91 additions and 7 deletions

View File

@ -256,7 +256,10 @@ pub fn expandPath(alloc: Allocator, cmd: []const u8) !?[]u8 {
const full_path = path_buf[0..path_len :0];
// Stat it
const f = std.fs.openFileAbsolute(full_path, .{}) catch |err| switch (err) {
const f = std.fs.cwd().openFile(
full_path,
.{},
) catch |err| switch (err) {
error.FileNotFound => continue,
error.AccessDenied => {
// Accumulate this and return it later so we can try other

View File

@ -9,7 +9,7 @@ const Config = @import("../config.zig").Config;
pub const Message = union(enum) {
/// Represents a write request. Magic number comes from the max size
/// we want this union to be.
pub const WriteReq = termio.MessageData(u8, 256);
pub const WriteReq = termio.MessageData(u8, 255);
/// Set the title of the surface.
/// TODO: we should change this to a "WriteReq" style structure in

View File

@ -378,7 +378,11 @@ fn doAction(self: *Parser, action: TransitionAction, c: u8) ?Action {
self.param_acc *|= 10;
}
self.param_acc +|= c - '0';
self.param_acc_idx += 1;
// Increment our accumulator index. If we overflow then
// we're out of bounds and we exit immediately.
self.param_acc_idx, const overflow = @addWithOverflow(self.param_acc_idx, 1);
if (overflow > 0) break :param null;
// The client is expected to perform no action.
break :param null;
@ -388,6 +392,9 @@ fn doAction(self: *Parser, action: TransitionAction, c: u8) ?Action {
break :osc_put null;
},
.csi_dispatch => csi_dispatch: {
// Ignore too many parameters
if (self.params_idx >= MAX_PARAMS) break :csi_dispatch null;
// Finalize parameters if we have one
if (self.param_acc_idx > 0) {
self.params[self.params_idx] = self.param_acc;
@ -904,3 +911,22 @@ test "csi followed by utf8" {
try testing.expect(a[2] == null);
}
}
test "csi: too many params" {
var p = init();
_ = p.next(0x1B);
_ = p.next('[');
for (0..100) |_| {
_ = p.next('1');
_ = p.next(';');
}
_ = p.next('1');
{
const a = p.next('C');
try testing.expect(p.state == .ground);
try testing.expect(a[0] == null);
try testing.expect(a[1] == null);
try testing.expect(a[2] == null);
}
}

View File

@ -969,43 +969,52 @@ pub fn Stream(comptime Handler: type) type {
.change_window_title => |title| {
if (@hasDecl(T, "changeWindowTitle")) {
try self.handler.changeWindowTitle(title);
return;
} else log.warn("unimplemented OSC callback: {}", .{cmd});
},
.clipboard_contents => |clip| {
if (@hasDecl(T, "clipboardContents")) {
try self.handler.clipboardContents(clip.kind, clip.data);
return;
} else log.warn("unimplemented OSC callback: {}", .{cmd});
},
.prompt_start => |v| {
if (@hasDecl(T, "promptStart")) switch (v.kind) {
.primary, .right => try self.handler.promptStart(v.aid, v.redraw),
.continuation => try self.handler.promptContinuation(v.aid),
if (@hasDecl(T, "promptStart")) {
switch (v.kind) {
.primary, .right => try self.handler.promptStart(v.aid, v.redraw),
.continuation => try self.handler.promptContinuation(v.aid),
}
return;
} else log.warn("unimplemented OSC callback: {}", .{cmd});
},
.prompt_end => {
if (@hasDecl(T, "promptEnd")) {
try self.handler.promptEnd();
return;
} else log.warn("unimplemented OSC callback: {}", .{cmd});
},
.end_of_input => {
if (@hasDecl(T, "endOfInput")) {
try self.handler.endOfInput();
return;
} else log.warn("unimplemented OSC callback: {}", .{cmd});
},
.end_of_command => |end| {
if (@hasDecl(T, "endOfCommand")) {
try self.handler.endOfCommand(end.exit_code);
return;
} else log.warn("unimplemented OSC callback: {}", .{cmd});
},
.report_pwd => |v| {
if (@hasDecl(T, "reportPwd")) {
try self.handler.reportPwd(v.value);
return;
} else log.warn("unimplemented OSC callback: {}", .{cmd});
},
@ -1017,12 +1026,14 @@ pub fn Stream(comptime Handler: type) type {
};
try self.handler.setMouseShape(shape);
return;
} else log.warn("unimplemented OSC callback: {}", .{cmd});
},
.report_default_color => |v| {
if (@hasDecl(T, "reportDefaultColor")) {
try self.handler.reportDefaultColor(v.kind, v.terminator);
return;
} else log.warn("unimplemented OSC callback: {}", .{cmd});
},
@ -1031,6 +1042,13 @@ pub fn Stream(comptime Handler: type) type {
else
log.warn("unimplemented OSC command: {}", .{cmd}),
}
// Fall through for when we don't have a handler.
if (@hasDecl(T, "oscUnimplemented")) {
try self.handler.oscUnimplemented(cmd);
} else {
log.warn("unimplemented OSC command: {s}", .{@tagName(cmd)});
}
}
fn configureCharset(
@ -1598,3 +1616,28 @@ test "stream: insert characters" {
for ("\x1B[?42@") |c| try s.next(c);
try testing.expect(!s.handler.called);
}
test "stream: too many csi params" {
const H = struct {
pub fn setCursorRight(self: *@This(), v: u16) !void {
_ = v;
_ = self;
unreachable;
}
};
var s: Stream(H) = .{ .handler = .{} };
try s.nextSlice("\x1B[1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1C");
}
test "stream: csi param too long" {
const H = struct {
pub fn setCursorRight(self: *@This(), v: u16) !void {
_ = v;
_ = self;
}
};
var s: Stream(H) = .{ .handler = .{} };
try s.nextSlice("\x1B[1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111C");
}

View File

@ -90,8 +90,9 @@ pub fn MessageData(comptime Elem: type, comptime small_size: comptime_int) type
pub const Small = struct {
pub const Max = small_size;
pub const Array = [Max]Elem;
pub const Len = std.math.IntFittingRange(0, small_size);
data: Array = undefined,
len: u8 = 0,
len: Len = 0,
};
pub const Alloc = struct {
@ -182,3 +183,14 @@ test "MessageData init alloc" {
try testing.expect(io == .alloc);
io.alloc.alloc.free(io.alloc.data);
}
test "MessageData small fits non-u8 sized data" {
const testing = std.testing;
const alloc = testing.allocator;
const len = 500;
const Data = MessageData(u8, len);
const input: []const u8 = "X" ** len;
const io = try Data.init(alloc, input);
try testing.expect(io == .small);
}