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_hybrid.h"
17
18 #include <sstream>
19 #include "errcode.h"
20 #include "log.h"
21
22 namespace OHOS {
23 namespace Security {
24 namespace CodeSign {
JitCodeSignerHybrid()25 JitCodeSignerHybrid::JitCodeSignerHybrid()
26 {
27 Reset();
28 }
29
Reset()30 void JitCodeSignerHybrid::Reset()
31 {
32 tmpBuffer_ = nullptr;
33 ctx_.InitSalt();
34 ctx_.Init(0);
35 ctxInited_ = true;
36 skipSize_ = 0;
37 offset_ = 0;
38 signTable_.clear();
39 skippedOffset_.clear();
40 while (!willSign_.empty()) {
41 willSign_.pop();
42 }
43 }
44
SignInstruction(Instr insn)45 void JitCodeSignerHybrid::SignInstruction(Instr insn)
46 {
47 #ifdef JIT_CODE_SIGN_DEBUGGABLE
48 if (static_cast<size_t>(GetIndexFromOffset(offset_)) != signTable_.size()) {
49 LOG_ERROR("Index = %{public}d not equal signtable size = %{public}zu.",
50 GetIndexFromOffset(offset_), signTable_.size());
51 }
52 LOG_INFO("Offset = %{public}x, insn = %{public}x", offset_, insn);
53 #endif
54 if (skipSize_ > 0) {
55 skippedOffset_.push_back(offset_);
56 signTable_.push_back(ctx_.SignSingle(insn, GetIndexFromOffset(offset_)));
57 skipSize_ -= 1;
58 } else {
59 if (!ctxInited_) {
60 ctx_.Init(GetIndexFromOffset(offset_));
61 ctxInited_ = true;
62 }
63 uint32_t signature = ctx_.Update(insn);
64 signTable_.push_back(signature);
65 }
66 offset_ += INSTRUCTION_SIZE;
67 }
68
SkipNext(uint32_t n)69 void JitCodeSignerHybrid::SkipNext(uint32_t n)
70 {
71 skipSize_ = std::max(skipSize_, n);
72 ctxInited_ = false;
73 }
74
PatchInstruction(int offset,Instr insn)75 int32_t JitCodeSignerHybrid::PatchInstruction(int offset, Instr insn)
76 {
77 #ifdef JIT_CODE_SIGN_DEBUGGABLE
78 if (std::find(skippedOffset_.begin(), skippedOffset_.end(), offset)
79 == skippedOffset_.end()) {
80 LOG_ERROR("Update no skipped instruction failed at offset" \
81 "= %{public}x", offset);
82 }
83 LOG_INFO("offset = %{public}x, insn = %{public}x", offset, insn);
84 #endif
85 int curIndex = 0;
86 if (!ConvertPatchOffsetToIndex(offset, curIndex)) {
87 LOG_ERROR("Offset invalid");
88 return CS_ERR_PATCH_INVALID;
89 }
90 uint32_t signature = ctx_.SignSingle(insn, curIndex);
91 signTable_[curIndex] = signature;
92 return CS_SUCCESS;
93 }
94
ValidateSubCode(Instr * jitMemory,PACSignCtx & verifyCtx,Byte * jitBuffer,int pos,int size)95 int32_t JitCodeSignerHybrid::ValidateSubCode(Instr *jitMemory, PACSignCtx &verifyCtx,
96 Byte *jitBuffer, int pos, int size)
97 {
98 if (size == 0) {
99 return CS_SUCCESS;
100 }
101 #if defined(JIT_CODE_SIGN_DEBUGGABLE) && defined(JIT_FORT_DISABLE)
102 LOG_INFO("Validate start = %{public}p, offset = %{public}x, size = %{public}d",
103 jitBuffer, pos, size);
104 #endif
105 int32_t index = GetIndexFromOffset(pos);
106 verifyCtx.Init(index);
107 auto insnPtr = reinterpret_cast<const Instr *>(jitBuffer + pos);
108 while (size > 0) {
109 uint32_t signature = verifyCtx.Update(*insnPtr);
110 if (signature != signTable_[index]) {
111 #ifdef JIT_FORT_DISABLE
112 LOG_ERROR("Validate insn (%{public}8x) failed at offset = %{public}x, " \
113 "signature(%{public}x) != wanted(%{public}x)",
114 *(insnPtr), index * INSTRUCTION_SIZE, signature, signTable_[index]);
115 #endif
116 #ifndef JIT_CODE_SIGN_PERMISSIVE
117 return CS_ERR_VALIDATE_CODE;
118 #else
119 break;
120 #endif
121 }
122 *(jitMemory + index) = *insnPtr;
123 index++;
124 insnPtr++;
125 size -= INSTRUCTION_SIZE;
126 }
127 return CS_SUCCESS;
128 }
129
ValidateCodeCopy(Instr * jitMemory,Byte * tmpBuffer,int size)130 __attribute__((no_sanitize("cfi"))) int32_t JitCodeSignerHybrid::ValidateCodeCopy(
131 Instr *jitMemory, Byte *tmpBuffer, int size)
132 {
133 int32_t ret = CheckDataCopy(jitMemory, tmpBuffer, size);
134 if (ret != CS_SUCCESS) {
135 return ret;
136 }
137
138 PACSignCtx verifyCtx(CTXPurpose::VERIFY, ctx_.GetSalt());
139 int offset = 0;
140 for (uint32_t i = 0; i < skippedOffset_.size(); i++) {
141 if (ValidateSubCode(jitMemory, verifyCtx, tmpBuffer_, offset,
142 skippedOffset_[i] - offset) != CS_SUCCESS) {
143 return CS_ERR_VALIDATE_CODE;
144 }
145
146 int32_t index = GetIndexFromOffset(skippedOffset_[i]);
147 Instr insn = *reinterpret_cast<const Instr *>(tmpBuffer_ + skippedOffset_[i]);
148 uint32_t signature = verifyCtx.SignSingle(insn, index);
149 if (signature != signTable_[index]) {
150 #ifdef JIT_FORT_DISABLE
151 LOG_ERROR("Validate insn (%{public}x) without context failed at index = %{public}x," \
152 "signature(%{public}x) != wanted(%{public}x).",
153 insn, index, signature, signTable_[index]);
154 #endif
155 #ifndef JIT_CODE_SIGN_PERMISSIVE
156 return CS_ERR_VALIDATE_CODE;
157 #endif
158 }
159 *(jitMemory + index) = insn;
160 offset = skippedOffset_[i] + INSTRUCTION_SIZE;
161 }
162
163 if (ValidateSubCode(jitMemory, verifyCtx, tmpBuffer_,
164 offset, size - offset) != CS_SUCCESS) {
165 return CS_ERR_VALIDATE_CODE;
166 }
167 return CS_SUCCESS;
168 }
169 }
170 }
171 }
172