1 /*
2 * Copyright (C) 2019 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
17 //#define LOG_NDEBUG 0
18 #define LOG_TAG "[email protected]"
19
20 #include <hidlmemory/mapping.h>
21 #include <media/cas/DescramblerAPI.h>
22 #include <media/hardware/CryptoAPI.h>
23 #include <media/stagefright/foundation/AUtils.h>
24 #include <utils/Log.h>
25
26 #include "DescramblerImpl.h"
27 #include "SharedLibrary.h"
28 #include "TypeConvert.h"
29
30 namespace android {
31 using hidl::memory::V1_0::IMemory;
32
33 namespace hardware {
34 namespace cas {
35 namespace V1_1 {
36 namespace implementation {
37
38 #define CHECK_SUBSAMPLE_DEF(type) \
39 static_assert(sizeof(SubSample) == sizeof(type::SubSample), "SubSample: size doesn't match"); \
40 static_assert(offsetof(SubSample, numBytesOfClearData) == \
41 offsetof(type::SubSample, mNumBytesOfClearData), \
42 "SubSample: numBytesOfClearData offset doesn't match"); \
43 static_assert(offsetof(SubSample, numBytesOfEncryptedData) == \
44 offsetof(type::SubSample, mNumBytesOfEncryptedData), \
45 "SubSample: numBytesOfEncryptedData offset doesn't match")
46
47 CHECK_SUBSAMPLE_DEF(DescramblerPlugin);
48 CHECK_SUBSAMPLE_DEF(CryptoPlugin);
49
DescramblerImpl(const sp<SharedLibrary> & library,DescramblerPlugin * plugin)50 DescramblerImpl::DescramblerImpl(const sp<SharedLibrary>& library, DescramblerPlugin* plugin)
51 : mLibrary(library), mPluginHolder(plugin) {
52 ALOGV("CTOR: plugin=%p", mPluginHolder.get());
53 }
54
~DescramblerImpl()55 DescramblerImpl::~DescramblerImpl() {
56 ALOGV("DTOR: plugin=%p", mPluginHolder.get());
57 release();
58 }
59
setMediaCasSession(const HidlCasSessionId & sessionId)60 Return<Status> DescramblerImpl::setMediaCasSession(const HidlCasSessionId& sessionId) {
61 ALOGV("%s: sessionId=%s", __FUNCTION__, sessionIdToString(sessionId).string());
62
63 std::shared_ptr<DescramblerPlugin> holder = std::atomic_load(&mPluginHolder);
64 if (holder.get() == nullptr) {
65 return toStatus(INVALID_OPERATION);
66 }
67
68 return toStatus(holder->setMediaCasSession(sessionId));
69 }
70
requiresSecureDecoderComponent(const hidl_string & mime)71 Return<bool> DescramblerImpl::requiresSecureDecoderComponent(const hidl_string& mime) {
72 std::shared_ptr<DescramblerPlugin> holder = std::atomic_load(&mPluginHolder);
73 if (holder.get() == nullptr) {
74 return false;
75 }
76
77 return holder->requiresSecureDecoderComponent(String8(mime.c_str()));
78 }
79
validateRangeForSize(uint64_t offset,uint64_t length,uint64_t size)80 static inline bool validateRangeForSize(uint64_t offset, uint64_t length, uint64_t size) {
81 return isInRange<uint64_t, uint64_t>(0, size, offset, length);
82 }
83
descramble(ScramblingControl scramblingControl,const hidl_vec<SubSample> & subSamples,const SharedBuffer & srcBuffer,uint64_t srcOffset,const DestinationBuffer & dstBuffer,uint64_t dstOffset,descramble_cb _hidl_cb)84 Return<void> DescramblerImpl::descramble(ScramblingControl scramblingControl,
85 const hidl_vec<SubSample>& subSamples,
86 const SharedBuffer& srcBuffer, uint64_t srcOffset,
87 const DestinationBuffer& dstBuffer, uint64_t dstOffset,
88 descramble_cb _hidl_cb) {
89 ALOGV("%s", __FUNCTION__);
90
91 // hidl_memory's size is stored in uint64_t, but mapMemory's mmap will map
92 // size in size_t. If size is over SIZE_MAX, mapMemory mapMemory could succeed
93 // but the mapped memory's actual size will be smaller than the reported size.
94 if (srcBuffer.heapBase.size() > SIZE_MAX) {
95 ALOGE("Invalid hidl_memory size: %llu", srcBuffer.heapBase.size());
96 android_errorWriteLog(0x534e4554, "79376389");
97 _hidl_cb(toStatus(BAD_VALUE), 0, NULL);
98 return Void();
99 }
100
101 sp<IMemory> srcMem = mapMemory(srcBuffer.heapBase);
102
103 // Validate if the offset and size in the SharedBuffer is consistent with the
104 // mapped ashmem, since the offset and size is controlled by client.
105 if (srcMem == NULL) {
106 ALOGE("Failed to map src buffer.");
107 _hidl_cb(toStatus(BAD_VALUE), 0, NULL);
108 return Void();
109 }
110 if (!validateRangeForSize(srcBuffer.offset, srcBuffer.size, (uint64_t)srcMem->getSize())) {
111 ALOGE("Invalid src buffer range: offset %llu, size %llu, srcMem size %llu",
112 srcBuffer.offset, srcBuffer.size, (uint64_t)srcMem->getSize());
113 android_errorWriteLog(0x534e4554, "67962232");
114 _hidl_cb(toStatus(BAD_VALUE), 0, NULL);
115 return Void();
116 }
117
118 // use 64-bit here to catch bad subsample size that might be overflowing.
119 uint64_t totalBytesInSubSamples = 0;
120 for (size_t i = 0; i < subSamples.size(); i++) {
121 totalBytesInSubSamples +=
122 (uint64_t)subSamples[i].numBytesOfClearData + subSamples[i].numBytesOfEncryptedData;
123 }
124 // Further validate if the specified srcOffset and requested total subsample size
125 // is consistent with the source shared buffer size.
126 if (!validateRangeForSize(srcOffset, totalBytesInSubSamples, srcBuffer.size)) {
127 ALOGE("Invalid srcOffset and subsample size: "
128 "srcOffset %llu, totalBytesInSubSamples %llu, srcBuffer size %llu",
129 srcOffset, totalBytesInSubSamples, srcBuffer.size);
130 android_errorWriteLog(0x534e4554, "67962232");
131 _hidl_cb(toStatus(BAD_VALUE), 0, NULL);
132 return Void();
133 }
134
135 void* srcPtr = (uint8_t*)(void*)srcMem->getPointer() + srcBuffer.offset;
136 void* dstPtr = NULL;
137 if (dstBuffer.type == BufferType::SHARED_MEMORY) {
138 // When using shared memory, src buffer is also used as dst,
139 // we don't map it again here.
140 dstPtr = srcPtr;
141
142 // In this case the dst and src would be the same buffer, need to validate
143 // dstOffset against the buffer size too.
144 if (!validateRangeForSize(dstOffset, totalBytesInSubSamples, srcBuffer.size)) {
145 ALOGE("Invalid dstOffset and subsample size: "
146 "dstOffset %llu, totalBytesInSubSamples %llu, srcBuffer size %llu",
147 dstOffset, totalBytesInSubSamples, srcBuffer.size);
148 android_errorWriteLog(0x534e4554, "67962232");
149 _hidl_cb(toStatus(BAD_VALUE), 0, NULL);
150 return Void();
151 }
152 } else {
153 native_handle_t* handle =
154 const_cast<native_handle_t*>(dstBuffer.secureMemory.getNativeHandle());
155 dstPtr = static_cast<void*>(handle);
156 }
157
158 // Get a local copy of the shared_ptr for the plugin. Note that before
159 // calling the HIDL callback, this shared_ptr must be manually reset,
160 // since the client side could proceed as soon as the callback is called
161 // without waiting for this method to go out of scope.
162 std::shared_ptr<DescramblerPlugin> holder = std::atomic_load(&mPluginHolder);
163 if (holder.get() == nullptr) {
164 _hidl_cb(toStatus(INVALID_OPERATION), 0, NULL);
165 return Void();
166 }
167
168 // Casting hidl SubSample to DescramblerPlugin::SubSample, but need
169 // to ensure structs are actually idential
170
171 int32_t result =
172 holder->descramble(dstBuffer.type != BufferType::SHARED_MEMORY,
173 (DescramblerPlugin::ScramblingControl)scramblingControl,
174 subSamples.size(), (DescramblerPlugin::SubSample*)subSamples.data(),
175 srcPtr, srcOffset, dstPtr, dstOffset, NULL);
176
177 holder.reset();
178 _hidl_cb(toStatus(result >= 0 ? OK : result), result, NULL);
179 return Void();
180 }
181
release()182 Return<Status> DescramblerImpl::release() {
183 ALOGV("%s: plugin=%p", __FUNCTION__, mPluginHolder.get());
184
185 std::shared_ptr<DescramblerPlugin> holder(nullptr);
186 std::atomic_store(&mPluginHolder, holder);
187
188 return Status::OK;
189 }
190
191 } // namespace implementation
192 } // namespace V1_1
193 } // namespace cas
194 } // namespace hardware
195 } // namespace android
196