• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 }