| 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 "sandbox/linux/syscall_broker/broker_host.h" | 5 #include "sandbox/linux/syscall_broker/broker_host.h" |
| 6 | 6 |
| 7 #include <fcntl.h> | 7 #include <fcntl.h> |
| 8 #include <sys/socket.h> | 8 #include <sys/socket.h> |
| 9 #include <sys/stat.h> | 9 #include <sys/stat.h> |
| 10 #include <sys/syscall.h> | 10 #include <sys/syscall.h> |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 52 return syscall(__NR_openat, AT_FDCWD, pathname, flags, mode); | 52 return syscall(__NR_openat, AT_FDCWD, pathname, flags, mode); |
| 53 } | 53 } |
| 54 } | 54 } |
| 55 | 55 |
| 56 // Open |requested_filename| with |flags| if allowed by our policy. | 56 // Open |requested_filename| with |flags| if allowed by our policy. |
| 57 // Write the syscall return value (-errno) to |write_pickle| and append | 57 // Write the syscall return value (-errno) to |write_pickle| and append |
| 58 // a file descriptor to |opened_files| if relevant. | 58 // a file descriptor to |opened_files| if relevant. |
| 59 void OpenFileForIPC(const BrokerPolicy& policy, | 59 void OpenFileForIPC(const BrokerPolicy& policy, |
| 60 const std::string& requested_filename, | 60 const std::string& requested_filename, |
| 61 int flags, | 61 int flags, |
| 62 Pickle* write_pickle, | 62 base::Pickle* write_pickle, |
| 63 std::vector<int>* opened_files) { | 63 std::vector<int>* opened_files) { |
| 64 DCHECK(write_pickle); | 64 DCHECK(write_pickle); |
| 65 DCHECK(opened_files); | 65 DCHECK(opened_files); |
| 66 const char* file_to_open = NULL; | 66 const char* file_to_open = NULL; |
| 67 bool unlink_after_open = false; | 67 bool unlink_after_open = false; |
| 68 const bool safe_to_open_file = policy.GetFileNameIfAllowedToOpen( | 68 const bool safe_to_open_file = policy.GetFileNameIfAllowedToOpen( |
| 69 requested_filename.c_str(), flags, &file_to_open, &unlink_after_open); | 69 requested_filename.c_str(), flags, &file_to_open, &unlink_after_open); |
| 70 | 70 |
| 71 if (safe_to_open_file) { | 71 if (safe_to_open_file) { |
| 72 CHECK(file_to_open); | 72 CHECK(file_to_open); |
| (...skipping 11 matching lines...) Expand all Loading... |
| 84 } else { | 84 } else { |
| 85 write_pickle->WriteInt(-policy.denied_errno()); | 85 write_pickle->WriteInt(-policy.denied_errno()); |
| 86 } | 86 } |
| 87 } | 87 } |
| 88 | 88 |
| 89 // Perform access(2) on |requested_filename| with mode |mode| if allowed by our | 89 // Perform access(2) on |requested_filename| with mode |mode| if allowed by our |
| 90 // policy. Write the syscall return value (-errno) to |write_pickle|. | 90 // policy. Write the syscall return value (-errno) to |write_pickle|. |
| 91 void AccessFileForIPC(const BrokerPolicy& policy, | 91 void AccessFileForIPC(const BrokerPolicy& policy, |
| 92 const std::string& requested_filename, | 92 const std::string& requested_filename, |
| 93 int mode, | 93 int mode, |
| 94 Pickle* write_pickle) { | 94 base::Pickle* write_pickle) { |
| 95 DCHECK(write_pickle); | 95 DCHECK(write_pickle); |
| 96 const char* file_to_access = NULL; | 96 const char* file_to_access = NULL; |
| 97 const bool safe_to_access_file = policy.GetFileNameIfAllowedToAccess( | 97 const bool safe_to_access_file = policy.GetFileNameIfAllowedToAccess( |
| 98 requested_filename.c_str(), mode, &file_to_access); | 98 requested_filename.c_str(), mode, &file_to_access); |
| 99 | 99 |
| 100 if (safe_to_access_file) { | 100 if (safe_to_access_file) { |
| 101 CHECK(file_to_access); | 101 CHECK(file_to_access); |
| 102 int access_ret = access(file_to_access, mode); | 102 int access_ret = access(file_to_access, mode); |
| 103 int access_errno = errno; | 103 int access_errno = errno; |
| 104 if (!access_ret) | 104 if (!access_ret) |
| 105 write_pickle->WriteInt(0); | 105 write_pickle->WriteInt(0); |
| 106 else | 106 else |
| 107 write_pickle->WriteInt(-access_errno); | 107 write_pickle->WriteInt(-access_errno); |
| 108 } else { | 108 } else { |
| 109 write_pickle->WriteInt(-policy.denied_errno()); | 109 write_pickle->WriteInt(-policy.denied_errno()); |
| 110 } | 110 } |
| 111 } | 111 } |
| 112 | 112 |
| 113 // Handle a |command_type| request contained in |iter| and send the reply | 113 // Handle a |command_type| request contained in |iter| and send the reply |
| 114 // on |reply_ipc|. | 114 // on |reply_ipc|. |
| 115 // Currently COMMAND_OPEN and COMMAND_ACCESS are supported. | 115 // Currently COMMAND_OPEN and COMMAND_ACCESS are supported. |
| 116 bool HandleRemoteCommand(const BrokerPolicy& policy, | 116 bool HandleRemoteCommand(const BrokerPolicy& policy, |
| 117 IPCCommand command_type, | 117 IPCCommand command_type, |
| 118 int reply_ipc, | 118 int reply_ipc, |
| 119 PickleIterator iter) { | 119 base::PickleIterator iter) { |
| 120 // Currently all commands have two arguments: filename and flags. | 120 // Currently all commands have two arguments: filename and flags. |
| 121 std::string requested_filename; | 121 std::string requested_filename; |
| 122 int flags = 0; | 122 int flags = 0; |
| 123 if (!iter.ReadString(&requested_filename) || !iter.ReadInt(&flags)) | 123 if (!iter.ReadString(&requested_filename) || !iter.ReadInt(&flags)) |
| 124 return false; | 124 return false; |
| 125 | 125 |
| 126 Pickle write_pickle; | 126 base::Pickle write_pickle; |
| 127 std::vector<int> opened_files; | 127 std::vector<int> opened_files; |
| 128 | 128 |
| 129 switch (command_type) { | 129 switch (command_type) { |
| 130 case COMMAND_ACCESS: | 130 case COMMAND_ACCESS: |
| 131 AccessFileForIPC(policy, requested_filename, flags, &write_pickle); | 131 AccessFileForIPC(policy, requested_filename, flags, &write_pickle); |
| 132 break; | 132 break; |
| 133 case COMMAND_OPEN: | 133 case COMMAND_OPEN: |
| 134 OpenFileForIPC( | 134 OpenFileForIPC( |
| 135 policy, requested_filename, flags, &write_pickle, &opened_files); | 135 policy, requested_filename, flags, &write_pickle, &opened_files); |
| 136 break; | 136 break; |
| 137 default: | 137 default: |
| 138 LOG(ERROR) << "Invalid IPC command"; | 138 LOG(ERROR) << "Invalid IPC command"; |
| 139 break; | 139 break; |
| 140 } | 140 } |
| 141 | 141 |
| 142 CHECK_LE(write_pickle.size(), kMaxMessageLength); | 142 CHECK_LE(write_pickle.size(), kMaxMessageLength); |
| 143 ssize_t sent = UnixDomainSocket::SendMsg( | 143 ssize_t sent = base::UnixDomainSocket::SendMsg( |
| 144 reply_ipc, write_pickle.data(), write_pickle.size(), opened_files); | 144 reply_ipc, write_pickle.data(), write_pickle.size(), opened_files); |
| 145 | 145 |
| 146 // Close anything we have opened in this process. | 146 // Close anything we have opened in this process. |
| 147 for (std::vector<int>::iterator it = opened_files.begin(); | 147 for (std::vector<int>::iterator it = opened_files.begin(); |
| 148 it != opened_files.end(); | 148 it != opened_files.end(); |
| 149 ++it) { | 149 ++it) { |
| 150 int ret = IGNORE_EINTR(close(*it)); | 150 int ret = IGNORE_EINTR(close(*it)); |
| 151 DCHECK(!ret) << "Could not close file descriptor"; | 151 DCHECK(!ret) << "Could not close file descriptor"; |
| 152 } | 152 } |
| 153 | 153 |
| (...skipping 15 matching lines...) Expand all Loading... |
| 169 } | 169 } |
| 170 | 170 |
| 171 // Handle a request on the IPC channel ipc_channel_. | 171 // Handle a request on the IPC channel ipc_channel_. |
| 172 // A request should have a file descriptor attached on which we will reply and | 172 // A request should have a file descriptor attached on which we will reply and |
| 173 // that we will then close. | 173 // that we will then close. |
| 174 // A request should start with an int that will be used as the command type. | 174 // A request should start with an int that will be used as the command type. |
| 175 BrokerHost::RequestStatus BrokerHost::HandleRequest() const { | 175 BrokerHost::RequestStatus BrokerHost::HandleRequest() const { |
| 176 ScopedVector<base::ScopedFD> fds; | 176 ScopedVector<base::ScopedFD> fds; |
| 177 char buf[kMaxMessageLength]; | 177 char buf[kMaxMessageLength]; |
| 178 errno = 0; | 178 errno = 0; |
| 179 const ssize_t msg_len = | 179 const ssize_t msg_len = base::UnixDomainSocket::RecvMsg( |
| 180 UnixDomainSocket::RecvMsg(ipc_channel_.get(), buf, sizeof(buf), &fds); | 180 ipc_channel_.get(), buf, sizeof(buf), &fds); |
| 181 | 181 |
| 182 if (msg_len == 0 || (msg_len == -1 && errno == ECONNRESET)) { | 182 if (msg_len == 0 || (msg_len == -1 && errno == ECONNRESET)) { |
| 183 // EOF from the client, or the client died, we should die. | 183 // EOF from the client, or the client died, we should die. |
| 184 return RequestStatus::LOST_CLIENT; | 184 return RequestStatus::LOST_CLIENT; |
| 185 } | 185 } |
| 186 | 186 |
| 187 // The client should send exactly one file descriptor, on which we | 187 // The client should send exactly one file descriptor, on which we |
| 188 // will write the reply. | 188 // will write the reply. |
| 189 // TODO(mdempsky): ScopedVector doesn't have 'at()', only 'operator[]'. | 189 // TODO(mdempsky): ScopedVector doesn't have 'at()', only 'operator[]'. |
| 190 if (msg_len < 0 || fds.size() != 1 || fds[0]->get() < 0) { | 190 if (msg_len < 0 || fds.size() != 1 || fds[0]->get() < 0) { |
| 191 PLOG(ERROR) << "Error reading message from the client"; | 191 PLOG(ERROR) << "Error reading message from the client"; |
| 192 return RequestStatus::FAILURE; | 192 return RequestStatus::FAILURE; |
| 193 } | 193 } |
| 194 | 194 |
| 195 base::ScopedFD temporary_ipc(fds[0]->Pass()); | 195 base::ScopedFD temporary_ipc(fds[0]->Pass()); |
| 196 | 196 |
| 197 Pickle pickle(buf, msg_len); | 197 base::Pickle pickle(buf, msg_len); |
| 198 PickleIterator iter(pickle); | 198 base::PickleIterator iter(pickle); |
| 199 int command_type; | 199 int command_type; |
| 200 if (iter.ReadInt(&command_type)) { | 200 if (iter.ReadInt(&command_type)) { |
| 201 bool command_handled = false; | 201 bool command_handled = false; |
| 202 // Go through all the possible IPC messages. | 202 // Go through all the possible IPC messages. |
| 203 switch (command_type) { | 203 switch (command_type) { |
| 204 case COMMAND_ACCESS: | 204 case COMMAND_ACCESS: |
| 205 case COMMAND_OPEN: | 205 case COMMAND_OPEN: |
| 206 // We reply on the file descriptor sent to us via the IPC channel. | 206 // We reply on the file descriptor sent to us via the IPC channel. |
| 207 command_handled = HandleRemoteCommand( | 207 command_handled = HandleRemoteCommand( |
| 208 broker_policy_, static_cast<IPCCommand>(command_type), | 208 broker_policy_, static_cast<IPCCommand>(command_type), |
| (...skipping 13 matching lines...) Expand all Loading... |
| 222 NOTREACHED(); | 222 NOTREACHED(); |
| 223 } | 223 } |
| 224 | 224 |
| 225 LOG(ERROR) << "Error parsing IPC request"; | 225 LOG(ERROR) << "Error parsing IPC request"; |
| 226 return RequestStatus::FAILURE; | 226 return RequestStatus::FAILURE; |
| 227 } | 227 } |
| 228 | 228 |
| 229 } // namespace syscall_broker | 229 } // namespace syscall_broker |
| 230 | 230 |
| 231 } // namespace sandbox | 231 } // namespace sandbox |
| OLD | NEW |