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 LIBPANDAFILE_DATA_PROTECT_H 17 #define LIBPANDAFILE_DATA_PROTECT_H 18 19 #include <cstdint> 20 #include <string> 21 #include <string_view> 22 #include <vector> 23 24 #if defined(PANDA_ENABLE_DATA_PROTECT) 25 #include <sys/auxv.h> 26 #include <asm/hwcap.h> 27 #endif 28 29 namespace panda::panda_file { 30 31 class DataProtect { 32 public: DataProtect()33 DataProtect() : protect_pointer_(0) {} DataProtect(const uintptr_t pointer)34 explicit DataProtect(const uintptr_t pointer) 35 { 36 if (pointer == 0) { 37 protect_pointer_ = 0; 38 return; 39 } 40 protect_pointer_ = DataProtectPac(pointer, reinterpret_cast<uintptr_t>(&protect_pointer_)); 41 } 42 43 ~DataProtect() = default; 44 DataProtectAut(const uintptr_t pointer,const uintptr_t address)45 static inline uintptr_t DataProtectAut(const uintptr_t pointer, [[maybe_unused]]const uintptr_t address) 46 { 47 #if defined(PANDA_ENABLE_DATA_PROTECT) 48 uint64_t hwcaps = getauxval(AT_HWCAP); 49 if (!(hwcaps & HWCAP_PACA) || !(hwcaps & HWCAP_PACG)) { 50 return pointer; 51 } 52 void *t1 = reinterpret_cast<void*>(pointer); 53 void *t2 = reinterpret_cast<void*>(address); 54 #ifdef PAC_DFI_PTR_BKEY 55 __asm__ __volatile__("autdb %0, %1":"+r"(t1):"r"(t2):); 56 #else 57 __asm__ __volatile__("autda %0, %1":"+r"(t1):"r"(t2):); 58 #endif 59 return reinterpret_cast<uintptr_t>(t1); 60 #else 61 return pointer; 62 #endif 63 } 64 DataProtectPac(const uintptr_t pointer,const uintptr_t address)65 static inline uintptr_t DataProtectPac(const uintptr_t pointer, [[maybe_unused]]const uintptr_t address) 66 { 67 #if defined(PANDA_ENABLE_DATA_PROTECT) 68 uint64_t hwcaps = getauxval(AT_HWCAP); 69 if (!(hwcaps & HWCAP_PACA) || !(hwcaps & HWCAP_PACG)) { 70 return pointer; 71 } 72 void *t1 = reinterpret_cast<void*>(pointer); 73 void *t2 = reinterpret_cast<void*>(address); 74 #ifdef PAC_DFI_PTR_BKEY 75 __asm__ __volatile__("pacdb %0, %1":"+r"(t1):"r"(t2):); 76 #else 77 __asm__ __volatile__("pacda %0, %1":"+r"(t1):"r"(t2):); 78 #endif 79 return reinterpret_cast<uintptr_t>(t1); 80 #else 81 return pointer; 82 #endif 83 } 84 Update(const uintptr_t pointer)85 void Update(const uintptr_t pointer) 86 { 87 if (pointer == 0) { 88 protect_pointer_ = 0; 89 return; 90 } 91 protect_pointer_ = DataProtectPac(pointer, reinterpret_cast<uintptr_t>(&protect_pointer_)); 92 } 93 GetOriginPointer()94 uintptr_t GetOriginPointer() const 95 { 96 if (protect_pointer_ == 0) { 97 return protect_pointer_; 98 } 99 return DataProtectAut(protect_pointer_, reinterpret_cast<uintptr_t>(&protect_pointer_)); 100 } 101 102 private: 103 uintptr_t protect_pointer_; 104 }; 105 106 class BoolPacProtect { 107 public: 108 enum PacBoolean : uintptr_t { 109 PAC_FALSE = 1, 110 PAC_TRUE = 2, 111 }; 112 BoolPacProtect()113 BoolPacProtect() 114 { 115 Update(false); 116 } 117 BoolPacProtect(const bool flag)118 explicit BoolPacProtect(const bool flag) 119 { 120 Update(flag); 121 } 122 Update(const bool flag)123 void Update(const bool flag) 124 { 125 protect_bool_ = DataProtect::DataProtectPac(flag ? PAC_TRUE : PAC_FALSE, 126 reinterpret_cast<uintptr_t>(&protect_bool_)); 127 } 128 GetBool()129 bool GetBool() const 130 { 131 auto value = DataProtect::DataProtectAut(protect_bool_, reinterpret_cast<uintptr_t>(&protect_bool_)); 132 return value == PAC_TRUE ? true : false; 133 } 134 135 private: 136 uintptr_t protect_bool_; 137 }; 138 139 class StringPacProtect { 140 public: 141 142 enum Shift : uint8_t { 143 SHIFT8 = 8, 144 SHIFT16 = 16, 145 SHIFT24 = 24, 146 SHIFT32 = 32 147 }; 148 StringPacProtect()149 StringPacProtect() : data_(std::vector<uintptr_t>()), origin_length_(0) {} 150 StringPacProtect(std::string_view str_data)151 explicit StringPacProtect(std::string_view str_data) 152 { 153 Update(str_data); 154 } 155 ~StringPacProtect()156 ~StringPacProtect() 157 { 158 Clear(); 159 } 160 161 // replace data with pac(str_data) Update(std::string_view str_data)162 void Update(std::string_view str_data) 163 { 164 Clear(); 165 AppendWithoutCheckBack(str_data); 166 } 167 Append(char ch)168 void Append(char ch) 169 { 170 constexpr uint32_t step = 4; 171 if (origin_length_ % step > 0) { 172 // Filling back empty 173 uint32_t empty_count = step - (origin_length_ % step); 174 auto last_data = DataProtect::DataProtectAut(data_.back(), reinterpret_cast<uintptr_t>(&data_)); 175 data_.pop_back(); 176 uint8_t shift = (SHIFT8 * (empty_count - 1)); 177 last_data |= static_cast<uintptr_t>(ch) << shift; 178 data_.push_back(DataProtect::DataProtectPac(last_data, reinterpret_cast<uintptr_t>(&data_))); 179 } else { 180 uintptr_t temp_data = uintptr_t(ch); 181 temp_data <<= SHIFT24; 182 data_.push_back(DataProtect::DataProtectPac(temp_data, reinterpret_cast<uintptr_t>(&data_))); 183 } 184 origin_length_++; 185 } 186 187 // data += pac(str_data) Append(std::string_view str_data)188 void Append(std::string_view str_data) 189 { 190 if (str_data.empty()) { 191 return; 192 } 193 constexpr uint32_t step = 4; 194 195 auto str = reinterpret_cast<const uint8_t *>(str_data.data()); 196 auto len = str_data.length(); 197 if (origin_length_ % step != 0) { 198 // Filling back empty 199 uint32_t iter = 0; 200 uint32_t empty_count = step - (origin_length_ % step); 201 auto last_data = DataProtect::DataProtectAut(data_.back(), reinterpret_cast<uintptr_t>(&data_)); 202 data_.pop_back(); 203 204 last_data >>= SHIFT8 * empty_count; 205 while (iter < empty_count) { 206 last_data <<= SHIFT8; 207 last_data += (iter < len ? str[iter] : 0); 208 iter++; 209 } 210 data_.push_back(DataProtect::DataProtectPac(last_data, reinterpret_cast<uintptr_t>(&data_))); 211 origin_length_ += (empty_count < len ? empty_count : len); 212 if (empty_count < len) { 213 AppendWithoutCheckBack(str_data.substr(empty_count)); 214 } 215 } else { 216 AppendWithoutCheckBack(str_data); 217 } 218 } 219 220 // return string(aut(data)) GetOriginString()221 std::string GetOriginString() const 222 { 223 if (data_.empty()) { 224 return ""; 225 } 226 227 std::string res = ""; 228 constexpr uintptr_t mask = 0xff000000; 229 for (uint32_t iter = 0; iter < data_.size(); ++iter) { 230 uintptr_t temp_data = DataProtect::DataProtectAut(data_[iter], reinterpret_cast<uintptr_t>(&data_)); 231 res.push_back(char((temp_data & mask) >> SHIFT24)); 232 temp_data <<= SHIFT8; 233 res.push_back(char((temp_data & mask) >> SHIFT24)); 234 temp_data <<= SHIFT8; 235 res.push_back(char((temp_data & mask) >> SHIFT24)); 236 temp_data <<= SHIFT8; 237 res.push_back(char((temp_data & mask) >> SHIFT24)); 238 } 239 240 // delete back empty 241 while (res.size() > origin_length_) { 242 res.pop_back(); 243 } 244 245 return res; 246 } 247 CompareStringWithPacedString(std::string_view str_data)248 bool CompareStringWithPacedString(std::string_view str_data) 249 { 250 uint32_t len = str_data.length(); 251 constexpr uint32_t step = 4; 252 if (len != origin_length_) { 253 return false; 254 } 255 auto str = reinterpret_cast<const uint8_t *>(str_data.data()); 256 257 auto data_ptr = data_.begin(); 258 uint32_t left = 0; 259 while (left < len) { 260 uint32_t right = left + step; 261 uintptr_t temp_data = 0; 262 263 while (left < right) { 264 temp_data <<= SHIFT8; 265 temp_data += (left < len ? str[left] : 0); 266 ++left; 267 } 268 auto res = DataProtect::DataProtectPac(temp_data, reinterpret_cast<uintptr_t>(&data_)); 269 if (res != *data_ptr) { 270 return false; 271 } 272 ++data_ptr; 273 } 274 return true; 275 } 276 Clear()277 void Clear() 278 { 279 std::vector<uintptr_t>().swap(data_); 280 origin_length_ = 0; 281 } 282 283 // PacDataSize = ceil(StrLength / 4) PacDataSize()284 uint32_t PacDataSize() 285 { 286 return data_.size(); 287 } 288 289 // Original String Length Before Pac StrLength()290 uint32_t StrLength() 291 { 292 return origin_length_; 293 } 294 295 private: 296 AppendWithoutCheckBack(std::string_view str_data)297 void AppendWithoutCheckBack(std::string_view str_data) 298 { 299 if (str_data.empty()) { 300 return; 301 } 302 auto str = reinterpret_cast<const uint8_t *>(str_data.data()); 303 uint32_t len = str_data.length(); 304 305 constexpr uint32_t step = 4; 306 uint32_t left = 0; 307 // uint32 = char << 24 | char << 16 | char << 8 | char 308 // compress 4 char => 1 uint32 => PAC(uint32) => uintptr_t 309 while (left < len) { 310 uint32_t right = left + step; 311 uintptr_t temp_data = 0; 312 313 while (left < right) { 314 temp_data <<= SHIFT8; 315 temp_data += (left < len ? str[left] : 0); 316 ++left; 317 } 318 data_.push_back(DataProtect::DataProtectPac(temp_data, reinterpret_cast<uintptr_t>(&data_))); 319 } 320 origin_length_ += str_data.length(); 321 } 322 323 std::vector<uintptr_t>data_; 324 uint32_t origin_length_; 325 }; 326 327 } 328 #endif // LIBPANDAFILE_DATA_PROTECT_H 329