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) { ...@@ -106,10 +106,6 @@ kj::Maybe<kj::Own<ClientHook>> BasicReaderArena::extractCap(uint index) {
return nullptr; return nullptr;
} }
kj::Maybe<kj::Own<ClientHook>> BasicReaderArena::newBrokenCap(kj::StringPtr description) {
return nullptr;
}
// ======================================================================================= // =======================================================================================
ImbuedReaderArena::ImbuedReaderArena(Arena* base, BrokenCapFactory& brokenCapFactory, ImbuedReaderArena::ImbuedReaderArena(Arena* base, BrokenCapFactory& brokenCapFactory,
...@@ -173,10 +169,6 @@ kj::Maybe<kj::Own<ClientHook>> ImbuedReaderArena::extractCap(uint index) { ...@@ -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) BasicBuilderArena::BasicBuilderArena(MessageBuilder* message)
...@@ -315,10 +307,6 @@ kj::Maybe<kj::Own<ClientHook>> BasicBuilderArena::extractCap(uint index) { ...@@ -315,10 +307,6 @@ kj::Maybe<kj::Own<ClientHook>> BasicBuilderArena::extractCap(uint index) {
return nullptr; return nullptr;
} }
kj::Maybe<kj::Own<ClientHook>> BasicBuilderArena::newBrokenCap(kj::StringPtr description) {
return nullptr;
}
uint BasicBuilderArena::injectCap(kj::Own<ClientHook>&& cap) { uint BasicBuilderArena::injectCap(kj::Own<ClientHook>&& cap) {
KJ_FAIL_REQUIRE("Cannot inject capability into a builder that has not been imbued with a " KJ_FAIL_REQUIRE("Cannot inject capability into a builder that has not been imbued with a "
"capability context.") { "capability context.") {
...@@ -394,10 +382,6 @@ kj::Maybe<kj::Own<ClientHook>> ImbuedBuilderArena::extractCap(uint index) { ...@@ -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) { SegmentBuilder* ImbuedBuilderArena::getSegment(SegmentId id) {
return imbue(base->getSegment(id)); return imbue(base->getSegment(id));
} }
......
...@@ -203,10 +203,6 @@ public: ...@@ -203,10 +203,6 @@ public:
// Extract the capability at the given index. If the index is invalid, returns a dummy // 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 whose methods all throw. Returns null only if the message is not imbued with a
// capability context. // 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 { class BasicReaderArena final: public Arena {
...@@ -219,7 +215,6 @@ public: ...@@ -219,7 +215,6 @@ public:
SegmentReader* tryGetSegment(SegmentId id) override; SegmentReader* tryGetSegment(SegmentId id) override;
void reportReadLimitReached() override; void reportReadLimitReached() override;
kj::Maybe<kj::Own<ClientHook>> extractCap(uint index); kj::Maybe<kj::Own<ClientHook>> extractCap(uint index);
kj::Maybe<kj::Own<ClientHook>> newBrokenCap(kj::StringPtr description);
private: private:
MessageReader* message; MessageReader* message;
...@@ -252,7 +247,6 @@ public: ...@@ -252,7 +247,6 @@ public:
SegmentReader* tryGetSegment(SegmentId id) override; SegmentReader* tryGetSegment(SegmentId id) override;
void reportReadLimitReached() override; void reportReadLimitReached() override;
kj::Maybe<kj::Own<ClientHook>> extractCap(uint index); kj::Maybe<kj::Own<ClientHook>> extractCap(uint index);
kj::Maybe<kj::Own<ClientHook>> newBrokenCap(kj::StringPtr description);
private: private:
Arena* base; Arena* base;
...@@ -312,7 +306,6 @@ public: ...@@ -312,7 +306,6 @@ public:
SegmentReader* tryGetSegment(SegmentId id) override; SegmentReader* tryGetSegment(SegmentId id) override;
void reportReadLimitReached() override; void reportReadLimitReached() override;
kj::Maybe<kj::Own<ClientHook>> extractCap(uint index); kj::Maybe<kj::Own<ClientHook>> extractCap(uint index);
kj::Maybe<kj::Own<ClientHook>> newBrokenCap(kj::StringPtr description);
// implements BuilderArena ----------------------------------------- // implements BuilderArena -----------------------------------------
SegmentBuilder* getSegment(SegmentId id) override; SegmentBuilder* getSegment(SegmentId id) override;
...@@ -352,7 +345,6 @@ public: ...@@ -352,7 +345,6 @@ public:
SegmentReader* tryGetSegment(SegmentId id) override; SegmentReader* tryGetSegment(SegmentId id) override;
void reportReadLimitReached() override; void reportReadLimitReached() override;
kj::Maybe<kj::Own<ClientHook>> extractCap(uint index); kj::Maybe<kj::Own<ClientHook>> extractCap(uint index);
kj::Maybe<kj::Own<ClientHook>> newBrokenCap(kj::StringPtr description);
// implements BuilderArena ----------------------------------------- // implements BuilderArena -----------------------------------------
SegmentBuilder* getSegment(SegmentId id) override; SegmentBuilder* getSegment(SegmentId id) override;
......
...@@ -30,6 +30,13 @@ ...@@ -30,6 +30,13 @@
namespace capnp { namespace capnp {
namespace _ {
void setGlobalBrokenCapFactoryForLayoutCpp(BrokenCapFactory& factory);
// Defined in layout.c++.
} // namespace _
namespace { namespace {
class BrokenCapFactoryImpl: public _::BrokenCapFactory { class BrokenCapFactoryImpl: public _::BrokenCapFactory {
...@@ -44,7 +51,9 @@ static BrokenCapFactoryImpl brokenCapFactory; ...@@ -44,7 +51,9 @@ static BrokenCapFactoryImpl brokenCapFactory;
} // namespace } // namespace
CapReaderContext::CapReaderContext(kj::Array<kj::Own<ClientHook>>&& capTable) CapReaderContext::CapReaderContext(kj::Array<kj::Own<ClientHook>>&& capTable)
: capTable(kj::mv(capTable)) {} : capTable(kj::mv(capTable)) {
setGlobalBrokenCapFactoryForLayoutCpp(brokenCapFactory);
}
CapReaderContext::~CapReaderContext() noexcept(false) { CapReaderContext::~CapReaderContext() noexcept(false) {
if (capTable == nullptr) { if (capTable == nullptr) {
kj::dtor(arena()); kj::dtor(arena());
...@@ -64,7 +73,9 @@ AnyPointer::Reader CapReaderContext::imbue(AnyPointer::Reader base) { ...@@ -64,7 +73,9 @@ AnyPointer::Reader CapReaderContext::imbue(AnyPointer::Reader base) {
return AnyPointer::Reader(base.reader.imbue(arena())); return AnyPointer::Reader(base.reader.imbue(arena()));
} }
CapBuilderContext::CapBuilderContext() {} CapBuilderContext::CapBuilderContext() {
setGlobalBrokenCapFactoryForLayoutCpp(brokenCapFactory);
}
CapBuilderContext::~CapBuilderContext() noexcept(false) { CapBuilderContext::~CapBuilderContext() noexcept(false) {
if (arenaAllocated) { if (arenaAllocated) {
kj::dtor(arena()); kj::dtor(arena());
......
...@@ -32,6 +32,16 @@ ...@@ -32,6 +32,16 @@
namespace capnp { namespace capnp {
namespace _ { // private 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 { struct WirePointer {
...@@ -1830,19 +1840,19 @@ struct WireHelpers { ...@@ -1830,19 +1840,19 @@ struct WireHelpers {
SegmentReader* segment, const WirePointer* ref, int nestingLimit)) { SegmentReader* segment, const WirePointer* ref, int nestingLimit)) {
kj::Maybe<kj::Own<ClientHook>> maybeCap; kj::Maybe<kj::Own<ClientHook>> maybeCap;
if (segment == nullptr) { KJ_REQUIRE(brokenCapFactory != nullptr,
// No capability context for unchecked messages. "Trying to read capabilities without ever having created a capability context. "
// TODO(now): This means a capability read from an omitted (and therefore default-valued) "To read capabilities from a message, you must imbue it with CapReaderContext, or "
// sub-message will throw a fatal exception. "use the Cap'n Proto RPC system.");
maybeCap = nullptr;
} else if (ref->isNull()) { if (ref->isNull()) {
maybeCap = segment->getArena()->newBrokenCap("Calling null capability pointer."); maybeCap = brokenCapFactory->newBrokenCap("Calling null capability pointer.");
} else if (!ref->isCapability()) { } else if (!ref->isCapability()) {
KJ_FAIL_REQUIRE( KJ_FAIL_REQUIRE(
"Message contains non-capability pointer where capability pointer was expected.") { "Message contains non-capability pointer where capability pointer was expected.") {
break; break;
} }
maybeCap = segment->getArena()->newBrokenCap( maybeCap = brokenCapFactory->newBrokenCap(
"Calling capability extracted from a non-capability pointer."); "Calling capability extracted from a non-capability pointer.");
} else { } else {
maybeCap = segment->getArena()->extractCap(ref->capRef.index.get()); 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