DXR is a code search and navigation tool aimed at making sense of large projects. It supports full-text and regex searches as well as structural queries.

Header

Mercurial (2d7b281bdf5d)

VCS Links

Line Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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 "SandboxFilterUtil.h"

#ifndef ANDROID
#  include <linux/ipc.h>
#endif
#include <linux/net.h>
#include <sys/socket.h>
#include <sys/syscall.h>
#include <unistd.h>

#include "mozilla/UniquePtr.h"
#include "sandbox/linux/bpf_dsl/bpf_dsl.h"

// Older kernel headers (mostly Android, but also some older desktop
// distributions) are missing some or all of these:
#ifndef SYS_ACCEPT4
#  define SYS_ACCEPT4 18
#endif
#ifndef SYS_RECVMMSG
#  define SYS_RECVMMSG 19
#endif
#ifndef SYS_SENDMMSG
#  define SYS_SENDMMSG 20
#endif

using namespace sandbox::bpf_dsl;
#define CASES SANDBOX_BPF_DSL_CASES

namespace mozilla {

sandbox::bpf_dsl::ResultExpr SandboxPolicyBase::EvaluateSyscall(
    int aSysno) const {
  switch (aSysno) {
#ifdef __NR_socketcall
    case __NR_socketcall: {
      Arg<int> call(0);
      UniquePtr<Caser<int>> acc(new Caser<int>(Switch(call)));
      for (int i = SYS_SOCKET; i <= SYS_SENDMMSG; ++i) {
        auto thisCase = EvaluateSocketCall(i, false);
        // Optimize out cases that are equal to the default.
        if (thisCase) {
          acc.reset(new Caser<int>(acc->Case(i, *thisCase)));
        }
      }
      return acc->Default(InvalidSyscall());
    }
#  ifndef ANDROID
    case __NR_ipc: {
      Arg<int> callAndVersion(0);
      auto call = callAndVersion & 0xFFFF;
      UniquePtr<Caser<int>> acc(new Caser<int>(Switch(call)));
      for (int i = SEMOP; i <= DIPC; ++i) {
        auto thisCase = EvaluateIpcCall(i);
        // Optimize out cases that are equal to the default.
        if (thisCase) {
          acc.reset(new Caser<int>(acc->Case(i, *thisCase)));
        }
      }
      return acc->Default(InvalidSyscall());
    }
#  endif  // ANDROID
#endif    // __NR_socketcall
          // clang-format off
#define DISPATCH_SOCKETCALL(sysnum, socketnum) \
  case sysnum:                                 \
    return EvaluateSocketCall(socketnum, true).valueOr(InvalidSyscall())
#ifdef __NR_socket
      DISPATCH_SOCKETCALL(__NR_socket,      SYS_SOCKET);
      DISPATCH_SOCKETCALL(__NR_bind,        SYS_BIND);
      DISPATCH_SOCKETCALL(__NR_connect,     SYS_CONNECT);
      DISPATCH_SOCKETCALL(__NR_listen,      SYS_LISTEN);
#ifdef __NR_accept
      DISPATCH_SOCKETCALL(__NR_accept,      SYS_ACCEPT);
#endif
      DISPATCH_SOCKETCALL(__NR_getsockname, SYS_GETSOCKNAME);
      DISPATCH_SOCKETCALL(__NR_getpeername, SYS_GETPEERNAME);
      DISPATCH_SOCKETCALL(__NR_socketpair,  SYS_SOCKETPAIR);
#ifdef __NR_send
      DISPATCH_SOCKETCALL(__NR_send,        SYS_SEND);
      DISPATCH_SOCKETCALL(__NR_recv,        SYS_RECV);
#endif  // __NR_send
      DISPATCH_SOCKETCALL(__NR_sendto,      SYS_SENDTO);
      DISPATCH_SOCKETCALL(__NR_recvfrom,    SYS_RECVFROM);
      DISPATCH_SOCKETCALL(__NR_shutdown,    SYS_SHUTDOWN);
      DISPATCH_SOCKETCALL(__NR_setsockopt,  SYS_SETSOCKOPT);
      DISPATCH_SOCKETCALL(__NR_getsockopt,  SYS_GETSOCKOPT);
      DISPATCH_SOCKETCALL(__NR_sendmsg,     SYS_SENDMSG);
      DISPATCH_SOCKETCALL(__NR_recvmsg,     SYS_RECVMSG);
      DISPATCH_SOCKETCALL(__NR_accept4,     SYS_ACCEPT4);
      DISPATCH_SOCKETCALL(__NR_recvmmsg,    SYS_RECVMMSG);
      DISPATCH_SOCKETCALL(__NR_sendmmsg,    SYS_SENDMMSG);
#endif  // __NR_socket
#undef DISPATCH_SOCKETCALL
#ifndef __NR_socketcall
#ifndef ANDROID
#define DISPATCH_SYSVCALL(sysnum, ipcnum) \
  case sysnum:                            \
    return EvaluateIpcCall(ipcnum).valueOr(InvalidSyscall())
      DISPATCH_SYSVCALL(__NR_semop,       SEMOP);
      DISPATCH_SYSVCALL(__NR_semget,      SEMGET);
      DISPATCH_SYSVCALL(__NR_semctl,      SEMCTL);
      DISPATCH_SYSVCALL(__NR_semtimedop,  SEMTIMEDOP);
      DISPATCH_SYSVCALL(__NR_msgsnd,      MSGSND);
      DISPATCH_SYSVCALL(__NR_msgrcv,      MSGRCV);
      DISPATCH_SYSVCALL(__NR_msgget,      MSGGET);
      DISPATCH_SYSVCALL(__NR_msgctl,      MSGCTL);
      DISPATCH_SYSVCALL(__NR_shmat,       SHMAT);
      DISPATCH_SYSVCALL(__NR_shmdt,       SHMDT);
      DISPATCH_SYSVCALL(__NR_shmget,      SHMGET);
      DISPATCH_SYSVCALL(__NR_shmctl,      SHMCTL);
#undef DISPATCH_SYSVCALL
#endif  // ANDROID
#endif  // __NR_socketcall
          // clang-format on
    default:
      return InvalidSyscall();
  }
}

/* static */ bool SandboxPolicyBase::HasSeparateSocketCalls() {
#ifdef __NR_socket
  // If there's no socketcall, then obviously there are separate syscalls.
#  ifdef __NR_socketcall
  // This could be memoized, but currently it's called at most once
  // per process.
  int fd = syscall(__NR_socket, AF_LOCAL, SOCK_STREAM, 0);
  if (fd < 0) {
    MOZ_DIAGNOSTIC_ASSERT(errno == ENOSYS);
    return false;
  }
  close(fd);
#  endif  // __NR_socketcall
  return true;
#else   // ifndef __NR_socket
  return false;
#endif  // __NR_socket
}

}  // namespace mozilla