1 // Copyright 2013 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 // TODO(vtl): I currently potentially overflow in doing index calculations. 6 // E.g., |start_index_| and |current_num_bytes_| fit into a |uint32_t|, but 7 // their sum may not. This is bad and poses a security risk. (We're currently 8 // saved by the limit on capacity -- the maximum size of the buffer, checked in 9 // |DataPipe::ValidateOptions()|, is currently sufficiently small. 10 11 #include "mojo/system/local_data_pipe.h" 12 13 #include <string.h> 14 15 #include <algorithm> 16 17 #include "base/logging.h" 18 #include "mojo/system/constants.h" 19 20 namespace mojo { 21 namespace system { 22 23 LocalDataPipe::LocalDataPipe(const MojoCreateDataPipeOptions& options) 24 : DataPipe(true, true, options), 25 start_index_(0), 26 current_num_bytes_(0) { 27 // Note: |buffer_| is lazily allocated, since a common case will be that one 28 // of the handles is immediately passed off to another process. 29 } 30 31 LocalDataPipe::~LocalDataPipe() { 32 } 33 34 void LocalDataPipe::ProducerCloseImplNoLock() { 35 // If the consumer is still open and we still have data, we have to keep the 36 // buffer around. Currently, we won't free it even if it empties later. (We 37 // could do this -- requiring a check on every read -- but that seems to be 38 // optimizing for the uncommon case.) 39 if (!consumer_open_no_lock() || !current_num_bytes_) { 40 // Note: There can only be a two-phase *read* (by the consumer) if we still 41 // have data. 42 DCHECK(!consumer_in_two_phase_read_no_lock()); 43 DestroyBufferNoLock(); 44 } 45 } 46 47 MojoResult LocalDataPipe::ProducerWriteDataImplNoLock(const void* elements, 48 uint32_t* num_bytes, 49 bool all_or_none) { 50 DCHECK_EQ(*num_bytes % element_num_bytes(), 0u); 51 DCHECK_GT(*num_bytes, 0u); 52 DCHECK(consumer_open_no_lock()); 53 54 size_t num_bytes_to_write = 0; 55 if (may_discard()) { 56 if (all_or_none && *num_bytes > capacity_num_bytes()) 57 return MOJO_RESULT_OUT_OF_RANGE; 58 59 num_bytes_to_write = std::min(static_cast<size_t>(*num_bytes), 60 capacity_num_bytes()); 61 if (num_bytes_to_write > capacity_num_bytes() - current_num_bytes_) { 62 // Discard as much as needed (discard oldest first). 63 MarkDataAsConsumedNoLock( 64 num_bytes_to_write - (capacity_num_bytes() - current_num_bytes_)); 65 // No need to wake up write waiters, since we're definitely going to leave 66 // the buffer full. 67 } 68 } else { 69 if (all_or_none && *num_bytes > capacity_num_bytes() - current_num_bytes_) { 70 // Don't return "should wait" since you can't wait for a specified amount 71 // of data. 72 return MOJO_RESULT_OUT_OF_RANGE; 73 } 74 75 num_bytes_to_write = std::min(static_cast<size_t>(*num_bytes), 76 capacity_num_bytes() - current_num_bytes_); 77 } 78 if (num_bytes_to_write == 0) 79 return MOJO_RESULT_SHOULD_WAIT; 80 81 // The amount we can write in our first |memcpy()|. 82 size_t num_bytes_to_write_first = 83 std::min(num_bytes_to_write, GetMaxNumBytesToWriteNoLock()); 84 // Do the first (and possibly only) |memcpy()|. 85 size_t first_write_index = 86 (start_index_ + current_num_bytes_) % capacity_num_bytes(); 87 EnsureBufferNoLock(); 88 memcpy(buffer_.get() + first_write_index, elements, num_bytes_to_write_first); 89 90 if (num_bytes_to_write_first < num_bytes_to_write) { 91 // The "second write index" is zero. 92 memcpy(buffer_.get(), 93 static_cast<const char*>(elements) + num_bytes_to_write_first, 94 num_bytes_to_write - num_bytes_to_write_first); 95 } 96 97 current_num_bytes_ += num_bytes_to_write; 98 DCHECK_LE(current_num_bytes_, capacity_num_bytes()); 99 *num_bytes = static_cast<uint32_t>(num_bytes_to_write); 100 return MOJO_RESULT_OK; 101 } 102 103 MojoResult LocalDataPipe::ProducerBeginWriteDataImplNoLock( 104 void** buffer, 105 uint32_t* buffer_num_bytes, 106 bool all_or_none) { 107 DCHECK(consumer_open_no_lock()); 108 109 // The index we need to start writing at. 110 size_t write_index = 111 (start_index_ + current_num_bytes_) % capacity_num_bytes(); 112 113 size_t max_num_bytes_to_write = GetMaxNumBytesToWriteNoLock(); 114 if (all_or_none && *buffer_num_bytes > max_num_bytes_to_write) { 115 // In "may discard" mode, we can always write from the write index to the 116 // end of the buffer. 117 if (may_discard() && 118 *buffer_num_bytes <= capacity_num_bytes() - write_index) { 119 // To do so, we need to discard an appropriate amount of data. 120 // We should only reach here if the start index is after the write index! 121 DCHECK_GE(start_index_, write_index); 122 DCHECK_GT(*buffer_num_bytes - max_num_bytes_to_write, 0u); 123 MarkDataAsConsumedNoLock(*buffer_num_bytes - max_num_bytes_to_write); 124 max_num_bytes_to_write = *buffer_num_bytes; 125 } else { 126 // Don't return "should wait" since you can't wait for a specified amount 127 // of data. 128 return MOJO_RESULT_OUT_OF_RANGE; 129 } 130 } 131 132 // Don't go into a two-phase write if there's no room. 133 if (max_num_bytes_to_write == 0) 134 return MOJO_RESULT_SHOULD_WAIT; 135 136 EnsureBufferNoLock(); 137 *buffer = buffer_.get() + write_index; 138 *buffer_num_bytes = static_cast<uint32_t>(max_num_bytes_to_write); 139 set_producer_two_phase_max_num_bytes_written_no_lock( 140 static_cast<uint32_t>(max_num_bytes_to_write)); 141 return MOJO_RESULT_OK; 142 } 143 144 MojoResult LocalDataPipe::ProducerEndWriteDataImplNoLock( 145 uint32_t num_bytes_written) { 146 DCHECK_LE(num_bytes_written, 147 producer_two_phase_max_num_bytes_written_no_lock()); 148 current_num_bytes_ += num_bytes_written; 149 DCHECK_LE(current_num_bytes_, capacity_num_bytes()); 150 set_producer_two_phase_max_num_bytes_written_no_lock(0); 151 return MOJO_RESULT_OK; 152 } 153 154 HandleSignalsState LocalDataPipe::ProducerGetHandleSignalsStateNoLock() const { 155 HandleSignalsState rv; 156 if (consumer_open_no_lock()) { 157 if ((may_discard() || current_num_bytes_ < capacity_num_bytes()) && 158 !producer_in_two_phase_write_no_lock()) 159 rv.satisfied_signals |= MOJO_HANDLE_SIGNAL_WRITABLE; 160 rv.satisfiable_signals |= MOJO_HANDLE_SIGNAL_WRITABLE; 161 } 162 return rv; 163 } 164 165 void LocalDataPipe::ConsumerCloseImplNoLock() { 166 // If the producer is around and in a two-phase write, we have to keep the 167 // buffer around. (We then don't free it until the producer is closed. This 168 // could be rectified, but again seems like optimizing for the uncommon case.) 169 if (!producer_open_no_lock() || !producer_in_two_phase_write_no_lock()) 170 DestroyBufferNoLock(); 171 current_num_bytes_ = 0; 172 } 173 174 MojoResult LocalDataPipe::ConsumerReadDataImplNoLock(void* elements, 175 uint32_t* num_bytes, 176 bool all_or_none) { 177 DCHECK_EQ(*num_bytes % element_num_bytes(), 0u); 178 DCHECK_GT(*num_bytes, 0u); 179 180 if (all_or_none && *num_bytes > current_num_bytes_) { 181 // Don't return "should wait" since you can't wait for a specified amount of 182 // data. 183 return producer_open_no_lock() ? MOJO_RESULT_OUT_OF_RANGE : 184 MOJO_RESULT_FAILED_PRECONDITION; 185 } 186 187 size_t num_bytes_to_read = 188 std::min(static_cast<size_t>(*num_bytes), current_num_bytes_); 189 if (num_bytes_to_read == 0) { 190 return producer_open_no_lock() ? MOJO_RESULT_SHOULD_WAIT : 191 MOJO_RESULT_FAILED_PRECONDITION; 192 } 193 194 // The amount we can read in our first |memcpy()|. 195 size_t num_bytes_to_read_first = 196 std::min(num_bytes_to_read, GetMaxNumBytesToReadNoLock()); 197 memcpy(elements, buffer_.get() + start_index_, num_bytes_to_read_first); 198 199 if (num_bytes_to_read_first < num_bytes_to_read) { 200 // The "second read index" is zero. 201 memcpy(static_cast<char*>(elements) + num_bytes_to_read_first, 202 buffer_.get(), 203 num_bytes_to_read - num_bytes_to_read_first); 204 } 205 206 MarkDataAsConsumedNoLock(num_bytes_to_read); 207 *num_bytes = static_cast<uint32_t>(num_bytes_to_read); 208 return MOJO_RESULT_OK; 209 } 210 211 MojoResult LocalDataPipe::ConsumerDiscardDataImplNoLock(uint32_t* num_bytes, 212 bool all_or_none) { 213 DCHECK_EQ(*num_bytes % element_num_bytes(), 0u); 214 DCHECK_GT(*num_bytes, 0u); 215 216 if (all_or_none && *num_bytes > current_num_bytes_) { 217 // Don't return "should wait" since you can't wait for a specified amount of 218 // data. 219 return producer_open_no_lock() ? MOJO_RESULT_OUT_OF_RANGE : 220 MOJO_RESULT_FAILED_PRECONDITION; 221 } 222 223 // Be consistent with other operations; error if no data available. 224 if (current_num_bytes_ == 0) { 225 return producer_open_no_lock() ? MOJO_RESULT_SHOULD_WAIT : 226 MOJO_RESULT_FAILED_PRECONDITION; 227 } 228 229 size_t num_bytes_to_discard = 230 std::min(static_cast<size_t>(*num_bytes), current_num_bytes_); 231 MarkDataAsConsumedNoLock(num_bytes_to_discard); 232 *num_bytes = static_cast<uint32_t>(num_bytes_to_discard); 233 return MOJO_RESULT_OK; 234 } 235 236 MojoResult LocalDataPipe::ConsumerQueryDataImplNoLock(uint32_t* num_bytes) { 237 // Note: This cast is safe, since the capacity fits into a |uint32_t|. 238 *num_bytes = static_cast<uint32_t>(current_num_bytes_); 239 return MOJO_RESULT_OK; 240 } 241 242 MojoResult LocalDataPipe::ConsumerBeginReadDataImplNoLock( 243 const void** buffer, 244 uint32_t* buffer_num_bytes, 245 bool all_or_none) { 246 size_t max_num_bytes_to_read = GetMaxNumBytesToReadNoLock(); 247 if (all_or_none && *buffer_num_bytes > max_num_bytes_to_read) { 248 // Don't return "should wait" since you can't wait for a specified amount of 249 // data. 250 return producer_open_no_lock() ? MOJO_RESULT_OUT_OF_RANGE : 251 MOJO_RESULT_FAILED_PRECONDITION; 252 } 253 254 // Don't go into a two-phase read if there's no data. 255 if (max_num_bytes_to_read == 0) { 256 return producer_open_no_lock() ? MOJO_RESULT_SHOULD_WAIT : 257 MOJO_RESULT_FAILED_PRECONDITION; 258 } 259 260 *buffer = buffer_.get() + start_index_; 261 *buffer_num_bytes = static_cast<uint32_t>(max_num_bytes_to_read); 262 set_consumer_two_phase_max_num_bytes_read_no_lock( 263 static_cast<uint32_t>(max_num_bytes_to_read)); 264 return MOJO_RESULT_OK; 265 } 266 267 MojoResult LocalDataPipe::ConsumerEndReadDataImplNoLock( 268 uint32_t num_bytes_read) { 269 DCHECK_LE(num_bytes_read, consumer_two_phase_max_num_bytes_read_no_lock()); 270 DCHECK_LE(start_index_ + num_bytes_read, capacity_num_bytes()); 271 MarkDataAsConsumedNoLock(num_bytes_read); 272 set_consumer_two_phase_max_num_bytes_read_no_lock(0); 273 return MOJO_RESULT_OK; 274 } 275 276 HandleSignalsState LocalDataPipe::ConsumerGetHandleSignalsStateNoLock() const { 277 HandleSignalsState rv; 278 if (current_num_bytes_ > 0) { 279 if (!consumer_in_two_phase_read_no_lock()) 280 rv.satisfied_signals |= MOJO_HANDLE_SIGNAL_READABLE; 281 rv.satisfiable_signals |= MOJO_HANDLE_SIGNAL_READABLE; 282 } else if (producer_open_no_lock()) { 283 rv.satisfiable_signals |= MOJO_HANDLE_SIGNAL_READABLE; 284 } 285 return rv; 286 } 287 288 void LocalDataPipe::EnsureBufferNoLock() { 289 DCHECK(producer_open_no_lock()); 290 if (buffer_.get()) 291 return; 292 buffer_.reset(static_cast<char*>( 293 base::AlignedAlloc(capacity_num_bytes(), kDataPipeBufferAlignmentBytes))); 294 } 295 296 void LocalDataPipe::DestroyBufferNoLock() { 297 #ifndef NDEBUG 298 // Scribble on the buffer to help detect use-after-frees. (This also helps the 299 // unit test detect certain bugs without needing ASAN or similar.) 300 if (buffer_.get()) 301 memset(buffer_.get(), 0xcd, capacity_num_bytes()); 302 #endif 303 buffer_.reset(); 304 } 305 306 size_t LocalDataPipe::GetMaxNumBytesToWriteNoLock() { 307 size_t next_index = start_index_ + current_num_bytes_; 308 if (next_index >= capacity_num_bytes()) { 309 next_index %= capacity_num_bytes(); 310 DCHECK_GE(start_index_, next_index); 311 DCHECK_EQ(start_index_ - next_index, 312 capacity_num_bytes() - current_num_bytes_); 313 return start_index_ - next_index; 314 } 315 return capacity_num_bytes() - next_index; 316 } 317 318 size_t LocalDataPipe::GetMaxNumBytesToReadNoLock() { 319 if (start_index_ + current_num_bytes_ > capacity_num_bytes()) 320 return capacity_num_bytes() - start_index_; 321 return current_num_bytes_; 322 } 323 324 void LocalDataPipe::MarkDataAsConsumedNoLock(size_t num_bytes) { 325 DCHECK_LE(num_bytes, current_num_bytes_); 326 start_index_ += num_bytes; 327 start_index_ %= capacity_num_bytes(); 328 current_num_bytes_ -= num_bytes; 329 } 330 331 } // namespace system 332 } // namespace mojo 333