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