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