summaryrefslogtreecommitdiffstats
path: root/runtime/dex_file_verifier.h
blob: 877dfc2efdba93ea0d7ea4ef019e771e905fbb29 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
/*
 * Copyright (C) 2011 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef ART_RUNTIME_DEX_FILE_VERIFIER_H_
#define ART_RUNTIME_DEX_FILE_VERIFIER_H_

#include <unordered_set>

#include "dex_file.h"
#include "safe_map.h"

namespace art {

class DexFileVerifier {
 public:
  static bool Verify(const DexFile* dex_file, const uint8_t* begin, size_t size,
                     const char* location, std::string* error_msg);

  const std::string& FailureReason() const {
    return failure_reason_;
  }

 private:
  DexFileVerifier(const DexFile* dex_file, const uint8_t* begin, size_t size, const char* location)
      : dex_file_(dex_file), begin_(begin), size_(size), location_(location),
        header_(&dex_file->GetHeader()), ptr_(nullptr), previous_item_(nullptr)  {
  }

  bool Verify();

  bool CheckShortyDescriptorMatch(char shorty_char, const char* descriptor, bool is_return_type);
  bool CheckListSize(const void* start, size_t count, size_t element_size, const char* label);
  // Check a list. The head is assumed to be at *ptr, and elements to be of size element_size. If
  // successful, the ptr will be moved forward the amount covered by the list.
  bool CheckList(size_t element_size, const char* label, const uint8_t* *ptr);
  // Checks whether the offset is zero (when size is zero) or that the offset falls within the area
  // claimed by the file.
  bool CheckValidOffsetAndSize(uint32_t offset, uint32_t size, const char* label);
  bool CheckIndex(uint32_t field, uint32_t limit, const char* label);

  bool CheckHeader();
  bool CheckMap();

  uint32_t ReadUnsignedLittleEndian(uint32_t size);
  bool CheckAndGetHandlerOffsets(const DexFile::CodeItem* code_item,
                                 uint32_t* handler_offsets, uint32_t handlers_size);
  bool CheckClassDataItemField(uint32_t idx, uint32_t access_flags, bool expect_static);
  bool CheckClassDataItemMethod(uint32_t idx, uint32_t access_flags, uint32_t code_offset,
                                bool expect_direct);
  bool CheckPadding(size_t offset, uint32_t aligned_offset);
  bool CheckEncodedValue();
  bool CheckEncodedArray();
  bool CheckEncodedAnnotation();

  bool CheckIntraClassDataItem();
  bool CheckIntraCodeItem();
  bool CheckIntraStringDataItem();
  bool CheckIntraDebugInfoItem();
  bool CheckIntraAnnotationItem();
  bool CheckIntraAnnotationsDirectoryItem();

  bool CheckIntraSectionIterate(size_t offset, uint32_t count, uint16_t type);
  bool CheckIntraIdSection(size_t offset, uint32_t count, uint16_t type);
  bool CheckIntraDataSection(size_t offset, uint32_t count, uint16_t type);
  bool CheckIntraSection();

  bool CheckOffsetToTypeMap(size_t offset, uint16_t type);

  // Note: as sometimes kDexNoIndex16, being 0xFFFF, is a valid return value, we need an
  // additional out parameter to signal any errors loading an index.
  uint16_t FindFirstClassDataDefiner(const uint8_t* ptr, bool* success);
  uint16_t FindFirstAnnotationsDirectoryDefiner(const uint8_t* ptr, bool* success);

  bool CheckInterStringIdItem();
  bool CheckInterTypeIdItem();
  bool CheckInterProtoIdItem();
  bool CheckInterFieldIdItem();
  bool CheckInterMethodIdItem();
  bool CheckInterClassDefItem();
  bool CheckInterAnnotationSetRefList();
  bool CheckInterAnnotationSetItem();
  bool CheckInterClassDataItem();
  bool CheckInterAnnotationsDirectoryItem();

  bool CheckInterSectionIterate(size_t offset, uint32_t count, uint16_t type);
  bool CheckInterSection();

  // Load a string by (type) index. Checks whether the index is in bounds, printing the error if
  // not. If there is an error, null is returned.
  const char* CheckLoadStringByIdx(uint32_t idx, const char* error_fmt);
  const char* CheckLoadStringByTypeIdx(uint32_t type_idx, const char* error_fmt);

  // Load a field/method Id by index. Checks whether the index is in bounds, printing the error if
  // not. If there is an error, null is returned.
  const DexFile::FieldId* CheckLoadFieldId(uint32_t idx, const char* error_fmt);
  const DexFile::MethodId* CheckLoadMethodId(uint32_t idx, const char* error_fmt);

  void ErrorStringPrintf(const char* fmt, ...)
      __attribute__((__format__(__printf__, 2, 3))) COLD_ATTR;

  const DexFile* const dex_file_;
  const uint8_t* const begin_;
  const size_t size_;
  const char* const location_;
  const DexFile::Header* const header_;

  AllocationTrackingSafeMap<uint32_t, uint16_t, kAllocatorTagDexFileVerifier> offset_to_type_map_;
  const uint8_t* ptr_;
  const void* previous_item_;

  std::string failure_reason_;

  // Set of type ids for which there are ClassDef elements in the dex file.
  std::unordered_set<decltype(DexFile::ClassDef::class_idx_)> defined_classes_;
};

}  // namespace art

#endif  // ART_RUNTIME_DEX_FILE_VERIFIER_H_