0
0
Fork 0
mirror of https://github.com/matrix-construct/construct synced 2024-12-26 15:33:54 +01:00

ircd:Ⓜ️:vm: Add redacted canonization cases prior to eval.

This commit is contained in:
Jason Volk 2020-11-29 19:46:20 -08:00
parent be7bab0c16
commit d49227c848
5 changed files with 102 additions and 53 deletions

View file

@ -95,6 +95,7 @@ struct ircd::m::vm::eval
hook::base *hook {nullptr};
vm::phase phase {vm::phase(0)};
bool room_internal {false};
bool redacted {false};
void mfetch_keys() const;

View file

@ -115,7 +115,7 @@ ircd::m::vm::conform_report
[](const m::event &event, eval &eval)
{
assert(eval.opts);
auto &opts(*eval.opts);
const auto &opts(*eval.opts);
// When opts.conformed is set the report is already generated
if(opts.conformed)
@ -124,17 +124,30 @@ ircd::m::vm::conform_report
return;
}
// Mask of checks to be bypassed
auto non_conform
{
opts.non_conform
};
// This hook is called prior to event_id determination; must be skipped
non_conform.set(event::conforms::INVALID_OR_MISSING_EVENT_ID);
// For internal rooms for now.
if(eval.room_internal)
non_conform.set(event::conforms::MISMATCH_ORIGIN_SENDER);
// Generate the report here.
eval.report = event::conforms
{
event, opts.non_conform.report
event, non_conform.report
};
// When opts.conforming is false a bad report is not an error.
if(!opts.conforming)
return;
const bool redacted
eval.redacted =
{
// redacted hint given in options
opts.redacted != -1?
@ -149,24 +162,33 @@ ircd::m::vm::conform_report
false:
// assume redacted when hash mismatch already allowed
(opts.non_conform.has(event::conforms::MISMATCH_HASHES))?
non_conform.has(event::conforms::MISMATCH_HASHES)?
true:
// assume no redaction for hash match
(!eval.report.has(event::conforms::MISMATCH_HASHES))?
!eval.report.has(event::conforms::MISMATCH_HASHES)?
false:
// case for authoritative redaction
eval.report.has(event::conforms::MISMATCH_HASHES)
&& opts.node_id == json::get<"origin"_>(event)?
true:
// make query
bool(m::redacted(event.event_id))
event.event_id?
bool(m::redacted(event.event_id)):
// otherwise deny redacted
false
};
auto report
{
eval.report
};;
};
// Allow content hash to fail on redacted events.
if(redacted)
if(eval.redacted)
report.del(event::conforms::MISMATCH_HASHES);
// Otherwise this will kill the eval

View file

@ -328,7 +328,7 @@ ircd::m::commit(const room &room,
// Some functionality on this server may create an event on behalf
// of remote users. It's safe for us to mask this here, but eval'ing
// this event in any replay later will require special casing.
opts.non_conform |= event::conforms::MISMATCH_ORIGIN_SENDER;
opts.non_conform.set(event::conforms::MISMATCH_ORIGIN_SENDER);
// Don't need this here
opts.phase.reset(vm::phase::VERIFY);

View file

@ -218,32 +218,16 @@ try
*eval.opts
};
assert(!eval.buf || size(eval.buf) >= event::MAX_SIZE);
if(!opts.json_source && !eval.buf)
eval.buf = unique_mutable_buffer
{
event::MAX_SIZE, 64
};
const scope_restore event_source
const scope_restore eval_report
{
mutable_cast(event).source,
// Canonize from some other serialized source.
!opts.json_source && event.source?
json::object(json::stringify(mutable_buffer{eval.buf}, event.source)):
// Canonize from no source; usually taken when my(event).
// XXX elision conditions go here
!opts.json_source?
json::object(json::stringify(mutable_buffer{eval.buf}, event)):
// Use the input directly.
event.source
eval.report, event::conforms{}
};
const scope_restore eval_redacted
{
eval.redacted, false
};
// Set a member to the room_id for convenient access, without stepping on
// any room_id reference that exists there for whatever reason.
const scope_restore eval_room_id
{
eval.room_id,
@ -253,7 +237,7 @@ try
eval.room_id:
// Use the room_id in the event
likely(valid(id::ROOM, json::get<"room_id"_>(event)))?
likely(json::get<"room_id"_>(event))?
string_view(json::get<"room_id"_>(event)):
eval.room_id,
@ -288,6 +272,68 @@ try
false
};
// These checks only require the event data itself.
if(likely(opts.phase[phase::CONFORM]) && !opts.edu)
{
const scope_restore eval_phase
{
eval.phase, phase::CONFORM
};
const ctx::critical_assertion ca;
call_hook(conform_hook, eval, event, eval);
}
assert(!eval.buf || size(eval.buf) >= event::MAX_SIZE);
const bool redacted
{
eval.redacted
|| eval.report.has(event::conforms::MISMATCH_HASHES)
};
if(!opts.edu && !eval.buf && (!opts.json_source || redacted))
eval.buf = unique_mutable_buffer
{
event::MAX_SIZE, 64
};
const scope_restore event_source
{
mutable_cast(event).source,
// Canonize and redact from some other serialized source.
!opts.edu && !opts.json_source && event.source && redacted?
json::stringify(mutable_buffer{eval.buf}, m::essential(event.source, event::buf[0])):
// Canonize and redact from no source.
!opts.edu && !opts.json_source && redacted?
json::stringify(mutable_buffer{eval.buf}, m::essential(event, event::buf[0])):
// Canonize from some other serialized source.
likely(!opts.edu && !opts.json_source && event.source)?
json::stringify(mutable_buffer{eval.buf}, event.source):
// Canonize from no source; usually taken when my(event).
// XXX elision conditions go here
likely(!opts.edu && !opts.json_source)?
json::stringify(mutable_buffer{eval.buf}, event):
// Use the input directly.
string_view{event.source}
};
const scope_restore eval_room_id_reref
{
eval.room_id,
// Re-assigns reference after any prior rewrites
likely(json::get<"room_id"_>(event))?
string_view(json::get<"room_id"_>(event)):
// No action
eval.room_id,
};
// Procure the room version.
char room_version_buf[room::VERSION_MAX_SIZE];
const scope_restore eval_room_version
@ -648,19 +694,6 @@ ircd::m::vm::execute_pdu(eval &eval,
fault::GENERAL, "Internal room event denied from external source."
};
// The conform hook runs static checks on an event's formatting and
// composure; these checks only require the event data itself.
if(likely(opts.phase[phase::CONFORM]))
{
const scope_restore eval_phase
{
eval.phase, phase::CONFORM
};
const ctx::critical_assertion ca;
call_hook(conform_hook, eval, event, eval);
}
// Wait for any pending duplicate evals before proceeding.
assert(eval::count(event_id));
if(likely(opts.phase[phase::DUPCHK] && opts.unique))

View file

@ -349,7 +349,6 @@ try
opts.warnlog &= ~vm::fault::EXISTS;
opts.notify_servers = false;
opts.node_id = origin;
log::debug
{
log, "Evaluating auth chain for %s in %s events:%zu",
@ -475,12 +474,6 @@ try
opts.phase.set(m::vm::phase::FETCH_STATE, false);
opts.node_id = result.origin;
opts.notify_servers = false;
// The result won't give us events with a content hash mismatch unless
// they were obtained from an authoritative source. For this we can
// unconditionally allow hash mismatch from here.
opts.redacted = 1;
vm::eval
{
pdus, opts