0
0
Fork 0
mirror of https://github.com/matrix-construct/construct synced 2024-11-29 18:22:50 +01:00

ircd:Ⓜ️:vm: Additional comments; minor simplifications.

This commit is contained in:
Jason Volk 2020-12-16 13:19:20 -08:00
parent e1e8286436
commit dfcf032b96
3 changed files with 49 additions and 23 deletions

View file

@ -25,9 +25,9 @@ enum ircd::m::vm::phase
NONE, ///< No phase; not entered. NONE, ///< No phase; not entered.
EXECUTE, ///< Execution entered. EXECUTE, ///< Execution entered.
CONFORM, ///< Conformity check phase. CONFORM, ///< Conformity check phase.
DUPWAIT, ///< Duplicate eval check & hold DUPWAIT, ///< Duplicate eval check & hold.
DUPCHK, ///< Duplicate existence check DUPCHK, ///< Duplicate existence check.
ISSUE, ///< Issue phase. ISSUE, ///< Issue phase (for my(event)'s only).
ACCESS, ///< Access control phase. ACCESS, ///< Access control phase.
VERIFY, ///< Signature verification. VERIFY, ///< Signature verification.
FETCH_AUTH, ///< Authentication events fetch phase. FETCH_AUTH, ///< Authentication events fetch phase.

View file

@ -105,7 +105,8 @@ ircd::m::vm::conform_check_size
} }
}; };
/// Check if an event originating from this server exceeds maximum size. /// Generate the conformity report and place the result into the eval. This
/// hook may do some IO to find out if an event is the target of a redaction.
decltype(ircd::m::vm::conform_report) decltype(ircd::m::vm::conform_report)
ircd::m::vm::conform_report ircd::m::vm::conform_report
{ {

View file

@ -308,12 +308,14 @@ try
// Determine if this is an internal room creation event // Determine if this is an internal room creation event
const bool is_internal_room_create const bool is_internal_room_create
{ {
json::get<"type"_>(event) == "m.room.create" && json::get<"type"_>(event) == "m.room.create"
json::get<"sender"_>(event) && && json::get<"sender"_>(event)
m::myself(json::get<"sender"_>(event)) && m::myself(json::get<"sender"_>(event))
}; };
// Query for whether the room apropos is an internal room. // Query for whether the room apropos is an internal room. Note that the
// room_id at this point may not be canonical; however, internal rooms
// do not and never will never use non-canonical room_id's.
const scope_restore room_internal const scope_restore room_internal
{ {
eval.room_internal, eval.room_internal,
@ -334,12 +336,14 @@ try
false false
}; };
// Reset the conformity report before and after this event's eval.
const scope_restore eval_report const scope_restore eval_report
{ {
eval.report, event::conforms{} eval.report, event::conforms{}
}; };
// These checks only require the event data itself. // Conformity checks only require the event data itself; note that some
// local queries may still be made by the hook, such as m::redacted().
if(likely(opts.phase[phase::CONFORM]) && !opts.edu) if(likely(opts.phase[phase::CONFORM]) && !opts.edu)
{ {
const scope_restore eval_phase const scope_restore eval_phase
@ -350,18 +354,25 @@ try
call_hook(conform_hook, eval, event, eval); call_hook(conform_hook, eval, event, eval);
} }
// If the event is simply missing content while not being authoritatively
// redacted, the conformity phase would have thrown a prior exception. Now
// we know if the event is legitimately missing content.
const bool redacted const bool redacted
{ {
eval.report.has(event::conforms::MISMATCH_HASHES) eval.report.has(event::conforms::MISMATCH_HASHES)
}; };
// If the input JSON is insufficient we'll need a buffer to rewrite the
// event. This buffer can be reused by subsequent events in the eval.
assert(!eval.buf || size(eval.buf) >= event::MAX_SIZE); assert(!eval.buf || size(eval.buf) >= event::MAX_SIZE);
if(!opts.edu && !eval.buf && (!opts.json_source || redacted)) if(!opts.edu && !eval.buf && (!opts.json_source || redacted))
eval.buf = unique_mutable_buffer eval.buf = unique_mutable_buffer
{ {
event::MAX_SIZE, 64 event::MAX_SIZE, simd::alignment
}; };
// Conjure a view of the correct canonical JSON representation. This will
// either reference the input directly or the rewrite into eval.buf.
const json::object event_source const json::object event_source
{ {
// Canonize from some other serialized source. // Canonize from some other serialized source.
@ -385,16 +396,18 @@ try
string_view{event.source} string_view{event.source}
}; };
m::event _event_ // Create a new event tuple from the canonical source, otherwise reference
// the existing input tuple directly. From now on we'll be referencing
// `_event` instead of `event` to ensure we have canonical values.
const m::event &_event
{ {
event_source event_source?
}; m::event{event_source}:
event
const auto &_event
{
event_source? _event_: event
}; };
// Now conjure the corrected room_id and reference that for the duration
// of this event's eval.
const scope_restore eval_room_id const scope_restore eval_room_id
{ {
eval.room_id, eval.room_id,
@ -453,6 +466,9 @@ try
event::id::buf{} event::id::buf{}
}; };
// Enter the phase to check and hold for other evals with the same event_id
// to prevent race-conditions. Note that duplicates are blocked but never
// rejected here, as the first eval might fail and the second might not.
if(likely(opts.phase[phase::DUPWAIT]) && eval.event_id) if(likely(opts.phase[phase::DUPWAIT]) && eval.event_id)
{ {
const scope_restore eval_phase const scope_restore eval_phase
@ -486,6 +502,9 @@ try
eval.event_, &_event eval.event_, &_event
}; };
// Now that the final input is constructed and everything is known about it,
// the next frame's exception handlers will build and propagate much better
// error messages.
return execute_du(eval, _event); return execute_du(eval, _event);
} }
catch(const vm::error &e) catch(const vm::error &e)
@ -764,6 +783,16 @@ ircd::m::vm::execute_pdu(eval &eval,
opts.auth && !eval.room_internal opts.auth && !eval.room_internal
}; };
// There is no reason for an event from another origin to be sent to an
// internal room. This boxes internal room access as a local problem, with
// local mistakes.
if(unlikely(eval.room_internal && !my(event)))
throw error
{
fault::GENERAL, "Internal room event denied from external source."
};
// Check if an event with the same ID was already accepted.
if(likely(opts.phase[phase::DUPCHK])) if(likely(opts.phase[phase::DUPCHK]))
{ {
const scope_restore eval_phase const scope_restore eval_phase
@ -784,14 +813,10 @@ ircd::m::vm::execute_pdu(eval &eval,
} }
} }
if(unlikely(eval.room_internal && !my(event)))
throw error
{
fault::GENERAL, "Internal room event denied from external source."
};
assert(!opts.unique || eval::count(event_id) == 1); assert(!opts.unique || eval::count(event_id) == 1);
assert(opts.replays || !m::exists(event_id)); assert(opts.replays || !m::exists(event_id));
// Check if event's proprietor is denied by the room ACL.
if(likely(opts.phase[phase::ACCESS])) if(likely(opts.phase[phase::ACCESS]))
{ {
const scope_restore eval_phase const scope_restore eval_phase