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 |
93 void NaClSandbox::InitializeLayerTwoSandbox(bool uses_nonsfi_mode) { | 91 void NaClSandbox::InitializeLayerTwoSandbox(bool uses_nonsfi_mode) { |
94 // seccomp-bpf only applies to the current thread, so it's critical to only | 92 // seccomp-bpf only applies to the current thread, so it's critical to only |
95 // have a single thread running here. | 93 // have a single thread running here. |
96 DCHECK(!layer_one_sealed_); | 94 DCHECK(!layer_one_sealed_); |
97 CHECK(IsSingleThreaded()); | 95 CHECK(IsSingleThreaded()); |
96 | |
97 if (setuid_sandbox_client_->IsSuidSandboxChild()) { | |
jln (very slow on Chromium)
2014/05/07 23:08:24
Do you mind putting this in its own bool-returning
Mark Seaborn
2014/05/09 22:02:31
I've created a separate function, but not a bool-r
| |
98 // We expect to have the following FDs open: | |
99 // 1-3) stdin, stdout, stderr. | |
100 // 4) /dev/urandom FD. | |
jln (very slow on Chromium)
2014/05/07 23:08:24
Do you want to reference base::GetUrandomFD() ?
Mark Seaborn
2014/05/09 22:02:31
Done.
| |
101 // 5) A dummy pipe FD used to overwrite kSandboxIPCChannel. | |
102 // 6) The socket created by the SUID sandbox helper, used by ChrootMe(). | |
103 // After ChrootMe(), this is no longer connected to anything. | |
104 // (Only present when running under the SUID sandbox.) | |
jln (very slow on Chromium)
2014/05/07 23:08:24
I will close this.
| |
105 // 7) The socket for the Chrome IPC channel that's connected to the | |
106 // browser process, kPrimaryIPCChannel. | |
jln (very slow on Chromium)
2014/05/07 23:08:24
It should only be open in SFI mode though: https:/
jln (very slow on Chromium)
2014/05/07 23:17:02
Sorry, was confused with kSandboxIPCChannel.
| |
107 // | |
108 // This sanity check ensures that dynamically loaded libraries don't | |
109 // leave any FDs open before we enable the sandbox. | |
110 sandbox::Credentials credentials; | |
111 CHECK_EQ(credentials.CountOpenFds(proc_fd_.get()), 7); | |
jln (very slow on Chromium)
2014/05/07 23:08:24
I was puzzled as to why this would work in non-sfi
jln (very slow on Chromium)
2014/05/07 23:17:02
err, I meant kSandboxIPCChannel.
| |
112 } | |
113 | |
98 if (uses_nonsfi_mode) { | 114 if (uses_nonsfi_mode) { |
99 layer_two_enabled_ = nacl::nonsfi::InitializeBPFSandbox(); | 115 layer_two_enabled_ = nacl::nonsfi::InitializeBPFSandbox(); |
100 layer_two_is_nonsfi_ = true; | 116 layer_two_is_nonsfi_ = true; |
101 } else { | 117 } else { |
102 layer_two_enabled_ = nacl::InitializeBPFSandbox(); | 118 layer_two_enabled_ = nacl::InitializeBPFSandbox(); |
103 } | 119 } |
104 } | 120 } |
105 | 121 |
106 void NaClSandbox::SealLayerOneSandbox() { | 122 void NaClSandbox::SealLayerOneSandbox() { |
107 if (!layer_two_enabled_) { | 123 if (!layer_two_enabled_) { |
(...skipping 29 matching lines...) Expand all Loading... | |
137 static const char kNoBpfMsg[] = | 153 static const char kNoBpfMsg[] = |
138 "The seccomp-bpf sandbox is not engaged for NaCl:"; | 154 "The seccomp-bpf sandbox is not engaged for NaCl:"; |
139 if (can_be_no_sandbox) | 155 if (can_be_no_sandbox) |
140 LOG(ERROR) << kNoBpfMsg << kItIsDangerousMsg; | 156 LOG(ERROR) << kNoBpfMsg << kItIsDangerousMsg; |
141 else | 157 else |
142 LOG(FATAL) << kNoBpfMsg << kItIsNotAllowedMsg; | 158 LOG(FATAL) << kNoBpfMsg << kItIsNotAllowedMsg; |
143 } | 159 } |
144 } | 160 } |
145 | 161 |
146 } // namespace nacl | 162 } // namespace nacl |
OLD | NEW |