• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "message_parcel.h"
17 
18 #include <sys/mman.h>
19 #include <unistd.h>
20 
21 #include "ashmem.h"
22 #ifndef CONFIG_IPC_SINGLE
23 #include "dbinder_callback_stub.h"
24 #include "dbinder_session_object.h"
25 #endif
26 #include "ipc_debug.h"
27 #include "ipc_file_descriptor.h"
28 #include "ipc_process_skeleton.h"
29 #include "iremote_object.h"
30 #include "log_tags.h"
31 #include "securec.h"
32 #include "sys_binder.h"
33 
34 namespace OHOS {
35 #ifndef TITLE
36 #define TITLE __PRETTY_FUNCTION__
37 #endif
38 
39 #ifndef CONFIG_IPC_SINGLE
40 static constexpr OHOS::HiviewDFX::HiLogLabel LOG_LABEL = { LOG_CORE, LOG_ID_RPC, "MessageParcel" };
41 #define DBINDER_LOGE(fmt, args...) \
42     (void)OHOS::HiviewDFX::HiLog::Error(LOG_LABEL, "%{public}s %{public}d: " fmt, TITLE, __LINE__, ##args)
43 #define DBINDER_LOGI(fmt, args...) \
44     (void)OHOS::HiviewDFX::HiLog::Info(LOG_LABEL, "%{public}s %{public}d: " fmt, TITLE, __LINE__, ##args)
45 #endif
46 
47 
MessageParcel()48 MessageParcel::MessageParcel()
49     : Parcel(),
50       writeRawDataFd_(-1),
51       readRawDataFd_(-1),
52       kernelMappedWrite_(nullptr),
53       kernelMappedRead_(nullptr),
54       rawData_(nullptr),
55       rawDataSize_(0)
56 {}
57 
MessageParcel(Allocator * allocator)58 MessageParcel::MessageParcel(Allocator *allocator)
59     : Parcel(allocator),
60       writeRawDataFd_(-1),
61       readRawDataFd_(-1),
62       kernelMappedWrite_(nullptr),
63       kernelMappedRead_(nullptr),
64       rawData_(nullptr),
65       rawDataSize_(0)
66 {}
67 
~MessageParcel()68 MessageParcel::~MessageParcel()
69 {
70     if (kernelMappedWrite_ != nullptr) {
71         ::munmap(kernelMappedWrite_, rawDataSize_);
72         kernelMappedWrite_ = nullptr;
73     }
74     if (kernelMappedRead_ != nullptr) {
75         ::munmap(kernelMappedRead_, rawDataSize_);
76         kernelMappedRead_ = nullptr;
77     }
78 
79     if (readRawDataFd_ > 0) {
80         ::close(readRawDataFd_);
81         readRawDataFd_ = -1;
82     }
83     if (writeRawDataFd_ > 0) {
84         ::close(writeRawDataFd_);
85         writeRawDataFd_ = -1;
86     }
87 
88     ClearFileDescriptor();
89 
90     rawData_ = nullptr;
91     rawDataSize_ = 0;
92 }
93 
94 
95 #ifndef CONFIG_IPC_SINGLE
WriteDBinderProxy(const sptr<IRemoteObject> & object,uint32_t handle,uint64_t stubIndex)96 bool MessageParcel::WriteDBinderProxy(const sptr<IRemoteObject> &object, uint32_t handle, uint64_t stubIndex)
97 {
98     IPCProcessSkeleton *current = IPCProcessSkeleton::GetCurrent();
99     if (current == nullptr) {
100         DBINDER_LOGE("current is nullptr");
101         return false;
102     }
103     std::shared_ptr<DBinderSessionObject> sessionOfPeer = current->ProxyQueryDBinderSession(handle);
104     if (sessionOfPeer == nullptr) {
105         DBINDER_LOGE("sessionOfPeer is nullptr");
106         return false;
107     }
108     std::string peerName = sessionOfPeer->GetServiceName();
109     std::string peerId = sessionOfPeer->GetDeviceId();
110     std::string localId = current->GetLocalDeviceID();
111     sptr<DBinderCallbackStub> fakeStub = current->QueryDBinderCallbackStub(object);
112     if (fakeStub == nullptr) {
113         // note that cannot use this proxy's descriptor
114         fakeStub = new DBinderCallbackStub(peerName, peerId, localId, stubIndex, handle);
115         if (!current->AttachDBinderCallbackStub(object, fakeStub)) {
116             DBINDER_LOGE("save callback of fake stub failed");
117             return false;
118         }
119     }
120     return WriteRemoteObject(fakeStub);
121 }
122 #endif
123 
WriteRemoteObject(const sptr<IRemoteObject> & object)124 bool MessageParcel::WriteRemoteObject(const sptr<IRemoteObject> &object)
125 {
126     if (object == nullptr) {
127         return false;
128     }
129     holders_.push_back(object);
130 #ifndef CONFIG_IPC_SINGLE
131     if (object->IsProxyObject()) {
132         const IPCObjectProxy *proxy = reinterpret_cast<const IPCObjectProxy *>(object.GetRefPtr());
133         const uint32_t handle = proxy ? proxy->GetHandle() : 0;
134         IPCProcessSkeleton *current = IPCProcessSkeleton::GetCurrent();
135         if (IPCProcessSkeleton::IsHandleMadeByUser(handle) && current != nullptr) {
136             DBINDER_LOGI("send dbinder object to local devices");
137             /* this is a fake proxy which handle get by MakeRemoteHandle(), Not binder driver of kernel */
138             uint64_t stubIndex = current->QueryHandleToIndex(handle);
139             if (stubIndex > 0) {
140                 DBINDER_LOGI("this is dbinder proxy want to send anthor process in this device");
141                 return WriteDBinderProxy(object, handle, stubIndex);
142             }
143         }
144     }
145 #endif
146     auto result = WriteObject<IRemoteObject>(object);
147     if (result == false) {
148         return result;
149     }
150     return result;
151 }
152 
ReadRemoteObject()153 sptr<IRemoteObject> MessageParcel::ReadRemoteObject()
154 {
155     sptr<IRemoteObject> temp = ReadObject<IRemoteObject>();
156 #ifndef CONFIG_IPC_SINGLE
157     if (temp != nullptr && !temp->IsProxyObject()) {
158         // if this stub is a DBinderCallbackStub, return corresponding proxy
159         IPCProcessSkeleton *current = IPCProcessSkeleton::GetCurrent();
160         if (current != nullptr) {
161             sptr<IRemoteObject> proxy = current->QueryDBinderCallbackProxy(temp);
162             if (proxy != nullptr) {
163                 temp = proxy;
164             }
165         }
166     }
167 #endif
168     return temp;
169 }
170 
WriteFileDescriptor(int fd)171 bool MessageParcel::WriteFileDescriptor(int fd)
172 {
173     if (fd < 0) {
174         return false;
175     }
176     int dupFd = dup(fd);
177     if (dupFd < 0) {
178         return false;
179     }
180     sptr<IPCFileDescriptor> descriptor = new IPCFileDescriptor(dupFd);
181     return WriteObject<IPCFileDescriptor>(descriptor);
182 }
183 
ReadFileDescriptor()184 int MessageParcel::ReadFileDescriptor()
185 {
186     sptr<IPCFileDescriptor> descriptor = ReadObject<IPCFileDescriptor>();
187     if (descriptor == nullptr) {
188         return -1;
189     }
190     int fd = descriptor->GetFd();
191     if (fd < 0) {
192         return -1;
193     }
194     holders_.push_back(descriptor);
195     return dup(fd);
196 }
197 
ClearFileDescriptor()198 void MessageParcel::ClearFileDescriptor()
199 {
200     binder_size_t *object = reinterpret_cast<binder_size_t *>(GetObjectOffsets());
201     size_t objectNum = GetOffsetsSize();
202     uintptr_t data = GetData();
203     for (size_t i = 0; i < objectNum; i++) {
204         const flat_binder_object *flat = reinterpret_cast<flat_binder_object *>(data + object[i]);
205         if (flat->hdr.type == BINDER_TYPE_FD && flat->handle > 0) {
206             ::close(flat->handle);
207         }
208     }
209 }
210 
ContainFileDescriptors() const211 bool MessageParcel::ContainFileDescriptors() const
212 {
213     binder_size_t *object = reinterpret_cast<binder_size_t *>(GetObjectOffsets());
214     size_t objectNum = GetOffsetsSize();
215     uintptr_t data = GetData();
216     for (size_t i = 0; i < objectNum; i++) {
217         const flat_binder_object *flat = reinterpret_cast<flat_binder_object *>(data + object[i]);
218         if (flat->hdr.type == BINDER_TYPE_FD) {
219             return true;
220         }
221     }
222 
223     return false;
224 }
225 
WriteInterfaceToken(std::u16string name)226 bool MessageParcel::WriteInterfaceToken(std::u16string name)
227 {
228     constexpr int strictModePolicy = 0x100;
229     constexpr int workSource = 0;
230     size_t rewindPos = GetWritePosition();
231     if (!WriteInt32(strictModePolicy)) {
232         return false;
233     }
234 
235     if (!WriteInt32(workSource)) {
236         if (!RewindWrite(rewindPos)) {
237             FlushBuffer();
238         }
239         return false;
240     }
241 
242     return WriteString16(name);
243 }
244 
ReadInterfaceToken()245 std::u16string MessageParcel::ReadInterfaceToken()
246 {
247     [[maybe_unused]] int strictModePolicy = ReadInt32();
248     [[maybe_unused]] int workSource = ReadInt32();
249     return ReadString16();
250 }
251 
WriteRawData(const void * data,size_t size)252 bool MessageParcel::WriteRawData(const void *data, size_t size)
253 {
254     if (data == nullptr || size > MAX_RAWDATA_SIZE) {
255         return false;
256     }
257     if (kernelMappedWrite_ != nullptr) {
258         return false;
259     }
260     if (!WriteInt32(size)) {
261         return false;
262     }
263     if (size <= MIN_RAWDATA_SIZE) {
264         return WriteUnpadBuffer(data, size);
265     }
266     int fd = AshmemCreate("Parcel RawData", size);
267     if (fd < 0) {
268         return false;
269     }
270     writeRawDataFd_ = fd;
271 
272     int result = AshmemSetProt(fd, PROT_READ | PROT_WRITE);
273     if (result < 0) {
274         return false;
275     }
276     void *ptr = ::mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
277     if (ptr == MAP_FAILED) {
278         return false;
279     }
280     if (!WriteFileDescriptor(fd)) {
281         ::munmap(ptr, size);
282         return false;
283     }
284     if (memcpy_s(ptr, size, data, size) != EOK) {
285         ::munmap(ptr, size);
286         return false;
287     }
288     kernelMappedWrite_ = ptr;
289     rawDataSize_ = size;
290     return true;
291 }
292 
RestoreRawData(std::shared_ptr<char> rawData,size_t size)293 bool MessageParcel::RestoreRawData(std::shared_ptr<char> rawData, size_t size)
294 {
295     if (rawData_ != nullptr || rawData == nullptr) {
296         return false;
297     }
298     rawData_ = rawData;
299     rawDataSize_ = size;
300     writeRawDataFd_ = 0;
301     return true;
302 }
303 
ReadRawData(size_t size)304 const void *MessageParcel::ReadRawData(size_t size)
305 {
306     int32_t bufferSize = ReadInt32();
307     if (static_cast<unsigned int>(bufferSize) != size) {
308         return nullptr;
309     }
310 
311     if (static_cast<unsigned int>(bufferSize) <= MIN_RAWDATA_SIZE) {
312         return ReadUnpadBuffer(size);
313     }
314 
315     /* if rawDataFd_ == 0 means rawData is received from remote
316      */
317     if (rawData_ != nullptr && writeRawDataFd_ == 0) {
318         /* should read fd for move readCursor of parcel */
319         if (ReadFileDescriptor()) {
320             // do nothing
321         }
322         if (rawDataSize_ != size) {
323             return nullptr;
324         }
325         return rawData_.get();
326     }
327     int fd = ReadFileDescriptor();
328     if (fd < 0) {
329         return nullptr;
330     }
331     readRawDataFd_ = fd;
332 
333     int ashmemSize = AshmemGetSize(fd);
334     if (ashmemSize < 0 || size_t(ashmemSize) < size) {
335         // do not close fd here. fd will be closed in FileDescriptor, ::close(fd)
336         return nullptr;
337     }
338     void *ptr = ::mmap(nullptr, size, PROT_READ, MAP_SHARED, fd, 0);
339     if (ptr == MAP_FAILED) {
340         // do not close fd here. fd will be closed in FileDescriptor, ::close(fd)
341         return nullptr;
342     }
343     kernelMappedRead_ = ptr;
344     rawDataSize_ = size;
345     return ptr;
346 }
347 
GetRawData() const348 const void *MessageParcel::GetRawData() const
349 {
350     if (rawData_ != nullptr) {
351         return rawData_.get();
352     }
353     if (kernelMappedWrite_ != nullptr) {
354         return kernelMappedWrite_;
355     }
356     if (kernelMappedRead_ != nullptr) {
357         return kernelMappedRead_;
358     }
359     return nullptr;
360 }
361 
GetRawDataSize() const362 size_t MessageParcel::GetRawDataSize() const
363 {
364     return rawDataSize_;
365 }
366 
GetRawDataCapacity() const367 size_t MessageParcel::GetRawDataCapacity() const
368 {
369     return MAX_RAWDATA_SIZE;
370 }
371 
WriteNoException()372 void MessageParcel::WriteNoException()
373 {
374     WriteInt32(0);
375 }
376 
ReadException()377 int32_t MessageParcel::ReadException()
378 {
379     int32_t errorCode = ReadInt32();
380     if (errorCode != 0) {
381         ReadString16();
382     }
383     return errorCode;
384 }
385 
WriteAshmem(sptr<Ashmem> ashmem)386 bool MessageParcel::WriteAshmem(sptr<Ashmem> ashmem)
387 {
388     int fd = ashmem->GetAshmemFd();
389     int32_t size = ashmem->GetAshmemSize();
390     if (fd < 0 || size <= 0) {
391         return false;
392     }
393     if (!WriteFileDescriptor(fd) || !WriteInt32(size)) {
394         return false;
395     }
396     return true;
397 }
398 
ReadAshmem()399 sptr<Ashmem> MessageParcel::ReadAshmem()
400 {
401     int fd = ReadFileDescriptor();
402     if (fd < 0) {
403         return nullptr;
404     }
405 
406     int32_t size = ReadInt32();
407     if (size <= 0) {
408         ::close(fd);
409         return nullptr;
410     }
411     return new Ashmem(fd, size);
412 }
413 } // namespace OHOS
414