1 /*
2  * Copyright (C) 2022 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_TAG "android.hardware.cas-DescramblerImpl"
18 
19 #include <aidlcommonsupport/NativeHandle.h>
20 #include <inttypes.h>
21 #include <media/cas/DescramblerAPI.h>
22 #include <media/hardware/CryptoAPI.h>
23 #include <media/stagefright/foundation/AUtils.h>
24 #include <sys/mman.h>
25 #include <utils/Log.h>
26 
27 #include "DescramblerImpl.h"
28 #include "TypeConvert.h"
29 
30 namespace aidl {
31 namespace android {
32 namespace hardware {
33 namespace cas {
34 
35 #define CHECK_SUBSAMPLE_DEF(type)                                                                 \
36     static_assert(sizeof(SubSample) == sizeof(type::SubSample), "SubSample: size doesn't match"); \
37     static_assert(offsetof(SubSample, numBytesOfClearData) ==                                     \
38                           offsetof(type::SubSample, mNumBytesOfClearData),                        \
39                   "SubSample: numBytesOfClearData offset doesn't match");                         \
40     static_assert(offsetof(SubSample, numBytesOfEncryptedData) ==                                 \
41                           offsetof(type::SubSample, mNumBytesOfEncryptedData),                    \
42                   "SubSample: numBytesOfEncryptedData offset doesn't match")
43 
44 CHECK_SUBSAMPLE_DEF(DescramblerPlugin);
45 CHECK_SUBSAMPLE_DEF(CryptoPlugin);
46 
DescramblerImpl(DescramblerPlugin * plugin)47 DescramblerImpl::DescramblerImpl(DescramblerPlugin* plugin) : mPluginHolder(plugin) {
48     ALOGV("CTOR: plugin=%p", mPluginHolder.get());
49 }
50 
~DescramblerImpl()51 DescramblerImpl::~DescramblerImpl() {
52     ALOGV("DTOR: plugin=%p", mPluginHolder.get());
53     release();
54 }
55 
setMediaCasSession(const vector<uint8_t> & in_sessionId)56 ScopedAStatus DescramblerImpl::setMediaCasSession(const vector<uint8_t>& in_sessionId) {
57     ALOGV("%s: sessionId=%s", __FUNCTION__, sessionIdToString(in_sessionId).c_str());
58 
59     shared_ptr<DescramblerPlugin> holder = atomic_load(&mPluginHolder);
60     if (holder.get() == nullptr) {
61         return toStatus(INVALID_OPERATION);
62     }
63 
64     return toStatus(holder->setMediaCasSession(in_sessionId));
65 }
66 
requiresSecureDecoderComponent(const string & in_mime,bool * _aidl_return)67 ScopedAStatus DescramblerImpl::requiresSecureDecoderComponent(const string& in_mime,
68                                                               bool* _aidl_return) {
69     shared_ptr<DescramblerPlugin> holder = atomic_load(&mPluginHolder);
70     if (holder.get() == nullptr) {
71         *_aidl_return = false;
72     }
73 
74     *_aidl_return = holder->requiresSecureDecoderComponent(in_mime.c_str());
75     return ScopedAStatus::ok();
76 }
77 
validateRangeForSize(int64_t offset,int64_t length,int64_t size)78 static inline bool validateRangeForSize(int64_t offset, int64_t length, int64_t size) {
79     return isInRange<int64_t, uint64_t>(0, (uint64_t)size, offset, (uint64_t)length);
80 }
81 
descramble(ScramblingControl scramblingControl,const vector<SubSample> & subSamples,const SharedBuffer & srcBuffer,int64_t srcOffset,const DestinationBuffer & dstBuffer,int64_t dstOffset,int32_t * _aidl_return)82 ScopedAStatus DescramblerImpl::descramble(ScramblingControl scramblingControl,
83                                           const vector<SubSample>& subSamples,
84                                           const SharedBuffer& srcBuffer, int64_t srcOffset,
85                                           const DestinationBuffer& dstBuffer, int64_t dstOffset,
86                                           int32_t* _aidl_return) {
87     ALOGV("%s", __FUNCTION__);
88 
89     // heapbase's size is stored in int64_t, but mapMemory's mmap will map size in
90     // size_t. If size is over SIZE_MAX, mapMemory mapMemory could succeed but the
91     // mapped memory's actual size will be smaller than the reported size.
92     if (srcBuffer.heapBase.size > SIZE_MAX) {
93         ALOGE("Invalid memory size: %" PRIu64 "", srcBuffer.heapBase.size);
94         android_errorWriteLog(0x534e4554, "79376389");
95         return toStatus(BAD_VALUE);
96     }
97 
98     void* srcPtr = mmap(NULL, srcBuffer.heapBase.size, PROT_READ | PROT_WRITE, MAP_SHARED,
99                         srcBuffer.heapBase.fd.get(), 0);
100 
101     // Validate if the offset and size in the SharedBuffer is consistent with the
102     // mapped heapbase, since the offset and size is controlled by client.
103     if (srcPtr == NULL) {
104         ALOGE("Failed to map src buffer.");
105         return toStatus(BAD_VALUE);
106     }
107     if (!validateRangeForSize(srcBuffer.offset, srcBuffer.size, srcBuffer.heapBase.size)) {
108         ALOGE("Invalid src buffer range: offset %" PRIu64 ", size %" PRIu64
109               ", srcMem"
110               "size %" PRIu64 "",
111               srcBuffer.offset, srcBuffer.size, srcBuffer.heapBase.size);
112         android_errorWriteLog(0x534e4554, "67962232");
113         return toStatus(BAD_VALUE);
114     }
115 
116     // use 64-bit here to catch bad subsample size that might be overflowing.
117     uint64_t totalBytesInSubSamples = 0;
118     for (size_t i = 0; i < subSamples.size(); i++) {
119         uint32_t numBytesOfClearData = subSamples[i].numBytesOfClearData;
120         uint32_t numBytesOfEncryptedData = subSamples[i].numBytesOfEncryptedData;
121         totalBytesInSubSamples += (uint64_t)numBytesOfClearData + numBytesOfEncryptedData;
122     }
123     // Further validate if the specified srcOffset and requested total subsample size
124     // is consistent with the source shared buffer size.
125     if (!validateRangeForSize(srcOffset, totalBytesInSubSamples, srcBuffer.size)) {
126         ALOGE("Invalid srcOffset and subsample size: "
127               "srcOffset %" PRIu64 ", totalBytesInSubSamples %" PRIu64
128               ", srcBuffer"
129               "size %" PRIu64 "",
130               srcOffset, totalBytesInSubSamples, srcBuffer.size);
131         android_errorWriteLog(0x534e4554, "67962232");
132         return toStatus(BAD_VALUE);
133     }
134     srcPtr = (uint8_t*)srcPtr + srcBuffer.offset;
135 
136     void* dstPtr = NULL;
137     if (dstBuffer.getTag() == DestinationBuffer::Tag::nonsecureMemory) {
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 %" PRIu64 ", totalBytesInSubSamples %" PRIu64
147                   ", srcBuffer"
148                   "size %" PRIu64 "",
149                   dstOffset, totalBytesInSubSamples, srcBuffer.size);
150             android_errorWriteLog(0x534e4554, "67962232");
151             return toStatus(BAD_VALUE);
152         }
153     } else {
154         native_handle_t* handle = makeFromAidl(dstBuffer.get<DestinationBuffer::secureMemory>());
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 callback, this shared_ptr must be manually reset, since
160     // the client side could proceed as soon as the callback is called
161     // without waiting for this method to go out of scope.
162     shared_ptr<DescramblerPlugin> holder = atomic_load(&mPluginHolder);
163     if (holder.get() == nullptr) {
164         return toStatus(INVALID_OPERATION);
165     }
166 
167     // Casting SubSample to DescramblerPlugin::SubSample, but need to ensure
168     // structs are actually identical
169 
170     auto returnStatus =
171             holder->descramble(dstBuffer.getTag() != DestinationBuffer::Tag::nonsecureMemory,
172                                (DescramblerPlugin::ScramblingControl)scramblingControl,
173                                subSamples.size(), (DescramblerPlugin::SubSample*)subSamples.data(),
174                                srcPtr, srcOffset, dstPtr, dstOffset, NULL);
175 
176     holder.reset();
177     *_aidl_return = returnStatus;
178     return toStatus(returnStatus >= 0 ? OK : returnStatus);
179 }
180 
release()181 ScopedAStatus DescramblerImpl::release() {
182     ALOGV("%s: plugin=%p", __FUNCTION__, mPluginHolder.get());
183 
184     shared_ptr<DescramblerPlugin> holder(nullptr);
185     atomic_store(&mPluginHolder, holder);
186 
187     return ScopedAStatus::ok();
188 }
189 
190 }  // namespace cas
191 }  // namespace hardware
192 }  // namespace android
193 }  // namespace aidl
194