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