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