1 /*
2 * Copyright (C) 2014 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 <androidfw/TypeWrappers.h>
18
19 namespace android {
20
TypeVariant(const ResTable_type * data)21 TypeVariant::TypeVariant(const ResTable_type* data)
22 : data(data)
23 , mLength(dtohl(data->entryCount))
24 , mSparse(data->flags & ResTable_type::FLAG_SPARSE) {
25 if (mSparse) {
26 const uint32_t entryCount = dtohl(data->entryCount);
27 const uintptr_t containerEnd = reinterpret_cast<uintptr_t>(data) + dtohl(data->header.size);
28 const uint32_t* const entryIndices = reinterpret_cast<const uint32_t*>(
29 reinterpret_cast<uintptr_t>(data) + dtohs(data->header.headerSize));
30 if (reinterpret_cast<uintptr_t>(entryIndices) + (sizeof(uint32_t) * entryCount)
31 > containerEnd) {
32 ALOGE("Type's entry indices extend beyond its boundaries");
33 mLength = 0;
34 } else {
35 mLength = dtohs(ResTable_sparseTypeEntry{entryIndices[entryCount - 1]}.idx) + 1;
36 }
37 }
38 }
39
operator ++()40 TypeVariant::iterator& TypeVariant::iterator::operator++() {
41 ++mIndex;
42 if (mIndex > mTypeVariant->mLength) {
43 mIndex = mTypeVariant->mLength;
44 }
45
46 if (!mTypeVariant->mSparse) {
47 return *this;
48 }
49
50 // Need to adjust |mSparseIndex| as well if we've passed its current element.
51 const ResTable_type* type = mTypeVariant->data;
52 const uint32_t entryCount = dtohl(type->entryCount);
53 if (mSparseIndex >= entryCount) {
54 return *this; // done
55 }
56 const auto entryIndices = reinterpret_cast<const uint32_t*>(
57 reinterpret_cast<uintptr_t>(type) + dtohs(type->header.headerSize));
58 const auto element = (const ResTable_sparseTypeEntry*)(entryIndices + mSparseIndex);
59 if (mIndex > dtohs(element->idx)) {
60 ++mSparseIndex;
61 }
62
63 return *this;
64 }
65
operator *() const66 const ResTable_entry* TypeVariant::iterator::operator*() const {
67 if (mIndex >= mTypeVariant->mLength) {
68 return nullptr;
69 }
70
71 const ResTable_type* type = mTypeVariant->data;
72 const uint32_t entryCount = dtohl(type->entryCount);
73 const uintptr_t containerEnd = reinterpret_cast<uintptr_t>(type)
74 + dtohl(type->header.size);
75 const uint32_t* const entryIndices = reinterpret_cast<const uint32_t*>(
76 reinterpret_cast<uintptr_t>(type) + dtohs(type->header.headerSize));
77 const size_t indexSize = type->flags & ResTable_type::FLAG_OFFSET16 ?
78 sizeof(uint16_t) : sizeof(uint32_t);
79 if (reinterpret_cast<uintptr_t>(entryIndices) + (indexSize * entryCount) > containerEnd) {
80 ALOGE("Type's entry indices extend beyond its boundaries");
81 return nullptr;
82 }
83
84 uint32_t entryOffset;
85 if (mTypeVariant->mSparse) {
86 if (mSparseIndex >= entryCount) {
87 return nullptr;
88 }
89 const auto element = (const ResTable_sparseTypeEntry*)(entryIndices + mSparseIndex);
90 if (dtohs(element->idx) != mIndex) {
91 return nullptr;
92 }
93 entryOffset = static_cast<uint32_t>(dtohs(element->offset)) * 4u;
94 } else if (type->flags & ResTable_type::FLAG_OFFSET16) {
95 auto entryIndices16 = reinterpret_cast<const uint16_t*>(entryIndices);
96 entryOffset = offset_from16(entryIndices16[mIndex]);
97 } else {
98 entryOffset = dtohl(entryIndices[mIndex]);
99 }
100
101 if (entryOffset == ResTable_type::NO_ENTRY) {
102 return nullptr;
103 }
104
105 if ((entryOffset & 0x3) != 0) {
106 ALOGE("Index %u points to entry with unaligned offset 0x%08x", mIndex, entryOffset);
107 return nullptr;
108 }
109
110 const ResTable_entry* entry = reinterpret_cast<const ResTable_entry*>(
111 reinterpret_cast<uintptr_t>(type) + dtohl(type->entriesStart) + entryOffset);
112 if (reinterpret_cast<uintptr_t>(entry) > containerEnd - sizeof(*entry)) {
113 ALOGE("Entry offset at index %u points outside the Type's boundaries", mIndex);
114 return nullptr;
115 } else if (reinterpret_cast<uintptr_t>(entry) + entry->size() > containerEnd) {
116 ALOGE("Entry at index %u extends beyond Type's boundaries", mIndex);
117 return nullptr;
118 } else if (entry->size() < sizeof(*entry)) {
119 ALOGE("Entry at index %u is too small (%zu)", mIndex, entry->size());
120 return nullptr;
121 }
122 return entry;
123 }
124
125 } // namespace android
126