Commit f6a42075 authored by Ken Rockot's avatar Ken Rockot Committed by Commit Bot

[Mojo] Add SetDefaultProcessErrorHandler ABI

This adds SetDefaultProcessErrorHandler to the public C ABI for Mojo
Core to replace the only remaining non-public, non-Init, non-test-only
API in the mojo::core namespace.

Setting a default process error handler is something the Network Service
uses as part of its own application logic in order to generate useful
crash reports when bad IPCs are received. This suggests that the feature
belongs in the public API, and indeed it must be exposed there in order
to support Chrome loading Mojo Core dynamically in some runtime
environments.

A follow-up CL will transition call sites from the static mojo::core API
to this new public one.

helper in mojo/public/cpp/test_support, which is migrated to the public
API by this CL.

Bug: 1082473
Test: Several content_unittests tests rely on the BadMessageObserver
Change-Id: I77378467afde722b8173df56538221fcaf82a4eb
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2227866
Commit-Queue: Ken Rockot <rockot@google.com>
Reviewed-by: default avatarOksana Zhuravlova <oksamyt@chromium.org>
Cr-Commit-Position: refs/heads/master@{#774869}
parent 349207a3
......@@ -1477,6 +1477,29 @@ MojoResult Core::QueryQuota(MojoHandle handle,
return dispatcher->QueryQuota(type, limit, usage);
}
MojoResult Core::SetDefaultProcessErrorHandler(
MojoDefaultProcessErrorHandler handler,
const MojoSetDefaultProcessErrorHandlerOptions* options) {
if (default_process_error_callback_ && handler)
return MOJO_RESULT_ALREADY_EXISTS;
if (!handler) {
default_process_error_callback_.Reset();
return MOJO_RESULT_OK;
}
default_process_error_callback_ = base::BindRepeating(
[](MojoDefaultProcessErrorHandler handler, const std::string& error) {
MojoProcessErrorDetails details = {0};
details.struct_size = sizeof(details);
details.error_message_length = static_cast<uint32_t>(error.size());
details.error_message = error.c_str();
handler(&details);
},
handler);
return MOJO_RESULT_OK;
}
void Core::GetActiveHandlesForTest(std::vector<MojoHandle>* handles) {
base::AutoLock lock(handles_->GetLock());
handles_->GetActiveHandlesForTest(handles);
......
......@@ -325,6 +325,10 @@ class MOJO_SYSTEM_IMPL_EXPORT Core {
uint64_t* limit,
uint64_t* usage);
MojoResult SetDefaultProcessErrorHandler(
MojoDefaultProcessErrorHandler handler,
const MojoSetDefaultProcessErrorHandlerOptions* options);
void GetActiveHandlesForTest(std::vector<MojoHandle>* handles);
private:
......
......@@ -350,6 +350,12 @@ MojoResult MojoShutdownImpl(const MojoShutdownOptions* options) {
return MOJO_RESULT_UNIMPLEMENTED;
}
MojoResult MojoSetDefaultProcessErrorHandlerImpl(
MojoDefaultProcessErrorHandler handler,
const MojoSetDefaultProcessErrorHandlerOptions* options) {
return g_core->SetDefaultProcessErrorHandler(handler, options);
}
} // extern "C"
MojoSystemThunks g_thunks = {sizeof(MojoSystemThunks),
......@@ -396,7 +402,8 @@ MojoSystemThunks g_thunks = {sizeof(MojoSystemThunks),
MojoAcceptInvitationImpl,
MojoSetQuotaImpl,
MojoQueryQuotaImpl,
MojoShutdownImpl};
MojoShutdownImpl,
MojoSetDefaultProcessErrorHandlerImpl};
} // namespace
......
......@@ -12,6 +12,7 @@
#include <stddef.h>
#include <stdint.h>
#include "mojo/public/c/system/invitation.h"
#include "mojo/public/c/system/system_export.h"
#include "mojo/public/c/system/types.h"
......
......@@ -251,6 +251,25 @@ struct MOJO_ALIGNAS(8) MojoAcceptInvitationOptions {
MOJO_STATIC_ASSERT(sizeof(struct MojoAcceptInvitationOptions) == 8,
"MojoAcceptInvitationOptions has wrong size");
// Flags passed to |MojoSetDefaultProcessErrorHandler()| via
// |MojoSetDefaultProcessErrorHandlerOptions|.
typedef uint32_t MojoSetDefaultProcessErrorHandlerFlags;
// No flags. Default behavior.
#define MOJO_SET_DEFAULT_PROCESS_ERROR_HANDLER_FLAG_NONE \
((MojoSetDefaultProcessErrorHandlerFlags)0)
// Options passed to |MojoSetDefaultProcessErrorHandler()|.
struct MOJO_ALIGNAS(8) MojoSetDefaultProcessErrorHandlerOptions {
// The size of this structure, used for versioning.
uint32_t struct_size;
// See |MojoSetDefaultProcessErrorHandlerFlags|.
MojoSetDefaultProcessErrorHandlerFlags flags;
};
MOJO_STATIC_ASSERT(sizeof(struct MojoSetDefaultProcessErrorHandlerOptions) == 8,
"MojoSetDefaultProcessErrorHandlerOptions has wrong size");
#ifdef __cplusplus
extern "C" {
#endif
......@@ -266,6 +285,12 @@ typedef void (*MojoProcessErrorHandler)(
uintptr_t context,
const struct MojoProcessErrorDetails* details);
// Similar to above, but registered globally via
// |MojoSetDefaultProcessErrorHandler()| and invoked only for communication
// errors regarding processes NOT invited by the calling process.
typedef void (*MojoDefaultProcessErrorHandler)(
const struct MojoProcessErrorDetails* details);
// Creates a new invitation to be sent to another process.
//
// An invitation is used to invite another process to join this process's
......@@ -474,6 +499,31 @@ MOJO_SYSTEM_EXPORT MojoResult MojoAcceptInvitation(
const struct MojoAcceptInvitationOptions* options,
MojoHandle* invitation_handle);
// Registers a process-wide handler to be invoked when an error is raised on a
// connection to a peer process. Such errors can be raised if the peer process
// sends malformed data to this process.
//
// Note that this handler is only invoked for connections to processes NOT
// explicitly invited by this process. To handle errors concerning processes
// invited by this process, see the MojoProcessErrorHandler argument to
// |MojoSendInvitation()|.
//
// The general use case for this API is to be able to log or report instances of
// bad IPCs received by a client process which no real ability or authority to
// identify the source.
//
// Returns:
// |MOJO_RESULT_OK| if |handler| is successfully registered as the global
// default process error handler within the calling process. If |handler|
// is null, any registered default process error handler is removed.
// |MOJO_RESULT_ALREADY_EXISTS| if |handler| is non-null and there is already
// a registered error handler. Callers wishing to replace an existing
// handler must first call |MojoSetDefaultProcessErrorHandler()| with null
// in order to do so.
MOJO_SYSTEM_EXPORT MojoResult MojoSetDefaultProcessErrorHandler(
MojoDefaultProcessErrorHandler handler,
const struct MojoSetDefaultProcessErrorHandlerOptions* options);
#ifdef __cplusplus
} // extern "C"
#endif
......
......@@ -476,6 +476,12 @@ MojoResult MojoShutdown(const MojoShutdownOptions* options) {
return INVOKE_THUNK(Shutdown, options);
}
MojoResult MojoSetDefaultProcessErrorHandler(
MojoDefaultProcessErrorHandler handler,
const struct MojoSetDefaultProcessErrorHandlerOptions* options) {
return INVOKE_THUNK(SetDefaultProcessErrorHandler, handler, options);
}
} // extern "C"
void MojoEmbedderSetSystemThunks(const MojoSystemThunks* thunks) {
......
......@@ -228,6 +228,11 @@ struct MojoSystemThunks {
// Core ABI version 2 additions begin here.
MojoResult (*Shutdown)(const struct MojoShutdownOptions* options);
// Core ABI version 3 additions begin here.
MojoResult (*SetDefaultProcessErrorHandler)(
MojoDefaultProcessErrorHandler handler,
const struct MojoSetDefaultProcessErrorHandlerOptions* options);
};
#pragma pack(pop)
......
......@@ -21,6 +21,7 @@ component("system") {
"file_data_source.h",
"filtered_data_source.cc",
"filtered_data_source.h",
"functions.cc",
"functions.h",
"handle.h",
"handle_signal_tracker.cc",
......
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "mojo/public/cpp/system/functions.h"
#include "base/callback.h"
#include "base/no_destructor.h"
namespace mojo {
namespace {
DefaultProcessErrorHandler& GetDefaultProcessErrorHandler() {
static base::NoDestructor<DefaultProcessErrorHandler> handler;
return *handler;
}
void HandleError(const MojoProcessErrorDetails* details) {
const DefaultProcessErrorHandler& handler = GetDefaultProcessErrorHandler();
handler.Run(
std::string(details->error_message, details->error_message_length));
}
} // namespace
void SetDefaultProcessErrorHandler(DefaultProcessErrorHandler handler) {
// Ensure any previously set handler is wiped out.
MojoSetDefaultProcessErrorHandler(nullptr, nullptr);
auto& global_handler = GetDefaultProcessErrorHandler();
global_handler = std::move(handler);
if (global_handler)
MojoSetDefaultProcessErrorHandler(&HandleError, nullptr);
}
} // namespace mojo
......@@ -11,7 +11,11 @@
#ifndef MOJO_PUBLIC_CPP_SYSTEM_FUNCTIONS_H_
#define MOJO_PUBLIC_CPP_SYSTEM_FUNCTIONS_H_
#include <string>
#include "base/callback_forward.h"
#include "mojo/public/c/system/functions.h"
#include "mojo/public/cpp/system/system_export.h"
namespace mojo {
......@@ -21,6 +25,17 @@ inline MojoTimeTicks GetTimeTicksNow() {
return MojoGetTimeTicksNow();
}
// Sets a callback to handle communication errors regarding peer processes whose
// identity is not explicitly known by this process, i.e. processes that are
// part of the same Mojo process network but which were not invited by this
// process.
//
// This can be used to globally listen for reports of bad incoming IPCs.
using DefaultProcessErrorHandler =
base::RepeatingCallback<void(const std::string& error)>;
void MOJO_CPP_SYSTEM_EXPORT
SetDefaultProcessErrorHandler(DefaultProcessErrorHandler handler);
} // namespace mojo
#endif // MOJO_PUBLIC_CPP_SYSTEM_FUNCTIONS_H_
......@@ -12,7 +12,6 @@ static_library("test_utils") {
]
deps = [
"//mojo/core/embedder",
"//mojo/public/c/test_support",
"//mojo/public/cpp/bindings",
"//mojo/public/cpp/system",
......
......@@ -10,7 +10,7 @@
#include <vector>
#include "base/bind.h"
#include "mojo/core/embedder/embedder.h"
#include "base/bind_helpers.h"
#include "mojo/public/cpp/system/core.h"
#include "mojo/public/cpp/system/wait.h"
#include "mojo/public/cpp/test_support/test_support.h"
......@@ -80,13 +80,12 @@ void IterateAndReportPerf(const char* test_name,
}
BadMessageObserver::BadMessageObserver() : got_bad_message_(false) {
mojo::core::SetDefaultProcessErrorCallback(base::BindRepeating(
mojo::SetDefaultProcessErrorHandler(base::BindRepeating(
&BadMessageObserver::OnReportBadMessage, base::Unretained(this)));
}
BadMessageObserver::~BadMessageObserver() {
mojo::core::SetDefaultProcessErrorCallback(
mojo::core::ProcessErrorCallback());
mojo::SetDefaultProcessErrorHandler(base::NullCallback());
}
std::string BadMessageObserver::WaitForBadMessage() {
......
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