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