// 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/attachment_broker_privileged_win.h" #include #include #include "base/process/process.h" #include "ipc/attachment_broker_messages.h" #include "ipc/brokerable_attachment.h" #include "ipc/handle_attachment_win.h" #include "ipc/ipc_channel.h" namespace IPC { AttachmentBrokerPrivilegedWin::AttachmentBrokerPrivilegedWin() {} AttachmentBrokerPrivilegedWin::~AttachmentBrokerPrivilegedWin() {} bool AttachmentBrokerPrivilegedWin::SendAttachmentToProcess( const scoped_refptr& attachment, base::ProcessId destination_process) { switch (attachment->GetBrokerableType()) { case BrokerableAttachment::WIN_HANDLE: { internal::HandleAttachmentWin* handle_attachment = static_cast(attachment.get()); HandleWireFormat wire_format = handle_attachment->GetWireFormat(destination_process); HandleWireFormat new_wire_format = DuplicateWinHandle(wire_format, base::Process::Current().Pid()); handle_attachment->reset_handle_ownership(); if (new_wire_format.handle == 0) return false; RouteDuplicatedHandle(new_wire_format); return true; } case BrokerableAttachment::MACH_PORT: case BrokerableAttachment::PLACEHOLDER: NOTREACHED(); return false; } return false; } bool AttachmentBrokerPrivilegedWin::OnMessageReceived(const Message& msg) { bool handled = true; switch (msg.type()) { IPC_MESSAGE_HANDLER_GENERIC(AttachmentBrokerMsg_DuplicateWinHandle, OnDuplicateWinHandle(msg)) IPC_MESSAGE_UNHANDLED(handled = false) } return handled; } void AttachmentBrokerPrivilegedWin::OnDuplicateWinHandle( const IPC::Message& message) { AttachmentBrokerMsg_DuplicateWinHandle::Param param; if (!AttachmentBrokerMsg_DuplicateWinHandle::Read(&message, ¶m)) return; IPC::internal::HandleAttachmentWin::WireFormat wire_format = std::get<0>(param); if (wire_format.destination_process == base::kNullProcessId) { LogError(NO_DESTINATION); return; } HandleWireFormat new_wire_format = DuplicateWinHandle(wire_format, message.get_sender_pid()); RouteDuplicatedHandle(new_wire_format); } void AttachmentBrokerPrivilegedWin::RouteDuplicatedHandle( const HandleWireFormat& wire_format) { // This process is the destination. if (wire_format.destination_process == base::Process::Current().Pid()) { scoped_refptr attachment( new internal::HandleAttachmentWin(wire_format)); HandleReceivedAttachment(attachment); return; } // Another process is the destination. base::ProcessId dest = wire_format.destination_process; base::AutoLock auto_lock(*get_lock()); AttachmentBrokerPrivileged::EndpointRunnerPair pair = GetSenderWithProcessId(dest); if (!pair.first) { // Assuming that this message was not sent from a malicious process, the // channel endpoint that would have received this message will block // forever. LOG(ERROR) << "Failed to deliver brokerable attachment to process with id: " << dest; LogError(DESTINATION_NOT_FOUND); return; } LogError(DESTINATION_FOUND); SendMessageToEndpoint( pair, new AttachmentBrokerMsg_WinHandleHasBeenDuplicated(wire_format)); } AttachmentBrokerPrivilegedWin::HandleWireFormat AttachmentBrokerPrivilegedWin::DuplicateWinHandle( const HandleWireFormat& wire_format, base::ProcessId source_pid) { // If the source process is the destination process, then no additional work // is required. if (source_pid == wire_format.destination_process) return wire_format; // If the handle is not valid, no additional work is required. if (wire_format.handle == 0) return wire_format; base::Process source_process = base::Process::OpenWithExtraPrivileges(source_pid); base::Process dest_process = base::Process::OpenWithExtraPrivileges(wire_format.destination_process); if (!source_process.Handle() || !dest_process.Handle()) { LogError(ERROR_COULD_NOT_OPEN_SOURCE_OR_DEST); return wire_format; } DWORD desired_access = 0; DWORD options = DUPLICATE_CLOSE_SOURCE; switch (wire_format.permissions) { case HandleWin::INVALID: LogError(ERROR_INVALID_PERMISSIONS); return CopyWireFormat(wire_format, 0); 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; HANDLE original_handle = LongToHandle(wire_format.handle); DWORD result = ::DuplicateHandle(source_process.Handle(), original_handle, dest_process.Handle(), &new_handle, desired_access, FALSE, options); int new_wire_format_handle = (result != 0) ? HandleToLong(new_handle) : 0; return CopyWireFormat(wire_format, new_wire_format_handle); } AttachmentBrokerPrivilegedWin::HandleWireFormat AttachmentBrokerPrivilegedWin::CopyWireFormat( const HandleWireFormat& wire_format, int handle) { return HandleWireFormat(handle, wire_format.destination_process, wire_format.permissions, wire_format.attachment_id); } } // namespace IPC