tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

SandboxProfiler.h (5265B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
      4 
      5 #ifndef SANDBOX_PROFILER_H
      6 #define SANDBOX_PROFILER_H
      7 
      8 #include <thread>
      9 #include <linux/limits.h>
     10 #include <semaphore.h>
     11 
     12 #include "base/trace_event/common/trace_event_common.h"
     13 
     14 #include "ProfilerNativeStack.h"
     15 #include "MicroGeckoProfiler.h"
     16 
     17 #include "mozilla/ProfileChunkedBuffer.h"
     18 #include "mozilla/ProfilerState.h"
     19 
     20 #include "mozilla/BoundedMPSCQueue.h"
     21 
     22 #if defined(HAVE_REPORT_UPROFILER_PARENT) && \
     23    defined(HAVE_REPORT_UPROFILER_CHILD)
     24 #  error Cannot include SandboxProfilerChild.h AND SandboxProfilerParent.h
     25 #endif
     26 
     27 namespace mozilla {
     28 
     29 #if defined(DEBUG)
     30 extern thread_local Atomic<bool> sInSignalContext;
     31 
     32 class MOZ_STACK_CLASS AutoForbidSignalContext {
     33 public:
     34  AutoForbidSignalContext();
     35  ~AutoForbidSignalContext();
     36 };
     37 #endif  // defined(DEBUG)
     38 
     39 enum class SandboxProfilerPayloadType : uint8_t { Init, Request, Log };
     40 
     41 using SandboxProfilerPayload = struct {
     42  NativeStack mStack;
     43  uint64_t mId;
     44  const char* mOp;
     45  int mFlags;
     46  char mPath[PATH_MAX];
     47  char mPath2[PATH_MAX];
     48  pid_t mPid;
     49  SandboxProfilerPayloadType mType;
     50 };
     51 
     52 using SandboxProfilerQueue = BoundedMPSCQueue<SandboxProfilerPayload, 15>;
     53 
     54 extern struct UprofilerFuncPtrs uprofiler;
     55 extern bool uprofiler_initted;
     56 
     57 class SandboxProfiler final {
     58 public:
     59  SandboxProfiler();
     60  ~SandboxProfiler();
     61 
     62  // Needs to be accessible in both child (within libmozsandbox.so) and parent
     63  // (within libxul.so) it's easier and less of a mess if this is done from the
     64  // header which can more easily be included by both sides.
     65  static bool Active() {
     66    if (!uprofiler_initted) {
     67      return false;
     68    }
     69 
     70    if (!uprofiler.is_active || uprofiler.is_active == is_active_noop) {
     71      return false;
     72    }
     73 
     74    if (!uprofiler.feature_active ||
     75        uprofiler.feature_active == feature_active_noop) {
     76      return false;
     77    }
     78 
     79    return uprofiler.is_active() &&
     80           uprofiler.feature_active(ProfilerFeature::Sandbox);
     81  }
     82 
     83  static void Shutdown();
     84 
     85  // Should NOT BE CALLED UNDER SIGSYS, this is here to make sure we do the
     86  // dlopen()/dlsym() on the main thread so it is available for later use on
     87  // others threads. We expect that only stack trace would be collected under
     88  // SIGSYS context, and the rest of the profiler marker would happen on another
     89  // safer thread.
     90  static inline bool Init();
     91 
     92  static void Create();
     93  static void inline ReportAudit(const char* aKind, const char* aOp, int aFlags,
     94                                 uint64_t aId, int aPerms, const char* aPath,
     95                                 pid_t aPid);
     96  static void ReportRequest(const void* top, uint64_t aId, const char* aOp,
     97                            int aFlags, const char* aPath, const char* aPath2,
     98                            pid_t aPid);
     99  static void ReportInit(const void* top);
    100  static void ReportLog(const char* buf);
    101 
    102 private:
    103  std::thread mThreadLogs;
    104  std::thread mThreadSyscalls;
    105 
    106  // For child and parent, same reason as Active() above
    107  template <typename N, typename T, typename V, size_t len>
    108  static constexpr void Report(const char* aKind, std::array<N, len> aArgNames,
    109                               std::array<T, len> aArgTypes,
    110                               std::array<V, len> aArgValues, void* aStack) {
    111    if (!Active()) {
    112      return;
    113    }
    114 
    115    if (!uprofiler_initted) {
    116      fprintf(stderr, "[%d] no uprofiler, skip\n", getpid());
    117      return;
    118    }
    119 
    120    MOZ_ASSERT(!sInSignalContext,
    121               "SandboxProfiler::Report called in SIGSYS handler");
    122 
    123    if (aStack) {
    124      uprofiler.simple_event_marker_with_stack(
    125          aKind, 'S', 'I', aArgNames.size(), aArgNames.data(), aArgTypes.data(),
    126          aArgValues.data(), aStack);
    127    } else {
    128      uprofiler.simple_event_marker(aKind, 'S', 'I', aArgNames.size(),
    129                                    aArgNames.data(), aArgTypes.data(),
    130                                    aArgValues.data());
    131    }
    132  }
    133 
    134  // Verify that:
    135  //  - Not in shutdown
    136  //  - SandboxProfiler exists
    137  //  - Profiler is active
    138  //  - aQueue exists
    139  static bool ActiveWithQueue(SandboxProfilerQueue* aQueue);
    140 
    141  // Rely on semaphores to handle consuming the queue:
    142  //  - One semaphore per queue (= thread)
    143  //  - Gets SIGNAL'd when a payload has been pushed to the SandboxProfilerQueue
    144  //  - SandboxProfiler dedicated thread WAIT's on the semaphore, gets unblocked
    145  //    on signal
    146  //  - Semaphore's sem_post() is safe to use in a signal context
    147  //  - Using semaphores allows to wake the SandboxProfiler dedicated thread
    148  //    only when needed and avoid using sleep()
    149  static void Signal(sem_t* aSem);
    150  static int Wait(sem_t* aSem);
    151 
    152  void ThreadMain(const char* aThreadName, SandboxProfilerQueue* aQueue,
    153                  sem_t* aRequest);
    154  void ReportInitImpl(SandboxProfilerPayload& payload,
    155                      ProfileChunkedBuffer& buffer);
    156  void ReportLogImpl(SandboxProfilerPayload& payload);
    157  void ReportRequestImpl(SandboxProfilerPayload& payload,
    158                         ProfileChunkedBuffer& buffer);
    159 };
    160 
    161 }  // namespace mozilla
    162 #endif  // SANDBOX_PROFILER_H