1 /*
2 * Copyright (c) 2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "jit_code_signer.h"
17
18 #include <sstream>
19 #include "errcode.h"
20 #include "log.h"
21
22 namespace OHOS {
23 namespace Security {
24 namespace CodeSign {
25
26 constexpr int32_t BYTE_BIT_SIZE = 8;
27 constexpr uint32_t UNALIGNMENT_MASK = 0x3;
28
JitCodeSigner()29 JitCodeSigner::JitCodeSigner()
30 {
31 Reset();
32 }
33
Reset()34 void JitCodeSigner::Reset()
35 {
36 tmpBuffer_ = nullptr;
37 ctx_.InitSalt();
38 ctx_.Init(0);
39 signTable_.clear();
40 offset_ = 0;
41 }
42
GetOneInstrForQueue(std::queue<Byte> & queue)43 inline static Instr GetOneInstrForQueue(std::queue<Byte> &queue)
44 {
45 Instr insn = 0;
46 int i = 0;
47 while ((i < INSTRUCTION_SIZE) && !queue.empty()) {
48 insn |= (queue.front() << (BYTE_BIT_SIZE * i));
49 queue.pop();
50 i++;
51 }
52 return insn;
53 }
54
RegisterTmpBuffer(Byte * tmpBuffer)55 void JitCodeSigner::RegisterTmpBuffer(Byte *tmpBuffer)
56 {
57 tmpBuffer_ = tmpBuffer;
58 }
59
SignData(const Byte * const data,uint32_t size)60 int32_t JitCodeSigner::SignData(const Byte *const data, uint32_t size)
61 {
62 if (data == nullptr) {
63 return CS_ERR_INVALID_DATA;
64 }
65 uint32_t cur = 0;
66 size_t unsignedSize = willSign_.size();
67 if ((unsignedSize == 0) && (size >= INSTRUCTION_SIZE)) {
68 auto insnPtr = reinterpret_cast<const Instr *const>(data);
69 while (cur + INSTRUCTION_SIZE <= size) {
70 SignInstruction(*insnPtr);
71 insnPtr++;
72 cur += INSTRUCTION_SIZE;
73 }
74 }
75
76 if (cur == size) {
77 return CS_SUCCESS;
78 }
79 unsignedSize += size - cur;
80 while (cur < size) {
81 willSign_.push(*(data + cur));
82 cur++;
83 }
84
85 while (unsignedSize >= INSTRUCTION_SIZE) {
86 Instr insn = GetOneInstrForQueue(willSign_);
87 SignInstruction(insn);
88 unsignedSize -= INSTRUCTION_SIZE;
89 }
90 return CS_SUCCESS;
91 }
92
PatchInstruction(Byte * buffer,Instr insn)93 int32_t JitCodeSigner::PatchInstruction(Byte *buffer, Instr insn)
94 {
95 if ((buffer == nullptr) || (tmpBuffer_ == nullptr)) {
96 return CS_ERR_PATCH_INVALID;
97 }
98 return PatchInstruction(static_cast<int>(buffer - tmpBuffer_), insn);
99 }
100
PatchData(int offset,const Byte * const data,uint32_t size)101 int32_t JitCodeSigner::PatchData(int offset, const Byte *const data, uint32_t size)
102 {
103 if (size & UNALIGNMENT_MASK) {
104 return CS_ERR_JIT_SIGN_SIZE;
105 }
106 if (data == nullptr) {
107 return CS_ERR_INVALID_DATA;
108 }
109 auto insnPtr = reinterpret_cast<const Instr *const>(data);
110 for (uint32_t i = 0; i < size; i += INSTRUCTION_SIZE) {
111 int ret = PatchInstruction(offset + i, *insnPtr);
112 if (ret != CS_SUCCESS) {
113 return ret;
114 }
115 insnPtr += 1;
116 }
117 return CS_SUCCESS;
118 }
119
PatchData(Byte * buffer,const Byte * const data,uint32_t size)120 int32_t JitCodeSigner::PatchData(Byte *buffer, const Byte *const data, uint32_t size)
121 {
122 if ((buffer == nullptr) || (tmpBuffer_ == nullptr)) {
123 return CS_ERR_PATCH_INVALID;
124 }
125 return PatchData(static_cast<int>(buffer - tmpBuffer_), data, size);
126 }
127
ConvertPatchOffsetToIndex(const int offset,int & curIndex)128 bool JitCodeSigner::ConvertPatchOffsetToIndex(const int offset, int &curIndex)
129 {
130 if ((offset < 0) || ((static_cast<uint32_t>(offset) & UNALIGNMENT_MASK) != 0)) {
131 return false;
132 }
133 curIndex = GetIndexFromOffset(offset);
134 if (static_cast<size_t>(curIndex) >= signTable_.size()) {
135 LOG_ERROR("Offset is out of range, index = %{public}d, signTable size = %{public}zu",
136 curIndex, signTable_.size());
137 return false;
138 }
139 return true;
140 }
141
CheckDataCopy(Instr * jitMemory,Byte * tmpBuffer,int size)142 int32_t JitCodeSigner::CheckDataCopy(Instr *jitMemory, Byte *tmpBuffer, int size)
143 {
144 if (jitMemory == nullptr) {
145 return CS_ERR_JIT_MEMORY;
146 }
147 if (tmpBuffer == nullptr) {
148 return CS_ERR_TMP_BUFFER;
149 }
150
151 // update tmp buffer
152 tmpBuffer_ = tmpBuffer;
153
154 if (((static_cast<uint32_t>(size) & UNALIGNMENT_MASK) != 0) ||
155 (static_cast<uint32_t>(size) > signTable_.size() * INSTRUCTION_SIZE)) {
156 #ifdef JIT_FORT_DISABLE
157 LOG_ERROR("Range invalid, size = %{public}d, table size = %{public}zu",
158 size, signTable_.size());
159 #endif
160 return CS_ERR_JIT_SIGN_SIZE;
161 }
162 return CS_SUCCESS;
163 }
164
SignInstruction(Instr insn)165 void JitCodeSigner::SignInstruction(Instr insn)
166 {
167 int index = GetIndexFromOffset(offset_);
168 #ifdef JIT_CODE_SIGN_DEBUGGABLE
169 LOG_INFO("Offset = %{public}x, insn = %{public}x", offset_, insn);
170 if (static_cast<size_t>(index) != signTable_.size()) {
171 LOG_ERROR("Index = %{public}d not equal signtable size = %{public}zu.",
172 GetIndexFromOffset(offset_), signTable_.size());
173 }
174 #endif
175 signTable_.push_back(ctx_.SignSingle(insn, index));
176 offset_ += INSTRUCTION_SIZE;
177 }
178
SkipNext(uint32_t n)179 void JitCodeSigner::SkipNext(uint32_t n) {}
180
PatchInstruction(int offset,Instr insn)181 int32_t JitCodeSigner::PatchInstruction(int offset, Instr insn)
182 {
183 #ifdef JIT_CODE_SIGN_DEBUGGABLE
184 LOG_INFO("offset = %{public}x, insn = %{public}x", offset, insn);
185 #endif
186 int curIndex = 0;
187 if (!ConvertPatchOffsetToIndex(offset, curIndex)) {
188 LOG_ERROR("Offset invalid");
189 return CS_ERR_PATCH_INVALID;
190 }
191 uint32_t signature = ctx_.SignSingle(insn, curIndex);
192 signTable_[curIndex] = signature;
193 return CS_SUCCESS;
194 }
195
ValidateCodeCopy(Instr * jitMemory,Byte * tmpBuffer,int size)196 int32_t JitCodeSigner::ValidateCodeCopy(Instr *jitMemory,
197 Byte *tmpBuffer, int size)
198 {
199 int32_t ret = CheckDataCopy(jitMemory, tmpBuffer, size);
200 if (ret != CS_SUCCESS) {
201 return ret;
202 }
203
204 PACSignCtx verifyCtx(CTXPurpose::VERIFY, ctx_.GetSalt());
205 int offset = 0;
206 while (offset < size) {
207 int index = GetIndexFromOffset(offset);
208 Instr insn = *reinterpret_cast<const Instr *>(tmpBuffer_ + offset);
209 uint32_t signature = verifyCtx.SignSingle(insn, index);
210 if (signature != signTable_[index]) {
211 #ifdef JIT_FORT_DISABLE
212 LOG_ERROR("validate insn(%{public}x) without context failed at index = " \
213 "%{public}x, signature(%{public}x) != wanted(%{public}x)",
214 insn, index * INSTRUCTION_SIZE, signature, signTable_[index]);
215 #endif
216 #ifndef JIT_CODE_SIGN_PERMISSIVE
217 return CS_ERR_VALIDATE_CODE;
218 #endif
219 }
220 *(jitMemory + index) = insn;
221 offset += INSTRUCTION_SIZE;
222 }
223 return CS_SUCCESS;
224 }
225 }
226 }
227 }