milestone 15: make a green run mean a real pass
This commit is contained in:
+57
-1
@@ -10,7 +10,10 @@
|
||||
//! - a `Name` that `parse` accepted ends inside the packet and survives a
|
||||
//! round trip through presentation form;
|
||||
//! - a buffer that `decrementTtls` aged still parses, and no record it aged
|
||||
//! holds a TTL below the minimum it reported.
|
||||
//! holds a TTL below the minimum it reported;
|
||||
//! - a query that `stripEcs` rewrote still parses, still carries a valid OPT
|
||||
//! record, no longer carries an ECS option, and kept all four of its
|
||||
//! section counts.
|
||||
//!
|
||||
//! The targets stay inside the documented safe entry points. `setId` is called
|
||||
//! only on a buffer long enough to hold a header, because it asserts that
|
||||
@@ -54,6 +57,10 @@ test "fuzz packet.decrementTtls" {
|
||||
try std.testing.fuzz({}, ttlTarget, fuzz_options);
|
||||
}
|
||||
|
||||
test "fuzz edns.stripEcs" {
|
||||
try std.testing.fuzz({}, stripEcsTarget, fuzz_options);
|
||||
}
|
||||
|
||||
fn parseTarget(_: void, smith: *Smith) anyerror!void {
|
||||
var buf: [max_input]u8 = undefined;
|
||||
const bytes = buf[0..smith.slice(&buf)];
|
||||
@@ -136,6 +143,55 @@ fn ttlTarget(_: void, smith: *Smith) anyerror!void {
|
||||
}
|
||||
}
|
||||
|
||||
/// `stripEcs` is the only attacker-facing entry point that rewrites a packet, so
|
||||
/// it is the only one where a finding can be a wrong output rather than a crash.
|
||||
///
|
||||
/// The input is derived exactly as `parseTarget` derives it, because `stripEcs`
|
||||
/// asserts its preconditions rather than returning an error: `query` must be the
|
||||
/// same bytes `pkt` was parsed from, and `out` must not overlap them. `out` is a
|
||||
/// separate stack buffer for that reason, and tripping either assertion from a
|
||||
/// hand-built argument would report a fault no packet can cause.
|
||||
fn stripEcsTarget(_: void, smith: *Smith) anyerror!void {
|
||||
var buf: [max_input]u8 = undefined;
|
||||
const bytes = buf[0..smith.slice(&buf)];
|
||||
|
||||
const p = packet.parse(bytes) catch return;
|
||||
const opt_record = packet.findOptRecord(p) orelse return;
|
||||
const opt = edns.parseOpt(bytes, opt_record) catch return;
|
||||
|
||||
// Removing an option only ever shortens the query, so a buffer the size of
|
||||
// the input always holds the rewrite.
|
||||
var out: [max_input]u8 = undefined;
|
||||
const result = edns.stripEcs(bytes, p, opt, &out) catch return;
|
||||
const rewritten = switch (result) {
|
||||
.unchanged => return,
|
||||
.rewritten => |message| message,
|
||||
};
|
||||
|
||||
try std.testing.expect(rewritten.len <= bytes.len);
|
||||
|
||||
const stripped = try packet.parse(rewritten);
|
||||
try std.testing.expectEqual(p.header.id, stripped.header.id);
|
||||
try std.testing.expectEqual(p.header.qdcount, stripped.header.qdcount);
|
||||
try std.testing.expectEqual(p.header.ancount, stripped.header.ancount);
|
||||
try std.testing.expectEqual(p.header.nscount, stripped.header.nscount);
|
||||
try std.testing.expectEqual(p.header.arcount, stripped.header.arcount);
|
||||
|
||||
const stripped_record = packet.findOptRecord(stripped) orelse
|
||||
return error.TestOptRecordLost;
|
||||
const stripped_opt = try edns.parseOpt(rewritten, stripped_record);
|
||||
try std.testing.expectEqual(opt.udp_payload_size, stripped_opt.udp_payload_size);
|
||||
try std.testing.expectEqual(opt.do_bit, stripped_opt.do_bit);
|
||||
|
||||
var options = edns.options(rewritten, stripped_opt);
|
||||
while (try options.next()) |option| {
|
||||
try std.testing.expect(option.code != edns.ecs_option_code);
|
||||
}
|
||||
try std.testing.expect(
|
||||
(try edns.findOption(rewritten, stripped_opt, edns.ecs_option_code)) == null,
|
||||
);
|
||||
}
|
||||
|
||||
/// Runs every typed RDATA accessor over a record. Each one rejects a record of
|
||||
/// the wrong type or a truncated RDATA, so only a panic is a finding here.
|
||||
fn sweepRdata(bytes: []const u8, rec: record.Record) void {
|
||||
|
||||
Reference in New Issue
Block a user