Skip to content

Commit

Permalink
Add TestConnectFailure, TestGetHandleFailure and TestConnectAndPipe t…
Browse files Browse the repository at this point in the history
…o PPAPI Broker UI test.

Also fix wrong sandbox options for broker process on Windows and Mac.

BUG=none
TEST=none


Review URL: http://codereview.chromium.org/8400024

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@110241 0039d316-1c4b-4281-b951-d872f2087c98
  • Loading branch information
xhwang@chromium.org committed Nov 16, 2011
1 parent bd4c7d6 commit 4bcfcd2
Show file tree
Hide file tree
Showing 4 changed files with 258 additions and 8 deletions.
3 changes: 2 additions & 1 deletion content/common/sandbox_init_mac.cc
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,8 @@ bool InitializeSandbox() {
} else if (process_type == switches::kGpuProcess) {
sandbox_process_type = Sandbox::SANDBOX_TYPE_GPU;
} else if ((process_type == switches::kPluginProcess) ||
(process_type == switches::kServiceProcess)) {
(process_type == switches::kServiceProcess) ||
(process_type == switches::kPpapiBrokerProcess)) {
return true;
} else if (process_type == switches::kPpapiPluginProcess) {
sandbox_process_type = Sandbox::SANDBOX_TYPE_PPAPI;
Expand Down
5 changes: 4 additions & 1 deletion content/common/sandbox_policy.cc
Original file line number Diff line number Diff line change
Expand Up @@ -402,6 +402,8 @@ base::ProcessHandle StartProcessWithAccess(CommandLine* cmd_line,
type = ChildProcessInfo::GPU_PROCESS;
} else if (type_str == switches::kPpapiPluginProcess) {
type = ChildProcessInfo::PPAPI_PLUGIN_PROCESS;
} else if (type_str == switches::kPpapiBrokerProcess) {
type = ChildProcessInfo::PPAPI_BROKER_PROCESS;
} else {
NOTREACHED();
return 0;
Expand All @@ -414,7 +416,8 @@ base::ProcessHandle StartProcessWithAccess(CommandLine* cmd_line,
// process are sandboxed by default.
bool in_sandbox =
(type != ChildProcessInfo::NACL_BROKER_PROCESS) &&
(type != ChildProcessInfo::PLUGIN_PROCESS);
(type != ChildProcessInfo::PLUGIN_PROCESS) &&
(type != ChildProcessInfo::PPAPI_BROKER_PROCESS);

// If it is the GPU process then it can be disabled by a command line flag.
if ((type == ChildProcessInfo::GPU_PROCESS) &&
Expand Down
253 changes: 248 additions & 5 deletions ppapi/tests/test_broker.cc
Original file line number Diff line number Diff line change
@@ -1,16 +1,201 @@
// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "ppapi/tests/test_broker.h"

#if defined(_MSC_VER)
#define OS_WIN 1
#include <windows.h>
#else
#define OS_POSIX 1
#include <errno.h>
#endif

#include <cstdio>
#include <cstring>
#include <fstream>
#include <limits>

#include "ppapi/c/pp_errors.h"
#include "ppapi/c/trusted/ppp_broker.h"
#include "ppapi/c/trusted/ppb_broker_trusted.h"
#include "ppapi/cpp/module.h"
#include "ppapi/tests/test_utils.h"
#include "ppapi/tests/testing_instance.h"

REGISTER_TEST_CASE(Broker);

namespace {

const char kHelloMessage[] = "Hello Plugin! This is Broker!";
// Message sent from broker to plugin if the broker is unsandboxed.
const char kBrokerUnsandboxed[] = "Broker is Unsandboxed!";
// Message sent from broker to plugin if the broker is sandboxed. This message
// needs to be longer than |kBrokerUnsandboxed| because the plugin is expecting
// |kBrokerUnsandboxed|. If it's shorter and the broker doesn't close its handle
// properly the plugin will hang waiting for all data of |kBrokerUnsandboxed| to
// be read.
const char kBrokerSandboxed[] = "Broker is Sandboxed! Verification failed!";

#if defined(OS_WIN)
typedef HANDLE PlatformFile;
const PlatformFile kInvalidPlatformFileValue = INVALID_HANDLE_VALUE;
const int32_t kInvalidHandle = static_cast<int32_t>(
reinterpret_cast<intptr_t>(INVALID_HANDLE_VALUE));
#elif defined(OS_POSIX)
typedef int PlatformFile;
const PlatformFile kInvalidPlatformFileValue = -1;
const int32_t kInvalidHandle = -1;
#endif

PlatformFile IntToPlatformFile(int32_t handle) {
#if defined(OS_WIN)
return reinterpret_cast<HANDLE>(static_cast<intptr_t>(handle));
#elif defined(OS_POSIX)
return handle;
#endif
}

#if defined(OS_POSIX)
#define HANDLE_EINTR(x) ({ \
typeof(x) __eintr_result__; \
do { \
__eintr_result__ = x; \
} while (__eintr_result__ == -1 && errno == EINTR); \
__eintr_result__;\
})
#endif

bool ReadMessage(PlatformFile file, size_t message_len, char* message) {
#if defined(OS_WIN)
assert(message_len < std::numeric_limits<DWORD>::max());
DWORD read = 0;
const DWORD size = static_cast<DWORD>(message_len);
return ::ReadFile(file, message, size, &read, NULL) && read == size;
#elif defined(OS_POSIX)
assert(message_len <
static_cast<size_t>(std::numeric_limits<ssize_t>::max()));
size_t total_read = 0;
while (total_read < message_len) {
ssize_t read = HANDLE_EINTR(::read(file, message + total_read,
message_len - total_read));
if (read <= 0)
break;
total_read += read;
}
return total_read == message_len;
#endif
}

bool WriteMessage(PlatformFile file, size_t message_len, const char* message) {
#if defined(OS_WIN)
assert(message_len < std::numeric_limits<DWORD>::max());
DWORD written = 0;
const DWORD size = static_cast<DWORD>(message_len);
return ::WriteFile(file, message, size, &written, NULL) && written == size;
#elif defined(OS_POSIX)
assert(message_len <
static_cast<size_t>(std::numeric_limits<ssize_t>::max()));
size_t total_written = 0;
while (total_written < message_len) {
ssize_t written = HANDLE_EINTR(::write(file, message + total_written,
message_len - total_written));
if (written <= 0)
break;
total_written += written;
}
return total_written == message_len;
#endif
}

bool VerifyMessage(PlatformFile file, size_t message_len, const char* message) {
char* message_received = new char[message_len];
bool success = ReadMessage(file, message_len, message_received) &&
!::strcmp(message_received, message);
delete [] message_received;
return success;
}

bool ClosePlatformFile(PlatformFile file) {
#if defined(OS_WIN)
return !!::CloseHandle(file);
#elif defined(OS_POSIX)
return !::close(file);
#endif
}

bool VerifyIsUnsandboxed() {
#if defined(OS_WIN)
FILE* file = NULL;
wchar_t temp_path[MAX_PATH] = {'\0'};
wchar_t file_name[MAX_PATH] = {'\0'};
if (!::GetTempPath(MAX_PATH, temp_path) ||
!::GetTempFileName(temp_path, L"test_pepper_broker", 0, file_name) ||
::_wfopen_s(&file, file_name, L"w"))
return false;

if (::fclose(file)) {
::DeleteFile(file_name);
return false;
}

return !!::DeleteFile(file_name);
#elif defined(OS_POSIX)
char file_name[] = "/tmp/test_pepper_broker_XXXXXX";
int fd = ::mkstemp(file_name);
if (-1 == fd)
return false;

if (::close(fd)) {
::remove(file_name);
return false;
}

return !::remove(file_name);
#endif
}

// Callback in the broker when a new broker connection occurs.
int32_t OnInstanceConnected(PP_Instance instance, int32_t handle) {
PlatformFile file = IntToPlatformFile(handle);
if (file == kInvalidPlatformFileValue)
return PP_ERROR_FAILED;

// Send hello message.
if (!WriteMessage(file, sizeof(kHelloMessage), kHelloMessage)) {
ClosePlatformFile(file);
return PP_ERROR_FAILED;
}

// Verify broker is not sandboxed and send result to plugin over the pipe.
if (VerifyIsUnsandboxed()) {
if (!WriteMessage(file, sizeof(kBrokerUnsandboxed), kBrokerUnsandboxed)) {
ClosePlatformFile(file);
return PP_ERROR_FAILED;
}
} else {
if (!WriteMessage(file, sizeof(kBrokerSandboxed), kBrokerSandboxed)) {
ClosePlatformFile(file);
return PP_ERROR_FAILED;
}
}

if (!ClosePlatformFile(file))
return PP_ERROR_FAILED;

return PP_OK;
}

} // namespace

PP_EXPORT int32_t PPP_InitializeBroker(
PP_ConnectInstance_Func* connect_instance_func) {
*connect_instance_func = &OnInstanceConnected;
return PP_OK;
}

PP_EXPORT void PPP_ShutdownBroker() {}

TestBroker::TestBroker(TestingInstance* instance)
: TestCase(instance),
broker_interface_(NULL) {
Expand All @@ -24,6 +209,11 @@ bool TestBroker::Init() {

void TestBroker::RunTest() {
RUN_TEST(Create);
RUN_TEST(GetHandleFailure);
RUN_TEST(ConnectFailure);
#if !defined(OS_WIN) // This is broken on Windows. See http://crbug.com/103975.
RUN_TEST(ConnectAndPipe);
#endif
}

std::string TestBroker::TestCreate() {
Expand All @@ -35,12 +225,65 @@ std::string TestBroker::TestCreate() {
ASSERT_FALSE(broker_interface_->IsBrokerTrusted(0));
ASSERT_TRUE(broker_interface_->IsBrokerTrusted(broker));

PASS();
}

// Test connection on invalid resource.
std::string TestBroker::TestConnectFailure() {
// Callback NOT force async. Connect should fail. The callback will not be
// posted so there's no need to wait for the callback to complete.
TestCompletionCallback cb_1(instance_->pp_instance(), false);
ASSERT_EQ(PP_ERROR_BADRESOURCE,
broker_interface_->Connect(
0, pp::CompletionCallback(cb_1).pp_completion_callback()));

// Callback force async. Connect will return PP_OK_COMPLETIONPENDING and the
// callback will be posted. However, the callback should fail.
TestCompletionCallback cb_2(instance_->pp_instance(), true);
ASSERT_EQ(PP_OK_COMPLETIONPENDING,
broker_interface_->Connect(
0, pp::CompletionCallback(cb_2).pp_completion_callback()));
ASSERT_EQ(PP_ERROR_BADRESOURCE, cb_2.WaitForResult());

PASS();
}

std::string TestBroker::TestGetHandleFailure() {
int32_t handle = kInvalidHandle;

// Test getting the handle for an invalid resource.
int32_t handle;
ASSERT_TRUE(broker_interface_->GetHandle(0, &handle) == PP_ERROR_BADRESOURCE);
ASSERT_EQ(PP_ERROR_BADRESOURCE, broker_interface_->GetHandle(0, &handle));

// Connect hasn't been called so this should fail.
ASSERT_TRUE(broker_interface_->GetHandle(broker, &handle) == PP_ERROR_FAILED);
PP_Resource broker = broker_interface_->CreateTrusted(
instance_->pp_instance());
ASSERT_TRUE(broker);
ASSERT_EQ(PP_ERROR_FAILED, broker_interface_->GetHandle(broker, &handle));

PASS();
}

std::string TestBroker::TestConnectAndPipe() {
PP_Resource broker = broker_interface_->CreateTrusted(
instance_->pp_instance());
ASSERT_TRUE(broker);

TestCompletionCallback cb_3(instance_->pp_instance());
ASSERT_EQ(PP_OK_COMPLETIONPENDING,
broker_interface_->Connect(
broker, pp::CompletionCallback(cb_3).pp_completion_callback()));
ASSERT_EQ(PP_OK, cb_3.WaitForResult());

int32_t handle = kInvalidHandle;
ASSERT_EQ(PP_OK, broker_interface_->GetHandle(broker, &handle));
ASSERT_NE(kInvalidHandle, handle);

PlatformFile file = IntToPlatformFile(handle);
ASSERT_TRUE(VerifyMessage(file, sizeof(kHelloMessage), kHelloMessage));
ASSERT_TRUE(VerifyMessage(file, sizeof(kBrokerUnsandboxed),
kBrokerUnsandboxed));

ASSERT_TRUE(ClosePlatformFile(file));

PASS();
}
5 changes: 4 additions & 1 deletion ppapi/tests/test_broker.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

Expand All @@ -22,6 +22,9 @@ class TestBroker : public TestCase {

private:
std::string TestCreate();
std::string TestConnectFailure();
std::string TestGetHandleFailure();
std::string TestConnectAndPipe();

const struct PPB_BrokerTrusted* broker_interface_;
};
Expand Down

0 comments on commit 4bcfcd2

Please sign in to comment.