OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "components/nacl/loader/sandbox_linux/nacl_sandbox_linux.h" | 5 #include "components/nacl/loader/sandbox_linux/nacl_sandbox_linux.h" |
6 | 6 |
7 #include <errno.h> | 7 #include <errno.h> |
8 #include <fcntl.h> | 8 #include <fcntl.h> |
9 #include <sys/stat.h> | 9 #include <sys/stat.h> |
10 #include <sys/types.h> | 10 #include <sys/types.h> |
(...skipping 28 matching lines...) Expand all Loading... |
39 return true; | 39 return true; |
40 } | 40 } |
41 | 41 |
42 } // namespace | 42 } // namespace |
43 | 43 |
44 NaClSandbox::NaClSandbox() | 44 NaClSandbox::NaClSandbox() |
45 : layer_one_enabled_(false), | 45 : layer_one_enabled_(false), |
46 layer_one_sealed_(false), | 46 layer_one_sealed_(false), |
47 layer_two_enabled_(false), | 47 layer_two_enabled_(false), |
48 layer_two_is_nonsfi_(false), | 48 layer_two_is_nonsfi_(false), |
49 proc_fd_(-1) { | 49 proc_fd_(-1), |
| 50 setuid_sandbox_client_(sandbox::SetuidSandboxClient::Create()) { |
50 proc_fd_.reset( | 51 proc_fd_.reset( |
51 HANDLE_EINTR(open("/proc", O_DIRECTORY | O_RDONLY | O_CLOEXEC))); | 52 HANDLE_EINTR(open("/proc", O_DIRECTORY | O_RDONLY | O_CLOEXEC))); |
52 PCHECK(proc_fd_.is_valid()); | 53 PCHECK(proc_fd_.is_valid()); |
53 } | 54 } |
54 | 55 |
55 NaClSandbox::~NaClSandbox() { | 56 NaClSandbox::~NaClSandbox() { |
56 } | 57 } |
57 | 58 |
58 bool NaClSandbox::IsSingleThreaded() { | 59 bool NaClSandbox::IsSingleThreaded() { |
59 CHECK(proc_fd_.is_valid()); | 60 CHECK(proc_fd_.is_valid()); |
60 base::ScopedFD proc_self_task(HANDLE_EINTR(openat( | 61 base::ScopedFD proc_self_task(HANDLE_EINTR(openat( |
61 proc_fd_.get(), "self/task/", O_RDONLY | O_DIRECTORY | O_CLOEXEC))); | 62 proc_fd_.get(), "self/task/", O_RDONLY | O_DIRECTORY | O_CLOEXEC))); |
62 PCHECK(proc_self_task.is_valid()); | 63 PCHECK(proc_self_task.is_valid()); |
63 return sandbox::ThreadHelpers::IsSingleThreaded(proc_self_task.get()); | 64 return sandbox::ThreadHelpers::IsSingleThreaded(proc_self_task.get()); |
64 } | 65 } |
65 | 66 |
66 bool NaClSandbox::HasOpenDirectory() { | 67 bool NaClSandbox::HasOpenDirectory() { |
67 CHECK(proc_fd_.is_valid()); | 68 CHECK(proc_fd_.is_valid()); |
68 sandbox::Credentials credentials; | 69 sandbox::Credentials credentials; |
69 return credentials.HasOpenDirectory(proc_fd_.get()); | 70 return credentials.HasOpenDirectory(proc_fd_.get()); |
70 } | 71 } |
71 | 72 |
72 void NaClSandbox::InitializeLayerOneSandbox() { | 73 void NaClSandbox::InitializeLayerOneSandbox() { |
73 // Check that IsSandboxed() works. We should not be sandboxed at this point. | 74 // Check that IsSandboxed() works. We should not be sandboxed at this point. |
74 CHECK(!IsSandboxed()) << "Unexpectedly sandboxed!"; | 75 CHECK(!IsSandboxed()) << "Unexpectedly sandboxed!"; |
75 scoped_ptr<sandbox::SetuidSandboxClient> setuid_sandbox_client( | |
76 sandbox::SetuidSandboxClient::Create()); | |
77 const bool suid_sandbox_child = setuid_sandbox_client->IsSuidSandboxChild(); | |
78 | 76 |
79 if (suid_sandbox_child) { | 77 if (setuid_sandbox_client_->IsSuidSandboxChild()) { |
80 setuid_sandbox_client->CloseDummyFile(); | 78 setuid_sandbox_client_->CloseDummyFile(); |
81 | 79 |
82 // Make sure that no directory file descriptor is open, as it would bypass | 80 // Make sure that no directory file descriptor is open, as it would bypass |
83 // the setuid sandbox model. | 81 // the setuid sandbox model. |
84 CHECK(!HasOpenDirectory()); | 82 CHECK(!HasOpenDirectory()); |
85 | 83 |
86 // Get sandboxed. | 84 // Get sandboxed. |
87 CHECK(setuid_sandbox_client->ChrootMe()); | 85 CHECK(setuid_sandbox_client_->ChrootMe()); |
88 CHECK(IsSandboxed()); | 86 CHECK(IsSandboxed()); |
89 layer_one_enabled_ = true; | 87 layer_one_enabled_ = true; |
90 } | 88 } |
91 } | 89 } |
92 | 90 |
| 91 void NaClSandbox::CheckForExpectedNumberOfOpenFds() { |
| 92 if (setuid_sandbox_client_->IsSuidSandboxChild()) { |
| 93 // We expect to have the following FDs open: |
| 94 // 1-3) stdin, stdout, stderr. |
| 95 // 4) The /dev/urandom FD used by base::GetUrandomFD(). |
| 96 // 5) A dummy pipe FD used to overwrite kSandboxIPCChannel. |
| 97 // 6) The socket created by the SUID sandbox helper, used by ChrootMe(). |
| 98 // After ChrootMe(), this is no longer connected to anything. |
| 99 // (Only present when running under the SUID sandbox.) |
| 100 // 7) The socket for the Chrome IPC channel that's connected to the |
| 101 // browser process, kPrimaryIPCChannel. |
| 102 // |
| 103 // This sanity check ensures that dynamically loaded libraries don't |
| 104 // leave any FDs open before we enable the sandbox. |
| 105 sandbox::Credentials credentials; |
| 106 CHECK_EQ(7, credentials.CountOpenFds(proc_fd_.get())); |
| 107 } |
| 108 } |
| 109 |
93 void NaClSandbox::InitializeLayerTwoSandbox(bool uses_nonsfi_mode) { | 110 void NaClSandbox::InitializeLayerTwoSandbox(bool uses_nonsfi_mode) { |
94 // seccomp-bpf only applies to the current thread, so it's critical to only | 111 // seccomp-bpf only applies to the current thread, so it's critical to only |
95 // have a single thread running here. | 112 // have a single thread running here. |
96 DCHECK(!layer_one_sealed_); | 113 DCHECK(!layer_one_sealed_); |
97 CHECK(IsSingleThreaded()); | 114 CHECK(IsSingleThreaded()); |
| 115 CheckForExpectedNumberOfOpenFds(); |
| 116 |
98 if (uses_nonsfi_mode) { | 117 if (uses_nonsfi_mode) { |
99 layer_two_enabled_ = nacl::nonsfi::InitializeBPFSandbox(); | 118 layer_two_enabled_ = nacl::nonsfi::InitializeBPFSandbox(); |
100 layer_two_is_nonsfi_ = true; | 119 layer_two_is_nonsfi_ = true; |
101 } else { | 120 } else { |
102 layer_two_enabled_ = nacl::InitializeBPFSandbox(); | 121 layer_two_enabled_ = nacl::InitializeBPFSandbox(); |
103 } | 122 } |
104 } | 123 } |
105 | 124 |
106 void NaClSandbox::SealLayerOneSandbox() { | 125 void NaClSandbox::SealLayerOneSandbox() { |
107 if (!layer_two_enabled_) { | 126 if (!layer_two_enabled_) { |
(...skipping 29 matching lines...) Expand all Loading... |
137 static const char kNoBpfMsg[] = | 156 static const char kNoBpfMsg[] = |
138 "The seccomp-bpf sandbox is not engaged for NaCl:"; | 157 "The seccomp-bpf sandbox is not engaged for NaCl:"; |
139 if (can_be_no_sandbox) | 158 if (can_be_no_sandbox) |
140 LOG(ERROR) << kNoBpfMsg << kItIsDangerousMsg; | 159 LOG(ERROR) << kNoBpfMsg << kItIsDangerousMsg; |
141 else | 160 else |
142 LOG(FATAL) << kNoBpfMsg << kItIsNotAllowedMsg; | 161 LOG(FATAL) << kNoBpfMsg << kItIsNotAllowedMsg; |
143 } | 162 } |
144 } | 163 } |
145 | 164 |
146 } // namespace nacl | 165 } // namespace nacl |
OLD | NEW |