1 /* 2 * Copyright (C) 2016 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/Chunk.h" 18 #include "androidfw/Util.h" 19 20 #include "android-base/logging.h" 21 22 namespace android { 23 Next()24Chunk ChunkIterator::Next() { 25 CHECK(len_ != 0) << "called Next() after last chunk"; 26 27 const incfs::map_ptr<ResChunk_header> this_chunk = next_chunk_; 28 CHECK((bool) this_chunk) << "Next() called without verifying next chunk"; 29 30 // We've already checked the values of this_chunk, so safely increment. 31 next_chunk_ = this_chunk.offset(dtohl(this_chunk->size)).convert<ResChunk_header>(); 32 len_ -= dtohl(this_chunk->size); 33 34 if (len_ != 0) { 35 // Prepare the next chunk. 36 if (VerifyNextChunkNonFatal()) { 37 VerifyNextChunk(); 38 } 39 } 40 return Chunk(this_chunk.verified()); 41 } 42 43 // TODO(b/111401637) remove this and have full resource file verification 44 // Returns false if there was an error. VerifyNextChunkNonFatal()45bool ChunkIterator::VerifyNextChunkNonFatal() { 46 if (len_ < sizeof(ResChunk_header)) { 47 last_error_ = "not enough space for header"; 48 last_error_was_fatal_ = false; 49 return false; 50 } 51 52 if (!next_chunk_) { 53 last_error_ = "failed to read chunk from data"; 54 last_error_was_fatal_ = false; 55 return false; 56 } 57 58 const size_t size = dtohl(next_chunk_->size); 59 if (size > len_) { 60 last_error_ = "chunk size is bigger than given data"; 61 last_error_was_fatal_ = false; 62 return false; 63 } 64 return true; 65 } 66 67 // Returns false if there was an error. VerifyNextChunk()68bool ChunkIterator::VerifyNextChunk() { 69 // This data must be 4-byte aligned, since we directly 70 // access 32-bit words, which must be aligned on 71 // certain architectures. 72 if (!util::IsFourByteAligned(next_chunk_)) { 73 last_error_ = "header not aligned on 4-byte boundary"; 74 return false; 75 } 76 77 if (len_ < sizeof(ResChunk_header)) { 78 last_error_ = "not enough space for header"; 79 return false; 80 } 81 82 if (!next_chunk_) { 83 last_error_ = "failed to read chunk from data"; 84 return false; 85 } 86 87 const size_t header_size = dtohs(next_chunk_->headerSize); 88 const size_t size = dtohl(next_chunk_->size); 89 if (header_size < sizeof(ResChunk_header)) { 90 last_error_ = "header size too small"; 91 return false; 92 } 93 94 if (header_size > size) { 95 last_error_ = "header size is larger than entire chunk"; 96 return false; 97 } 98 99 if (size > len_) { 100 last_error_ = "chunk size is bigger than given data"; 101 return false; 102 } 103 104 if ((size | header_size) & 0x03U) { 105 last_error_ = "header sizes are not aligned on 4-byte boundary"; 106 return false; 107 } 108 return true; 109 } 110 111 } // namespace android 112