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 #ifndef CODE_SIGN_JIT_BUFFER_INTEGRITY_H
17 #define CODE_SIGN_JIT_BUFFER_INTEGRITY_H
18
19 #include <cstdint>
20 #include <cstring>
21
22 #include "errcode.h"
23 #include "jit_code_signer_base.h"
24 #include "jit_code_signer_factory.h"
25 #include "jit_fort_helper.h"
26 #include "securec.h"
27
28 namespace OHOS {
29 namespace Security {
30 namespace CodeSign {
31
32 #define CAST_TO_CONST_BYTES(buffer) (reinterpret_cast<const Byte *const>(buffer))
33 #define CAST_TO_BYTES(buffer) (reinterpret_cast<Byte *>(buffer))
34
35 #define CHECK_NULL_AND_RETURN_CODE(ptr) do { \
36 if ((ptr) == nullptr) { \
37 return JitCodeSignErrCode::CS_ERR_NO_SIGNER; \
38 } \
39 } while (0)
40
41 /**
42 * @brief Create Jit Code signer of specific level
43 * @param level see jit_code_signer_factory.h
44 * @return error code, see errcode.h
45 */
CreateJitCodeSigner(JitBufferIntegrityLevel level)46 static inline JitCodeSignerBase *CreateJitCodeSigner(JitBufferIntegrityLevel level)
47 {
48 return JitCodeSignerFactory::GetInstance().CreateJitCodeSigner(level);
49 }
50
51 /**
52 * @brief Return whether Jit code signing is supported
53 * @return true if supported, otherwise false
54 */
IsSupportJitCodeSigner()55 static bool IsSupportJitCodeSigner()
56 {
57 return IsSupportPACFeature();
58 }
59
60 /**
61 * @brief Register start address of tmp buffer if patching target address of buffer
62 * @param signer jit code signer
63 * @param tmpBuffer tmp buffer storing jit code
64 * @return error code, see errcode.h
65 */
RegisterTmpBuffer(JitCodeSignerBase * signer,void * tmpBuffer)66 static inline int32_t RegisterTmpBuffer(JitCodeSignerBase *signer, void *tmpBuffer)
67 {
68 CHECK_NULL_AND_RETURN_CODE(signer);
69 signer->RegisterTmpBuffer(CAST_TO_BYTES(tmpBuffer));
70 return CS_SUCCESS;
71 }
72
73 /**
74 * @brief Sign an intruction when appending it to tmp buffer
75 * @param signer jit code signer
76 * @param instr an instruction to be signed
77 * @return error code, see errcode.h
78 */
AppendInstruction(JitCodeSignerBase * signer,Instr instr)79 static inline int32_t AppendInstruction(JitCodeSignerBase *signer, Instr instr)
80 {
81 CHECK_NULL_AND_RETURN_CODE(signer);
82 signer->SignInstruction(instr);
83 return CS_SUCCESS;
84 }
85
86 /**
87 * @brief Sign data when appending it to tmp buffer
88 * @param signer jit code signer
89 * @param data data to be signed
90 * @param size data size
91 * @return error code, see errcode.h
92 */
AppendData(JitCodeSignerBase * signer,const void * const data,uint32_t size)93 static inline int32_t AppendData(JitCodeSignerBase *signer, const void *const data, uint32_t size)
94 {
95 CHECK_NULL_AND_RETURN_CODE(signer);
96 return signer->SignData(CAST_TO_CONST_BYTES(data), size);
97 }
98
99 /**
100 * @brief Declare the next intsructions to be fixed up later
101 * @param signer jit code signer
102 * @param n the amount of intsructions
103 * @return error code, see errcode.h
104 */
105 static inline int32_t WillFixUp(JitCodeSignerBase *signer, uint32_t n = 1)
106 {
107 CHECK_NULL_AND_RETURN_CODE(signer);
108 signer->SkipNext(n);
109 return CS_SUCCESS;
110 }
111
112 /**
113 * @brief Patch an intruction at offset
114 * @param signer jit code signer
115 * @param instr target intruction
116 * @return error code, see errcode.h
117 */
PatchInstruction(JitCodeSignerBase * signer,int offset,Instr instr)118 static inline int32_t PatchInstruction(JitCodeSignerBase *signer, int offset, Instr instr)
119 {
120 CHECK_NULL_AND_RETURN_CODE(signer);
121 return signer->PatchInstruction(offset, instr);
122 }
123
124 /**
125 * @brief Patch an intruction at address
126 * @param signer jit code signer
127 * @param address address of patching instruction
128 * @param instr target intruction
129 * @return error code, see errcode.h
130 */
PatchInstruction(JitCodeSignerBase * signer,void * address,Instr insn)131 static inline int32_t PatchInstruction(JitCodeSignerBase *signer,
132 void *address, Instr insn)
133 {
134 CHECK_NULL_AND_RETURN_CODE(signer);
135 return signer->PatchInstruction(CAST_TO_BYTES(address), insn);
136 }
137
138 /**
139 * @brief Patch data at offset of buffer
140 * @param signer jit code signer
141 * @param data data to be signed
142 * @param size data size
143 * @return error code, see errcode.h
144 */
PatchData(JitCodeSignerBase * signer,int offset,const void * const data,uint32_t size)145 static inline int32_t PatchData(JitCodeSignerBase *signer, int offset,
146 const void *const data, uint32_t size)
147 {
148 CHECK_NULL_AND_RETURN_CODE(signer);
149 return signer->PatchData(offset, CAST_TO_CONST_BYTES(data), size);
150 }
151
152 /**
153 * @brief Patch data at address
154 * @param signer jit code signer
155 * @param address address of patching instruction
156 * @param data data to be signed
157 * @param size data size
158 * @return error code, see errcode.h
159 */
PatchData(JitCodeSignerBase * signer,void * address,const void * const data,uint32_t size)160 static inline int32_t PatchData(JitCodeSignerBase *signer, void *address,
161 const void *const data, uint32_t size)
162 {
163 CHECK_NULL_AND_RETURN_CODE(signer);
164 return signer->PatchData(CAST_TO_BYTES(address),
165 CAST_TO_CONST_BYTES(data), size);
166 }
167
168 /**
169 * @brief Reset jit memory
170 * @param jitMemory jit memory to be reset
171 * @param size memory size
172 * @return error code, see errcode.h
173 */
ResetJitCode(void * jitMemory,int size)174 __attribute__((no_sanitize("cfi"))) static inline int32_t ResetJitCode(
175 void *jitMemory, int size)
176 {
177 if (jitMemory == nullptr) {
178 return CS_ERR_JIT_MEMORY;
179 }
180 #ifndef JIT_FORT_DISABLE
181 int32_t prctlRet = PrctlWrapper(JITFORT_PRCTL_OPTION, JITFORT_SWITCH_IN, 0);
182 if (prctlRet < 0) {
183 return CS_ERR_JITFORT_IN;
184 }
185 #endif
186 (void) __builtin_memset(jitMemory, 0, size);
187 #ifndef JIT_FORT_DISABLE
188 prctlRet = PrctlWrapper(JITFORT_PRCTL_OPTION, JITFORT_SWITCH_OUT, 0);
189 if (prctlRet < 0) {
190 return CS_ERR_JITFORT_OUT;
191 }
192 #endif
193 return CS_SUCCESS;
194 }
195
196 /**
197 * @brief Copy jit code for cache to jit memory
198 * @param signer jit code signer
199 * @param jitMemory dest address
200 * @param tmpBuffer tmp buffer stored jit code
201 * @param size memory size
202 * @return error code, see errcode.h
203 */
CopyToJitCode(JitCodeSignerBase * signer,void * jitMemory,void * tmpBuffer,int size)204 __attribute__((no_sanitize("cfi"))) static inline int32_t CopyToJitCode(
205 JitCodeSignerBase *signer, void *jitMemory, void *tmpBuffer, int size)
206 {
207 CHECK_NULL_AND_RETURN_CODE(signer);
208 int32_t ret = CS_SUCCESS;
209 // try not to depend on other dynamic library in JITFORT
210 #ifndef JIT_FORT_DISABLE
211 int32_t prctlRet = PrctlWrapper(JITFORT_PRCTL_OPTION, JITFORT_SWITCH_IN, 0);
212 if (prctlRet < 0) {
213 return CS_ERR_JITFORT_IN;
214 }
215 #endif
216 if (IsSupportJitCodeSigner()) {
217 ret = signer->ValidateCodeCopy(reinterpret_cast<Instr *>(jitMemory),
218 reinterpret_cast<Byte *>(tmpBuffer), size);
219 } else {
220 void *ptr = __builtin_memcpy(jitMemory, tmpBuffer, size);
221 if (reinterpret_cast<uintptr_t>(ptr) - reinterpret_cast<uintptr_t>(jitMemory) !=
222 static_cast<uintptr_t>(size)) {
223 ret = CS_ERR_MEMORY;
224 }
225 }
226 #ifndef JIT_FORT_DISABLE
227 prctlRet = PrctlWrapper(JITFORT_PRCTL_OPTION, JITFORT_SWITCH_OUT, 0);
228 if (prctlRet < 0) {
229 return CS_ERR_JITFORT_OUT;
230 }
231 #endif
232 return ret;
233 }
234 }
235 }
236 }
237 #endif