summaryrefslogtreecommitdiffstats
path: root/content/common/sandbox_linux/sandbox_linux.h
blob: 12aabcfc06da020d693ae8b721beb90f805723d1 (plain)
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
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
// Copyright (c) 2012 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.

#ifndef CONTENT_COMMON_SANDBOX_LINUX_SANDBOX_LINUX_H_
#define CONTENT_COMMON_SANDBOX_LINUX_SANDBOX_LINUX_H_

#include <string>
#include <vector>

#include "base/basictypes.h"
#include "base/memory/scoped_ptr.h"
#include "content/public/common/sandbox_linux.h"

#if defined(ADDRESS_SANITIZER) || defined(MEMORY_SANITIZER) || \
    defined(THREAD_SANITIZER) || defined(LEAK_SANITIZER) || \
    defined(UNDEFINED_SANITIZER) || defined(SANITIZER_COVERAGE)
#include <sanitizer/common_interface_defs.h>
#define ANY_OF_AMTLU_SANITIZER 1
#endif

template <typename T> struct DefaultSingletonTraits;
namespace base {
class Thread;
}
namespace sandbox { class SetuidSandboxClient; }

namespace content {

// A singleton class to represent and change our sandboxing state for the
// three main Linux sandboxes.
// The sandboxing model allows using two layers of sandboxing. The first layer
// can be implemented either with unprivileged namespaces or with the setuid
// sandbox. This class provides a way to engage the namespace sandbox, but does
// not deal with the legacy setuid sandbox directly.
// The second layer is mainly based on seccomp-bpf and is engaged with
// InitializeSandbox(). InitializeSandbox() is also responsible for "sealing"
// the first layer of sandboxing. That is, InitializeSandbox must always be
// called to have any meaningful sandboxing at all.
class LinuxSandbox {
 public:
  // This is a list of sandbox IPC methods which the renderer may send to the
  // sandbox host. See http://code.google.com/p/chromium/wiki/LinuxSandboxIPC
  // This isn't the full list, values < 32 are reserved for methods called from
  // Skia.
  enum LinuxSandboxIPCMethods {
    METHOD_GET_FALLBACK_FONT_FOR_CHAR = 32,
    METHOD_LOCALTIME = 33,
    DEPRECATED_METHOD_GET_CHILD_WITH_INODE = 34,
    METHOD_GET_STYLE_FOR_STRIKE = 35,
    METHOD_MAKE_SHARED_MEMORY_SEGMENT = 36,
    METHOD_MATCH_WITH_FALLBACK = 37,
  };

  // Get our singleton instance.
  static LinuxSandbox* GetInstance();

  // Do some initialization that can only be done before any of the sandboxes
  // are enabled. If using the setuid sandbox, this should be called manually
  // before the setuid sandbox is engaged.
  // Security: When this runs, it is imperative that either InitializeSandbox()
  // runs as well or that all file descriptors returned in
  // GetFileDescriptorsToClose() get closed.
  // Otherwise file descriptors that bypass the security of the setuid sandbox
  // would be kept open. One must be particularly careful if a process performs
  // a fork().
  void PreinitializeSandbox();

  // Check that the current process is the init process of a new PID
  // namespace and then proceed to drop access to the file system by using
  // a new unprivileged namespace. This is a layer-1 sandbox.
  // In order for this sandbox to be effective, it must be "sealed" by calling
  // InitializeSandbox().
  void EngageNamespaceSandbox();

  // Return a list of file descriptors to close if PreinitializeSandbox() ran
  // but InitializeSandbox() won't. Avoid using.
  // TODO(jln): get rid of this hack.
  std::vector<int> GetFileDescriptorsToClose();

  // Seal an eventual layer-1 sandbox and initialize the layer-2 sandbox with
  // an adequate policy depending on the process type and command line
  // arguments.
  // Currently the layer-2 sandbox is composed of seccomp-bpf and address space
  // limitations. This will instantiate the LinuxSandbox singleton if it
  // doesn't already exist.
  // This function should only be called without any thread running.
  static bool InitializeSandbox();

