193c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao/* 293c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao * Copyright (C) 2015 The Android Open Source Project 393c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao * 493c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao * Licensed under the Apache License, Version 2.0 (the "License"); 593c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao * you may not use this file except in compliance with the License. 693c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao * You may obtain a copy of the License at 793c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao * 893c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao * http://www.apache.org/licenses/LICENSE-2.0 993c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao * 1093c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao * Unless required by applicable law or agreed to in writing, software 1193c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao * distributed under the License is distributed on an "AS IS" BASIS, 1293c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1393c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao * See the License for the specific language governing permissions and 1493c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao * limitations under the License. 1593c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao */ 1693c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao 1793c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao#ifndef _PRIVATE_WRITEPROTECTED_H 1893c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao#define _PRIVATE_WRITEPROTECTED_H 1993c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao 2093c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao#include <errno.h> 2193c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao#include <string.h> 2293c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao#include <sys/cdefs.h> 2393c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao#include <sys/mman.h> 2493c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao#include <sys/user.h> 2593c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao 2693c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao#include "private/bionic_macros.h" 2793c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao#include "private/bionic_prctl.h" 2893c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao#include "private/libc_logging.h" 2993c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao 3093c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gaotemplate <typename T> 3193c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gaounion WriteProtectedContents { 3293c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao T value; 3393c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao char padding[PAGE_SIZE]; 3493c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao 3593c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao WriteProtectedContents() = default; 3693c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao DISALLOW_COPY_AND_ASSIGN(WriteProtectedContents); 3793c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao} __attribute__((aligned(PAGE_SIZE))); 3893c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao 3993c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao// Write protected wrapper class that aligns its contents to a page boundary, 4093c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao// and sets the memory protection to be non-writable, except when being modified 4193c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao// explicitly. 4293c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gaotemplate <typename T> 4393c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gaoclass WriteProtected { 4493c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao static_assert(sizeof(T) < PAGE_SIZE, 4593c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao "WriteProtected only supports contents up to PAGE_SIZE"); 4693c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao static_assert(__is_pod(T), "WriteProtected only supports POD contents"); 4793c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao 4893c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao WriteProtectedContents<T> contents; 4993c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao 5093c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao public: 5193c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao WriteProtected() = default; 5293c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao DISALLOW_COPY_AND_ASSIGN(WriteProtected); 5393c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao 5493c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao void initialize() { 5593c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao // Not strictly necessary, but this will hopefully segfault if we initialize 5693c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao // multiple times by accident. 5793c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao memset(&contents, 0, sizeof(contents)); 5893c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao 5993c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao if (mprotect(&contents, PAGE_SIZE, PROT_READ)) { 6093c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao __libc_fatal("failed to make WriteProtected nonwritable in initialize"); 6193c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao } 6293c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao } 6393c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao 6493c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao const T* operator->() { 6593c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao return &contents.value; 6693c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao } 6793c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao 6893c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao const T& operator*() { 6993c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao return contents.value; 7093c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao } 7193c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao 7293c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao template <typename Mutator> 7393c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao void mutate(Mutator mutator) { 7493c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao if (mprotect(&contents, PAGE_SIZE, PROT_READ | PROT_WRITE) != 0) { 7593c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao __libc_fatal("failed to make WriteProtected writable in mutate: %s", 7693c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao strerror(errno)); 7793c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao } 7893c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao mutator(&contents.value); 7993c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao if (mprotect(&contents, PAGE_SIZE, PROT_READ) != 0) { 8093c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao __libc_fatal("failed to make WriteProtected nonwritable in mutate: %s", 8193c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao strerror(errno)); 8293c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao } 8393c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao } 8493c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao}; 8593c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao 8693c0f5ee00d1357247fda333c9d49c8673c9c83bJosh Gao#endif 87