Commit 110ca1c0 authored by Kenton Varda's avatar Kenton Varda

Hack to make it safe to read capabilities from default values (returning broken…

Hack to make it safe to read capabilities from default values (returning broken caps) without introducing a dependency from libcapnp on libcapnp-rpc.
parent fd769d56
......@@ -106,10 +106,6 @@ kj::Maybe<kj::Own<ClientHook>> BasicReaderArena::extractCap(uint index) {
return nullptr;
}
kj::Maybe<kj::Own<ClientHook>> BasicReaderArena::newBrokenCap(kj::StringPtr description) {
return nullptr;
}
// =======================================================================================
ImbuedReaderArena::ImbuedReaderArena(Arena* base, BrokenCapFactory& brokenCapFactory,
......@@ -173,10 +169,6 @@ kj::Maybe<kj::Own<ClientHook>> ImbuedReaderArena::extractCap(uint index) {
}
}
kj::Maybe<kj::Own<ClientHook>> ImbuedReaderArena::newBrokenCap(kj::StringPtr description) {
return brokenCapFactory.newBrokenCap(description);
}
// =======================================================================================
BasicBuilderArena::BasicBuilderArena(MessageBuilder* message)
......@@ -315,10 +307,6 @@ kj::Maybe<kj::Own<ClientHook>> BasicBuilderArena::extractCap(uint index) {
return nullptr;
}
kj::Maybe<kj::Own<ClientHook>> BasicBuilderArena::newBrokenCap(kj::StringPtr description) {
return nullptr;
}
uint BasicBuilderArena::injectCap(kj::Own<ClientHook>&& cap) {
KJ_FAIL_REQUIRE("Cannot inject capability into a builder that has not been imbued with a "
"capability context.") {
......@@ -394,10 +382,6 @@ kj::Maybe<kj::Own<ClientHook>> ImbuedBuilderArena::extractCap(uint index) {
}
}
kj::Maybe<kj::Own<ClientHook>> ImbuedBuilderArena::newBrokenCap(kj::StringPtr description) {
return brokenCapFactory.newBrokenCap(description);
}
SegmentBuilder* ImbuedBuilderArena::getSegment(SegmentId id) {
return imbue(base->getSegment(id));
}
......
......@@ -203,10 +203,6 @@ public:
// Extract the capability at the given index. If the index is invalid, returns a dummy
// capability whose methods all throw. Returns null only if the message is not imbued with a
// capability context.
virtual kj::Maybe<kj::Own<ClientHook>> newBrokenCap(kj::StringPtr description) = 0;
// Returns a capability which, when called, always throws an exception with the given description.
// Returns null if the message is not imbued with a capability context.
};
class BasicReaderArena final: public Arena {
......@@ -219,7 +215,6 @@ public:
SegmentReader* tryGetSegment(SegmentId id) override;
void reportReadLimitReached() override;
kj::Maybe<kj::Own<ClientHook>> extractCap(uint index);
kj::Maybe<kj::Own<ClientHook>> newBrokenCap(kj::StringPtr description);
private:
MessageReader* message;
......@@ -252,7 +247,6 @@ public:
SegmentReader* tryGetSegment(SegmentId id) override;
void reportReadLimitReached() override;
kj::Maybe<kj::Own<ClientHook>> extractCap(uint index);
kj::Maybe<kj::Own<ClientHook>> newBrokenCap(kj::StringPtr description);
private:
Arena* base;
......@@ -312,7 +306,6 @@ public:
SegmentReader* tryGetSegment(SegmentId id) override;
void reportReadLimitReached() override;
kj::Maybe<kj::Own<ClientHook>> extractCap(uint index);
kj::Maybe<kj::Own<ClientHook>> newBrokenCap(kj::StringPtr description);
// implements BuilderArena -----------------------------------------
SegmentBuilder* getSegment(SegmentId id) override;
......@@ -352,7 +345,6 @@ public:
SegmentReader* tryGetSegment(SegmentId id) override;
void reportReadLimitReached() override;
kj::Maybe<kj::Own<ClientHook>> extractCap(uint index);
kj::Maybe<kj::Own<ClientHook>> newBrokenCap(kj::StringPtr description);
// implements BuilderArena -----------------------------------------
SegmentBuilder* getSegment(SegmentId id) override;
......
......@@ -30,6 +30,13 @@
namespace capnp {
namespace _ {
void setGlobalBrokenCapFactoryForLayoutCpp(BrokenCapFactory& factory);
// Defined in layout.c++.
} // namespace _
namespace {
class BrokenCapFactoryImpl: public _::BrokenCapFactory {
......@@ -44,7 +51,9 @@ static BrokenCapFactoryImpl brokenCapFactory;
} // namespace
CapReaderContext::CapReaderContext(kj::Array<kj::Own<ClientHook>>&& capTable)
: capTable(kj::mv(capTable)) {}
: capTable(kj::mv(capTable)) {
setGlobalBrokenCapFactoryForLayoutCpp(brokenCapFactory);
}
CapReaderContext::~CapReaderContext() noexcept(false) {
if (capTable == nullptr) {
kj::dtor(arena());
......@@ -64,7 +73,9 @@ AnyPointer::Reader CapReaderContext::imbue(AnyPointer::Reader base) {
return AnyPointer::Reader(base.reader.imbue(arena()));
}
CapBuilderContext::CapBuilderContext() {}
CapBuilderContext::CapBuilderContext() {
setGlobalBrokenCapFactoryForLayoutCpp(brokenCapFactory);
}
CapBuilderContext::~CapBuilderContext() noexcept(false) {
if (arenaAllocated) {
kj::dtor(arena());
......
......@@ -32,6 +32,16 @@
namespace capnp {
namespace _ { // private
static BrokenCapFactory* brokenCapFactory = nullptr;
// Horrible hack: We need to be able to construct broken caps without any capability context,
// but we can't have a link-time dependency on libcapnp-rpc.
void setGlobalBrokenCapFactoryForLayoutCpp(BrokenCapFactory& factory) {
// Called from capability-context.c++ when a capability context is created. May be called
// multiple times but always with the same value.
__atomic_store_n(&brokenCapFactory, &factory, __ATOMIC_RELAXED);
}
// =======================================================================================
struct WirePointer {
......@@ -1830,19 +1840,19 @@ struct WireHelpers {
SegmentReader* segment, const WirePointer* ref, int nestingLimit)) {
kj::Maybe<kj::Own<ClientHook>> maybeCap;
if (segment == nullptr) {
// No capability context for unchecked messages.
// TODO(now): This means a capability read from an omitted (and therefore default-valued)
// sub-message will throw a fatal exception.
maybeCap = nullptr;
} else if (ref->isNull()) {
maybeCap = segment->getArena()->newBrokenCap("Calling null capability pointer.");
KJ_REQUIRE(brokenCapFactory != nullptr,
"Trying to read capabilities without ever having created a capability context. "
"To read capabilities from a message, you must imbue it with CapReaderContext, or "
"use the Cap'n Proto RPC system.");
if (ref->isNull()) {
maybeCap = brokenCapFactory->newBrokenCap("Calling null capability pointer.");
} else if (!ref->isCapability()) {
KJ_FAIL_REQUIRE(
"Message contains non-capability pointer where capability pointer was expected.") {
break;
}
maybeCap = segment->getArena()->newBrokenCap(
maybeCap = brokenCapFactory->newBrokenCap(
"Calling capability extracted from a non-capability pointer.");
} else {
maybeCap = segment->getArena()->extractCap(ref->capRef.index.get());
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment