Home | History | Annotate | Download | only in private
      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 
     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>
     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