  // Stop |thread| in a way that can be trusted by the sandbox.
  static void StopThread(base::Thread* thread);

  // Returns the status of the renderer, worker and ppapi sandbox. Can only
  // be queried after going through PreinitializeSandbox(). This is a bitmask
  // and uses the constants defined in "enum LinuxSandboxStatus". Since the
  // status needs to be provided before the sandboxes are actually started,
  // this returns what will actually happen once InitializeSandbox()
  // is called from inside these processes.
  int GetStatus();
  // Returns true if the current process is single-threaded or if the number
  // of threads cannot be determined.
  bool IsSingleThreaded() const;
  // Did we start Seccomp BPF?
  bool seccomp_bpf_started() const;

  // Simple accessor for our instance of the setuid sandbox. Will never return
  // NULL.
  // There is no StartSetuidSandbox(), the SetuidSandboxClient instance should
  // be used directly.
  sandbox::SetuidSandboxClient* setuid_sandbox_client() const;

  // Check the policy and eventually start the seccomp-bpf sandbox. This should
  // never be called with threads started. If we detect that threads have
  // started we will crash.
  bool StartSeccompBPF(const std::string& process_type);

  // Limit the address space of the current process (and its children).
  // to make some vulnerabilities harder to exploit.
  bool LimitAddressSpace(const std::string& process_type);

#if defined(ANY_OF_AMTLU_SANITIZER)
  __sanitizer_sandbox_arguments* sanitizer_args() const {
    return sanitizer_args_.get();
  };
#endif

 private:
  friend struct DefaultSingletonTraits<LinuxSandbox>;

  LinuxSandbox();
  ~LinuxSandbox();

  // Some methods are static and get an instance of the Singleton. These
  // are the non-static implementations.
  bool InitializeSandboxImpl();
  void StopThreadImpl(base::Thread* thread);
  // We must have been pre_initialized_ before using these.
  bool seccomp_bpf_supported() const;
  bool seccomp_bpf_with_tsync_supported() const;
  // Returns true if it can be determined that the current process has open
  // directories that are not managed by the LinuxSandbox class. This would
  // be a vulnerability as it would allow to bypass the setuid sandbox.
  bool HasOpenDirectories() const;
  // The last part of the initialization is to make sure any temporary "hole"
  // in the sandbox is closed. For now, this consists of closing proc_fd_.
  void SealSandbox();
  // GetStatus() makes promises as to how the sandbox will behave. This
  // checks that no promises have been broken.
  void CheckForBrokenPromises(const std::string& process_type);
  // Stop |thread| and make sure it does not appear in /proc/self/tasks/
  // anymore.
  void StopThreadAndEnsureNotCounted(base::Thread* thread) const;

  // A file descriptor to /proc. It's dangerous to have it around as it could
  // allow for sandbox bypasses. It needs to be closed before we consider
  // ourselves sandboxed.
  int proc_fd_;
  bool seccomp_bpf_started_;
  // The value returned by GetStatus(). Gets computed once and then cached.
  int sandbox_status_flags_;
  // Did PreinitializeSandbox() run?
  bool pre_initialized_;
  bool seccomp_bpf_supported_;  // Accurate if pre_initialized_.
  bool seccomp_bpf_with_tsync_supported_;  // Accurate if pre_initialized_.
  bool yama_is_enforcing_;  // Accurate if pre_initialized_.
  bool initialize_sandbox_ran_;  // InitializeSandbox() was called.
  scoped_ptr<sandbox::SetuidSandboxClient> setuid_sandbox_client_;
#if defined(ANY_OF_AMTLU_SANITIZER)
  scoped_ptr<__sanitizer_sandbox_arguments> sanitizer_args_;
#endif

  DISALLOW_COPY_AND_ASSIGN(LinuxSandbox);
};

}  // namespace content

#endif  // CONTENT_COMMON_SANDBOX_LINUX_SANDBOX_LINUX_H_