• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2012 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 "ppapi/tests/test_broker.h"
6 
7 #if defined(_MSC_VER)
8 #define OS_WIN 1
9 #include <windows.h>
10 #else
11 #define OS_POSIX 1
12 #include <errno.h>
13 #include <unistd.h>
14 #endif
15 
16 #include <cstdio>
17 #include <cstring>
18 #include <fstream>
19 #include <limits>
20 
21 #include "ppapi/c/pp_errors.h"
22 #include "ppapi/c/trusted/ppp_broker.h"
23 #include "ppapi/c/trusted/ppb_broker_trusted.h"
24 #include "ppapi/tests/test_utils.h"
25 #include "ppapi/tests/testing_instance.h"
26 
27 REGISTER_TEST_CASE(Broker);
28 
29 namespace {
30 
31 const char kHelloMessage[] = "Hello Plugin! This is Broker!";
32 // Message sent from broker to plugin if the broker is unsandboxed.
33 const char kBrokerUnsandboxed[] = "Broker is Unsandboxed!";
34 // Message sent from broker to plugin if the broker is sandboxed. This message
35 // needs to be longer than |kBrokerUnsandboxed| because the plugin is expecting
36 // |kBrokerUnsandboxed|. If it's shorter and the broker doesn't close its handle
37 // properly the plugin will hang waiting for all data of |kBrokerUnsandboxed| to
38 // be read.
39 const char kBrokerSandboxed[] = "Broker is Sandboxed! Verification failed!";
40 
41 #if defined(OS_WIN)
42 typedef HANDLE PlatformFile;
43 const PlatformFile kInvalidPlatformFileValue = INVALID_HANDLE_VALUE;
44 const int32_t kInvalidHandle = static_cast<int32_t>(
45     reinterpret_cast<intptr_t>(INVALID_HANDLE_VALUE));
46 #elif defined(OS_POSIX)
47 typedef int PlatformFile;
48 const PlatformFile kInvalidPlatformFileValue = -1;
49 const int32_t kInvalidHandle = -1;
50 #endif
51 
IntToPlatformFile(int32_t handle)52 PlatformFile IntToPlatformFile(int32_t handle) {
53 #if defined(OS_WIN)
54   return reinterpret_cast<HANDLE>(static_cast<intptr_t>(handle));
55 #elif defined(OS_POSIX)
56   return handle;
57 #endif
58 }
59 
60 #if defined(OS_POSIX)
61 
62 #define HANDLE_EINTR(x) ({ \
63   typeof(x) eintr_wrapper_result; \
64   do { \
65     eintr_wrapper_result = (x); \
66   } while (eintr_wrapper_result == -1 && errno == EINTR); \
67   eintr_wrapper_result; \
68 })
69 
70 #define IGNORE_EINTR(x) ({ \
71   typeof(x) eintr_wrapper_result; \
72   do { \
73     eintr_wrapper_result = (x); \
74     if (eintr_wrapper_result == -1 && errno == EINTR) { \
75       eintr_wrapper_result = 0; \
76     } \
77   } while (0); \
78   eintr_wrapper_result; \
79 })
80 
81 #endif
82 
ReadMessage(PlatformFile file,size_t message_len,char * message)83 bool ReadMessage(PlatformFile file, size_t message_len, char* message) {
84 #if defined(OS_WIN)
85   assert(message_len < std::numeric_limits<DWORD>::max());
86   DWORD read = 0;
87   const DWORD size = static_cast<DWORD>(message_len);
88   return ::ReadFile(file, message, size, &read, NULL) && read == size;
89 #elif defined(OS_POSIX)
90   assert(message_len <
91          static_cast<size_t>(std::numeric_limits<ssize_t>::max()));
92   size_t total_read = 0;
93   while (total_read < message_len) {
94     ssize_t read = HANDLE_EINTR(::read(file, message + total_read,
95                                        message_len - total_read));
96     if (read <= 0)
97       break;
98     total_read += read;
99   }
100   return total_read == message_len;
101 #endif
102 }
103 
WriteMessage(PlatformFile file,size_t message_len,const char * message)104 bool WriteMessage(PlatformFile file, size_t message_len, const char* message) {
105 #if defined(OS_WIN)
106   assert(message_len < std::numeric_limits<DWORD>::max());
107   DWORD written = 0;
108   const DWORD size = static_cast<DWORD>(message_len);
109   return ::WriteFile(file, message, size, &written, NULL) && written == size;
110 #elif defined(OS_POSIX)
111   assert(message_len <
112          static_cast<size_t>(std::numeric_limits<ssize_t>::max()));
113   size_t total_written = 0;
114   while (total_written < message_len) {
115     ssize_t written = HANDLE_EINTR(::write(file, message + total_written,
116                                            message_len - total_written));
117     if (written <= 0)
118       break;
119     total_written += written;
120   }
121   return total_written == message_len;
122 #endif
123 }
124 
VerifyMessage(PlatformFile file,size_t message_len,const char * message)125 bool VerifyMessage(PlatformFile file, size_t message_len, const char* message) {
126   char* message_received = new char[message_len];
127   bool success = ReadMessage(file, message_len, message_received) &&
128                  !::strcmp(message_received, message);
129   delete [] message_received;
130   return success;
131 }
132 
ClosePlatformFile(PlatformFile file)133 bool ClosePlatformFile(PlatformFile file) {
134 #if defined(OS_WIN)
135   return !!::CloseHandle(file);
136 #elif defined(OS_POSIX)
137   return !IGNORE_EINTR(::close(file));
138 #endif
139 }
140 
VerifyIsUnsandboxed()141 bool VerifyIsUnsandboxed() {
142 #if defined(OS_WIN)
143   FILE* file = NULL;
144   wchar_t temp_path[MAX_PATH] = {'\0'};
145   wchar_t file_name[MAX_PATH] = {'\0'};
146   if (!::GetTempPath(MAX_PATH, temp_path) ||
147       !::GetTempFileName(temp_path, L"test_pepper_broker", 0, file_name) ||
148       ::_wfopen_s(&file, file_name, L"w"))
149     return false;
150 
151   if (::fclose(file)) {
152     ::DeleteFile(file_name);
153     return false;
154   }
155 
156   return !!::DeleteFile(file_name);
157 #elif defined(OS_POSIX)
158   char file_name[] = "/tmp/test_pepper_broker_XXXXXX";
159   int fd = ::mkstemp(file_name);
160   if (-1 == fd)
161     return false;
162 
163   if (IGNORE_EINTR(::close(fd))) {
164     ::remove(file_name);
165     return false;
166   }
167 
168   return !::remove(file_name);
169 #endif
170 }
171 
172 // Callback in the broker when a new broker connection occurs.
OnInstanceConnected(PP_Instance instance,int32_t handle)173 int32_t OnInstanceConnected(PP_Instance instance, int32_t handle) {
174   PlatformFile file = IntToPlatformFile(handle);
175   if (file == kInvalidPlatformFileValue)
176     return PP_ERROR_FAILED;
177 
178   // Send hello message.
179   if (!WriteMessage(file, sizeof(kHelloMessage), kHelloMessage)) {
180     ClosePlatformFile(file);
181     return PP_ERROR_FAILED;
182   }
183 
184   // Verify broker is not sandboxed and send result to plugin over the pipe.
185   if (VerifyIsUnsandboxed()) {
186     if (!WriteMessage(file, sizeof(kBrokerUnsandboxed), kBrokerUnsandboxed)) {
187       ClosePlatformFile(file);
188       return PP_ERROR_FAILED;
189     }
190   } else {
191     if (!WriteMessage(file, sizeof(kBrokerSandboxed), kBrokerSandboxed)) {
192       ClosePlatformFile(file);
193       return PP_ERROR_FAILED;
194     }
195   }
196 
197   if (!ClosePlatformFile(file))
198     return PP_ERROR_FAILED;
199 
200   return PP_OK;
201 }
202 
203 }  // namespace
204 
PPP_InitializeBroker(PP_ConnectInstance_Func * connect_instance_func)205 PP_EXPORT int32_t PPP_InitializeBroker(
206     PP_ConnectInstance_Func* connect_instance_func) {
207   *connect_instance_func = &OnInstanceConnected;
208   return PP_OK;
209 }
210 
PPP_ShutdownBroker()211 PP_EXPORT void PPP_ShutdownBroker() {}
212 
TestBroker(TestingInstance * instance)213 TestBroker::TestBroker(TestingInstance* instance)
214     : TestCase(instance),
215       broker_interface_(NULL) {
216 }
217 
Init()218 bool TestBroker::Init() {
219   broker_interface_ = static_cast<const PPB_BrokerTrusted*>(
220       pp::Module::Get()->GetBrowserInterface(PPB_BROKER_TRUSTED_INTERFACE));
221   return !!broker_interface_;
222 }
223 
RunTests(const std::string & filter)224 void TestBroker::RunTests(const std::string& filter) {
225   RUN_TEST(Create, filter);
226   RUN_TEST(Create, filter);
227   RUN_TEST(GetHandleFailure, filter);
228   RUN_TEST_FORCEASYNC_AND_NOT(ConnectFailure, filter);
229   RUN_TEST_FORCEASYNC_AND_NOT(ConnectAndPipe, filter);
230 
231   // The following tests require special setup, so only run them if they're
232   // explicitly specified by the filter.
233   if (!ShouldRunAllTests(filter)) {
234     RUN_TEST(ConnectPermissionDenied, filter);
235     RUN_TEST(ConnectPermissionGranted, filter);
236     RUN_TEST(IsAllowedPermissionDenied, filter);
237     RUN_TEST(IsAllowedPermissionGranted, filter);
238   }
239 }
240 
TestCreate()241 std::string TestBroker::TestCreate() {
242   // Very simplistic test to make sure we can create a broker interface.
243   // TODO(raymes): All of the resources created in this file are leaked. Write
244   // a C++ wrapper for PPB_Broker_Trusted to avoid these leaks.
245   PP_Resource broker = broker_interface_->CreateTrusted(
246       instance_->pp_instance());
247   ASSERT_TRUE(broker);
248 
249   ASSERT_FALSE(broker_interface_->IsBrokerTrusted(0));
250   ASSERT_TRUE(broker_interface_->IsBrokerTrusted(broker));
251 
252   PASS();
253 }
254 
255 // Test connection on invalid resource.
TestConnectFailure()256 std::string TestBroker::TestConnectFailure() {
257   TestCompletionCallback callback(instance_->pp_instance(), callback_type());
258   callback.WaitForResult(broker_interface_->Connect(0,
259       callback.GetCallback().pp_completion_callback()));
260   CHECK_CALLBACK_BEHAVIOR(callback);
261   ASSERT_EQ(PP_ERROR_BADRESOURCE, callback.result());
262 
263   PASS();
264 }
265 
TestGetHandleFailure()266 std::string TestBroker::TestGetHandleFailure() {
267   int32_t handle = kInvalidHandle;
268 
269   // Test getting the handle for an invalid resource.
270   ASSERT_EQ(PP_ERROR_BADRESOURCE, broker_interface_->GetHandle(0, &handle));
271 
272   // Connect hasn't been called so this should fail.
273   PP_Resource broker = broker_interface_->CreateTrusted(
274       instance_->pp_instance());
275   ASSERT_TRUE(broker);
276   ASSERT_EQ(PP_ERROR_FAILED, broker_interface_->GetHandle(broker, &handle));
277 
278   PASS();
279 }
280 
TestConnectAndPipe()281 std::string TestBroker::TestConnectAndPipe() {
282   PP_Resource broker = broker_interface_->CreateTrusted(
283       instance_->pp_instance());
284   ASSERT_TRUE(broker);
285 
286   TestCompletionCallback callback(instance_->pp_instance(), callback_type());
287   callback.WaitForResult(broker_interface_->Connect(broker,
288       callback.GetCallback().pp_completion_callback()));
289   CHECK_CALLBACK_BEHAVIOR(callback);
290   ASSERT_EQ(PP_OK, callback.result());
291 
292   int32_t handle = kInvalidHandle;
293   ASSERT_EQ(PP_OK, broker_interface_->GetHandle(broker, &handle));
294   ASSERT_NE(kInvalidHandle, handle);
295 
296   PlatformFile file = IntToPlatformFile(handle);
297   ASSERT_TRUE(VerifyMessage(file, sizeof(kHelloMessage), kHelloMessage));
298   ASSERT_TRUE(VerifyMessage(file, sizeof(kBrokerUnsandboxed),
299                             kBrokerUnsandboxed));
300 
301   ASSERT_TRUE(ClosePlatformFile(file));
302 
303   PASS();
304 }
305 
TestConnectPermissionDenied()306 std::string TestBroker::TestConnectPermissionDenied() {
307   // This assumes that the browser side is set up to deny access to the broker.
308   PP_Resource broker = broker_interface_->CreateTrusted(
309       instance_->pp_instance());
310   ASSERT_TRUE(broker);
311 
312   TestCompletionCallback callback(instance_->pp_instance(), callback_type());
313   callback.WaitForResult(broker_interface_->Connect(broker,
314       callback.GetCallback().pp_completion_callback()));
315   CHECK_CALLBACK_BEHAVIOR(callback);
316   ASSERT_EQ(PP_ERROR_NOACCESS, callback.result());
317 
318   PASS();
319 }
320 
TestConnectPermissionGranted()321 std::string TestBroker::TestConnectPermissionGranted() {
322   // This assumes that the browser side is set up to allow access to the broker.
323   PP_Resource broker = broker_interface_->CreateTrusted(
324       instance_->pp_instance());
325   ASSERT_TRUE(broker);
326 
327   TestCompletionCallback callback(instance_->pp_instance(), callback_type());
328   callback.WaitForResult(broker_interface_->Connect(broker,
329       callback.GetCallback().pp_completion_callback()));
330   CHECK_CALLBACK_BEHAVIOR(callback);
331   ASSERT_EQ(PP_OK, callback.result());
332 
333   PASS();
334 }
335 
TestIsAllowedPermissionDenied()336 std::string TestBroker::TestIsAllowedPermissionDenied() {
337   PP_Resource broker = broker_interface_->CreateTrusted(
338       instance_->pp_instance());
339   ASSERT_TRUE(broker);
340   ASSERT_EQ(PP_FALSE, broker_interface_->IsAllowed(broker));
341 
342   PASS();
343 }
344 
TestIsAllowedPermissionGranted()345 std::string TestBroker::TestIsAllowedPermissionGranted() {
346   PP_Resource broker = broker_interface_->CreateTrusted(
347       instance_->pp_instance());
348   ASSERT_TRUE(broker);
349   ASSERT_EQ(PP_TRUE, broker_interface_->IsAllowed(broker));
350 
351   PASS();
352 }
353