Bug 1828389 - Ensure IPC channel is closed with error after KillHard, r=ipc-reviewers,mccr8

This patch changes KillHard() such that the IPC channel is immediately
shut down with an error after a KillHard() is performed. This is done by
fixing the previously-broken CLOSE_CHANNEL_WITH_ERROR support in
ShutDownProcess, and calling that method after KillHard().

This ensures that after the process has been killed, no further messages
will be delivered and processed, even if they were sent before the
process was killed.

In addition, the assertions and KillHard calls which are disabled for
fuzzing were changed to also shut down the channel, making fuzzing IPC
errors cause the connection to be terminated like it is in production
for these actors.

This change does not impact actors which ignore processing errors.

Differential Revision: https://phabricator.services.mozilla.com/D178383
This commit is contained in:
Nika Layzell 2023-05-26 17:44:57 +00:00
Родитель 759d19c6b9
Коммит 2f2588cf4f
21 изменённых файлов: 43 добавлений и 30 удалений

Просмотреть файл

@ -1879,17 +1879,18 @@ bool ContentParent::ShutDownProcess(ShutDownMethod aMethod) {
qms->AbortOperationsForProcess(mChildID);
}
// If Close() fails with an error, we'll end up back in this function, but
// with aMethod = CLOSE_CHANNEL_WITH_ERROR.
if (aMethod == CLOSE_CHANNEL) {
if (aMethod == CLOSE_CHANNEL || aMethod == CLOSE_CHANNEL_WITH_ERROR) {
if (!mCalledClose) {
MaybeLogBlockShutdownDiagnostics(
this, "ShutDownProcess: Closing channel.", __FILE__, __LINE__);
// Close() can only be called once: It kicks off the destruction
// sequence.
// Close()/CloseWithError() can only be called once: They kick off the
// destruction sequence.
mCalledClose = true;
Close();
if (aMethod == CLOSE_CHANNEL_WITH_ERROR) {
CloseWithError();
} else {
Close();
}
}
result = true;
}
@ -2074,10 +2075,11 @@ void ContentParent::ProcessingError(Result aCode, const char* aReason) {
if (MsgDropped == aCode) {
return;
}
#ifndef FUZZING
// Other errors are big deals.
#ifndef FUZZING
KillHard(aReason);
#endif
ShutDownProcess(CLOSE_CHANNEL_WITH_ERROR);
}
void ContentParent::ActorDestroy(ActorDestroyReason why) {
@ -4515,6 +4517,7 @@ void ContentParent::KillHard(const char* aReason) {
ProcessHandle otherProcessHandle;
if (!base::OpenProcessHandle(OtherPid(), &otherProcessHandle)) {
NS_ERROR("Failed to open child process when attempting kill.");
ShutDownProcess(CLOSE_CHANNEL_WITH_ERROR);
return;
}
@ -4535,6 +4538,10 @@ void ContentParent::KillHard(const char* aReason) {
mSubprocess->SetAlreadyDead();
}
// After we've killed the remote process, also ensure we close the IPC channel
// with an error to immediately stop all IPC communication on this channel.
ShutDownProcess(CLOSE_CHANNEL_WITH_ERROR);
// EnsureProcessTerminated has responsibilty for closing otherProcessHandle.
XRE_GetIOMessageLoop()->PostTask(
NewRunnableFunction("EnsureProcessTerminatedRunnable",

Просмотреть файл

@ -859,7 +859,7 @@ void RemoteDecoderManagerChild::DeallocateSurfaceDescriptor(
})));
}
void RemoteDecoderManagerChild::HandleFatalError(const char* aMsg) const {
void RemoteDecoderManagerChild::HandleFatalError(const char* aMsg) {
dom::ContentChild::FatalErrorIfNotUsingGPUProcess(aMsg, OtherPid());
}

Просмотреть файл

@ -107,7 +107,7 @@ class RemoteDecoderManagerChild final
RemoteDecodeIn aLocation);
protected:
void HandleFatalError(const char* aMsg) const override;
void HandleFatalError(const char* aMsg) override;
PRemoteDecoderChild* AllocPRemoteDecoderChild(
const RemoteDecoderInfoIPDL& aRemoteDecoderInfo,

Просмотреть файл

@ -119,7 +119,7 @@ void VsyncBridgeChild::ProcessingError(Result aCode, const char* aReason) {
"Processing error in VsyncBridgeChild");
}
void VsyncBridgeChild::HandleFatalError(const char* aMsg) const {
void VsyncBridgeChild::HandleFatalError(const char* aMsg) {
dom::ContentChild::FatalErrorIfNotUsingGPUProcess(aMsg, OtherPid());
}

Просмотреть файл

@ -31,7 +31,7 @@ class VsyncBridgeChild final : public PVsyncBridgeChild {
void NotifyVsync(const VsyncEvent& aVsync, const layers::LayersId& aLayersId);
void HandleFatalError(const char* aMsg) const override;
void HandleFatalError(const char* aMsg) override;
private:
VsyncBridgeChild(RefPtr<VsyncIOThreadHolder>, const uint64_t& aProcessToken);

Просмотреть файл

@ -211,7 +211,7 @@ void CompositorManagerChild::ActorDestroy(ActorDestroyReason aReason) {
}
}
void CompositorManagerChild::HandleFatalError(const char* aMsg) const {
void CompositorManagerChild::HandleFatalError(const char* aMsg) {
dom::ContentChild::FatalErrorIfNotUsingGPUProcess(aMsg, OtherPid());
}

Просмотреть файл

@ -83,7 +83,7 @@ class CompositorManagerChild : public PCompositorManagerChild {
void ActorDestroy(ActorDestroyReason aReason) override;
void HandleFatalError(const char* aMsg) const override;
void HandleFatalError(const char* aMsg) override;
void ProcessingError(Result aCode, const char* aReason) override;

Просмотреть файл

@ -920,7 +920,7 @@ bool ImageBridgeChild::CanSend() const {
return mCanSend;
}
void ImageBridgeChild::HandleFatalError(const char* aMsg) const {
void ImageBridgeChild::HandleFatalError(const char* aMsg) {
dom::ContentChild::FatalErrorIfNotUsingGPUProcess(aMsg, OtherPid());
}

Просмотреть файл

@ -312,7 +312,7 @@ class ImageBridgeChild final : public PImageBridgeChild,
bool InForwarderThread() override { return InImageBridgeChildThread(); }
void HandleFatalError(const char* aMsg) const override;
void HandleFatalError(const char* aMsg) override;
wr::MaybeExternalImageId GetNextExternalImageId() override;

Просмотреть файл

@ -210,7 +210,7 @@ void UiCompositorControllerChild::ProcessingError(Result aCode,
}
}
void UiCompositorControllerChild::HandleFatalError(const char* aMsg) const {
void UiCompositorControllerChild::HandleFatalError(const char* aMsg) {
dom::ContentChild::FatalErrorIfNotUsingGPUProcess(aMsg, OtherPid());
}

Просмотреть файл

@ -77,7 +77,7 @@ class UiCompositorControllerChild final
protected:
void ActorDestroy(ActorDestroyReason aWhy) override;
void ProcessingError(Result aCode, const char* aReason) override;
void HandleFatalError(const char* aMsg) const override;
void HandleFatalError(const char* aMsg) override;
mozilla::ipc::IPCResult RecvToolbarAnimatorMessageFromCompositor(
const int32_t& aMessage);
mozilla::ipc::IPCResult RecvRootFrameMetrics(const ScreenPoint& aScrollOffset,

Просмотреть файл

@ -166,7 +166,7 @@ bool VideoBridgeChild::IsSameProcess() const {
return OtherPid() == base::GetCurrentProcId();
}
void VideoBridgeChild::HandleFatalError(const char* aMsg) const {
void VideoBridgeChild::HandleFatalError(const char* aMsg) {
dom::ContentChild::FatalErrorIfNotUsingGPUProcess(aMsg, OtherPid());
}

Просмотреть файл

@ -63,7 +63,7 @@ class VideoBridgeChild final : public PVideoBridgeChild,
static void Open(Endpoint<PVideoBridgeChild>&& aEndpoint);
protected:
void HandleFatalError(const char* aMsg) const override;
void HandleFatalError(const char* aMsg) override;
bool DispatchAllocShmemInternal(size_t aSize, mozilla::ipc::Shmem* aShmem,
bool aUnsafe);
void ProxyAllocShmemNow(SynchronousTask* aTask, size_t aSize,

Просмотреть файл

@ -589,7 +589,7 @@ void VRManagerChild::StopActivity() {
Unused << SendStopActivity();
}
void VRManagerChild::HandleFatalError(const char* aMsg) const {
void VRManagerChild::HandleFatalError(const char* aMsg) {
dom::ContentChild::FatalErrorIfNotUsingGPUProcess(aMsg, OtherPid());
}

Просмотреть файл

@ -102,7 +102,7 @@ class VRManagerChild : public PVRManagerChild {
void FireDOMVRDisplayPresentChangeEvent(uint32_t aDisplayID);
void FireDOMVRDisplayConnectEventsForLoad(VRManagerEventObserver* aObserver);
void HandleFatalError(const char* aMsg) const override;
void HandleFatalError(const char* aMsg) override;
void ActorDestroy(ActorDestroyReason aReason) override;
void RunPuppet(const nsTArray<uint64_t>& aBuffer, dom::Promise* aPromise,

Просмотреть файл

@ -389,17 +389,20 @@ Maybe<IProtocol*> IProtocol::ReadActor(IPC::MessageReader* aReader,
return Some(listener);
}
void IProtocol::FatalError(const char* const aErrorMsg) const {
void IProtocol::FatalError(const char* const aErrorMsg) {
HandleFatalError(aErrorMsg);
}
void IProtocol::HandleFatalError(const char* aErrorMsg) const {
void IProtocol::HandleFatalError(const char* aErrorMsg) {
if (IProtocol* manager = Manager()) {
manager->HandleFatalError(aErrorMsg);
return;
}
mozilla::ipc::FatalError(aErrorMsg, mSide == ParentSide);
if (CanSend()) {
GetIPCChannel()->CloseWithError();
}
}
bool IProtocol::AllocShmem(size_t aSize, Shmem* aOutMem) {
@ -630,6 +633,8 @@ void IToplevelProtocol::NotifyImpendingShutdown() {
void IToplevelProtocol::Close() { GetIPCChannel()->Close(); }
void IToplevelProtocol::CloseWithError() { GetIPCChannel()->CloseWithError(); }
void IToplevelProtocol::SetReplyTimeoutMs(int32_t aTimeoutMs) {
GetIPCChannel()->SetReplyTimeoutMs(aTimeoutMs);
}

Просмотреть файл

@ -242,8 +242,8 @@ class IProtocol : public HasResultCodes {
bool AllocUnsafeShmem(size_t aSize, Shmem* aOutMem);
bool DeallocShmem(Shmem& aMem);
void FatalError(const char* const aErrorMsg) const;
virtual void HandleFatalError(const char* aErrorMsg) const;
void FatalError(const char* const aErrorMsg);
virtual void HandleFatalError(const char* aErrorMsg);
protected:
virtual ~IProtocol();
@ -433,6 +433,7 @@ class IToplevelProtocol : public IProtocol {
void NotifyImpendingShutdown();
void Close();
void CloseWithError();
void SetReplyTimeoutMs(int32_t aTimeoutMs);

Просмотреть файл

@ -23,7 +23,7 @@ mozilla::ipc::IPCResult TestActorPunningParent::RecvPun(
// By default, fatal errors kill the parent process, but this makes it
// hard to test, so instead we use the previous behavior and kill the
// child process.
void TestActorPunningParent::HandleFatalError(const char* aErrorMsg) const {
void TestActorPunningParent::HandleFatalError(const char* aErrorMsg) {
if (!!strcmp(aErrorMsg, "Error deserializing 'PTestActorPunningSubParent'")) {
fail("wrong fatal error");
}

Просмотреть файл

@ -38,7 +38,7 @@ class TestActorPunningParent : public PTestActorPunningParent {
QuitParent();
}
virtual void HandleFatalError(const char* aErrorMsg) const override;
virtual void HandleFatalError(const char* aErrorMsg) override;
};
class TestActorPunningPunnedParent : public PTestActorPunningPunnedParent {

Просмотреть файл

@ -19,7 +19,7 @@ void TestBadActorParent::Main() {
// By default, fatal errors kill the parent process, but this makes it
// hard to test, so instead we use the previous behavior and kill the
// child process.
void TestBadActorParent::HandleFatalError(const char* aErrorMsg) const {
void TestBadActorParent::HandleFatalError(const char* aErrorMsg) {
if (!!strcmp(aErrorMsg, "incoming message racing with actor deletion")) {
fail("wrong fatal error");
}

Просмотреть файл

@ -31,7 +31,7 @@ class TestBadActorParent : public PTestBadActorParent {
QuitParent();
}
virtual void HandleFatalError(const char* aErrorMsg) const override;
virtual void HandleFatalError(const char* aErrorMsg) override;
PTestBadActorSubParent* AllocPTestBadActorSubParent();