• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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()24 Chunk 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()45 bool 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()68 bool 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