Skip to content

Commit

Permalink
implement proxy-wasm ABI restriction
Browse files Browse the repository at this point in the history
Signed-off-by: Ryan Apilado <[email protected]>
  • Loading branch information
ryanapilado committed Nov 19, 2020
1 parent 8d62990 commit f468a96
Show file tree
Hide file tree
Showing 24 changed files with 570 additions and 83 deletions.
11 changes: 10 additions & 1 deletion api/envoy/extensions/wasm/v3/wasm.proto
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,12 @@ option (udpa.annotations.file_status).package_version_status = ACTIVE;
// [#protodoc-title: Wasm]
// [#extension: envoy.bootstrap.wasm]

// Configuration for restricting proxy-wasm capabilities available to modules.
message CapabilityRestrictionConfig {
// The list of proxy-wasm capabilities which will be exposed to the module.
repeated string allowed_abi_functions = 1;
}

// Configuration for a Wasm VM.
// [#next-free-field: 7]
message VmConfig {
Expand Down Expand Up @@ -74,7 +80,7 @@ message VmConfig {
}

// Base Configuration for Wasm Plugins e.g. filters and services.
// [#next-free-field: 6]
// [#next-free-field: 7]
message PluginConfig {
// A unique name for a filters/services in a VM for use in identifying the filter/service if
// multiple filters/services are handled by the same *vm_id* and *root_id* and for
Expand Down Expand Up @@ -105,6 +111,9 @@ message PluginConfig {
// during xDS updates the xDS configuration will be rejected and when on_start or on_configuration return false on initial
// startup the proxy will not start.
bool fail_open = 5;

// Configuration for restricting proxy-wasm capabilities available to modules.
CapabilityRestrictionConfig capability_restriction_config = 6;
}

// WasmService is configured as a built-in *envoy.wasm_service* :ref:`WasmService
Expand Down
11 changes: 10 additions & 1 deletion generated_api_shadow/envoy/extensions/wasm/v3/wasm.proto

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 4 additions & 3 deletions source/extensions/access_loggers/wasm/config.cc
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,10 @@ WasmAccessLogFactory::createAccessLogInstance(const Protobuf::Message& proto_con
};

if (!Common::Wasm::createWasm(
config.config().vm_config(), plugin, context.scope().createScope(""),
context.clusterManager(), context.initManager(), context.dispatcher(), context.api(),
context.lifecycleNotifier(), remote_data_provider_, std::move(callback))) {
config.config().vm_config(), config.config().capability_restriction_config(), plugin,
context.scope().createScope(""), context.clusterManager(), context.initManager(),
context.dispatcher(), context.api(), context.lifecycleNotifier(), remote_data_provider_,
std::move(callback))) {
throw Common::Wasm::WasmException(
fmt::format("Unable to create Wasm access log {}", plugin->name_));
}
Expand Down
7 changes: 4 additions & 3 deletions source/extensions/bootstrap/wasm/config.cc
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,10 @@ void WasmFactory::createWasm(const envoy::extensions::wasm::v3::WasmService& con
};

if (!Common::Wasm::createWasm(
config.config().vm_config(), plugin, context.scope().createScope(""),
context.clusterManager(), context.initManager(), context.dispatcher(), context.api(),
context.lifecycleNotifier(), remote_data_provider_, std::move(callback))) {
config.config().vm_config(), config.config().capability_restriction_config(), plugin,
context.scope().createScope(""), context.clusterManager(), context.initManager(),
context.dispatcher(), context.api(), context.lifecycleNotifier(), remote_data_provider_,
std::move(callback))) {
// NB: throw if we get a synchronous configuration failures as this is how such failures are
// reported to xDS.
throw Common::Wasm::WasmException(
Expand Down
1 change: 1 addition & 0 deletions source/extensions/common/wasm/context.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ using proxy_wasm::WasmResult;
using proxy_wasm::WasmStreamType;

using VmConfig = envoy::extensions::wasm::v3::VmConfig;
using CapabilityRestrictionConfig = envoy::extensions::wasm::v3::CapabilityRestrictionConfig;
using GrpcService = envoy::config::core::v3::GrpcService;

class Wasm;
Expand Down
36 changes: 20 additions & 16 deletions source/extensions/common/wasm/wasm.cc
Original file line number Diff line number Diff line change
Expand Up @@ -100,10 +100,12 @@ void Wasm::initializeLifecycle(Server::ServerLifecycleNotifier& lifecycle_notifi
}

Wasm::Wasm(absl::string_view runtime, absl::string_view vm_id, absl::string_view vm_configuration,
absl::string_view vm_key, const Stats::ScopeSharedPtr& scope,
Upstream::ClusterManager& cluster_manager, Event::Dispatcher& dispatcher)
: WasmBase(createWasmVm(runtime, scope), vm_id, vm_configuration, vm_key), scope_(scope),
cluster_manager_(cluster_manager), dispatcher_(dispatcher),
absl::string_view vm_key, std::unordered_set<std::string> allowed_abi_functions,
const Stats::ScopeSharedPtr& scope, Upstream::ClusterManager& cluster_manager,
Event::Dispatcher& dispatcher)
: WasmBase(createWasmVm(runtime, scope), vm_id, vm_configuration, vm_key,
allowed_abi_functions),
scope_(scope), cluster_manager_(cluster_manager), dispatcher_(dispatcher),
time_source_(dispatcher.timeSource()),
wasm_stats_(WasmStats{
ALL_WASM_STATS(POOL_COUNTER_PREFIX(*scope_, absl::StrCat("wasm.", runtime, ".")),
Expand Down Expand Up @@ -314,8 +316,9 @@ WasmEvent toWasmEvent(const std::shared_ptr<WasmHandleBase>& wasm) {
NOT_IMPLEMENTED_GCOVR_EXCL_LINE;
}

static bool createWasmInternal(const VmConfig& vm_config, const PluginSharedPtr& plugin,
const Stats::ScopeSharedPtr& scope,
static bool createWasmInternal(const VmConfig& vm_config,
const CapabilityRestrictionConfig& cr_config,
const PluginSharedPtr& plugin, const Stats::ScopeSharedPtr& scope,
Upstream::ClusterManager& cluster_manager,
Init::Manager& init_manager, Event::Dispatcher& dispatcher,
Api::Api& api, Server::ServerLifecycleNotifier& lifecycle_notifier,
Expand Down Expand Up @@ -382,7 +385,7 @@ static bool createWasmInternal(const VmConfig& vm_config, const PluginSharedPtr&
.value_or(code.empty() ? EMPTY_STRING : INLINE_STRING);
}

auto complete_cb = [cb, vm_config, plugin, scope, &cluster_manager, &dispatcher,
auto complete_cb = [cb, vm_config, cr_config, plugin, scope, &cluster_manager, &dispatcher,
&lifecycle_notifier, create_root_context_for_testing,
wasm_extension](std::string code) -> bool {
if (code.empty()) {
Expand All @@ -393,10 +396,10 @@ static bool createWasmInternal(const VmConfig& vm_config, const PluginSharedPtr&
proxy_wasm::makeVmKey(vm_config.vm_id(), anyToBytes(vm_config.configuration()), code);
auto wasm_factory = wasm_extension->wasmFactory();
proxy_wasm::WasmHandleFactory proxy_wasm_factory =
[&vm_config, scope, &cluster_manager, &dispatcher, &lifecycle_notifier,
[&vm_config, &cr_config, scope, &cluster_manager, &dispatcher, &lifecycle_notifier,
wasm_factory](absl::string_view vm_key) -> WasmHandleBaseSharedPtr {
return wasm_factory(vm_config, scope, cluster_manager, dispatcher, lifecycle_notifier,
vm_key);
return wasm_factory(vm_config, cr_config, scope, cluster_manager, dispatcher,
lifecycle_notifier, vm_key);
};
auto wasm = proxy_wasm::createWasm(
vm_key, code, plugin, proxy_wasm_factory,
Expand Down Expand Up @@ -471,15 +474,16 @@ static bool createWasmInternal(const VmConfig& vm_config, const PluginSharedPtr&
return true;
}

bool createWasm(const VmConfig& vm_config, const PluginSharedPtr& plugin,
const Stats::ScopeSharedPtr& scope, Upstream::ClusterManager& cluster_manager,
Init::Manager& init_manager, Event::Dispatcher& dispatcher, Api::Api& api,
bool createWasm(const VmConfig& vm_config, const CapabilityRestrictionConfig& cr_config,
const PluginSharedPtr& plugin, const Stats::ScopeSharedPtr& scope,
Upstream::ClusterManager& cluster_manager, Init::Manager& init_manager,
Event::Dispatcher& dispatcher, Api::Api& api,
Envoy::Server::ServerLifecycleNotifier& lifecycle_notifier,
Config::DataSource::RemoteAsyncDataProviderPtr& remote_data_provider,
CreateWasmCallback&& cb, CreateContextFn create_root_context_for_testing) {
return createWasmInternal(vm_config, plugin, scope, cluster_manager, init_manager, dispatcher,
api, lifecycle_notifier, remote_data_provider, std::move(cb),
create_root_context_for_testing);
return createWasmInternal(vm_config, cr_config, plugin, scope, cluster_manager, init_manager,
dispatcher, api, lifecycle_notifier, remote_data_provider,
std::move(cb), create_root_context_for_testing);
}

PluginHandleSharedPtr
Expand Down
12 changes: 7 additions & 5 deletions source/extensions/common/wasm/wasm.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,9 @@ struct WasmStats {
class Wasm : public WasmBase, Logger::Loggable<Logger::Id::wasm> {
public:
Wasm(absl::string_view runtime, absl::string_view vm_id, absl::string_view vm_configuration,
absl::string_view vm_key, const Stats::ScopeSharedPtr& scope,
Upstream::ClusterManager& cluster_manager, Event::Dispatcher& dispatcher);
absl::string_view vm_key, std::unordered_set<std::string> allowed_abi_functions,
const Stats::ScopeSharedPtr& scope, Upstream::ClusterManager& cluster_manager,
Event::Dispatcher& dispatcher);
Wasm(std::shared_ptr<WasmHandle> other, Event::Dispatcher& dispatcher);
~Wasm() override;

Expand Down Expand Up @@ -160,9 +161,10 @@ using CreateWasmCallback = std::function<void(WasmHandleSharedPtr)>;
// all failures synchronously as it has no facility to report configuration update failures
// asynchronously. Callers should throw an exception if they are part of a synchronous xDS update
// because that is the mechanism for reporting configuration errors.
bool createWasm(const VmConfig& vm_config, const PluginSharedPtr& plugin,
const Stats::ScopeSharedPtr& scope, Upstream::ClusterManager& cluster_manager,
Init::Manager& init_manager, Event::Dispatcher& dispatcher, Api::Api& api,
bool createWasm(const VmConfig& vm_config, const CapabilityRestrictionConfig& cr_config,
const PluginSharedPtr& plugin, const Stats::ScopeSharedPtr& scope,
Upstream::ClusterManager& cluster_manager, Init::Manager& init_manager,
Event::Dispatcher& dispatcher, Api::Api& api,
Envoy::Server::ServerLifecycleNotifier& lifecycle_notifier,
Config::DataSource::RemoteAsyncDataProviderPtr& remote_data_provider,
CreateWasmCallback&& callback,
Expand Down
12 changes: 7 additions & 5 deletions source/extensions/common/wasm/wasm_extension.cc
Original file line number Diff line number Diff line change
Expand Up @@ -55,13 +55,15 @@ PluginHandleExtensionFactory EnvoyWasm::pluginFactory() {
}

WasmHandleExtensionFactory EnvoyWasm::wasmFactory() {
return [](const VmConfig vm_config, const Stats::ScopeSharedPtr& scope,
Upstream::ClusterManager& cluster_manager, Event::Dispatcher& dispatcher,
Server::ServerLifecycleNotifier& lifecycle_notifier,
return [](const VmConfig vm_config, const CapabilityRestrictionConfig cr_config,
const Stats::ScopeSharedPtr& scope, Upstream::ClusterManager& cluster_manager,
Event::Dispatcher& dispatcher, Server::ServerLifecycleNotifier& lifecycle_notifier,
absl::string_view vm_key) -> WasmHandleBaseSharedPtr {
std::unordered_set<std::string> allowed_abi_functions(cr_config.allowed_abi_functions().begin(),
cr_config.allowed_abi_functions().end());
auto wasm = std::make_shared<Wasm>(vm_config.runtime(), vm_config.vm_id(),
anyToBytes(vm_config.configuration()), vm_key, scope,
cluster_manager, dispatcher);
anyToBytes(vm_config.configuration()), vm_key,
allowed_abi_functions, scope, cluster_manager, dispatcher);
wasm->initializeLifecycle(lifecycle_notifier);
return std::static_pointer_cast<WasmHandleBase>(std::make_shared<WasmHandle>(std::move(wasm)));
};
Expand Down
7 changes: 4 additions & 3 deletions source/extensions/common/wasm/wasm_extension.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,10 @@ using CreateContextFn =
using PluginHandleExtensionFactory = std::function<PluginHandleBaseSharedPtr(
const WasmHandleSharedPtr& base_wasm, absl::string_view plugin_key)>;
using WasmHandleExtensionFactory = std::function<WasmHandleBaseSharedPtr(
const VmConfig& vm_config, const Stats::ScopeSharedPtr& scope,
Upstream::ClusterManager& cluster_manager, Event::Dispatcher& dispatcher,
Server::ServerLifecycleNotifier& lifecycle_notifier, absl::string_view vm_key)>;
const VmConfig& vm_config, const CapabilityRestrictionConfig& cr_config,
const Stats::ScopeSharedPtr& scope, Upstream::ClusterManager& cluster_manager,
Event::Dispatcher& dispatcher, Server::ServerLifecycleNotifier& lifecycle_notifier,
absl::string_view vm_key)>;
using WasmHandleExtensionCloneFactory = std::function<WasmHandleBaseSharedPtr(
const WasmHandleSharedPtr& base_wasm, Event::Dispatcher& dispatcher,
CreateContextFn create_root_context_for_testing)>;
Expand Down
7 changes: 4 additions & 3 deletions source/extensions/filters/http/wasm/wasm_filter.cc
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,10 @@ FilterConfig::FilterConfig(const envoy::extensions::filters::http::wasm::v3::Was
};

if (!Common::Wasm::createWasm(
config.config().vm_config(), plugin_, context.scope().createScope(""),
context.clusterManager(), context.initManager(), context.dispatcher(), context.api(),
context.lifecycleNotifier(), remote_data_provider_, std::move(callback))) {
config.config().vm_config(), config.config().capability_restriction_config(), plugin_,
context.scope().createScope(""), context.clusterManager(), context.initManager(),
context.dispatcher(), context.api(), context.lifecycleNotifier(), remote_data_provider_,
std::move(callback))) {
throw Common::Wasm::WasmException(
fmt::format("Unable to create Wasm HTTP filter {}", plugin->name_));
}
Expand Down
7 changes: 4 additions & 3 deletions source/extensions/filters/network/wasm/wasm_filter.cc
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,10 @@ FilterConfig::FilterConfig(const envoy::extensions::filters::network::wasm::v3::
};

if (!Common::Wasm::createWasm(
config.config().vm_config(), plugin_, context.scope().createScope(""),
context.clusterManager(), context.initManager(), context.dispatcher(), context.api(),
context.lifecycleNotifier(), remote_data_provider_, std::move(callback))) {
config.config().vm_config(), config.config().capability_restriction_config(), plugin_,
context.scope().createScope(""), context.clusterManager(), context.initManager(),
context.dispatcher(), context.api(), context.lifecycleNotifier(), remote_data_provider_,
std::move(callback))) {
throw Common::Wasm::WasmException(
fmt::format("Unable to create Wasm network filter {}", plugin->name_));
}
Expand Down
7 changes: 4 additions & 3 deletions source/extensions/stat_sinks/wasm/config.cc
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,10 @@ WasmSinkFactory::createStatsSink(const Protobuf::Message& proto_config,
};

if (!Common::Wasm::createWasm(
config.config().vm_config(), plugin, context.scope().createScope(""),
context.clusterManager(), context.initManager(), context.dispatcher(), context.api(),
context.lifecycleNotifier(), remote_data_provider_, std::move(callback))) {
config.config().vm_config(), config.config().capability_restriction_config(), plugin,
context.scope().createScope(""), context.clusterManager(), context.initManager(),
context.dispatcher(), context.api(), context.lifecycleNotifier(), remote_data_provider_,
std::move(callback))) {
throw Common::Wasm::WasmException(
fmt::format("Unable to create Wasm Stat Sink {}", plugin->name_));
}
Expand Down
5 changes: 3 additions & 2 deletions test/extensions/bootstrap/wasm/wasm_speed_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,10 @@ static void bmWasmSimpleCallSpeedTest(benchmark::State& state, std::string test,
auto plugin = std::make_shared<Extensions::Common::Wasm::Plugin>(
name, root_id, vm_id, runtime, plugin_configuration, false,
envoy::config::core::v3::TrafficDirection::UNSPECIFIED, local_info, nullptr);
std::unordered_set<std::string> allowed_abi_functions;
auto wasm = std::make_unique<Extensions::Common::Wasm::Wasm>(
absl::StrCat("envoy.wasm.runtime.", runtime), vm_id, vm_configuration, vm_key, scope,
cluster_manager, *dispatcher);
absl::StrCat("envoy.wasm.runtime.", runtime), vm_id, vm_configuration, vm_key,
allowed_abi_functions, scope, cluster_manager, *dispatcher);
std::string code;
if (runtime == "null") {
code = "WasmSpeedCpp";
Expand Down
5 changes: 3 additions & 2 deletions test/extensions/bootstrap/wasm/wasm_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,8 @@ class WasmTestBase {
name_, root_id_, vm_id_, runtime, plugin_configuration_, false,
envoy::config::core::v3::TrafficDirection::UNSPECIFIED, local_info_, nullptr);
wasm_ = std::make_shared<Extensions::Common::Wasm::Wasm>(
absl::StrCat("envoy.wasm.runtime.", runtime), vm_id_, vm_configuration_, vm_key_, scope_,
cluster_manager, *dispatcher_);
absl::StrCat("envoy.wasm.runtime.", runtime), vm_id_, vm_configuration_, vm_key_,
allowed_abi_functions, scope_, cluster_manager, *dispatcher_);
EXPECT_NE(wasm_, nullptr);
wasm_->setCreateContextForTesting(
nullptr,
Expand All @@ -69,6 +69,7 @@ class WasmTestBase {
std::string vm_id_;
std::string vm_configuration_;
std::string vm_key_;
std::unordered_set<std::string> allowed_abi_functions;
std::string plugin_configuration_;
std::shared_ptr<Extensions::Common::Wasm::Plugin> plugin_;
std::shared_ptr<Extensions::Common::Wasm::Wasm> wasm_;
Expand Down
2 changes: 2 additions & 0 deletions test/extensions/common/wasm/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ envoy_cc_test(
"//test/extensions/common/wasm/test_data:bad_signature_cpp.wasm",
"//test/extensions/common/wasm/test_data:test_context_cpp.wasm",
"//test/extensions/common/wasm/test_data:test_cpp.wasm",
"//test/extensions/common/wasm/test_data:test_restriction_cpp.wasm",
]),
external_deps = ["abseil_optional"],
deps = [
Expand All @@ -47,6 +48,7 @@ envoy_cc_test(
"//source/extensions/common/crypto:utility_lib",
"//source/extensions/common/wasm:wasm_lib",
"//test/extensions/common/wasm:wasm_runtime",
"//test/extensions/common/wasm/test_data:test_restriction_cpp_plugin",
"//test/extensions/common/wasm/test_data:test_context_cpp_plugin",
"//test/extensions/common/wasm/test_data:test_cpp_plugin",
"//test/mocks/server:server_mocks",
Expand Down
26 changes: 26 additions & 0 deletions test/extensions/common/wasm/test_data/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,24 @@ envoy_cc_library(
],
)

envoy_cc_library(
name = "test_restriction_cpp_plugin",
srcs = [
"test_restriction_cpp.cc",
"test_restriction_cpp_null_plugin.cc",
],
copts = ["-DNULL_PLUGIN=1"],
deps = [
"//external:abseil_node_hash_map",
"//source/common/common:assert_lib",
"//source/common/common:c_smart_ptr_lib",
"//source/extensions/common/wasm:wasm_hdr",
"//source/extensions/common/wasm:wasm_lib",
"//source/extensions/common/wasm:well_known_names",
"//source/extensions/common/wasm/ext:envoy_null_plugin",
],
)

envoy_wasm_cc_binary(
name = "test_cpp.wasm",
srcs = ["test_cpp.cc"],
Expand All @@ -66,6 +84,14 @@ envoy_wasm_cc_binary(
],
)

envoy_wasm_cc_binary(
name = "test_restriction_cpp.wasm",
srcs = ["test_restriction_cpp.cc"],
deps = [
"@proxy_wasm_cpp_sdk//:proxy_wasm_intrinsics",
],
)

envoy_wasm_cc_binary(
name = "bad_signature_cpp.wasm",
srcs = ["bad_signature_cpp.cc"],
Expand Down
Loading

0 comments on commit f468a96

Please sign in to comment.