diff options
author | Moonchild <moonchild@palemoon.org> | 2021-05-03 11:35:41 +0000 |
---|---|---|
committer | Moonchild <moonchild@palemoon.org> | 2021-05-03 11:35:41 +0000 |
commit | 1bf0734a7249eb0dc1a96d825e7310eb46cac6dc (patch) | |
tree | 1f941b9822dabf5301601c83b3ac8ab91d8a622e /xpcom/build/PoisonIOInterposerMac.cpp | |
parent | b1eb04d3f0fde242edb8e9b8b11d00539ceeade7 (diff) | |
download | uxp-1bf0734a7249eb0dc1a96d825e7310eb46cac6dc.tar.gz |
Issue #1751 -- Remove XP_MACOSX conditionals and support files from /xpcom
Diffstat (limited to 'xpcom/build/PoisonIOInterposerMac.cpp')
-rw-r--r-- | xpcom/build/PoisonIOInterposerMac.cpp | 385 |
1 files changed, 0 insertions, 385 deletions
diff --git a/xpcom/build/PoisonIOInterposerMac.cpp b/xpcom/build/PoisonIOInterposerMac.cpp deleted file mode 100644 index dca9ba0297..0000000000 --- a/xpcom/build/PoisonIOInterposerMac.cpp +++ /dev/null @@ -1,385 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "PoisonIOInterposer.h" -#include "mach_override.h" - -#include "mozilla/ArrayUtils.h" -#include "mozilla/Assertions.h" -#include "mozilla/DebugOnly.h" -#include "mozilla/IOInterposer.h" -#include "mozilla/Mutex.h" -#include "mozilla/ProcessedStack.h" -#include "mozilla/Telemetry.h" -#include "mozilla/UniquePtrExtensions.h" -#include "nsPrintfCString.h" -#include "mozilla/StackWalk.h" -#include "nsTraceRefcnt.h" -#include "plstr.h" -#include "prio.h" - -#include <algorithm> -#include <vector> - -#include <sys/param.h> -#include <sys/stat.h> -#include <sys/socket.h> -#include <sys/uio.h> -#include <aio.h> -#include <dlfcn.h> -#include <fcntl.h> -#include <unistd.h> - -#ifdef MOZ_REPLACE_MALLOC -#include "replace_malloc_bridge.h" -#endif - -namespace { - -using namespace mozilla; - -// Bit tracking if poisoned writes are enabled -static bool sIsEnabled = false; - -// Check if writes are dirty before reporting IO -static bool sOnlyReportDirtyWrites = false; - -// Routines for write validation -bool IsValidWrite(int aFd, const void* aWbuf, size_t aCount); -bool IsIPCWrite(int aFd, const struct stat& aBuf); - -/******************************** IO AutoTimer ********************************/ - -/** - * RAII class for timing the duration of an I/O call and reporting the result - * to the IOInterposeObserver API. - */ -class MacIOAutoObservation : public IOInterposeObserver::Observation -{ -public: - MacIOAutoObservation(IOInterposeObserver::Operation aOp, int aFd) - : IOInterposeObserver::Observation(aOp, sReference, sIsEnabled && - !IsDebugFile(aFd)) - , mFd(aFd) - , mHasQueriedFilename(false) - , mFilename(nullptr) - { - } - - MacIOAutoObservation(IOInterposeObserver::Operation aOp, int aFd, - const void* aBuf, size_t aCount) - : IOInterposeObserver::Observation(aOp, sReference, sIsEnabled && - !IsDebugFile(aFd) && - IsValidWrite(aFd, aBuf, aCount)) - , mFd(aFd) - , mHasQueriedFilename(false) - , mFilename(nullptr) - { - } - - // Custom implementation of IOInterposeObserver::Observation::Filename - const char16_t* Filename() override; - - ~MacIOAutoObservation() - { - Report(); - if (mFilename) { - free(mFilename); - mFilename = nullptr; - } - } - -private: - int mFd; - bool mHasQueriedFilename; - char16_t* mFilename; - static const char* sReference; -}; - -const char* MacIOAutoObservation::sReference = "PoisonIOInterposer"; - -// Get filename for this observation -const char16_t* -MacIOAutoObservation::Filename() -{ - // If mHasQueriedFilename is true, then we already have it - if (mHasQueriedFilename) { - return mFilename; - } - char filename[MAXPATHLEN]; - if (fcntl(mFd, F_GETPATH, filename) != -1) { - mFilename = UTF8ToNewUnicode(nsDependentCString(filename)); - } else { - mFilename = nullptr; - } - mHasQueriedFilename = true; - - // Return filename - return mFilename; -} - -/****************************** Write Validation ******************************/ - -// We want to detect "actual" writes, not IPC. Some IPC mechanisms are -// implemented with file descriptors, so filter them out. -bool -IsIPCWrite(int aFd, const struct stat& aBuf) -{ - if ((aBuf.st_mode & S_IFMT) == S_IFIFO) { - return true; - } - - if ((aBuf.st_mode & S_IFMT) != S_IFSOCK) { - return false; - } - - sockaddr_storage address; - socklen_t len = sizeof(address); - if (getsockname(aFd, (sockaddr*)&address, &len) != 0) { - return true; // Ignore the aFd if we can't find what it is. - } - - return address.ss_family == AF_UNIX; -} - -// We want to report actual disk IO not things that don't move bits on the disk -bool -IsValidWrite(int aFd, const void* aWbuf, size_t aCount) -{ - // Ignore writes of zero bytes, Firefox does some during shutdown. - if (aCount == 0) { - return false; - } - - { - struct stat buf; - int rv = fstat(aFd, &buf); - if (rv != 0) { - return true; - } - - if (IsIPCWrite(aFd, buf)) { - return false; - } - } - - // For writev we pass a nullptr aWbuf. We should only get here from - // dbm, and it uses write, so assert that we have aWbuf. - if (!aWbuf) { - return true; - } - - // Break, here if we're allowed to report non-dirty writes - if (!sOnlyReportDirtyWrites) { - return true; - } - - // As a really bad hack, accept writes that don't change the on disk - // content. This is needed because dbm doesn't keep track of dirty bits - // and can end up writing the same data to disk twice. Once when the - // user (nss) asks it to sync and once when closing the database. - auto wbuf2 = MakeUniqueFallible<char[]>(aCount); - if (!wbuf2) { - return true; - } - off_t pos = lseek(aFd, 0, SEEK_CUR); - if (pos == -1) { - return true; - } - ssize_t r = read(aFd, wbuf2.get(), aCount); - if (r < 0 || (size_t)r != aCount) { - return true; - } - int cmp = memcmp(aWbuf, wbuf2.get(), aCount); - if (cmp != 0) { - return true; - } - off_t pos2 = lseek(aFd, pos, SEEK_SET); - if (pos2 != pos) { - return true; - } - - // Otherwise this is not a valid write - return false; -} - -/*************************** Function Interception ***************************/ - -/** Structure for declaration of function override */ -struct FuncData -{ - const char* Name; // Name of the function for the ones we use dlsym - const void* Wrapper; // The function that we will replace 'Function' with - void* Function; // The function that will be replaced with 'Wrapper' - void* Buffer; // Will point to the jump buffer that lets us call - // 'Function' after it has been replaced. -}; - -// Wrap aio_write. We have not seen it before, so just assert/report it. -typedef ssize_t (*aio_write_t)(struct aiocb* aAioCbp); -ssize_t wrap_aio_write(struct aiocb* aAioCbp); -FuncData aio_write_data = { 0, (void*)wrap_aio_write, (void*)aio_write }; -ssize_t -wrap_aio_write(struct aiocb* aAioCbp) -{ - MacIOAutoObservation timer(IOInterposeObserver::OpWrite, - aAioCbp->aio_fildes); - - aio_write_t old_write = (aio_write_t)aio_write_data.Buffer; - return old_write(aAioCbp); -} - -// Wrap pwrite-like functions. -// We have not seen them before, so just assert/report it. -typedef ssize_t (*pwrite_t)(int aFd, const void* buf, size_t aNumBytes, - off_t aOffset); -template<FuncData& foo> -ssize_t -wrap_pwrite_temp(int aFd, const void* aBuf, size_t aNumBytes, off_t aOffset) -{ - MacIOAutoObservation timer(IOInterposeObserver::OpWrite, aFd); - pwrite_t old_write = (pwrite_t)foo.Buffer; - return old_write(aFd, aBuf, aNumBytes, aOffset); -} - -// Define a FuncData for a pwrite-like functions. -#define DEFINE_PWRITE_DATA(X, NAME) \ -FuncData X ## _data = { NAME, (void*) wrap_pwrite_temp<X ## _data> }; \ - -// This exists everywhere. -DEFINE_PWRITE_DATA(pwrite, "pwrite") -// These exist on 32 bit OS X -DEFINE_PWRITE_DATA(pwrite_NOCANCEL_UNIX2003, "pwrite$NOCANCEL$UNIX2003"); -DEFINE_PWRITE_DATA(pwrite_UNIX2003, "pwrite$UNIX2003"); -// This exists on 64 bit OS X -DEFINE_PWRITE_DATA(pwrite_NOCANCEL, "pwrite$NOCANCEL"); - - -typedef ssize_t (*writev_t)(int aFd, const struct iovec* aIov, int aIovCount); -template<FuncData& foo> -ssize_t -wrap_writev_temp(int aFd, const struct iovec* aIov, int aIovCount) -{ - MacIOAutoObservation timer(IOInterposeObserver::OpWrite, aFd, nullptr, - aIovCount); - writev_t old_write = (writev_t)foo.Buffer; - return old_write(aFd, aIov, aIovCount); -} - -// Define a FuncData for a writev-like functions. -#define DEFINE_WRITEV_DATA(X, NAME) \ -FuncData X ## _data = { NAME, (void*) wrap_writev_temp<X ## _data> }; \ - -// This exists everywhere. -DEFINE_WRITEV_DATA(writev, "writev"); -// These exist on 32 bit OS X -DEFINE_WRITEV_DATA(writev_NOCANCEL_UNIX2003, "writev$NOCANCEL$UNIX2003"); -DEFINE_WRITEV_DATA(writev_UNIX2003, "writev$UNIX2003"); -// This exists on 64 bit OS X -DEFINE_WRITEV_DATA(writev_NOCANCEL, "writev$NOCANCEL"); - -typedef ssize_t (*write_t)(int aFd, const void* aBuf, size_t aCount); -template<FuncData& foo> -ssize_t -wrap_write_temp(int aFd, const void* aBuf, size_t aCount) -{ - MacIOAutoObservation timer(IOInterposeObserver::OpWrite, aFd, aBuf, aCount); - write_t old_write = (write_t)foo.Buffer; - return old_write(aFd, aBuf, aCount); -} - -// Define a FuncData for a write-like functions. -#define DEFINE_WRITE_DATA(X, NAME) \ -FuncData X ## _data = { NAME, (void*) wrap_write_temp<X ## _data> }; \ - -// This exists everywhere. -DEFINE_WRITE_DATA(write, "write"); -// These exist on 32 bit OS X -DEFINE_WRITE_DATA(write_NOCANCEL_UNIX2003, "write$NOCANCEL$UNIX2003"); -DEFINE_WRITE_DATA(write_UNIX2003, "write$UNIX2003"); -// This exists on 64 bit OS X -DEFINE_WRITE_DATA(write_NOCANCEL, "write$NOCANCEL"); - -FuncData* Functions[] = { - &aio_write_data, - - &pwrite_data, - &pwrite_NOCANCEL_UNIX2003_data, - &pwrite_UNIX2003_data, - &pwrite_NOCANCEL_data, - - &write_data, - &write_NOCANCEL_UNIX2003_data, - &write_UNIX2003_data, - &write_NOCANCEL_data, - - &writev_data, - &writev_NOCANCEL_UNIX2003_data, - &writev_UNIX2003_data, - &writev_NOCANCEL_data -}; - -const int NumFunctions = ArrayLength(Functions); - -} // namespace - -/******************************** IO Poisoning ********************************/ - -namespace mozilla { - -void -InitPoisonIOInterposer() -{ - // Enable reporting from poisoned write methods - sIsEnabled = true; - - // Make sure we only poison writes once! - static bool WritesArePoisoned = false; - if (WritesArePoisoned) { - return; - } - WritesArePoisoned = true; - - // stdout and stderr are OK. - MozillaRegisterDebugFD(1); - MozillaRegisterDebugFD(2); - -#ifdef MOZ_REPLACE_MALLOC - // The contract with InitDebugFd is that the given registry can be used - // at any moment, so the instance needs to persist longer than the scope - // of this functions. - static DebugFdRegistry registry; - ReplaceMalloc::InitDebugFd(registry); -#endif - - for (int i = 0; i < NumFunctions; ++i) { - FuncData* d = Functions[i]; - if (!d->Function) { - d->Function = dlsym(RTLD_DEFAULT, d->Name); - } - if (!d->Function) { - continue; - } - DebugOnly<mach_error_t> t = mach_override_ptr(d->Function, d->Wrapper, - &d->Buffer); - MOZ_ASSERT(t == err_none); - } -} - -void -OnlyReportDirtyWrites() -{ - sOnlyReportDirtyWrites = true; -} - -void -ClearPoisonIOInterposer() -{ - // Not sure how or if we can unpoison the functions. Would be nice, but no - // worries we won't need to do this anyway. - sIsEnabled = false; -} - -} // namespace mozilla |