1 /*
2  * Copyright (C) 2020 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 #pragma once
17 
18 #include <aidl/android/hardware/common/fmq/MQDescriptor.h>
19 #include <aidl/android/hardware/common/fmq/SynchronizedReadWrite.h>
20 #include <aidl/android/hardware/common/fmq/UnsynchronizedWrite.h>
21 #include <cutils/native_handle.h>
22 #include <fmq/AidlMessageQueue.h>
23 #include <hidl/MQDescriptor.h>
24 
25 namespace android {
26 using aidl::android::hardware::common::fmq::GrantorDescriptor;
27 using aidl::android::hardware::common::fmq::MQDescriptor;
28 using hardware::details::logError;
29 
30 /**
31  * This function converts a HIDL hardware::MQDescriptor to an AIDL
32  * aidl::android::hardware::common::fmq::MQDescriptor for Fast
33  * Message Queue.
34  *
35  * This is considered UNSAFE because it is not checking the offsets of each of the
36  * paylod types' fields. In order for these objects to be passed through shared memory safely,
37  * they must have the exact same memory layout. Same size, same alignment, and same
38  * offsets for each field. Make sure this is the case before using this!
39  * Same sized C++ fundamental types and enums with same sized backing types are OK.
40  * Ex 1: uint64_t is compatible with int64_t
41  * Ex 2:
42  * @FixedSize parcelable Foo {
43  *   int a;
44  *   long b;
45  *   MyEnum c; // backed by int32_t
46  * }
47  * struct Bar {
48  *   int a;
49  *   long b;
50  *   YourEnum c; // backed by uint32_t
51  * }
52  * The two types above are compatible with each other as long as the fields have
53  * the same offsets.
54  *
55  * Template params:
56  *    HidlPayload - the type of the payload used for the HIDL MessageQueue
57  *    AidlPayload - the type of the payload used for the AIDL AidlMessageQueue
58  *    AidlFlavor - the flavor of the queues. Either SynchronizedReadWrite,
59  *                 or UnsynchronizedWrite
60  * Function params:
61  *    hidlDesc - reference to the HIDL MQDescriptor to be copied from
62  *    aidlDesc - pointer to the AIDL MQDescriptor to be copied to
63  */
64 template <typename HidlPayload, typename AidlPayload, typename AidlFlavor>
unsafeHidlToAidlMQDescriptor(const hardware::MQDescriptor<HidlPayload,FlavorTypeToValue<AidlFlavor>::value> & hidlDesc,MQDescriptor<AidlPayload,AidlFlavor> * aidlDesc)65 bool unsafeHidlToAidlMQDescriptor(
66         const hardware::MQDescriptor<HidlPayload, FlavorTypeToValue<AidlFlavor>::value>& hidlDesc,
67         MQDescriptor<AidlPayload, AidlFlavor>* aidlDesc) {
68     static_assert(sizeof(HidlPayload) == sizeof(AidlPayload),
69                   "Payload types are definitely incompatible");
70     static_assert(alignof(HidlPayload) == alignof(AidlPayload),
71                   "Payload types are definitely incompatible");
72     STATIC_AIDL_TYPE_CHECK(AidlPayload);
73     if (!aidlDesc->grantors.empty()) {
74         logError("Destination AIDL MQDescriptor should be empty, but already contains grantors.");
75         return false;
76     }
77 
78     for (const auto& grantor : hidlDesc.grantors()) {
79         if (static_cast<int32_t>(grantor.offset) < 0 || static_cast<int64_t>(grantor.extent) < 0 ||
80             static_cast<int64_t>(grantor.fdIndex) < 0) {
81             logError(
82                     "Unsafe static_cast of grantor fields. Either the hardware::MQDescriptor is "
83                     "invalid, or the MessageQueue is too large to be described by AIDL.");
84             return false;
85         }
86         aidlDesc->grantors.push_back(
87                 GrantorDescriptor{.fdIndex = static_cast<int32_t>(grantor.fdIndex),
88                                   .offset = static_cast<int32_t>(grantor.offset),
89                                   .extent = static_cast<int64_t>(grantor.extent)});
90     }
91 
92     std::vector<ndk::ScopedFileDescriptor> fds;
93     std::vector<int> ints;
94     int data_index = 0;
95     for (; data_index < hidlDesc.handle()->numFds; data_index++) {
96         fds.push_back(ndk::ScopedFileDescriptor(dup(hidlDesc.handle()->data[data_index])));
97     }
98     for (; data_index < hidlDesc.handle()->numFds + hidlDesc.handle()->numInts; data_index++) {
99         ints.push_back(hidlDesc.handle()->data[data_index]);
100     }
101 
102     aidlDesc->handle = {std::move(fds), std::move(ints)};
103     if (static_cast<int32_t>(hidlDesc.getQuantum()) < 0 ||
104         static_cast<int32_t>(hidlDesc.getFlags()) < 0) {
105         logError(
106                 "Unsafe static_cast of quantum or flags. Either the hardware::MQDescriptor is "
107                 "invalid, or the MessageQueue is too large to be described by AIDL.");
108         return false;
109     }
110     if (hidlDesc.getFlags() != FlavorTypeToValue<AidlFlavor>::value) {
111         logError("hardware::MQDescriptor hidlDesc is invalid. Unexpected getFlags() value: " +
112                  std::to_string(hidlDesc.getFlags()) +
113                  ". Expected value: " + std::to_string(FlavorTypeToValue<AidlFlavor>::value));
114         return false;
115     }
116     aidlDesc->quantum = static_cast<int32_t>(hidlDesc.getQuantum());
117     aidlDesc->flags = static_cast<int32_t>(hidlDesc.getFlags());
118     return true;
119 }
120 
121 }  // namespace android
122