blob: 69a68229bb9a80a31edfd34cf9db83f64b85f9b8 [file] [log] [blame]
Josh Gao93c0f5e2015-10-06 11:08:13 -07001/*
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
Elliott Hughes5e62b342018-10-25 11:00:00 -070017#pragma once
Josh Gao93c0f5e2015-10-06 11:08:13 -070018
19#include <errno.h>
20#include <string.h>
21#include <sys/cdefs.h>
22#include <sys/mman.h>
23#include <sys/user.h>
24
Christopher Ferris7a3681e2017-04-24 17:48:32 -070025#include <async_safe/log.h>
26
Josh Gao93c0f5e2015-10-06 11:08:13 -070027#include "private/bionic_macros.h"
Josh Gao93c0f5e2015-10-06 11:08:13 -070028
29template <typename T>
30union WriteProtectedContents {
31 T value;
32 char padding[PAGE_SIZE];
33
34 WriteProtectedContents() = default;
Elliott Hughes5e62b342018-10-25 11:00:00 -070035 BIONIC_DISALLOW_COPY_AND_ASSIGN(WriteProtectedContents);
Josh Gao93c0f5e2015-10-06 11:08:13 -070036} __attribute__((aligned(PAGE_SIZE)));
37
38// Write protected wrapper class that aligns its contents to a page boundary,
39// and sets the memory protection to be non-writable, except when being modified
40// explicitly.
41template <typename T>
42class WriteProtected {
43 static_assert(sizeof(T) < PAGE_SIZE,
44 "WriteProtected only supports contents up to PAGE_SIZE");
45 static_assert(__is_pod(T), "WriteProtected only supports POD contents");
46
47 WriteProtectedContents<T> contents;
48
49 public:
50 WriteProtected() = default;
Elliott Hughes5e62b342018-10-25 11:00:00 -070051 BIONIC_DISALLOW_COPY_AND_ASSIGN(WriteProtected);
Josh Gao93c0f5e2015-10-06 11:08:13 -070052
53 void initialize() {
54 // Not strictly necessary, but this will hopefully segfault if we initialize
55 // multiple times by accident.
56 memset(&contents, 0, sizeof(contents));
57
58 if (mprotect(&contents, PAGE_SIZE, PROT_READ)) {
Christopher Ferris7a3681e2017-04-24 17:48:32 -070059 async_safe_fatal("failed to make WriteProtected nonwritable in initialize");
Josh Gao93c0f5e2015-10-06 11:08:13 -070060 }
61 }
62
63 const T* operator->() {
64 return &contents.value;
65 }
66
67 const T& operator*() {
68 return contents.value;
69 }
70
71 template <typename Mutator>
72 void mutate(Mutator mutator) {
73 if (mprotect(&contents, PAGE_SIZE, PROT_READ | PROT_WRITE) != 0) {
Christopher Ferris7a3681e2017-04-24 17:48:32 -070074 async_safe_fatal("failed to make WriteProtected writable in mutate: %s",
75 strerror(errno));
Josh Gao93c0f5e2015-10-06 11:08:13 -070076 }
77 mutator(&contents.value);
78 if (mprotect(&contents, PAGE_SIZE, PROT_READ) != 0) {
Christopher Ferris7a3681e2017-04-24 17:48:32 -070079 async_safe_fatal("failed to make WriteProtected nonwritable in mutate: %s",
80 strerror(errno));
Josh Gao93c0f5e2015-10-06 11:08:13 -070081 }
82 }
83};