mirror of
https://github.com/matrix-construct/construct
synced 2024-11-26 00:32:35 +01:00
ircd:Ⓜ️:vm: Add redacted canonization cases prior to eval.
This commit is contained in:
parent
be7bab0c16
commit
d49227c848
5 changed files with 102 additions and 53 deletions
|
@ -95,6 +95,7 @@ struct ircd::m::vm::eval
|
||||||
hook::base *hook {nullptr};
|
hook::base *hook {nullptr};
|
||||||
vm::phase phase {vm::phase(0)};
|
vm::phase phase {vm::phase(0)};
|
||||||
bool room_internal {false};
|
bool room_internal {false};
|
||||||
|
bool redacted {false};
|
||||||
|
|
||||||
void mfetch_keys() const;
|
void mfetch_keys() const;
|
||||||
|
|
||||||
|
|
|
@ -115,7 +115,7 @@ ircd::m::vm::conform_report
|
||||||
[](const m::event &event, eval &eval)
|
[](const m::event &event, eval &eval)
|
||||||
{
|
{
|
||||||
assert(eval.opts);
|
assert(eval.opts);
|
||||||
auto &opts(*eval.opts);
|
const auto &opts(*eval.opts);
|
||||||
|
|
||||||
// When opts.conformed is set the report is already generated
|
// When opts.conformed is set the report is already generated
|
||||||
if(opts.conformed)
|
if(opts.conformed)
|
||||||
|
@ -124,17 +124,30 @@ ircd::m::vm::conform_report
|
||||||
return;
|
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.
|
// Generate the report here.
|
||||||
eval.report = event::conforms
|
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.
|
// When opts.conforming is false a bad report is not an error.
|
||||||
if(!opts.conforming)
|
if(!opts.conforming)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const bool redacted
|
eval.redacted =
|
||||||
{
|
{
|
||||||
// redacted hint given in options
|
// redacted hint given in options
|
||||||
opts.redacted != -1?
|
opts.redacted != -1?
|
||||||
|
@ -149,24 +162,33 @@ ircd::m::vm::conform_report
|
||||||
false:
|
false:
|
||||||
|
|
||||||
// assume redacted when hash mismatch already allowed
|
// assume redacted when hash mismatch already allowed
|
||||||
(opts.non_conform.has(event::conforms::MISMATCH_HASHES))?
|
non_conform.has(event::conforms::MISMATCH_HASHES)?
|
||||||
true:
|
true:
|
||||||
|
|
||||||
// assume no redaction for hash match
|
// assume no redaction for hash match
|
||||||
(!eval.report.has(event::conforms::MISMATCH_HASHES))?
|
!eval.report.has(event::conforms::MISMATCH_HASHES)?
|
||||||
false:
|
false:
|
||||||
|
|
||||||
|
// case for authoritative redaction
|
||||||
|
eval.report.has(event::conforms::MISMATCH_HASHES)
|
||||||
|
&& opts.node_id == json::get<"origin"_>(event)?
|
||||||
|
true:
|
||||||
|
|
||||||
// make query
|
// make query
|
||||||
bool(m::redacted(event.event_id))
|
event.event_id?
|
||||||
|
bool(m::redacted(event.event_id)):
|
||||||
|
|
||||||
|
// otherwise deny redacted
|
||||||
|
false
|
||||||
};
|
};
|
||||||
|
|
||||||
auto report
|
auto report
|
||||||
{
|
{
|
||||||
eval.report
|
eval.report
|
||||||
};;
|
};
|
||||||
|
|
||||||
// Allow content hash to fail on redacted events.
|
// Allow content hash to fail on redacted events.
|
||||||
if(redacted)
|
if(eval.redacted)
|
||||||
report.del(event::conforms::MISMATCH_HASHES);
|
report.del(event::conforms::MISMATCH_HASHES);
|
||||||
|
|
||||||
// Otherwise this will kill the eval
|
// Otherwise this will kill the eval
|
||||||
|
|
|
@ -328,7 +328,7 @@ ircd::m::commit(const room &room,
|
||||||
// Some functionality on this server may create an event on behalf
|
// 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
|
// 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.
|
// 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
|
// Don't need this here
|
||||||
opts.phase.reset(vm::phase::VERIFY);
|
opts.phase.reset(vm::phase::VERIFY);
|
||||||
|
|
|
@ -218,32 +218,16 @@ try
|
||||||
*eval.opts
|
*eval.opts
|
||||||
};
|
};
|
||||||
|
|
||||||
assert(!eval.buf || size(eval.buf) >= event::MAX_SIZE);
|
const scope_restore eval_report
|
||||||
if(!opts.json_source && !eval.buf)
|
|
||||||
eval.buf = unique_mutable_buffer
|
|
||||||
{
|
{
|
||||||
event::MAX_SIZE, 64
|
eval.report, event::conforms{}
|
||||||
};
|
};
|
||||||
|
|
||||||
const scope_restore event_source
|
const scope_restore eval_redacted
|
||||||
{
|
{
|
||||||
mutable_cast(event).source,
|
eval.redacted, false
|
||||||
|
|
||||||
// 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
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// 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
|
const scope_restore eval_room_id
|
||||||
{
|
{
|
||||||
eval.room_id,
|
eval.room_id,
|
||||||
|
@ -253,7 +237,7 @@ try
|
||||||
eval.room_id:
|
eval.room_id:
|
||||||
|
|
||||||
// Use the room_id in the event
|
// 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)):
|
string_view(json::get<"room_id"_>(event)):
|
||||||
|
|
||||||
eval.room_id,
|
eval.room_id,
|
||||||
|
@ -288,6 +272,68 @@ try
|
||||||
false
|
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.
|
// Procure the room version.
|
||||||
char room_version_buf[room::VERSION_MAX_SIZE];
|
char room_version_buf[room::VERSION_MAX_SIZE];
|
||||||
const scope_restore eval_room_version
|
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."
|
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.
|
// Wait for any pending duplicate evals before proceeding.
|
||||||
assert(eval::count(event_id));
|
assert(eval::count(event_id));
|
||||||
if(likely(opts.phase[phase::DUPCHK] && opts.unique))
|
if(likely(opts.phase[phase::DUPCHK] && opts.unique))
|
||||||
|
|
|
@ -349,7 +349,6 @@ try
|
||||||
opts.warnlog &= ~vm::fault::EXISTS;
|
opts.warnlog &= ~vm::fault::EXISTS;
|
||||||
opts.notify_servers = false;
|
opts.notify_servers = false;
|
||||||
opts.node_id = origin;
|
opts.node_id = origin;
|
||||||
|
|
||||||
log::debug
|
log::debug
|
||||||
{
|
{
|
||||||
log, "Evaluating auth chain for %s in %s events:%zu",
|
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.phase.set(m::vm::phase::FETCH_STATE, false);
|
||||||
opts.node_id = result.origin;
|
opts.node_id = result.origin;
|
||||||
opts.notify_servers = false;
|
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
|
vm::eval
|
||||||
{
|
{
|
||||||
pdus, opts
|
pdus, opts
|
||||||
|
|
Loading…
Reference in a new issue