1*8d67ca89SAndroid Build Coastguard Worker /* 2*8d67ca89SAndroid Build Coastguard Worker * Copyright (C) 2015 The Android Open Source Project 3*8d67ca89SAndroid Build Coastguard Worker * 4*8d67ca89SAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License"); 5*8d67ca89SAndroid Build Coastguard Worker * you may not use this file except in compliance with the License. 6*8d67ca89SAndroid Build Coastguard Worker * You may obtain a copy of the License at 7*8d67ca89SAndroid Build Coastguard Worker * 8*8d67ca89SAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0 9*8d67ca89SAndroid Build Coastguard Worker * 10*8d67ca89SAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software 11*8d67ca89SAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS, 12*8d67ca89SAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13*8d67ca89SAndroid Build Coastguard Worker * See the License for the specific language governing permissions and 14*8d67ca89SAndroid Build Coastguard Worker * limitations under the License. 15*8d67ca89SAndroid Build Coastguard Worker */ 16*8d67ca89SAndroid Build Coastguard Worker 17*8d67ca89SAndroid Build Coastguard Worker #pragma once 18*8d67ca89SAndroid Build Coastguard Worker 19*8d67ca89SAndroid Build Coastguard Worker #include <errno.h> 20*8d67ca89SAndroid Build Coastguard Worker #include <string.h> 21*8d67ca89SAndroid Build Coastguard Worker #include <sys/cdefs.h> 22*8d67ca89SAndroid Build Coastguard Worker #include <sys/mman.h> 23*8d67ca89SAndroid Build Coastguard Worker #include <sys/user.h> 24*8d67ca89SAndroid Build Coastguard Worker 25*8d67ca89SAndroid Build Coastguard Worker #include <async_safe/log.h> 26*8d67ca89SAndroid Build Coastguard Worker 27*8d67ca89SAndroid Build Coastguard Worker #include "platform/bionic/macros.h" 28*8d67ca89SAndroid Build Coastguard Worker #include "platform/bionic/page.h" 29*8d67ca89SAndroid Build Coastguard Worker 30*8d67ca89SAndroid Build Coastguard Worker template <typename T> 31*8d67ca89SAndroid Build Coastguard Worker union WriteProtectedContents { 32*8d67ca89SAndroid Build Coastguard Worker T value; 33*8d67ca89SAndroid Build Coastguard Worker char padding[max_android_page_size()]; 34*8d67ca89SAndroid Build Coastguard Worker 35*8d67ca89SAndroid Build Coastguard Worker WriteProtectedContents() = default; 36*8d67ca89SAndroid Build Coastguard Worker BIONIC_DISALLOW_COPY_AND_ASSIGN(WriteProtectedContents); 37*8d67ca89SAndroid Build Coastguard Worker } __attribute__((aligned(max_android_page_size()))); 38*8d67ca89SAndroid Build Coastguard Worker 39*8d67ca89SAndroid Build Coastguard Worker // Write protected wrapper class that aligns its contents to a page boundary, 40*8d67ca89SAndroid Build Coastguard Worker // and sets the memory protection to be non-writable, except when being modified 41*8d67ca89SAndroid Build Coastguard Worker // explicitly. 42*8d67ca89SAndroid Build Coastguard Worker template <typename T> 43*8d67ca89SAndroid Build Coastguard Worker class WriteProtected { 44*8d67ca89SAndroid Build Coastguard Worker public: 45*8d67ca89SAndroid Build Coastguard Worker static_assert(sizeof(T) < max_android_page_size(), 46*8d67ca89SAndroid Build Coastguard Worker "WriteProtected only supports contents up to max_android_page_size()"); 47*8d67ca89SAndroid Build Coastguard Worker 48*8d67ca89SAndroid Build Coastguard Worker WriteProtected() = default; 49*8d67ca89SAndroid Build Coastguard Worker BIONIC_DISALLOW_COPY_AND_ASSIGN(WriteProtected); 50*8d67ca89SAndroid Build Coastguard Worker initialize()51*8d67ca89SAndroid Build Coastguard Worker void initialize() { 52*8d67ca89SAndroid Build Coastguard Worker // Not strictly necessary, but this will hopefully segfault if we initialize 53*8d67ca89SAndroid Build Coastguard Worker // multiple times by accident. 54*8d67ca89SAndroid Build Coastguard Worker memset(contents_addr(), 0, sizeof(contents)); 55*8d67ca89SAndroid Build Coastguard Worker set_protection(PROT_READ); 56*8d67ca89SAndroid Build Coastguard Worker } 57*8d67ca89SAndroid Build Coastguard Worker 58*8d67ca89SAndroid Build Coastguard Worker const T* operator->() { 59*8d67ca89SAndroid Build Coastguard Worker return &contents_addr()->value; 60*8d67ca89SAndroid Build Coastguard Worker } 61*8d67ca89SAndroid Build Coastguard Worker 62*8d67ca89SAndroid Build Coastguard Worker const T& operator*() { 63*8d67ca89SAndroid Build Coastguard Worker return contents_addr()->value; 64*8d67ca89SAndroid Build Coastguard Worker } 65*8d67ca89SAndroid Build Coastguard Worker 66*8d67ca89SAndroid Build Coastguard Worker template <typename Mutator> mutate(Mutator mutator)67*8d67ca89SAndroid Build Coastguard Worker void mutate(Mutator mutator) { 68*8d67ca89SAndroid Build Coastguard Worker set_protection(PROT_READ | PROT_WRITE); 69*8d67ca89SAndroid Build Coastguard Worker mutator(&contents_addr()->value); 70*8d67ca89SAndroid Build Coastguard Worker set_protection(PROT_READ); 71*8d67ca89SAndroid Build Coastguard Worker } 72*8d67ca89SAndroid Build Coastguard Worker 73*8d67ca89SAndroid Build Coastguard Worker private: 74*8d67ca89SAndroid Build Coastguard Worker WriteProtectedContents<T> contents; 75*8d67ca89SAndroid Build Coastguard Worker contents_addr()76*8d67ca89SAndroid Build Coastguard Worker WriteProtectedContents<T>* contents_addr() { 77*8d67ca89SAndroid Build Coastguard Worker auto addr = &contents; 78*8d67ca89SAndroid Build Coastguard Worker // Hide the fact that we're returning the address of contents from the compiler. 79*8d67ca89SAndroid Build Coastguard Worker // Otherwise it may generate code assuming alignment of 64KB even though the 80*8d67ca89SAndroid Build Coastguard Worker // variable is only guaranteed to have 4KB alignment. 81*8d67ca89SAndroid Build Coastguard Worker __asm__ __volatile__("" : "+r"(addr)); 82*8d67ca89SAndroid Build Coastguard Worker return addr; 83*8d67ca89SAndroid Build Coastguard Worker } 84*8d67ca89SAndroid Build Coastguard Worker set_protection(int prot)85*8d67ca89SAndroid Build Coastguard Worker void set_protection(int prot) { 86*8d67ca89SAndroid Build Coastguard Worker auto addr = contents_addr(); 87*8d67ca89SAndroid Build Coastguard Worker #if __has_feature(hwaddress_sanitizer) 88*8d67ca89SAndroid Build Coastguard Worker // The mprotect system call does not currently untag pointers, so do it 89*8d67ca89SAndroid Build Coastguard Worker // ourselves. 90*8d67ca89SAndroid Build Coastguard Worker addr = untag_address(addr); 91*8d67ca89SAndroid Build Coastguard Worker #endif 92*8d67ca89SAndroid Build Coastguard Worker if (mprotect(reinterpret_cast<void*>(addr), max_android_page_size(), prot) == -1) { 93*8d67ca89SAndroid Build Coastguard Worker async_safe_fatal("WriteProtected mprotect %x failed: %s", prot, strerror(errno)); 94*8d67ca89SAndroid Build Coastguard Worker } 95*8d67ca89SAndroid Build Coastguard Worker } 96*8d67ca89SAndroid Build Coastguard Worker }; 97