• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2015 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 _PRIVATE_WRITEPROTECTED_H
18 #define _PRIVATE_WRITEPROTECTED_H
19 
20 #include <errno.h>
21 #include <string.h>
22 #include <sys/cdefs.h>
23 #include <sys/mman.h>
24 #include <sys/user.h>
25 
26 #include <async_safe/log.h>
27 
28 #include "private/bionic_macros.h"
29 #include "private/bionic_prctl.h"
30 
31 template <typename T>
32 union WriteProtectedContents {
33   T value;
34   char padding[PAGE_SIZE];
35 
36   WriteProtectedContents() = default;
37   DISALLOW_COPY_AND_ASSIGN(WriteProtectedContents);
38 } __attribute__((aligned(PAGE_SIZE)));
39 
40 // Write protected wrapper class that aligns its contents to a page boundary,
41 // and sets the memory protection to be non-writable, except when being modified
42 // explicitly.
43 template <typename T>
44 class WriteProtected {
45   static_assert(sizeof(T) < PAGE_SIZE,
46                 "WriteProtected only supports contents up to PAGE_SIZE");
47   static_assert(__is_pod(T), "WriteProtected only supports POD contents");
48 
49   WriteProtectedContents<T> contents;
50 
51  public:
52   WriteProtected() = default;
53   DISALLOW_COPY_AND_ASSIGN(WriteProtected);
54 
initialize()55   void initialize() {
56     // Not strictly necessary, but this will hopefully segfault if we initialize
57     // multiple times by accident.
58     memset(&contents, 0, sizeof(contents));
59 
60     if (mprotect(&contents, PAGE_SIZE, PROT_READ)) {
61       async_safe_fatal("failed to make WriteProtected nonwritable in initialize");
62     }
63   }
64 
65   const T* operator->() {
66     return &contents.value;
67   }
68 
69   const T& operator*() {
70     return contents.value;
71   }
72 
73   template <typename Mutator>
mutate(Mutator mutator)74   void mutate(Mutator mutator) {
75     if (mprotect(&contents, PAGE_SIZE, PROT_READ | PROT_WRITE) != 0) {
76       async_safe_fatal("failed to make WriteProtected writable in mutate: %s",
77                        strerror(errno));
78     }
79     mutator(&contents.value);
80     if (mprotect(&contents, PAGE_SIZE, PROT_READ) != 0) {
81       async_safe_fatal("failed to make WriteProtected nonwritable in mutate: %s",
82                        strerror(errno));
83     }
84   }
85 };
86 
87 #endif
88