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 "pac_sign_ctx.h"
17 
18 #include <memory>
19 #include "errcode.h"
20 #include "log.h"
21 #include "random_helper.h"
22 
23 namespace OHOS {
24 namespace Security {
25 namespace CodeSign {
26 
27 constexpr uint64_t SIGN_WITH_CONTEXT_PREFIX = 0x2LL << 60;
28 constexpr uint64_t SIGN_WITHOUT_CONTEXT_PREFIX = 0x3LL << 60;
29 constexpr uint64_t AUTH_CONTEXT_PREFIX = 0x1LL << 60;
30 constexpr uint32_t HIGH_BITS_RIGHT_SHIFT = 32;
31 
PACDB(uint64_t value,uint64_t modifier)32 static inline uint64_t PACDB(uint64_t value, uint64_t modifier)
33 {
34 #ifdef ARCH_PAC_SUPPORT
35     asm volatile("pacdb %0, %1" : "+r"(value) : "r"(modifier) :);
36 #endif
37     return value;
38 }
39 
AUTDB(uint64_t value,uint64_t modifier)40 static inline uint64_t AUTDB(uint64_t value, uint64_t modifier)
41 {
42 #ifdef ARCH_PAC_SUPPORT
43     asm volatile("autdb %0, %1" : "+r"(value) : "r"(modifier) :);
44 #endif
45     return value;
46 }
47 
PACGA(uint64_t value,uint64_t modifier)48 static inline uint32_t PACGA(uint64_t value, uint64_t modifier)
49 {
50 #ifdef ARCH_PAC_SUPPORT
51     uint64_t ret = 0;
52     asm volatile("pacga %0, %1, %2" : "=r"(ret) : "r"(value), "r"(modifier) :);
53 #else
54     uint64_t ret = value;
55 #endif
56     return static_cast<uint32_t>(ret >> HIGH_BITS_RIGHT_SHIFT);
57 }
58 
PACSignCtx(CTXPurpose purpose,uint32_t salt)59 PACSignCtx::PACSignCtx(CTXPurpose purpose, uint32_t salt)
60     : context_(0), salt_(salt), index_(0), purpose_(purpose) {}
61 
~PACSignCtx()62 PACSignCtx::~PACSignCtx() {}
63 
InitSalt()64 void PACSignCtx::InitSalt()
65 {
66     static RandomHelper randomHelper;
67     uint32_t random = 0;
68     if (randomHelper.GetUint32(random) != CS_SUCCESS) {
69         LOG_ERROR("Init salt failed.");
70         int tmpAddr = 0;
71         // use random address as salt
72         random = static_cast<uint32_t>(
73             reinterpret_cast<uintptr_t>(&tmpAddr));
74     }
75     salt_ = random;
76 }
77 
Init(int index)78 void PACSignCtx::Init(int index)
79 {
80     index_ = index;
81     SetContext(GetSalt());
82 }
83 
PaddingContext(ContextType type,int index)84 uint64_t PACSignCtx::PaddingContext(ContextType type, int index)
85 {
86     uint32_t context;
87     uint64_t prefix;
88     switch (type) {
89         case SIGN_WITH_CONTEXT:
90             context = context_;
91             prefix = SIGN_WITH_CONTEXT_PREFIX;
92             index = index_;
93             break;
94         case SIGN_WITHOUT_CONTEXT:
95             context = GetSalt();
96             prefix = SIGN_WITHOUT_CONTEXT_PREFIX;
97             break;
98         case AUTH_CONTEXT:
99             context = GetSalt();
100             index = index_;
101             prefix = AUTH_CONTEXT_PREFIX;
102             break;
103         default:
104             return CS_ERR_UNSUPPORT;
105     }
106 #if defined(JIT_CODE_SIGN_DEBUGGABLE) && defined(JIT_FORT_DISABLE)
107     LOG_INFO("Padding prefix = %{public}lx, index = %{public}x, context = %{public}x",
108         prefix, index_, context);
109 #endif
110     uint64_t ret = prefix | ((static_cast<uint64_t>(index) & 0xfffffff) << 32) | context;
111     return ret;
112 }
113 
SetContext(uint32_t context)114 void PACSignCtx::SetContext(uint32_t context)
115 {
116     if (purpose_ == CTXPurpose::VERIFY) {
117         context_ = context;
118         return;
119     }
120     uint64_t paddingContext = PaddingContext(AUTH_CONTEXT);
121     context_ = PACDB(context, paddingContext);
122 }
123 
GetRealContext()124 uint64_t PACSignCtx::GetRealContext()
125 {
126     uint64_t paddingContext = PaddingContext(AUTH_CONTEXT);
127     return AUTDB(context_, paddingContext);
128 }
129 
SignWithContext(uint32_t value)130 uint32_t PACSignCtx::SignWithContext(uint32_t value)
131 {
132     uint64_t paddingContext = PaddingContext(SIGN_WITH_CONTEXT);
133     return PACGA(value, paddingContext);
134 }
135 
Update(uint32_t value)136 uint32_t PACSignCtx::Update(uint32_t value)
137 {
138 #if defined(JIT_CODE_SIGN_DEBUGGABLE) && defined(JIT_FORT_DISABLE)
139     LOG_INFO("Before update context = %{public}lx", context_);
140 #endif
141     if (purpose_ == CTXPurpose::SIGN) {
142         context_ = GetRealContext();
143     }
144     index_ += 1;
145     uint32_t signature = SignWithContext(value);
146     SetContext(signature);
147 #if defined(JIT_CODE_SIGN_DEBUGGABLE) && defined(JIT_FORT_DISABLE)
148     LOG_INFO("After update context = %{public}lx, signature = %{public}x",
149         context_, signature);
150 #endif
151     return signature;
152 }
153 
SignSingle(uint32_t value,uint32_t index)154 uint32_t PACSignCtx::SignSingle(uint32_t value, uint32_t index)
155 {
156     uint64_t paddingContext = PaddingContext(SIGN_WITHOUT_CONTEXT, index);
157     uint32_t signature = PACGA(value, paddingContext);
158 #if defined(JIT_CODE_SIGN_DEBUGGABLE) && defined(JIT_FORT_DISABLE)
159     LOG_INFO("Get signature = %{public}x", signature);
160 #endif
161     return signature;
162 }
163 
GetSalt()164 uint32_t PACSignCtx::GetSalt()
165 {
166     return salt_;
167 }
168 }
169 }
170 }