| // Copyright 2015 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 "build/build_config.h" |
| |
| #include <windows.h> |
| |
| #include <memory> |
| #include <tuple> |
| |
| #include "base/files/file_path.h" |
| #include "base/files/file_util.h" |
| #include "base/files/scoped_temp_dir.h" |
| #include "base/memory/shared_memory.h" |
| #include "base/memory/shared_memory_handle.h" |
| #include "base/run_loop.h" |
| #include "base/win/scoped_handle.h" |
| #include "ipc/attachment_broker_privileged_win.h" |
| #include "ipc/attachment_broker_unprivileged_win.h" |
| #include "ipc/handle_attachment_win.h" |
| #include "ipc/handle_win.h" |
| #include "ipc/ipc_listener.h" |
| #include "ipc/ipc_message.h" |
| #include "ipc/ipc_test_base.h" |
| #include "ipc/ipc_test_messages.h" |
| |
| namespace { |
| |
| using base::win::ScopedHandle; |
| |
| const char kDataBuffer[] = "This is some test data to write to the file."; |
| const size_t kSharedMemorySize = 20000; |
| |
| // Returns the contents of the file represented by |h| as a std::string. |
| std::string ReadFromFile(HANDLE h) { |
| SetFilePointer(h, 0, nullptr, FILE_BEGIN); |
| char buffer[100]; |
| DWORD bytes_read; |
| BOOL success = ::ReadFile(h, buffer, static_cast<DWORD>(strlen(kDataBuffer)), |
| &bytes_read, nullptr); |
| return success ? std::string(buffer, bytes_read) : std::string(); |
| } |
| |
| ScopedHandle GetHandleFromBrokeredAttachment( |
| const scoped_refptr<IPC::BrokerableAttachment>& attachment) { |
| if (attachment->GetType() != |
| IPC::BrokerableAttachment::TYPE_BROKERABLE_ATTACHMENT) { |
| LOG(INFO) << "Attachment type not TYPE_BROKERABLE_ATTACHMENT."; |
| return ScopedHandle(nullptr); |
| } |
| |
| if (attachment->GetBrokerableType() != |
| IPC::BrokerableAttachment::WIN_HANDLE) { |
| LOG(INFO) << "Brokerable type not WIN_HANDLE."; |
| return ScopedHandle(nullptr); |
| } |
| |
| IPC::internal::HandleAttachmentWin* received_handle_attachment = |
| static_cast<IPC::internal::HandleAttachmentWin*>(attachment.get()); |
| ScopedHandle h(received_handle_attachment->get_handle()); |
| received_handle_attachment->reset_handle_ownership(); |
| return h; |
| } |
| |
| // |message| must be deserializable as a TestHandleWinMsg. Returns the HANDLE, |
| // or nullptr if deserialization failed. |
| ScopedHandle GetHandleFromTestHandleWinMsg(const IPC::Message& message) { |
| // Expect a message with a brokered attachment. |
| if (!message.HasBrokerableAttachments()) { |
| LOG(INFO) << "Message missing brokerable attachment."; |
| return ScopedHandle(nullptr); |
| } |
| |
| TestHandleWinMsg::Schema::Param p; |
| bool success = TestHandleWinMsg::Read(&message, &p); |
| if (!success) { |
| LOG(INFO) << "Failed to deserialize message."; |
| return ScopedHandle(nullptr); |
| } |
| |
| IPC::HandleWin handle_win = std::get<1>(p); |
| return ScopedHandle(handle_win.get_handle()); |
| } |
| |
| // Returns a mapped, shared memory region based on the handle in |message|. |
| std::unique_ptr<base::SharedMemory> GetSharedMemoryFromSharedMemoryHandleMsg1( |
| const IPC::Message& message, |
| size_t size) { |
| // Expect a message with a brokered attachment. |
| if (!message.HasBrokerableAttachments()) { |
| LOG(INFO) << "Message missing brokerable attachment."; |
| return nullptr; |
| } |
| |
| TestSharedMemoryHandleMsg1::Schema::Param p; |
| bool success = TestSharedMemoryHandleMsg1::Read(&message, &p); |
| if (!success) { |
| LOG(INFO) << "Failed to deserialize message."; |
| return nullptr; |
| } |
| |
| base::SharedMemoryHandle handle = std::get<0>(p); |
| std::unique_ptr<base::SharedMemory> shared_memory( |
| new base::SharedMemory(handle, false)); |
| |
| shared_memory->Map(size); |
| return shared_memory; |
| } |
| |
| // |message| must be deserializable as a TestTwoHandleWinMsg. Returns the |
| // HANDLE, or nullptr if deserialization failed. |
| bool GetHandleFromTestTwoHandleWinMsg(const IPC::Message& message, |
| HANDLE* h1, |
| HANDLE* h2) { |
| // Expect a message with a brokered attachment. |
| if (!message.HasBrokerableAttachments()) { |
| LOG(INFO) << "Message missing brokerable attachment."; |
| return false; |
| } |
| |
| TestTwoHandleWinMsg::Schema::Param p; |
| bool success = TestTwoHandleWinMsg::Read(&message, &p); |
| if (!success) { |
| LOG(INFO) << "Failed to deserialize message."; |
| return false; |
| } |
| |
| IPC::HandleWin handle_win = std::get<0>(p); |
| *h1 = handle_win.get_handle(); |
| handle_win = std::get<1>(p); |
| *h2 = handle_win.get_handle(); |
| return true; |
| } |
| |
| // |message| must be deserializable as a TestHandleWinMsg. Returns true if the |
| // attached file HANDLE has contents |kDataBuffer|. |
| bool CheckContentsOfTestMessage(const IPC::Message& message) { |
| ScopedHandle h(GetHandleFromTestHandleWinMsg(message)); |
| if (h.Get() == nullptr) { |
| LOG(INFO) << "Failed to get handle from TestHandleWinMsg."; |
| return false; |
| } |
| |
| std::string contents = ReadFromFile(h.Get()); |
| bool success = (contents == std::string(kDataBuffer)); |
| if (!success) { |
| LOG(INFO) << "Expected contents: " << std::string(kDataBuffer); |
| LOG(INFO) << "Read contents: " << contents; |
| } |
| return success; |
| } |
| |
| // Returns 0 on error. |
| DWORD GetCurrentProcessHandleCount() { |
| DWORD handle_count = 0; |
| BOOL success = ::GetProcessHandleCount(::GetCurrentProcess(), &handle_count); |
| return success ? handle_count : 0; |
| } |
| |
| enum TestResult { |
| RESULT_UNKNOWN, |
| RESULT_SUCCESS, |
| RESULT_FAILURE, |
| }; |
| |
| // Once the test is finished, send a control message to the parent process with |
| // the result. The message may require the runloop to be run before its |
| // dispatched. |
| void SendControlMessage(IPC::Sender* sender, bool success) { |
| IPC::Message* message = new IPC::Message(0, 2, IPC::Message::PRIORITY_NORMAL); |
| TestResult result = success ? RESULT_SUCCESS : RESULT_FAILURE; |
| message->WriteInt(result); |
| sender->Send(message); |
| } |
| |
| class MockObserver : public IPC::AttachmentBroker::Observer { |
| public: |
| void ReceivedBrokerableAttachmentWithId( |
| const IPC::BrokerableAttachment::AttachmentId& id) override { |
| id_ = id; |
| } |
| IPC::BrokerableAttachment::AttachmentId* get_id() { return &id_; } |
| |
| private: |
| IPC::BrokerableAttachment::AttachmentId id_; |
| }; |
| |
| // Forwards all messages to |listener_|. Quits the message loop after a |
| // message is received, or the channel has an error. |
| class ProxyListener : public IPC::Listener { |
| public: |
| ProxyListener() : listener_(nullptr), reason_(MESSAGE_RECEIVED) {} |
| ~ProxyListener() override {} |
| |
| // The reason for exiting the message loop. |
| enum Reason { MESSAGE_RECEIVED, CHANNEL_ERROR }; |
| |
| bool OnMessageReceived(const IPC::Message& message) override { |
| bool result = false; |
| if (listener_) |
| result = listener_->OnMessageReceived(message); |
| reason_ = MESSAGE_RECEIVED; |
| messages_.push_back(message); |
| base::MessageLoop::current()->QuitNow(); |
| return result; |
| } |
| |
| void OnChannelError() override { |
| reason_ = CHANNEL_ERROR; |
| base::MessageLoop::current()->QuitNow(); |
| } |
| |
| void set_listener(IPC::Listener* listener) { listener_ = listener; } |
| Reason get_reason() { return reason_; } |
| IPC::Message get_first_message() { return messages_[0]; } |
| void pop_first_message() { messages_.erase(messages_.begin()); } |
| bool has_message() { return !messages_.empty(); } |
| |
| private: |
| IPC::Listener* listener_; |
| Reason reason_; |
| std::vector<IPC::Message> messages_; |
| }; |
| |
| // Waits for a result to be sent over the channel. Quits the message loop |
| // after a message is received, or the channel has an error. |
| class ResultListener : public IPC::Listener { |
| public: |
| ResultListener() : result_(RESULT_UNKNOWN) {} |
| ~ResultListener() override {} |
| |
| bool OnMessageReceived(const IPC::Message& message) override { |
| base::PickleIterator iter(message); |
| |
| int result; |
| EXPECT_TRUE(iter.ReadInt(&result)); |
| result_ = static_cast<TestResult>(result); |
| return true; |
| } |
| |
| TestResult get_result() { return result_; } |
| |
| private: |
| TestResult result_; |
| }; |
| |
| // The parent process acts as an unprivileged process. The forked process acts |
| // as the privileged process. |
| class IPCAttachmentBrokerPrivilegedWinTest : public IPCTestBase { |
| public: |
| IPCAttachmentBrokerPrivilegedWinTest() {} |
| ~IPCAttachmentBrokerPrivilegedWinTest() override {} |
| |
| void SetUp() override { |
| IPCTestBase::SetUp(); |
| ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); |
| ASSERT_TRUE( |
| base::CreateTemporaryFileInDir(temp_dir_.GetPath(), &temp_path_)); |
| } |
| |
| void TearDown() override { IPCTestBase::TearDown(); } |
| |
| // Takes ownership of |broker|. Has no effect if called after CommonSetUp(). |
| void set_broker(IPC::AttachmentBrokerUnprivilegedWin* broker) { |
| broker_.reset(broker); |
| } |
| |
| void CommonSetUp() { |
| PreConnectSetUp(); |
| PostConnectSetUp(); |
| } |
| |
| // All of setup before the channel is connected. |
| void PreConnectSetUp() { |
| if (!broker_.get()) |
| set_broker(new IPC::AttachmentBrokerUnprivilegedWin); |
| broker_->AddObserver(&observer_, task_runner()); |
| CreateChannel(&proxy_listener_); |
| broker_->RegisterBrokerCommunicationChannel(channel()); |
| } |
| |
| // All of setup including the connection and everything after. |
| void PostConnectSetUp() { |
| ASSERT_TRUE(ConnectChannel()); |
| ASSERT_TRUE(StartClient()); |
| |
| handle_count_ = GetCurrentProcessHandleCount(); |
| EXPECT_NE(handle_count_, 0u); |
| } |
| |
| void CommonTearDown() { |
| EXPECT_EQ(handle_count_, handle_count_); |
| |
| // Close the channel so the client's OnChannelError() gets fired. |
| channel()->Close(); |
| |
| EXPECT_TRUE(WaitForClientShutdown()); |
| DestroyChannel(); |
| broker_.reset(); |
| } |
| |
| HANDLE CreateTempFile() { |
| EXPECT_NE(-1, WriteFile(temp_path_, kDataBuffer, |
| static_cast<int>(strlen(kDataBuffer)))); |
| |
| HANDLE h = |
| CreateFile(temp_path_.value().c_str(), GENERIC_READ | GENERIC_WRITE, 0, |
| nullptr, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr); |
| EXPECT_NE(h, INVALID_HANDLE_VALUE); |
| return h; |
| } |
| |
| void SendMessageWithAttachment(HANDLE h) { |
| IPC::HandleWin handle_win(h, IPC::HandleWin::FILE_READ_WRITE); |
| IPC::Message* message = new TestHandleWinMsg(100, handle_win, 200); |
| sender()->Send(message); |
| } |
| |
| ProxyListener* get_proxy_listener() { return &proxy_listener_; } |
| IPC::AttachmentBrokerUnprivilegedWin* get_broker() { return broker_.get(); } |
| MockObserver* get_observer() { return &observer_; } |
| |
| private: |
| base::ScopedTempDir temp_dir_; |
| base::FilePath temp_path_; |
| ProxyListener proxy_listener_; |
| std::unique_ptr<IPC::AttachmentBrokerUnprivilegedWin> broker_; |
| MockObserver observer_; |
| DWORD handle_count_; |
| }; |
| |
| // A broker which always sets the current process as the destination process |
| // for attachments. |
| class MockBroker : public IPC::AttachmentBrokerUnprivilegedWin { |
| public: |
| MockBroker() {} |
| ~MockBroker() override {} |
| bool SendAttachmentToProcess( |
| const scoped_refptr<IPC::BrokerableAttachment>& attachment, |
| base::ProcessId destination_process) override { |
| return IPC::AttachmentBrokerUnprivilegedWin::SendAttachmentToProcess( |
| attachment, base::Process::Current().Pid()); |
| } |
| }; |
| |
| // An unprivileged process makes a file HANDLE, and writes a string to it. The |
| // file HANDLE is sent to the privileged process using the attachment broker. |
| // The privileged process dups the HANDLE into its own HANDLE table. This test |
| // checks that the file has the same contents in the privileged process. |
| TEST_F(IPCAttachmentBrokerPrivilegedWinTest, SendHandle) { |
| Init("SendHandle"); |
| |
| CommonSetUp(); |
| ResultListener result_listener; |
| get_proxy_listener()->set_listener(&result_listener); |
| |
| HANDLE h = CreateTempFile(); |
| SendMessageWithAttachment(h); |
| base::RunLoop().Run(); |
| |
| // Check the result. |
| ASSERT_EQ(ProxyListener::MESSAGE_RECEIVED, |
| get_proxy_listener()->get_reason()); |
| ASSERT_EQ(result_listener.get_result(), RESULT_SUCCESS); |
| |
| CommonTearDown(); |
| } |
| |
| // Similar to SendHandle, except the file HANDLE attached to the message has |
| // neither read nor write permissions. |
| TEST_F(IPCAttachmentBrokerPrivilegedWinTest, |
| SendHandleWithoutPermissions) { |
| Init("SendHandleWithoutPermissions"); |
| |
| CommonSetUp(); |
| ResultListener result_listener; |
| get_proxy_listener()->set_listener(&result_listener); |
| |
| HANDLE h = CreateTempFile(); |
| HANDLE h2; |
| BOOL result = ::DuplicateHandle(GetCurrentProcess(), h, GetCurrentProcess(), |
| &h2, 0, FALSE, DUPLICATE_CLOSE_SOURCE); |
| ASSERT_TRUE(result); |
| IPC::HandleWin handle_win(h2, IPC::HandleWin::DUPLICATE); |
| IPC::Message* message = new TestHandleWinMsg(100, handle_win, 200); |
| sender()->Send(message); |
| base::RunLoop().Run(); |
| |
| // Check the result. |
| ASSERT_EQ(ProxyListener::MESSAGE_RECEIVED, |
| get_proxy_listener()->get_reason()); |
| ASSERT_EQ(result_listener.get_result(), RESULT_SUCCESS); |
| |
| CommonTearDown(); |
| } |
| |
| // Similar to SendHandle, except the attachment's destination process is this |
| // process. This is an unrealistic scenario, but simulates an unprivileged |
| // process sending an attachment to another unprivileged process. |
| TEST_F(IPCAttachmentBrokerPrivilegedWinTest, SendHandleToSelf) { |
| Init("SendHandleToSelf"); |
| |
| set_broker(new MockBroker); |
| |
| PreConnectSetUp(); |
| // Technically, the channel is an endpoint, but we need the proxy listener to |
| // receive the messages so that it can quit the message loop. |
| channel()->SetAttachmentBrokerEndpoint(false); |
| PostConnectSetUp(); |
| get_proxy_listener()->set_listener(get_broker()); |
| |
| HANDLE h = CreateTempFile(); |
| SendMessageWithAttachment(h); |
| base::RunLoop().Run(); |
| |
| // Get the received attachment. |
| IPC::BrokerableAttachment::AttachmentId* id = get_observer()->get_id(); |
| scoped_refptr<IPC::BrokerableAttachment> received_attachment; |
| get_broker()->GetAttachmentWithId(*id, &received_attachment); |
| ASSERT_NE(received_attachment.get(), nullptr); |
| |
| // Check that it's a different entry in the HANDLE table. |
| ScopedHandle h2(GetHandleFromBrokeredAttachment(received_attachment)); |
| EXPECT_NE(h2.Get(), h); |
| |
| // But still points to the same file. |
| std::string contents = ReadFromFile(h2.Get()); |
| EXPECT_EQ(contents, std::string(kDataBuffer)); |
| |
| CommonTearDown(); |
| } |
| |
| // Similar to SendHandle, but sends a message with two instances of the same |
| // handle. |
| TEST_F(IPCAttachmentBrokerPrivilegedWinTest, SendTwoHandles) { |
| Init("SendTwoHandles"); |
| |
| CommonSetUp(); |
| ResultListener result_listener; |
| get_proxy_listener()->set_listener(&result_listener); |
| |
| HANDLE h = CreateTempFile(); |
| HANDLE h2; |
| BOOL result = ::DuplicateHandle(GetCurrentProcess(), h, GetCurrentProcess(), |
| &h2, 0, FALSE, DUPLICATE_SAME_ACCESS); |
| ASSERT_TRUE(result); |
| IPC::HandleWin handle_win1(h, IPC::HandleWin::FILE_READ_WRITE); |
| IPC::HandleWin handle_win2(h2, IPC::HandleWin::FILE_READ_WRITE); |
| IPC::Message* message = new TestTwoHandleWinMsg(handle_win1, handle_win2); |
| sender()->Send(message); |
| base::RunLoop().Run(); |
| |
| // Check the result. |
| ASSERT_EQ(ProxyListener::MESSAGE_RECEIVED, |
| get_proxy_listener()->get_reason()); |
| ASSERT_EQ(result_listener.get_result(), RESULT_SUCCESS); |
| |
| CommonTearDown(); |
| } |
| |
| // Similar to SendHandle, but sends the same message twice. |
| TEST_F(IPCAttachmentBrokerPrivilegedWinTest, SendHandleTwice) { |
| Init("SendHandleTwice"); |
| |
| CommonSetUp(); |
| ResultListener result_listener; |
| get_proxy_listener()->set_listener(&result_listener); |
| |
| HANDLE h = CreateTempFile(); |
| HANDLE h2; |
| BOOL result = ::DuplicateHandle(GetCurrentProcess(), h, GetCurrentProcess(), |
| &h2, 0, FALSE, DUPLICATE_SAME_ACCESS); |
| ASSERT_TRUE(result); |
| SendMessageWithAttachment(h); |
| SendMessageWithAttachment(h2); |
| base::RunLoop().Run(); |
| |
| // Check the result. |
| ASSERT_EQ(ProxyListener::MESSAGE_RECEIVED, |
| get_proxy_listener()->get_reason()); |
| ASSERT_EQ(result_listener.get_result(), RESULT_SUCCESS); |
| |
| CommonTearDown(); |
| } |
| |
| // An unprivileged process makes a shared memory region and sends it to the |
| // privileged process. |
| TEST_F(IPCAttachmentBrokerPrivilegedWinTest, SendSharedMemoryHandle) { |
| Init("SendSharedMemoryHandle"); |
| |
| CommonSetUp(); |
| ResultListener result_listener; |
| get_proxy_listener()->set_listener(&result_listener); |
| |
| std::unique_ptr<base::SharedMemory> shared_memory(new base::SharedMemory); |
| shared_memory->CreateAndMapAnonymous(kSharedMemorySize); |
| memcpy(shared_memory->memory(), kDataBuffer, strlen(kDataBuffer)); |
| sender()->Send(new TestSharedMemoryHandleMsg1(shared_memory->handle())); |
| base::RunLoop().Run(); |
| |
| // Check the result. |
| ASSERT_EQ(ProxyListener::MESSAGE_RECEIVED, |
| get_proxy_listener()->get_reason()); |
| ASSERT_EQ(result_listener.get_result(), RESULT_SUCCESS); |
| |
| CommonTearDown(); |
| } |
| |
| using OnMessageReceivedCallback = void (*)(IPC::Sender* sender, |
| const IPC::Message& message); |
| |
| int CommonPrivilegedProcessMain(OnMessageReceivedCallback callback, |
| const char* channel_name) { |
| LOG(INFO) << "Privileged process start."; |
| base::MessageLoopForIO main_message_loop; |
| ProxyListener listener; |
| |
| // Set up IPC channel. |
| IPC::AttachmentBrokerPrivilegedWin broker; |
| std::unique_ptr<IPC::Channel> channel(IPC::Channel::CreateClient( |
| IPCTestBase::GetChannelName(channel_name), &listener)); |
| broker.RegisterCommunicationChannel(channel.get(), nullptr); |
| CHECK(channel->Connect()); |
| |
| while (true) { |
| LOG(INFO) << "Privileged process spinning run loop."; |
| base::RunLoop().Run(); |
| ProxyListener::Reason reason = listener.get_reason(); |
| if (reason == ProxyListener::CHANNEL_ERROR) |
| break; |
| |
| while (listener.has_message()) { |
| LOG(INFO) << "Privileged process running callback."; |
| callback(channel.get(), listener.get_first_message()); |
| LOG(INFO) << "Privileged process finishing callback."; |
| listener.pop_first_message(); |
| } |
| } |
| |
| LOG(INFO) << "Privileged process end."; |
| return 0; |
| } |
| |
| void SendHandleCallback(IPC::Sender* sender, const IPC::Message& message) { |
| bool success = CheckContentsOfTestMessage(message); |
| SendControlMessage(sender, success); |
| } |
| |
| MULTIPROCESS_IPC_TEST_CLIENT_MAIN(SendHandle) { |
| return CommonPrivilegedProcessMain(&SendHandleCallback, "SendHandle"); |
| } |
| |
| void SendHandleWithoutPermissionsCallback(IPC::Sender* sender, |
| const IPC::Message& message) { |
| ScopedHandle h(GetHandleFromTestHandleWinMsg(message)); |
| if (h.Get() != nullptr) { |
| SetFilePointer(h.Get(), 0, nullptr, FILE_BEGIN); |
| |
| char buffer[100]; |
| DWORD bytes_read; |
| BOOL success = |
| ::ReadFile(h.Get(), buffer, static_cast<DWORD>(strlen(kDataBuffer)), |
| &bytes_read, nullptr); |
| if (!success && GetLastError() == ERROR_ACCESS_DENIED) { |
| SendControlMessage(sender, true); |
| return; |
| } |
| } |
| |
| SendControlMessage(sender, false); |
| } |
| |
| MULTIPROCESS_IPC_TEST_CLIENT_MAIN(SendHandleWithoutPermissions) { |
| return CommonPrivilegedProcessMain(&SendHandleWithoutPermissionsCallback, |
| "SendHandleWithoutPermissions"); |
| } |
| |
| void SendHandleToSelfCallback(IPC::Sender* sender, const IPC::Message&) { |
| // Do nothing special. The default behavior already runs the |
| // AttachmentBrokerPrivilegedWin. |
| } |
| |
| MULTIPROCESS_IPC_TEST_CLIENT_MAIN(SendHandleToSelf) { |
| return CommonPrivilegedProcessMain(&SendHandleToSelfCallback, |
| "SendHandleToSelf"); |
| } |
| |
| void SendTwoHandlesCallback(IPC::Sender* sender, const IPC::Message& message) { |
| // Check for two handles. |
| HANDLE h1, h2; |
| EXPECT_TRUE(GetHandleFromTestTwoHandleWinMsg(message, &h1, &h2)); |
| if (h1 == nullptr || h2 == nullptr) { |
| SendControlMessage(sender, false); |
| return; |
| } |
| |
| // Check that their contents are correct. |
| std::string contents1 = ReadFromFile(h1); |
| std::string contents2 = ReadFromFile(h2); |
| if (contents1 != std::string(kDataBuffer) || |
| contents2 != std::string(kDataBuffer)) { |
| SendControlMessage(sender, false); |
| return; |
| } |
| |
| // Check that the handles point to the same file. |
| const char text[] = "katy perry"; |
| DWORD bytes_written = 0; |
| SetFilePointer(h1, 0, nullptr, FILE_BEGIN); |
| BOOL success = ::WriteFile(h1, text, static_cast<DWORD>(strlen(text)), |
| &bytes_written, nullptr); |
| if (!success) { |
| SendControlMessage(sender, false); |
| return; |
| } |
| |
| SetFilePointer(h2, 0, nullptr, FILE_BEGIN); |
| char buffer[100]; |
| DWORD bytes_read; |
| success = ::ReadFile(h2, buffer, static_cast<DWORD>(strlen(text)), |
| &bytes_read, nullptr); |
| if (!success) { |
| SendControlMessage(sender, false); |
| return; |
| } |
| success = std::string(buffer, bytes_read) == std::string(text); |
| SendControlMessage(sender, success); |
| } |
| |
| MULTIPROCESS_IPC_TEST_CLIENT_MAIN(SendTwoHandles) { |
| return CommonPrivilegedProcessMain(&SendTwoHandlesCallback, "SendTwoHandles"); |
| } |
| |
| void SendHandleTwiceCallback(IPC::Sender* sender, const IPC::Message& message) { |
| // We expect the same message twice. |
| static int i = 0; |
| static bool success = true; |
| success &= CheckContentsOfTestMessage(message); |
| if (i == 0) { |
| LOG(INFO) << "Received first message."; |
| ++i; |
| } else { |
| LOG(INFO) << "Received second message."; |
| SendControlMessage(sender, success); |
| } |
| } |
| |
| MULTIPROCESS_IPC_TEST_CLIENT_MAIN(SendHandleTwice) { |
| return CommonPrivilegedProcessMain(&SendHandleTwiceCallback, |
| "SendHandleTwice"); |
| } |
| |
| void SendSharedMemoryHandleCallback(IPC::Sender* sender, |
| const IPC::Message& message) { |
| std::unique_ptr<base::SharedMemory> shared_memory = |
| GetSharedMemoryFromSharedMemoryHandleMsg1(message, kSharedMemorySize); |
| bool success = |
| memcmp(shared_memory->memory(), kDataBuffer, strlen(kDataBuffer)) == 0; |
| SendControlMessage(sender, success); |
| } |
| |
| MULTIPROCESS_IPC_TEST_CLIENT_MAIN(SendSharedMemoryHandle) { |
| return CommonPrivilegedProcessMain(&SendSharedMemoryHandleCallback, |
| "SendSharedMemoryHandle"); |
| } |
| |
| } // namespace |