1 // Copyright 2015 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 "base/memory/shared_memory_handle.h"
6 
7 #include <mach/mach_vm.h>
8 #include <stddef.h>
9 #include <sys/mman.h>
10 #include <unistd.h>
11 
12 #include "base/mac/mac_util.h"
13 #include "base/posix/eintr_wrapper.h"
14 
15 namespace base {
16 
SharedMemoryHandle()17 SharedMemoryHandle::SharedMemoryHandle() {}
18 
SharedMemoryHandle(mach_vm_size_t size)19 SharedMemoryHandle::SharedMemoryHandle(mach_vm_size_t size) {
20   mach_port_t named_right;
21   kern_return_t kr = mach_make_memory_entry_64(
22       mach_task_self(),
23       &size,
24       0,  // Address.
25       MAP_MEM_NAMED_CREATE | VM_PROT_READ | VM_PROT_WRITE,
26       &named_right,
27       MACH_PORT_NULL);  // Parent handle.
28   if (kr != KERN_SUCCESS) {
29     memory_object_ = MACH_PORT_NULL;
30     return;
31   }
32 
33   memory_object_ = named_right;
34   size_ = size;
35   pid_ = GetCurrentProcId();
36   ownership_passes_to_ipc_ = false;
37 }
38 
SharedMemoryHandle(mach_port_t memory_object,mach_vm_size_t size,base::ProcessId pid)39 SharedMemoryHandle::SharedMemoryHandle(mach_port_t memory_object,
40                                        mach_vm_size_t size,
41                                        base::ProcessId pid)
42     : memory_object_(memory_object),
43       size_(size),
44       pid_(pid),
45       ownership_passes_to_ipc_(false) {}
46 
SharedMemoryHandle(const SharedMemoryHandle & handle)47 SharedMemoryHandle::SharedMemoryHandle(const SharedMemoryHandle& handle) {
48   CopyRelevantData(handle);
49 }
50 
operator =(const SharedMemoryHandle & handle)51 SharedMemoryHandle& SharedMemoryHandle::operator=(
52     const SharedMemoryHandle& handle) {
53   if (this == &handle)
54     return *this;
55 
56   CopyRelevantData(handle);
57   return *this;
58 }
59 
Duplicate() const60 SharedMemoryHandle SharedMemoryHandle::Duplicate() const {
61   if (!IsValid())
62     return SharedMemoryHandle(MACH_PORT_NULL, 0, 0);
63 
64   // Increment the ref count.
65   kern_return_t kr = mach_port_mod_refs(mach_task_self(), memory_object_,
66                                         MACH_PORT_RIGHT_SEND, 1);
67   DCHECK_EQ(kr, KERN_SUCCESS);
68   SharedMemoryHandle handle(*this);
69   handle.SetOwnershipPassesToIPC(true);
70   return handle;
71 }
72 
operator ==(const SharedMemoryHandle & handle) const73 bool SharedMemoryHandle::operator==(const SharedMemoryHandle& handle) const {
74   if (!IsValid() && !handle.IsValid())
75     return true;
76 
77   return memory_object_ == handle.memory_object_ && size_ == handle.size_ &&
78          pid_ == handle.pid_;
79 }
80 
operator !=(const SharedMemoryHandle & handle) const81 bool SharedMemoryHandle::operator!=(const SharedMemoryHandle& handle) const {
82   return !(*this == handle);
83 }
84 
IsValid() const85 bool SharedMemoryHandle::IsValid() const {
86   return memory_object_ != MACH_PORT_NULL;
87 }
88 
GetMemoryObject() const89 mach_port_t SharedMemoryHandle::GetMemoryObject() const {
90   return memory_object_;
91 }
92 
GetSize(size_t * size) const93 bool SharedMemoryHandle::GetSize(size_t* size) const {
94   if (!IsValid()) {
95     *size = 0;
96     return true;
97   }
98 
99   *size = size_;
100   return true;
101 }
102 
MapAt(off_t offset,size_t bytes,void ** memory,bool read_only)103 bool SharedMemoryHandle::MapAt(off_t offset,
104                                size_t bytes,
105                                void** memory,
106                                bool read_only) {
107   DCHECK(IsValid());
108   DCHECK_EQ(pid_, GetCurrentProcId());
109   kern_return_t kr = mach_vm_map(
110       mach_task_self(),
111       reinterpret_cast<mach_vm_address_t*>(memory),  // Output parameter
112       bytes,
113       0,  // Alignment mask
114       VM_FLAGS_ANYWHERE, memory_object_, offset,
115       FALSE,                                           // Copy
116       VM_PROT_READ | (read_only ? 0 : VM_PROT_WRITE),  // Current protection
117       VM_PROT_WRITE | VM_PROT_READ | VM_PROT_IS_MASK,  // Maximum protection
118       VM_INHERIT_NONE);
119   return kr == KERN_SUCCESS;
120 }
121 
Close() const122 void SharedMemoryHandle::Close() const {
123   if (!IsValid())
124     return;
125 
126   kern_return_t kr = mach_port_deallocate(mach_task_self(), memory_object_);
127   if (kr != KERN_SUCCESS)
128     DPLOG(ERROR) << "Error deallocating mach port: " << kr;
129 }
130 
SetOwnershipPassesToIPC(bool ownership_passes)131 void SharedMemoryHandle::SetOwnershipPassesToIPC(bool ownership_passes) {
132   ownership_passes_to_ipc_ = ownership_passes;
133 }
134 
OwnershipPassesToIPC() const135 bool SharedMemoryHandle::OwnershipPassesToIPC() const {
136   return ownership_passes_to_ipc_;
137 }
138 
CopyRelevantData(const SharedMemoryHandle & handle)139 void SharedMemoryHandle::CopyRelevantData(const SharedMemoryHandle& handle) {
140   memory_object_ = handle.memory_object_;
141   size_ = handle.size_;
142   pid_ = handle.pid_;
143   ownership_passes_to_ipc_ = handle.ownership_passes_to_ipc_;
144 }
145 
146 }  // namespace base
147