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 #include "content/browser/renderer_host/pepper/pepper_udp_socket_message_filter.h"
6
7 #include <cstring>
8 #include <utility>
9
10 #include "base/bind.h"
11 #include "base/callback_helpers.h"
12 #include "base/compiler_specific.h"
13 #include "base/logging.h"
14 #include "base/metrics/histogram_macros.h"
15 #include "build/build_config.h"
16 #include "build/chromeos_buildflags.h"
17 #include "content/browser/renderer_host/pepper/browser_ppapi_host_impl.h"
18 #include "content/browser/renderer_host/pepper/pepper_socket_utils.h"
19 #include "content/public/browser/browser_context.h"
20 #include "content/public/browser/browser_task_traits.h"
21 #include "content/public/browser/browser_thread.h"
22 #include "content/public/browser/content_browser_client.h"
23 #include "content/public/browser/render_frame_host.h"
24 #include "content/public/browser/site_instance.h"
25 #include "content/public/browser/storage_partition.h"
26 #include "content/public/common/process_type.h"
27 #include "content/public/common/socket_permission_request.h"
28 #include "ipc/ipc_message_macros.h"
29 #include "net/base/io_buffer.h"
30 #include "net/base/net_errors.h"
31 #include "net/log/net_log_source.h"
32 #include "net/traffic_annotation/network_traffic_annotation.h"
33 #include "ppapi/c/pp_errors.h"
34 #include "ppapi/c/private/ppb_net_address_private.h"
35 #include "ppapi/host/dispatch_host_message.h"
36 #include "ppapi/host/error_conversion.h"
37 #include "ppapi/host/host_message_context.h"
38 #include "ppapi/host/ppapi_host.h"
39 #include "ppapi/host/resource_host.h"
40 #include "ppapi/proxy/ppapi_messages.h"
41 #include "ppapi/proxy/udp_socket_resource_constants.h"
42 #include "ppapi/shared_impl/private/net_address_private_impl.h"
43 #include "ppapi/shared_impl/socket_option_data.h"
44 #include "services/network/public/mojom/network_context.mojom.h"
45
46 #if BUILDFLAG(IS_CHROMEOS_ASH)
47 #include "chromeos/network/firewall_hole.h"
48 #endif // BUILDFLAG(IS_CHROMEOS_ASH)
49
50 using ppapi::NetAddressPrivateImpl;
51 using ppapi::host::NetErrorToPepperError;
52 using ppapi::proxy::UDPSocketResourceConstants;
53
54 namespace content {
55
56 namespace {
57
58 const PepperUDPSocketMessageFilter::CreateUDPSocketCallback*
59 g_create_udp_socket_callback_for_testing = nullptr;
60
61 size_t g_num_udp_filter_instances = 0;
62
63 } // namespace
64
PendingSend(const net::IPAddress & address,int port,std::vector<uint8_t> data,const ppapi::host::ReplyMessageContext & context)65 PepperUDPSocketMessageFilter::PendingSend::PendingSend(
66 const net::IPAddress& address,
67 int port,
68 std::vector<uint8_t> data,
69 const ppapi::host::ReplyMessageContext& context)
70 : address(address), port(port), data(std::move(data)), context(context) {}
71
72 PepperUDPSocketMessageFilter::PendingSend::PendingSend(
73 const PendingSend& other) = default;
74
~PendingSend()75 PepperUDPSocketMessageFilter::PendingSend::~PendingSend() {
76 }
77
PepperUDPSocketMessageFilter(BrowserPpapiHostImpl * host,PP_Instance instance,bool private_api)78 PepperUDPSocketMessageFilter::PepperUDPSocketMessageFilter(
79 BrowserPpapiHostImpl* host,
80 PP_Instance instance,
81 bool private_api)
82 : socket_options_(0),
83 rcvbuf_size_(0),
84 sndbuf_size_(0),
85 multicast_ttl_(0),
86 can_use_multicast_(PP_ERROR_FAILED),
87 closed_(false),
88 remaining_recv_slots_(
89 UDPSocketResourceConstants::kPluginReceiveBufferSlots),
90 external_plugin_(host->external_plugin()),
91 private_api_(private_api),
92 render_process_id_(0),
93 render_frame_id_(0),
94 is_potentially_secure_plugin_context_(
95 host->IsPotentiallySecurePluginContext(instance)) {
96 ++g_num_udp_filter_instances;
97 DCHECK(host);
98
99 if (!host->GetRenderFrameIDsForInstance(
100 instance, &render_process_id_, &render_frame_id_)) {
101 NOTREACHED();
102 }
103 }
104
~PepperUDPSocketMessageFilter()105 PepperUDPSocketMessageFilter::~PepperUDPSocketMessageFilter() {
106 DCHECK(closed_);
107 DCHECK(!socket_);
108 DCHECK(!receiver_.is_bound());
109 --g_num_udp_filter_instances;
110 }
111
SetCreateUDPSocketCallbackForTesting(const CreateUDPSocketCallback * create_udp_socket_callback)112 void PepperUDPSocketMessageFilter::SetCreateUDPSocketCallbackForTesting(
113 const CreateUDPSocketCallback* create_udp_socket_callback) {
114 DCHECK(!create_udp_socket_callback ||
115 !g_create_udp_socket_callback_for_testing);
116 g_create_udp_socket_callback_for_testing = create_udp_socket_callback;
117 }
118
119 // static
GetNumInstances()120 size_t PepperUDPSocketMessageFilter::GetNumInstances() {
121 return g_num_udp_filter_instances;
122 }
123
OnFilterDestroyed()124 void PepperUDPSocketMessageFilter::OnFilterDestroyed() {
125 ResourceMessageFilter::OnFilterDestroyed();
126 // Need to close the socket on the UI thread. Calling Close() also ensures
127 // that future messages will be ignored, so the mojo pipes won't be
128 // re-created, so after Close() runs, |this| can be safely deleted on the IO
129 // thread.
130 GetUIThreadTaskRunner({})->PostTask(
131 FROM_HERE, base::BindOnce(&PepperUDPSocketMessageFilter::Close, this));
132 }
133
134 scoped_refptr<base::SequencedTaskRunner>
OverrideTaskRunnerForMessage(const IPC::Message & message)135 PepperUDPSocketMessageFilter::OverrideTaskRunnerForMessage(
136 const IPC::Message& message) {
137 switch (message.type()) {
138 case PpapiHostMsg_UDPSocket_SetOption::ID:
139 case PpapiHostMsg_UDPSocket_Close::ID:
140 case PpapiHostMsg_UDPSocket_RecvSlotAvailable::ID:
141 case PpapiHostMsg_UDPSocket_Bind::ID:
142 case PpapiHostMsg_UDPSocket_SendTo::ID:
143 case PpapiHostMsg_UDPSocket_JoinGroup::ID:
144 case PpapiHostMsg_UDPSocket_LeaveGroup::ID:
145 return GetUIThreadTaskRunner({});
146 }
147 return nullptr;
148 }
149
OnResourceMessageReceived(const IPC::Message & msg,ppapi::host::HostMessageContext * context)150 int32_t PepperUDPSocketMessageFilter::OnResourceMessageReceived(
151 const IPC::Message& msg,
152 ppapi::host::HostMessageContext* context) {
153 PPAPI_BEGIN_MESSAGE_MAP(PepperUDPSocketMessageFilter, msg)
154 PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_UDPSocket_SetOption,
155 OnMsgSetOption)
156 PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_UDPSocket_Bind, OnMsgBind)
157 PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_UDPSocket_SendTo,
158 OnMsgSendTo)
159 PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(PpapiHostMsg_UDPSocket_Close,
160 OnMsgClose)
161 PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(
162 PpapiHostMsg_UDPSocket_RecvSlotAvailable, OnMsgRecvSlotAvailable)
163 PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_UDPSocket_JoinGroup,
164 OnMsgJoinGroup)
165 PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_UDPSocket_LeaveGroup,
166 OnMsgLeaveGroup)
167 PPAPI_END_MESSAGE_MAP()
168 return PP_ERROR_FAILED;
169 }
170
OnMsgSetOption(const ppapi::host::HostMessageContext * context,PP_UDPSocket_Option name,const ppapi::SocketOptionData & value)171 int32_t PepperUDPSocketMessageFilter::OnMsgSetOption(
172 const ppapi::host::HostMessageContext* context,
173 PP_UDPSocket_Option name,
174 const ppapi::SocketOptionData& value) {
175 DCHECK_CURRENTLY_ON(BrowserThread::UI);
176
177 if (closed_)
178 return PP_ERROR_FAILED;
179
180 switch (name) {
181 case PP_UDPSOCKET_OPTION_ADDRESS_REUSE: {
182 if (socket_) {
183 // AllowReuseAddress is only effective before Bind().
184 // Note that this limitation originally comes from Windows, but
185 // PPAPI tries to provide platform independent APIs.
186 return PP_ERROR_FAILED;
187 }
188
189 bool boolean_value = false;
190 if (!value.GetBool(&boolean_value))
191 return PP_ERROR_BADARGUMENT;
192
193 if (boolean_value) {
194 socket_options_ |= SOCKET_OPTION_ADDRESS_REUSE;
195 } else {
196 socket_options_ &= ~SOCKET_OPTION_ADDRESS_REUSE;
197 }
198 return PP_OK;
199 }
200 case PP_UDPSOCKET_OPTION_BROADCAST: {
201 bool boolean_value = false;
202 if (!value.GetBool(&boolean_value))
203 return PP_ERROR_BADARGUMENT;
204
205 if (socket_) {
206 socket_->SetBroadcast(
207 boolean_value,
208 CreateCompletionCallback<PpapiPluginMsg_UDPSocket_SetOptionReply>(
209 context));
210 return PP_OK_COMPLETIONPENDING;
211 }
212
213 if (boolean_value) {
214 socket_options_ |= SOCKET_OPTION_BROADCAST;
215 } else {
216 socket_options_ &= ~SOCKET_OPTION_BROADCAST;
217 }
218
219 return PP_OK;
220 }
221 case PP_UDPSOCKET_OPTION_SEND_BUFFER_SIZE: {
222 int32_t integer_value = 0;
223 if (!value.GetInt32(&integer_value) || integer_value <= 0 ||
224 integer_value > UDPSocketResourceConstants::kMaxSendBufferSize)
225 return PP_ERROR_BADARGUMENT;
226
227 socket_options_ |= SOCKET_OPTION_SNDBUF_SIZE;
228 sndbuf_size_ = integer_value;
229
230 // If the socket is already initialized, proxy the value to UDPSocket.
231 if (socket_) {
232 socket_->SetSendBufferSize(
233 integer_value,
234 CreateCompletionCallback<PpapiPluginMsg_UDPSocket_SetOptionReply>(
235 context));
236 return PP_OK_COMPLETIONPENDING;
237 }
238
239 return PP_OK;
240 }
241 case PP_UDPSOCKET_OPTION_RECV_BUFFER_SIZE: {
242 int32_t integer_value = 0;
243 if (!value.GetInt32(&integer_value) || integer_value <= 0 ||
244 integer_value > UDPSocketResourceConstants::kMaxReceiveBufferSize)
245 return PP_ERROR_BADARGUMENT;
246
247 socket_options_ |= SOCKET_OPTION_RCVBUF_SIZE;
248 rcvbuf_size_ = integer_value;
249
250 // If the socket is already initialized, proxy the value to UDPSocket.
251 if (socket_) {
252 socket_->SetReceiveBufferSize(
253 integer_value,
254 CreateCompletionCallback<PpapiPluginMsg_UDPSocket_SetOptionReply>(
255 context));
256 return PP_OK_COMPLETIONPENDING;
257 }
258
259 return PP_OK;
260 }
261 case PP_UDPSOCKET_OPTION_MULTICAST_LOOP: {
262 bool boolean_value = false;
263 if (!value.GetBool(&boolean_value))
264 return PP_ERROR_BADARGUMENT;
265
266 if (boolean_value) {
267 socket_options_ |= SOCKET_OPTION_MULTICAST_LOOP;
268 } else {
269 socket_options_ &= ~SOCKET_OPTION_MULTICAST_LOOP;
270 }
271
272 // If the socket is already initialized, either fail if permissions
273 // disallow multicast, or lie and claim it succeeded, to maintain previous
274 // behavior.
275 if (socket_) {
276 if (can_use_multicast_ != PP_OK)
277 return can_use_multicast_;
278
279 return PP_OK;
280 }
281
282 return PP_OK;
283 }
284 case PP_UDPSOCKET_OPTION_MULTICAST_TTL: {
285 int32_t integer_value = 0;
286 if (!value.GetInt32(&integer_value) ||
287 integer_value < 0 || integer_value > 255)
288 return PP_ERROR_BADARGUMENT;
289
290 // UDPSocket instance is not yet created, so remember the value here.
291 socket_options_ |= SOCKET_OPTION_MULTICAST_TTL;
292 multicast_ttl_ = integer_value;
293
294 // If the socket is already initialized, either fail if permissions
295 // disallow multicast, or lie and claim it succeeded, to maintain previous
296 // behavior.
297 if (socket_) {
298 if (can_use_multicast_ != PP_OK)
299 return can_use_multicast_;
300
301 return PP_OK;
302 }
303
304 return PP_OK;
305 }
306 default: {
307 NOTREACHED();
308 return PP_ERROR_BADARGUMENT;
309 }
310 }
311 }
312
OnMsgBind(const ppapi::host::HostMessageContext * context,const PP_NetAddress_Private & addr)313 int32_t PepperUDPSocketMessageFilter::OnMsgBind(
314 const ppapi::host::HostMessageContext* context,
315 const PP_NetAddress_Private& addr) {
316 DCHECK_CURRENTLY_ON(BrowserThread::UI);
317 DCHECK(context);
318
319 if (closed_ || socket_)
320 return PP_ERROR_FAILED;
321
322 // Check for permissions to use multicast APIS. This check must be done while
323 // on the UI thread, so we cache the value here to be used later on.
324 PP_NetAddress_Private any_addr;
325 NetAddressPrivateImpl::GetAnyAddress(PP_FALSE, &any_addr);
326 can_use_multicast_ = CanUseMulticastAPI(any_addr);
327
328 SocketPermissionRequest request =
329 pepper_socket_utils::CreateSocketPermissionRequest(
330 SocketPermissionRequest::UDP_BIND, addr);
331 if (!pepper_socket_utils::CanUseSocketAPIs(external_plugin_,
332 private_api_,
333 &request,
334 render_process_id_,
335 render_frame_id_)) {
336 return PP_ERROR_NOACCESS;
337 }
338
339 net::IPAddressBytes address;
340 uint16_t port;
341 if (!NetAddressPrivateImpl::NetAddressToIPEndPoint(addr, &address, &port))
342 return PP_ERROR_ADDRESS_INVALID;
343 net::IPEndPoint end_point(net::IPAddress(address), port);
344
345 network::mojom::UDPSocketOptionsPtr udp_socket_options =
346 network::mojom::UDPSocketOptions::New();
347 udp_socket_options->allow_address_reuse =
348 !!(socket_options_ & SOCKET_OPTION_ADDRESS_REUSE);
349 udp_socket_options->allow_broadcast =
350 !!(socket_options_ & SOCKET_OPTION_BROADCAST);
351 if (socket_options_ & SOCKET_OPTION_SNDBUF_SIZE)
352 udp_socket_options->send_buffer_size = sndbuf_size_;
353 if (socket_options_ & SOCKET_OPTION_RCVBUF_SIZE)
354 udp_socket_options->receive_buffer_size = rcvbuf_size_;
355
356 if (socket_options_ & SOCKET_OPTION_MULTICAST_LOOP) {
357 if (can_use_multicast_ != PP_OK) {
358 // TODO(mmenke): The above line implies |can_use_multicast_| is a PP
359 // error code, but the next line implies it is a net error code. Fix that.
360 return NetErrorToPepperError(can_use_multicast_);
361 }
362 // TODO(mmenke): This doesn't seem to be doing anything - this is the
363 // default behavior.
364 udp_socket_options->multicast_loopback_mode = true;
365 }
366 if (socket_options_ & SOCKET_OPTION_MULTICAST_TTL) {
367 if (can_use_multicast_ != PP_OK) {
368 // TODO(mmenke): The above line implies |can_use_multicast_| is a PP
369 // error code, but the next line implies it is a net error code. Fix that.
370 return NetErrorToPepperError(can_use_multicast_);
371 }
372
373 udp_socket_options->multicast_time_to_live = multicast_ttl_;
374 }
375
376 RenderFrameHost* render_frame_host =
377 RenderFrameHost::FromID(render_process_id_, render_frame_id_);
378 // If the RenderFrameHost has been closed, just fail the request.
379 if (!render_frame_host)
380 return PP_ERROR_NOACCESS;
381
382 mojo::PendingRemote<network::mojom::UDPSocketListener> udp_socket_listener;
383 // Avoid binding the listener until the socket has been successfully Bound (in
384 // a socket sense), to avoid providing read data to the caller until it has
385 // been told that the socket was bound.
386 mojo::PendingReceiver<network::mojom::UDPSocketListener> listener_receiver =
387 udp_socket_listener.InitWithNewPipeAndPassReceiver();
388
389 SiteInstance* site_instance = render_frame_host->GetSiteInstance();
390 network::mojom::NetworkContext* network_context =
391 BrowserContext::GetStoragePartition(site_instance->GetBrowserContext(),
392 site_instance)
393 ->GetNetworkContext();
394 if (g_create_udp_socket_callback_for_testing) {
395 g_create_udp_socket_callback_for_testing->Run(
396 network_context, socket_.BindNewPipeAndPassReceiver(),
397 std::move(udp_socket_listener));
398 } else {
399 network_context->CreateUDPSocket(socket_.BindNewPipeAndPassReceiver(),
400 std::move(udp_socket_listener));
401 }
402
403 ppapi::host::ReplyMessageContext reply_context =
404 context->MakeReplyMessageContext();
405 // Watch the socket for errors during the the Bind call.
406 socket_.set_disconnect_handler(
407 base::BindOnce(&PepperUDPSocketMessageFilter::SendBindError,
408 base::Unretained(this), reply_context, PP_ERROR_FAILED));
409
410 // This is the actual socket Bind call (i.e., not a Mojo Bind call).
411 socket_->Bind(end_point, std::move(udp_socket_options),
412 base::BindOnce(&PepperUDPSocketMessageFilter::DoBindCallback,
413 base::Unretained(this),
414 std::move(listener_receiver), reply_context));
415
416 return PP_OK_COMPLETIONPENDING;
417 }
418
OnMsgSendTo(const ppapi::host::HostMessageContext * context,const std::string & data,const PP_NetAddress_Private & addr)419 int32_t PepperUDPSocketMessageFilter::OnMsgSendTo(
420 const ppapi::host::HostMessageContext* context,
421 const std::string& data,
422 const PP_NetAddress_Private& addr) {
423 DCHECK_CURRENTLY_ON(BrowserThread::UI);
424 DCHECK(context);
425
426 // Check |receiver_| instead of |socket_| because |receiver_| is only set
427 // after the Bind() call completes.
428 if (closed_ || !receiver_.is_bound())
429 return PP_ERROR_FAILED;
430
431 SocketPermissionRequest request =
432 pepper_socket_utils::CreateSocketPermissionRequest(
433 SocketPermissionRequest::UDP_SEND_TO, addr);
434 if (!pepper_socket_utils::CanUseSocketAPIs(external_plugin_,
435 private_api_,
436 &request,
437 render_process_id_,
438 render_frame_id_)) {
439 return PP_ERROR_NOACCESS;
440 }
441
442 // Make sure a malicious plugin can't queue up an unlimited number of buffers.
443 size_t num_pending_sends = pending_sends_.size();
444 if (num_pending_sends == UDPSocketResourceConstants::kPluginSendBufferSlots) {
445 return PP_ERROR_FAILED;
446 }
447
448 size_t num_bytes = data.size();
449 if (num_bytes == 0 ||
450 num_bytes >
451 static_cast<size_t>(UDPSocketResourceConstants::kMaxWriteSize)) {
452 // Size of |data| is checked on the plugin side.
453 NOTREACHED();
454 return PP_ERROR_BADARGUMENT;
455 }
456
457 net::IPAddressBytes address;
458 uint16_t port;
459 if (!NetAddressPrivateImpl::NetAddressToIPEndPoint(addr, &address, &port)) {
460 return PP_ERROR_ADDRESS_INVALID;
461 }
462
463 const uint8_t* data_ptr = reinterpret_cast<const uint8_t*>(data.data());
464 std::vector<uint8_t> data_vector(data_ptr, data_ptr + num_bytes);
465
466 pending_sends_.push(PendingSend(net::IPAddress(address), port,
467 std::move(data_vector),
468 context->MakeReplyMessageContext()));
469 // Can only start the send if there isn't another send pending.
470 if (num_pending_sends == 0)
471 StartPendingSend();
472 return PP_OK_COMPLETIONPENDING;
473 }
474
OnMsgClose(const ppapi::host::HostMessageContext * context)475 int32_t PepperUDPSocketMessageFilter::OnMsgClose(
476 const ppapi::host::HostMessageContext* context) {
477 DCHECK_CURRENTLY_ON(BrowserThread::UI);
478 Close();
479 return PP_OK;
480 }
481
OnMsgRecvSlotAvailable(const ppapi::host::HostMessageContext * context)482 int32_t PepperUDPSocketMessageFilter::OnMsgRecvSlotAvailable(
483 const ppapi::host::HostMessageContext* context) {
484 DCHECK_CURRENTLY_ON(BrowserThread::UI);
485
486 if (remaining_recv_slots_ <
487 UDPSocketResourceConstants::kPluginReceiveBufferSlots) {
488 // If the pipe was closed, but the consumer has not yet closed the UDP
489 // socket, keep the read buffer filled with errors.
490 if (!receiver_.is_bound()) {
491 PepperUDPSocketMessageFilter::SendRecvFromError(PP_ERROR_FAILED);
492 return PP_OK;
493 }
494
495 remaining_recv_slots_++;
496 socket_->ReceiveMore(1);
497 }
498
499 return PP_OK;
500 }
501
OnMsgJoinGroup(const ppapi::host::HostMessageContext * context,const PP_NetAddress_Private & addr)502 int32_t PepperUDPSocketMessageFilter::OnMsgJoinGroup(
503 const ppapi::host::HostMessageContext* context,
504 const PP_NetAddress_Private& addr) {
505 DCHECK_CURRENTLY_ON(BrowserThread::UI);
506
507 int32_t ret = CanUseMulticastAPI(addr);
508 if (ret != PP_OK)
509 return ret;
510
511 if (!socket_)
512 return PP_ERROR_FAILED;
513
514 net::IPAddressBytes group;
515 uint16_t port;
516
517 if (!NetAddressPrivateImpl::NetAddressToIPEndPoint(addr, &group, &port))
518 return PP_ERROR_ADDRESS_INVALID;
519
520 socket_->JoinGroup(
521 net::IPAddress(group),
522 CreateCompletionCallback<PpapiPluginMsg_UDPSocket_SetOptionReply>(
523 context));
524 return PP_OK_COMPLETIONPENDING;
525 }
526
OnMsgLeaveGroup(const ppapi::host::HostMessageContext * context,const PP_NetAddress_Private & addr)527 int32_t PepperUDPSocketMessageFilter::OnMsgLeaveGroup(
528 const ppapi::host::HostMessageContext* context,
529 const PP_NetAddress_Private& addr) {
530 DCHECK_CURRENTLY_ON(BrowserThread::UI);
531
532 int32_t ret = CanUseMulticastAPI(addr);
533 if (ret != PP_OK)
534 return ret;
535
536 if (!socket_)
537 return PP_ERROR_FAILED;
538
539 net::IPAddressBytes group;
540 uint16_t port;
541
542 if (!NetAddressPrivateImpl::NetAddressToIPEndPoint(addr, &group, &port))
543 return PP_ERROR_ADDRESS_INVALID;
544
545 socket_->LeaveGroup(
546 net::IPAddress(group),
547 CreateCompletionCallback<PpapiPluginMsg_UDPSocket_LeaveGroupReply>(
548 context));
549 return PP_OK_COMPLETIONPENDING;
550 }
551
DoBindCallback(mojo::PendingReceiver<network::mojom::UDPSocketListener> listener_receiver,const ppapi::host::ReplyMessageContext & context,int result,const base::Optional<net::IPEndPoint> & local_addr_out)552 void PepperUDPSocketMessageFilter::DoBindCallback(
553 mojo::PendingReceiver<network::mojom::UDPSocketListener> listener_receiver,
554 const ppapi::host::ReplyMessageContext& context,
555 int result,
556 const base::Optional<net::IPEndPoint>& local_addr_out) {
557 DCHECK_CURRENTLY_ON(BrowserThread::UI);
558
559 if (result != net::OK) {
560 SendBindError(context, NetErrorToPepperError(result));
561 return;
562 }
563
564 PP_NetAddress_Private net_address = NetAddressPrivateImpl::kInvalidNetAddress;
565 if (!local_addr_out || !NetAddressPrivateImpl::IPEndPointToNetAddress(
566 local_addr_out->address().bytes(),
567 local_addr_out->port(), &net_address)) {
568 SendBindError(context, PP_ERROR_ADDRESS_INVALID);
569 return;
570 }
571
572 #if BUILDFLAG(IS_CHROMEOS_ASH)
573 pepper_socket_utils::OpenUDPFirewallHole(
574 *local_addr_out,
575 base::BindOnce(&PepperUDPSocketMessageFilter::OnFirewallHoleOpened,
576 firewall_hole_weak_ptr_factory_.GetWeakPtr(),
577 base::Passed(std::move(listener_receiver)), context,
578 net_address));
579 #else // !BUILDFLAG(IS_CHROMEOS_ASH)
580 OnBindComplete(std::move(listener_receiver), context, net_address);
581 #endif // !BUILDFLAG(IS_CHROMEOS_ASH)
582 }
583
OnBindComplete(mojo::PendingReceiver<network::mojom::UDPSocketListener> listener_receiver,const ppapi::host::ReplyMessageContext & context,const PP_NetAddress_Private & net_address)584 void PepperUDPSocketMessageFilter::OnBindComplete(
585 mojo::PendingReceiver<network::mojom::UDPSocketListener> listener_receiver,
586 const ppapi::host::ReplyMessageContext& context,
587 const PP_NetAddress_Private& net_address) {
588 DCHECK_CURRENTLY_ON(BrowserThread::UI);
589 DCHECK(socket_);
590
591 SendBindReply(context, PP_OK, net_address);
592
593 receiver_.Bind(std::move(listener_receiver));
594 receiver_.set_disconnect_handler(base::BindOnce(
595 &PepperUDPSocketMessageFilter::PipeClosed, base::Unretained(this)));
596 socket_.set_disconnect_handler(base::BindOnce(
597 &PepperUDPSocketMessageFilter::PipeClosed, base::Unretained(this)));
598 socket_->ReceiveMore(UDPSocketResourceConstants::kPluginReceiveBufferSlots);
599 }
600
601 #if BUILDFLAG(IS_CHROMEOS_ASH)
OnFirewallHoleOpened(mojo::PendingReceiver<network::mojom::UDPSocketListener> listener_receiver,const ppapi::host::ReplyMessageContext & context,const PP_NetAddress_Private & net_address,std::unique_ptr<chromeos::FirewallHole> hole)602 void PepperUDPSocketMessageFilter::OnFirewallHoleOpened(
603 mojo::PendingReceiver<network::mojom::UDPSocketListener> listener_receiver,
604 const ppapi::host::ReplyMessageContext& context,
605 const PP_NetAddress_Private& net_address,
606 std::unique_ptr<chromeos::FirewallHole> hole) {
607 DCHECK_CURRENTLY_ON(BrowserThread::UI);
608
609 LOG_IF(WARNING, !hole.get()) << "Firewall hole could not be opened.";
610 firewall_hole_.reset(hole.release());
611
612 OnBindComplete(std::move(listener_receiver), context, net_address);
613 }
614 #endif // BUILDFLAG(IS_CHROMEOS_ASH)
615
StartPendingSend()616 void PepperUDPSocketMessageFilter::StartPendingSend() {
617 DCHECK_CURRENTLY_ON(BrowserThread::UI);
618 DCHECK(!pending_sends_.empty());
619 DCHECK(socket_);
620
621 const PendingSend& pending_send = pending_sends_.front();
622 // See OnMsgRecvFrom() for the reason why we use base::Unretained(this)
623 // when calling |socket_| methods.
624 socket_->SendTo(
625 net::IPEndPoint(pending_send.address, pending_send.port),
626 pending_send.data, pepper_socket_utils::PepperUDPNetworkAnnotationTag(),
627 base::BindOnce(&PepperUDPSocketMessageFilter::OnSendToCompleted,
628 base::Unretained(this)));
629 }
630
Close()631 void PepperUDPSocketMessageFilter::Close() {
632 DCHECK_CURRENTLY_ON(BrowserThread::UI);
633 socket_.reset();
634 receiver_.reset();
635 closed_ = true;
636 }
637
OnReceived(int result,const base::Optional<net::IPEndPoint> & src_addr,base::Optional<base::span<const uint8_t>> data)638 void PepperUDPSocketMessageFilter::OnReceived(
639 int result,
640 const base::Optional<net::IPEndPoint>& src_addr,
641 base::Optional<base::span<const uint8_t>> data) {
642 DCHECK_CURRENTLY_ON(BrowserThread::UI);
643 DCHECK(!closed_);
644
645 int32_t pp_result = NetErrorToPepperError(result);
646
647 // Convert IPEndPoint we get back from RecvFrom to a PP_NetAddress_Private
648 // to send back.
649 PP_NetAddress_Private addr = NetAddressPrivateImpl::kInvalidNetAddress;
650 if (pp_result == PP_OK &&
651 (!src_addr ||
652 !NetAddressPrivateImpl::IPEndPointToNetAddress(
653 src_addr->address().bytes(), src_addr->port(), &addr))) {
654 pp_result = PP_ERROR_ADDRESS_INVALID;
655 }
656
657 if (pp_result == PP_OK) {
658 std::string data_string;
659 if (data) {
660 data_string = std::string(reinterpret_cast<const char*>(data->data()),
661 data->size());
662 }
663 SendRecvFromResult(PP_OK, data_string, addr);
664 } else {
665 SendRecvFromError(pp_result);
666 }
667
668 // This should always be the case, but best to protect against a broken /
669 // taken over network service.
670 if (remaining_recv_slots_ > 0)
671 remaining_recv_slots_--;
672 }
673
OnSendToCompleted(int net_result)674 void PepperUDPSocketMessageFilter::OnSendToCompleted(int net_result) {
675 DCHECK_CURRENTLY_ON(BrowserThread::UI);
676 FinishPendingSend(net_result);
677
678 if (!pending_sends_.empty())
679 StartPendingSend();
680 }
681
FinishPendingSend(int net_result)682 void PepperUDPSocketMessageFilter::FinishPendingSend(int net_result) {
683 DCHECK(!pending_sends_.empty());
684 const PendingSend& pending_send = pending_sends_.front();
685 int32_t pp_result = NetErrorToPepperError(net_result);
686 if (pp_result < 0) {
687 SendSendToError(pending_send.context, pp_result);
688 } else {
689 // The cast should be safe because of the
690 // UDPSocketResourceConstants::kMaxSendBufferSize before enqueuing the send.
691 SendSendToReply(pending_send.context, PP_OK,
692 static_cast<int>(pending_send.data.size()));
693 }
694
695 pending_sends_.pop();
696 }
697
SendBindReply(const ppapi::host::ReplyMessageContext & context,int32_t result,const PP_NetAddress_Private & addr)698 void PepperUDPSocketMessageFilter::SendBindReply(
699 const ppapi::host::ReplyMessageContext& context,
700 int32_t result,
701 const PP_NetAddress_Private& addr) {
702 UMA_HISTOGRAM_BOOLEAN("Pepper.PluginContextSecurity.UDPBind",
703 is_potentially_secure_plugin_context_);
704
705 ppapi::host::ReplyMessageContext reply_context(context);
706 reply_context.params.set_result(result);
707 SendReply(reply_context, PpapiPluginMsg_UDPSocket_BindReply(addr));
708 }
709
SendRecvFromResult(int32_t result,const std::string & data,const PP_NetAddress_Private & addr)710 void PepperUDPSocketMessageFilter::SendRecvFromResult(
711 int32_t result,
712 const std::string& data,
713 const PP_NetAddress_Private& addr) {
714 // Unlike SendReply, which is safe to call on any thread, SendUnsolicitedReply
715 // calls are only safe to make on the IO thread.
716 GetIOThreadTaskRunner({})->PostTask(
717 FROM_HERE,
718 base::BindOnce(
719 &PepperUDPSocketMessageFilter::SendRecvFromResultOnIOThread, this,
720 result, data, addr));
721 }
722
SendRecvFromResultOnIOThread(int32_t result,const std::string & data,const PP_NetAddress_Private & addr)723 void PepperUDPSocketMessageFilter::SendRecvFromResultOnIOThread(
724 int32_t result,
725 const std::string& data,
726 const PP_NetAddress_Private& addr) {
727 if (resource_host()) {
728 resource_host()->host()->SendUnsolicitedReply(
729 resource_host()->pp_resource(),
730 PpapiPluginMsg_UDPSocket_PushRecvResult(result, data, addr));
731 }
732 }
733
SendSendToReply(const ppapi::host::ReplyMessageContext & context,int32_t result,int32_t bytes_written)734 void PepperUDPSocketMessageFilter::SendSendToReply(
735 const ppapi::host::ReplyMessageContext& context,
736 int32_t result,
737 int32_t bytes_written) {
738 ppapi::host::ReplyMessageContext reply_context(context);
739 reply_context.params.set_result(result);
740 SendReply(reply_context, PpapiPluginMsg_UDPSocket_SendToReply(bytes_written));
741 }
742
SendBindError(const ppapi::host::ReplyMessageContext & context,int32_t result)743 void PepperUDPSocketMessageFilter::SendBindError(
744 const ppapi::host::ReplyMessageContext& context,
745 int32_t result) {
746 socket_.reset();
747 #if BUILDFLAG(IS_CHROMEOS_ASH)
748 // In the unlikely case that this is due to a Mojo error while trying to open
749 // a hole in the firewall on ChromeOS, abandon opening a hole in the firewall.
750 firewall_hole_weak_ptr_factory_.InvalidateWeakPtrs();
751 #endif // BUILDFLAG(IS_CHROMEOS_ASH)
752 SendBindReply(context, result, NetAddressPrivateImpl::kInvalidNetAddress);
753 }
754
SendRecvFromError(int32_t result)755 void PepperUDPSocketMessageFilter::SendRecvFromError(
756 int32_t result) {
757 SendRecvFromResult(result, std::string(),
758 NetAddressPrivateImpl::kInvalidNetAddress);
759 }
760
SendSendToError(const ppapi::host::ReplyMessageContext & context,int32_t result)761 void PepperUDPSocketMessageFilter::SendSendToError(
762 const ppapi::host::ReplyMessageContext& context,
763 int32_t result) {
764 SendSendToReply(context, result, 0);
765 }
766
PipeClosed()767 void PepperUDPSocketMessageFilter::PipeClosed() {
768 Close();
769
770 while (!pending_sends_.empty())
771 FinishPendingSend(PP_ERROR_FAILED);
772
773 // Any reads should fail, after a pipe error.
774 while (remaining_recv_slots_ > 0) {
775 --remaining_recv_slots_;
776 SendRecvFromError(PP_ERROR_FAILED);
777 }
778 }
779
CanUseMulticastAPI(const PP_NetAddress_Private & addr)780 int32_t PepperUDPSocketMessageFilter::CanUseMulticastAPI(
781 const PP_NetAddress_Private& addr) {
782 // Check for plugin permissions.
783 SocketPermissionRequest request =
784 pepper_socket_utils::CreateSocketPermissionRequest(
785 SocketPermissionRequest::UDP_MULTICAST_MEMBERSHIP, addr);
786 if (!pepper_socket_utils::CanUseSocketAPIs(external_plugin_,
787 private_api_,
788 &request,
789 render_process_id_,
790 render_frame_id_)) {
791 return PP_ERROR_NOACCESS;
792 }
793
794 return PP_OK;
795 }
796
797 template <class ReturnMessage>
798 base::OnceCallback<void(int result)>
CreateCompletionCallback(const ppapi::host::HostMessageContext * context)799 PepperUDPSocketMessageFilter::CreateCompletionCallback(
800 const ppapi::host::HostMessageContext* context) {
801 std::unique_ptr<int> result = std::make_unique<int>(net::ERR_FAILED);
802 int* result_ptr = result.get();
803 base::ScopedClosureRunner closure_runner(
804 base::BindOnce(&PepperUDPSocketMessageFilter::ReturnResult<ReturnMessage>,
805 base::Unretained(this), context->MakeReplyMessageContext(),
806 std::move(result)));
807 return base::BindOnce(
808 [](base::ScopedClosureRunner closure_runner, int* result_ptr,
809 int net_result) { *result_ptr = net_result; },
810 std::move(closure_runner), result_ptr);
811 }
812
813 template <class ReturnMessage>
ReturnResult(const ppapi::host::ReplyMessageContext & context,std::unique_ptr<int> result)814 void PepperUDPSocketMessageFilter::ReturnResult(
815 const ppapi::host::ReplyMessageContext& context,
816 std::unique_ptr<int> result) {
817 ppapi::host::ReplyMessageContext reply_context(context);
818 reply_context.params.set_result(NetErrorToPepperError(*result));
819 SendReply(reply_context, ReturnMessage());
820 }
821
822 } // namespace content
823