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