• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2012 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifdef UNSAFE_BUFFERS_BUILD
6 // TODO(crbug.com/351564777): Remove this and convert code to safer constructs.
7 #pragma allow_unsafe_buffers
8 #endif
9 
10 #include "ipc/ipc_channel_reader.h"
11 
12 #include <stddef.h>
13 
14 #include <algorithm>
15 
16 #include "base/logging.h"
17 #include "ipc/ipc_listener.h"
18 #include "ipc/ipc_logging.h"
19 #include "ipc/ipc_message.h"
20 #include "ipc/ipc_message_attachment_set.h"
21 #include "ipc/ipc_message_macros.h"
22 
23 namespace IPC {
24 namespace internal {
25 
26 #if BUILDFLAG(IPC_MESSAGE_LOG_ENABLED)
27 
28 namespace {
GetMessageText(const Message & message)29 std::string GetMessageText(const Message& message) {
30   std::string name;
31   Logging::GetInstance()->GetMessageText(
32       message.type(), &name, &message, nullptr);
33   return name;
34 }
35 }  // namespace
36 
37 #define EMIT_TRACE_EVENT(message)                                       \
38   TRACE_EVENT_WITH_FLOW1(                                               \
39       "ipc,toplevel", "ChannelReader::DispatchInputData",               \
40       (message).flags(), TRACE_EVENT_FLAG_FLOW_IN, "name",              \
41       GetMessageText(message));
42 #else
43 #define EMIT_TRACE_EVENT(message)                                              \
44   TRACE_EVENT_WITH_FLOW2("ipc,toplevel", "ChannelReader::DispatchInputData",   \
45                          (message).flags(), TRACE_EVENT_FLAG_FLOW_IN, "class", \
46                          IPC_MESSAGE_ID_CLASS((message).type()), "line",       \
47                          IPC_MESSAGE_ID_LINE((message).type()));
48 #endif  // BUILDFLAG(IPC_MESSAGE_LOG_ENABLED)
49 
ChannelReader(Listener * listener)50 ChannelReader::ChannelReader(Listener* listener)
51   : listener_(listener),
52     max_input_buffer_size_(Channel::kMaximumReadBufferSize) {
53   memset(input_buf_, 0, sizeof(input_buf_));
54 }
55 
56 ChannelReader::~ChannelReader() = default;
57 
ProcessIncomingMessages()58 ChannelReader::DispatchState ChannelReader::ProcessIncomingMessages() {
59   while (true) {
60     int bytes_read = 0;
61     ReadState read_state = ReadData(input_buf_, Channel::kReadBufferSize,
62                                     &bytes_read);
63     if (read_state == READ_FAILED)
64       return DISPATCH_ERROR;
65     if (read_state == READ_PENDING)
66       return DISPATCH_FINISHED;
67 
68     DCHECK(bytes_read > 0);
69     if (!TranslateInputData(input_buf_, bytes_read))
70       return DISPATCH_ERROR;
71   }
72 }
73 
AsyncReadComplete(int bytes_read)74 ChannelReader::DispatchState ChannelReader::AsyncReadComplete(int bytes_read) {
75   if (!TranslateInputData(input_buf_, bytes_read))
76     return DISPATCH_ERROR;
77 
78   return DISPATCH_FINISHED;
79 }
80 
IsInternalMessage(const Message & m)81 bool ChannelReader::IsInternalMessage(const Message& m) {
82   return m.routing_id() == MSG_ROUTING_NONE &&
83       m.type() >= Channel::CLOSE_FD_MESSAGE_TYPE &&
84       m.type() <= Channel::HELLO_MESSAGE_TYPE;
85 }
86 
IsHelloMessage(const Message & m)87 bool ChannelReader::IsHelloMessage(const Message& m) {
88   return m.routing_id() == MSG_ROUTING_NONE &&
89       m.type() == Channel::HELLO_MESSAGE_TYPE;
90 }
91 
CleanUp()92 void ChannelReader::CleanUp() {
93 }
94 
DispatchMessage(Message * m)95 void ChannelReader::DispatchMessage(Message* m) {
96   EMIT_TRACE_EVENT(*m);
97   listener_->OnMessageReceived(*m);
98   HandleDispatchError(*m);
99 }
100 
TranslateInputData(const char * input_data,int input_data_len)101 bool ChannelReader::TranslateInputData(const char* input_data,
102                                        int input_data_len) {
103   const char* p;
104   const char* end;
105 
106   // Possibly combine with the overflow buffer to make a larger buffer.
107   if (input_overflow_buf_.empty()) {
108     p = input_data;
109     end = input_data + input_data_len;
110   } else {
111     if (!CheckMessageSize(input_overflow_buf_.size() + input_data_len))
112       return false;
113     input_overflow_buf_.append(input_data, input_data_len);
114     p = input_overflow_buf_.data();
115     end = p + input_overflow_buf_.size();
116   }
117 
118   size_t next_message_size = 0;
119 
120   // Dispatch all complete messages in the data buffer.
121   while (p < end) {
122     Message::NextMessageInfo info;
123     Message::FindNext(p, end, &info);
124     if (info.message_found) {
125       int pickle_len = static_cast<int>(info.pickle_end - p);
126       Message translated_message(p, pickle_len);
127 
128       if (!HandleTranslatedMessage(&translated_message))
129         return false;
130 
131       p = info.message_end;
132     } else {
133       // Last message is partial.
134       next_message_size = info.message_size;
135       if (!CheckMessageSize(next_message_size))
136         return false;
137       break;
138     }
139   }
140 
141   // Account for the case where last message's byte is in the next data chunk.
142   size_t next_message_buffer_size = next_message_size ?
143       next_message_size + Channel::kReadBufferSize - 1:
144       0;
145 
146   // Save any partial data in the overflow buffer.
147   if (p != input_overflow_buf_.data())
148     input_overflow_buf_.assign(p, end - p);
149 
150   if (!input_overflow_buf_.empty()) {
151     // We have something in the overflow buffer, which means that we will
152     // append the next data chunk (instead of parsing it directly). So we
153     // resize the buffer to fit the next message, to avoid repeatedly
154     // growing the buffer as we receive all message' data chunks.
155     if (next_message_buffer_size > input_overflow_buf_.capacity()) {
156       input_overflow_buf_.reserve(next_message_buffer_size);
157     }
158   }
159 
160   // Trim the buffer if we can
161   if (next_message_buffer_size < max_input_buffer_size_ &&
162       input_overflow_buf_.size() < max_input_buffer_size_ &&
163       input_overflow_buf_.capacity() > max_input_buffer_size_) {
164     // std::string doesn't really have a method to shrink capacity to
165     // a specific value, so we have to swap with another string.
166     std::string trimmed_buf;
167     trimmed_buf.reserve(max_input_buffer_size_);
168     if (trimmed_buf.capacity() > max_input_buffer_size_) {
169       // Since we don't control how much space reserve() actually reserves,
170       // we have to go other way around and change the max size to avoid
171       // getting into the outer if() again.
172       max_input_buffer_size_ = trimmed_buf.capacity();
173     }
174     trimmed_buf.assign(input_overflow_buf_.data(),
175                        input_overflow_buf_.size());
176     input_overflow_buf_.swap(trimmed_buf);
177   }
178 
179   if (input_overflow_buf_.empty() && !DidEmptyInputBuffers())
180     return false;
181   return true;
182 }
183 
HandleTranslatedMessage(Message * translated_message)184 bool ChannelReader::HandleTranslatedMessage(Message* translated_message) {
185   // Immediately handle internal messages.
186   if (IsInternalMessage(*translated_message)) {
187     EMIT_TRACE_EVENT(*translated_message);
188     HandleInternalMessage(*translated_message);
189     HandleDispatchError(*translated_message);
190     return true;
191   }
192 
193   return HandleExternalMessage(translated_message);
194 }
195 
HandleExternalMessage(Message * external_message)196 bool ChannelReader::HandleExternalMessage(Message* external_message) {
197   if (!GetAttachments(external_message))
198     return false;
199 
200   DispatchMessage(external_message);
201   return true;
202 }
203 
HandleDispatchError(const Message & message)204 void ChannelReader::HandleDispatchError(const Message& message) {
205   if (message.dispatch_error())
206     listener_->OnBadMessageReceived(message);
207 }
208 
CheckMessageSize(size_t size)209 bool ChannelReader::CheckMessageSize(size_t size) {
210   if (size <= Channel::kMaximumMessageSize) {
211     return true;
212   }
213   input_overflow_buf_.clear();
214   LOG(ERROR) << "IPC message is too big: " << size;
215   return false;
216 }
217 
218 }  // namespace internal
219 }  // namespace IPC
220