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_base.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 
GetOneInstrForQueue(std::queue<Byte> & queue)29 inline static Instr GetOneInstrForQueue(std::queue<Byte> &queue)
30 {
31     Instr insn = 0;
32     int i = 0;
33     while ((i < INSTRUCTION_SIZE) && !queue.empty()) {
34         insn |= (queue.front() << (BYTE_BIT_SIZE * i));
35         queue.pop();
36         i++;
37     }
38     return insn;
39 }
40 
RegisterTmpBuffer(Byte * tmpBuffer)41 void JitCodeSignerBase::RegisterTmpBuffer(Byte *tmpBuffer)
42 {
43     tmpBuffer_ = tmpBuffer;
44 }
45 
SignData(const Byte * const data,uint32_t size)46 int32_t JitCodeSignerBase::SignData(const Byte *const data, uint32_t size)
47 {
48     if (data == nullptr) {
49         return CS_ERR_INVALID_DATA;
50     }
51     uint32_t cur = 0;
52     size_t unsignedSize = willSign_.size();
53     if ((unsignedSize == 0) && (size >= INSTRUCTION_SIZE)) {
54         auto insnPtr = reinterpret_cast<const Instr *const>(data);
55         while (cur + INSTRUCTION_SIZE <= size) {
56             SignInstruction(*insnPtr);
57             insnPtr++;
58             cur += INSTRUCTION_SIZE;
59         }
60     }
61 
62     if (cur == size) {
63         return CS_SUCCESS;
64     }
65     unsignedSize += size - cur;
66     while (cur < size) {
67         willSign_.push(*(data + cur));
68         cur++;
69     }
70 
71     while (unsignedSize >= INSTRUCTION_SIZE) {
72         Instr insn = GetOneInstrForQueue(willSign_);
73         SignInstruction(insn);
74         unsignedSize -= INSTRUCTION_SIZE;
75     }
76     return CS_SUCCESS;
77 }
78 
PatchInstruction(Byte * buffer,Instr insn)79 int32_t JitCodeSignerBase::PatchInstruction(Byte *buffer, Instr insn)
80 {
81     if ((buffer == nullptr) || (tmpBuffer_ == nullptr)) {
82         return CS_ERR_PATCH_INVALID;
83     }
84     return PatchInstruction(static_cast<int>(buffer - tmpBuffer_), insn);
85 }
86 
PatchData(int offset,const Byte * const data,uint32_t size)87 int32_t JitCodeSignerBase::PatchData(int offset, const Byte *const data, uint32_t size)
88 {
89     if (size & UNALIGNMENT_MASK) {
90         return CS_ERR_JIT_SIGN_SIZE;
91     }
92     if (data == nullptr) {
93         return CS_ERR_INVALID_DATA;
94     }
95     auto insnPtr = reinterpret_cast<const Instr *const>(data);
96     for (uint32_t i = 0; i < size; i += INSTRUCTION_SIZE) {
97         int ret = PatchInstruction(offset + i, *insnPtr);
98         if (ret != CS_SUCCESS) {
99             return ret;
100         }
101         insnPtr += 1;
102     }
103     return CS_SUCCESS;
104 }
105 
PatchData(Byte * buffer,const Byte * const data,uint32_t size)106 int32_t JitCodeSignerBase::PatchData(Byte *buffer, const Byte *const data, uint32_t size)
107 {
108     if ((buffer == nullptr) || (tmpBuffer_ == nullptr)) {
109         return CS_ERR_PATCH_INVALID;
110     }
111     return PatchData(static_cast<int>(buffer - tmpBuffer_), data, size);
112 }
113 
ConvertPatchOffsetToIndex(const int offset,int & curIndex)114 bool JitCodeSignerBase::ConvertPatchOffsetToIndex(const int offset, int &curIndex)
115 {
116     if ((offset < 0) || ((static_cast<uint32_t>(offset) & UNALIGNMENT_MASK) != 0)) {
117         return false;
118     }
119     curIndex = GetIndexFromOffset(offset);
120     if (static_cast<size_t>(curIndex) >= signTable_.size()) {
121         LOG_ERROR("Offset is out of range, index = %{public}d, signTable size = %{public}zu",
122             curIndex, signTable_.size());
123         return false;
124     }
125     return true;
126 }
127 
CheckDataCopy(Instr * jitMemory,Byte * tmpBuffer,int size)128 int32_t JitCodeSignerBase::CheckDataCopy(Instr *jitMemory, Byte *tmpBuffer, int size)
129 {
130     if (jitMemory == nullptr) {
131         return CS_ERR_JIT_MEMORY;
132     }
133     if (tmpBuffer == nullptr) {
134         return CS_ERR_TMP_BUFFER;
135     }
136 
137     // update tmp buffer
138     tmpBuffer_ = tmpBuffer;
139 
140     if (((static_cast<uint32_t>(size) & UNALIGNMENT_MASK) != 0) ||
141         (static_cast<uint32_t>(size) > signTable_.size() * INSTRUCTION_SIZE)) {
142 #ifdef JIT_FORT_DISABLE
143         LOG_ERROR("Range invalid, size = %{public}d, table size = %{public}zu",
144             size, signTable_.size());
145 #endif
146         return CS_ERR_JIT_SIGN_SIZE;
147     }
148     return CS_SUCCESS;
149 }
150 }
151 }
152 }