1 /*
2  * Copyright (C) 2023 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #ifndef BERBERIS_BASE_EXEC_REGION_H_
18 #define BERBERIS_BASE_EXEC_REGION_H_
19 
20 #include <cstddef>
21 #include <cstdint>
22 
23 namespace berberis {
24 
25 // ExecRegion manages a range of writable executable memory.
26 // This implementation works with 2 mappings of memfd file,
27 // one is executable and is read only another one is writable
28 // and not executable.
29 //
30 // Because both mappings are backed by memfd file msync is not
31 // needed in order to keep them up to date. It is backed by shmem
32 // and always consistent. shmem implementation of fsync is no-op:
33 // https://github.com/torvalds/linux/blob/3de0c269adc6c2fac0bb1fb11965f0de699dc32b/mm/shmem.c#L3931
34 //
35 //
36 // Move-only!
37 class ExecRegion {
38  public:
39   ExecRegion() = default;
ExecRegion(uint8_t * exec,uint8_t * write,size_t size)40   explicit ExecRegion(uint8_t* exec, uint8_t* write, size_t size)
41       : exec_{exec}, write_{write}, size_{size} {}
42 
43   ExecRegion(const ExecRegion& other) = delete;
44   ExecRegion& operator=(const ExecRegion& other) = delete;
45 
ExecRegion(ExecRegion && other)46   ExecRegion(ExecRegion&& other) noexcept {
47     exec_ = other.exec_;
48     write_ = other.write_;
49     size_ = other.size_;
50     other.exec_ = nullptr;
51     other.write_ = nullptr;
52     other.size_ = 0;
53   }
54 
55   ExecRegion& operator=(ExecRegion&& other) noexcept {
56     if (this == &other) {
57       return *this;
58     }
59     exec_ = other.exec_;
60     write_ = other.write_;
61     size_ = other.size_;
62     other.exec_ = nullptr;
63     other.write_ = nullptr;
64     other.size_ = 0;
65     return *this;
66   }
67 
begin()68   [[nodiscard]] const uint8_t* begin() const { return exec_; }
end()69   [[nodiscard]] const uint8_t* end() const { return exec_ + size_; }
70 
71   void Write(const uint8_t* dst, const void* src, size_t size);
72 
73   void Detach();
74   void Free();
75 
76  private:
77   uint8_t* exec_ = nullptr;
78   uint8_t* write_ = nullptr;
79   size_t size_ = 0;
80 };
81 
82 }  // namespace berberis
83 
84 #endif  // BERBERIS_BASE_EXEC_REGION_H_
85