Skip to content

Commit

Permalink
ipc: Add the class HandleWin.
Browse files Browse the repository at this point in the history
HandleWin is a wrapper around a Windows HANDLE that can be transported across
IPC channels that support attachment brokering. The attachment broker is
responsible for duplicating the HANDLE into the destination process.

BUG=493414

Review URL: https://codereview.chromium.org/1281083004

Cr-Commit-Position: refs/heads/master@{#342897}
  • Loading branch information
erikchen authored and Commit bot committed Aug 11, 2015
1 parent 1d30631 commit 959039d
Show file tree
Hide file tree
Showing 11 changed files with 179 additions and 14 deletions.
2 changes: 2 additions & 0 deletions ipc/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ component("ipc") {
"brokerable_attachment.h",
"handle_attachment_win.cc",
"handle_attachment_win.h",
"handle_win.cc",
"handle_win.h",
"ipc_channel.cc",
"ipc_channel.h",
"ipc_channel_common.cc",
Expand Down
4 changes: 4 additions & 0 deletions ipc/attachment_broker_messages.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,13 @@
// ----------------------------------------------------------------------------

#if defined(OS_WIN)
// Define the serialization for Permissions.
IPC_ENUM_TRAITS_MAX_VALUE(HandleWin::Permissions, HandleWin::MAX_PERMISSIONS);

IPC_STRUCT_TRAITS_BEGIN(IPC::internal::HandleAttachmentWin::WireFormat)
IPC_STRUCT_TRAITS_MEMBER(handle)
IPC_STRUCT_TRAITS_MEMBER(destination_process)
IPC_STRUCT_TRAITS_MEMBER(permissions)
IPC_STRUCT_TRAITS_MEMBER(attachment_id)
IPC_STRUCT_TRAITS_END()
#endif // defined(OS_WIN)
Expand Down
23 changes: 19 additions & 4 deletions ipc/attachment_broker_privileged_win.cc
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,8 @@ AttachmentBrokerPrivilegedWin::DuplicateWinHandle(
HandleWireFormat new_wire_format;
new_wire_format.destination_process = wire_format.destination_process;
new_wire_format.attachment_id = wire_format.attachment_id;
new_wire_format.permissions = wire_format.permissions;
new_wire_format.handle = 0;

HANDLE original_handle = LongToHandle(wire_format.handle);

Expand All @@ -103,15 +105,28 @@ AttachmentBrokerPrivilegedWin::DuplicateWinHandle(
base::Process dest_process =
base::Process::OpenWithExtraPrivileges(wire_format.destination_process);
if (source_process.Handle() && dest_process.Handle()) {
DWORD desired_access = 0;
DWORD options = 0;
switch (wire_format.permissions) {
case HandleWin::INVALID:
LOG(ERROR) << "Received invalid permissions for duplication.";
return new_wire_format;
case HandleWin::DUPLICATE:
options = DUPLICATE_SAME_ACCESS;
break;
case HandleWin::FILE_READ_WRITE:
desired_access = FILE_GENERIC_READ | FILE_GENERIC_WRITE;
break;
}

HANDLE new_handle;
DWORD result = ::DuplicateHandle(source_process.Handle(), original_handle,
dest_process.Handle(), &new_handle, 0,
FALSE, DUPLICATE_SAME_ACCESS);
dest_process.Handle(), &new_handle,
desired_access, FALSE, options);

new_wire_format.handle = (result != 0) ? HandleToLong(new_handle) : 0;
} else {
new_wire_format.handle = 0;
}

return new_wire_format;
}

Expand Down
2 changes: 1 addition & 1 deletion ipc/attachment_broker_privileged_win.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ class IPC_EXPORT AttachmentBrokerPrivilegedWin
private:
using HandleWireFormat = internal::HandleAttachmentWin::WireFormat;
// IPC message handlers.
void OnDuplicateWinHandle(const IPC::Message& message);
void OnDuplicateWinHandle(const Message& message);

// Duplicates |wire_Format| from |source_process| into its destination
// process.
Expand Down
31 changes: 30 additions & 1 deletion ipc/attachment_broker_privileged_win_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#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"
Expand Down Expand Up @@ -191,7 +192,7 @@ class IPCAttachmentBrokerPrivilegedWinTest : public IPCTestBase {
new IPC::Message(0, 2, IPC::Message::PRIORITY_NORMAL);
message->WriteInt(message_index_++);
scoped_refptr<IPC::internal::HandleAttachmentWin> attachment(
new IPC::internal::HandleAttachmentWin(h));
new IPC::internal::HandleAttachmentWin(h, IPC::HandleWin::DUPLICATE));
ASSERT_TRUE(message->WriteAttachment(attachment));
sender()->Send(message);
}
Expand Down Expand Up @@ -305,6 +306,30 @@ TEST_F(IPCAttachmentBrokerPrivilegedWinTest, SendHandleToSelf) {
CommonTearDown();
}

// Similar to SendHandle, except this test uses the HandleWin class.
TEST_F(IPCAttachmentBrokerPrivilegedWinTest, SendHandleWin) {
Init("SendHandleWin");

CommonSetUp();
ResultListener result_listener;
get_proxy_listener()->set_listener(&result_listener);

HANDLE h = CreateTempFile();
IPC::HandleWin handle_win(h, IPC::HandleWin::FILE_READ_WRITE);
IPC::Message* message = new IPC::Message(0, 2, IPC::Message::PRIORITY_NORMAL);
message->WriteInt(0);
IPC::ParamTraits<IPC::HandleWin>::Write(message, handle_win);
sender()->Send(message);
base::MessageLoop::current()->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 (*)(MockObserver* observer,
IPC::AttachmentBrokerPrivilegedWin* broker,
Expand Down Expand Up @@ -399,4 +424,8 @@ MULTIPROCESS_IPC_TEST_CLIENT_MAIN(SendHandleToSelf) {
"SendHandleToSelf");
}

MULTIPROCESS_IPC_TEST_CLIENT_MAIN(SendHandleWin) {
return CommonPrivilegedProcessMain(&SendHandleCallback, "SendHandleWin");
}

} // namespace
4 changes: 2 additions & 2 deletions ipc/attachment_broker_unprivileged_win_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ TEST(AttachmentBrokerUnprivilegedWinTest, ReceiveValidMessage) {
HANDLE handle = LongToHandle(8);
base::ProcessId destination = base::Process::Current().Pid();
scoped_refptr<internal::HandleAttachmentWin> attachment(
new internal::HandleAttachmentWin(handle));
new internal::HandleAttachmentWin(handle, HandleWin::DUPLICATE));
AttachmentBrokerMsg_WinHandleHasBeenDuplicated msg(
attachment->GetWireFormat(destination));
AttachmentBrokerUnprivilegedWin attachment_broker;
Expand All @@ -40,7 +40,7 @@ TEST(AttachmentBrokerUnprivilegedWinTest, ReceiveInvalidMessage) {
HANDLE handle = LongToHandle(8);
base::ProcessId destination = base::Process::Current().Pid() + 1;
scoped_refptr<internal::HandleAttachmentWin> attachment(
new internal::HandleAttachmentWin(handle));
new internal::HandleAttachmentWin(handle, HandleWin::DUPLICATE));
AttachmentBrokerMsg_WinHandleHasBeenDuplicated msg(
attachment->GetWireFormat(destination));
AttachmentBrokerUnprivilegedWin attachment_broker;
Expand Down
14 changes: 9 additions & 5 deletions ipc/handle_attachment_win.cc
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,20 @@
namespace IPC {
namespace internal {

HandleAttachmentWin::HandleAttachmentWin(const HANDLE& handle)
: handle_(handle) {
}
HandleAttachmentWin::HandleAttachmentWin(const HANDLE& handle,
HandleWin::Permissions permissions)
: handle_(handle), permissions_(permissions) {}

HandleAttachmentWin::HandleAttachmentWin(const WireFormat& wire_format)
: BrokerableAttachment(wire_format.attachment_id, false),
handle_(LongToHandle(wire_format.handle)) {}
handle_(LongToHandle(wire_format.handle)),
permissions_(wire_format.permissions) {}

HandleAttachmentWin::HandleAttachmentWin(
const BrokerableAttachment::AttachmentId& id)
: BrokerableAttachment(id, true), handle_(INVALID_HANDLE_VALUE) {}
: BrokerableAttachment(id, true),
handle_(INVALID_HANDLE_VALUE),
permissions_(HandleWin::INVALID) {}

HandleAttachmentWin::~HandleAttachmentWin() {
}
Expand Down Expand Up @@ -48,6 +51,7 @@ HandleAttachmentWin::WireFormat HandleAttachmentWin::GetWireFormat(
format.handle = HandleToLong(handle_);
format.attachment_id = GetIdentifier();
format.destination_process = destination;
format.permissions = permissions_;
return format;
}

Expand Down
6 changes: 5 additions & 1 deletion ipc/handle_attachment_win.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

#include "base/process/process_handle.h"
#include "ipc/brokerable_attachment.h"
#include "ipc/handle_win.h"
#include "ipc/ipc_export.h"

namespace IPC {
Expand All @@ -29,10 +30,12 @@ class IPC_EXPORT HandleAttachmentWin : public BrokerableAttachment {
int32_t handle;
// The id of the destination process that the handle is duplicated into.
base::ProcessId destination_process;
// The permissions to use when duplicating the handle.
HandleWin::Permissions permissions;
AttachmentId attachment_id;
};

explicit HandleAttachmentWin(const HANDLE& handle);
HandleAttachmentWin(const HANDLE& handle, HandleWin::Permissions permissions);
explicit HandleAttachmentWin(const WireFormat& wire_format);
explicit HandleAttachmentWin(const BrokerableAttachment::AttachmentId& id);

Expand All @@ -47,6 +50,7 @@ class IPC_EXPORT HandleAttachmentWin : public BrokerableAttachment {
private:
~HandleAttachmentWin() override;
HANDLE handle_;
HandleWin::Permissions permissions_;
};

} // namespace internal
Expand Down
53 changes: 53 additions & 0 deletions ipc/handle_win.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// 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 "ipc/handle_win.h"

#include "base/logging.h"
#include "base/memory/ref_counted.h"
#include "base/strings/string_number_conversions.h"
#include "ipc/handle_attachment_win.h"

namespace IPC {

HandleWin::HandleWin(const HANDLE& handle, Permissions permissions)
: handle_(handle), permissions_(permissions) {}

// static
void ParamTraits<HandleWin>::Write(Message* m, const param_type& p) {
scoped_refptr<IPC::internal::HandleAttachmentWin> attachment(
new IPC::internal::HandleAttachmentWin(p.get_handle(),
p.get_permissions()));
if (!m->WriteAttachment(attachment.Pass()))
NOTREACHED();
}

// static
bool ParamTraits<HandleWin>::Read(const Message* m,
base::PickleIterator* iter,
param_type* r) {
scoped_refptr<MessageAttachment> attachment;
if (!m->ReadAttachment(iter, &attachment))
return false;
if (attachment->GetType() != MessageAttachment::TYPE_BROKERABLE_ATTACHMENT)
return false;
BrokerableAttachment* brokerable_attachment =
static_cast<BrokerableAttachment*>(attachment.get());
if (brokerable_attachment->GetBrokerableType() !=
BrokerableAttachment::WIN_HANDLE) {
return false;
}
IPC::internal::HandleAttachmentWin* handle_attachment =
static_cast<IPC::internal::HandleAttachmentWin*>(brokerable_attachment);
r->set_handle(handle_attachment->get_handle());
return true;
}

// static
void ParamTraits<HandleWin>::Log(const param_type& p, std::string* l) {
l->append(base::StringPrintf("0x%X", p.get_handle()));
l->append(base::IntToString(p.get_permissions()));
}

} // namespace IPC
52 changes: 52 additions & 0 deletions ipc/handle_win.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// 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.

#ifndef IPC_HANDLE_WIN_H_
#define IPC_HANDLE_WIN_H_

#include <windows.h>

#include "ipc/ipc_export.h"
#include "ipc/ipc_message_macros.h"

namespace IPC {

// HandleWin is a wrapper around a Windows HANDLE that can be transported
// across Chrome IPC channels that support attachment brokering. The HANDLE will
// be duplicated into the destination process.
class IPC_EXPORT HandleWin {
public:
enum Permissions {
// A placeholder value to be used by the receiving IPC channel, since the
// permissions information is only used by the broker process.
INVALID,
// The new HANDLE will have the same permissions as the old HANDLE.
DUPLICATE,
// The new HANDLE will have file read and write permissions.
FILE_READ_WRITE,
MAX_PERMISSIONS = FILE_READ_WRITE
};

HandleWin(const HANDLE& handle, Permissions permissions);

HANDLE get_handle() const { return handle_; }
void set_handle(HANDLE handle) { handle_ = handle; }
Permissions get_permissions() const { return permissions_; }

private:
HANDLE handle_;
Permissions permissions_;
};

template <>
struct IPC_EXPORT ParamTraits<HandleWin> {
typedef HandleWin param_type;
static void Write(Message* m, const param_type& p);
static bool Read(const Message* m, base::PickleIterator* iter, param_type* p);
static void Log(const param_type& p, std::string* l);
};

} // namespace IPC

#endif // IPC_HANDLE_WIN_H_
2 changes: 2 additions & 0 deletions ipc/ipc.gypi
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@
'brokerable_attachment.h',
'handle_attachment_win.cc',
'handle_attachment_win.h',
'handle_win.cc',
'handle_win.h',
'ipc_channel.cc',
'ipc_channel.h',
'ipc_channel_factory.cc',
Expand Down

0 comments on commit 959039d

Please sign in to comment.