• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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