1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * * Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * * Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in 12 * the documentation and/or other materials provided with the 13 * distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 16 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 17 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 18 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 19 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 21 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 22 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 23 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 25 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29 #include "system_properties/contexts_serialized.h" 30 31 #include <fcntl.h> 32 #include <limits.h> 33 #include <sys/mman.h> 34 #include <sys/stat.h> 35 #include <sys/types.h> 36 37 #include <new> 38 39 #include <async_safe/log.h> 40 41 #include "private/bionic_prctl.h" 42 #include "system_properties/system_properties.h" 43 44 bool ContextsSerialized::InitializeContextNodes() { 45 auto num_context_nodes = property_info_area_file_->num_contexts(); 46 auto context_nodes_mmap_size = sizeof(ContextNode) * num_context_nodes; 47 // We want to avoid malloc in system properties, so we take an anonymous map instead (b/31659220). 48 void* const map_result = mmap(nullptr, context_nodes_mmap_size, PROT_READ | PROT_WRITE, 49 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); 50 if (map_result == MAP_FAILED) { 51 return false; 52 } 53 54 prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, map_result, context_nodes_mmap_size, 55 "System property context nodes"); 56 57 context_nodes_ = reinterpret_cast<ContextNode*>(map_result); 58 num_context_nodes_ = num_context_nodes; 59 context_nodes_mmap_size_ = context_nodes_mmap_size; 60 61 for (size_t i = 0; i < num_context_nodes; ++i) { 62 new (&context_nodes_[i]) ContextNode(property_info_area_file_->context(i), filename_); 63 } 64 65 return true; 66 } 67 68 bool ContextsSerialized::MapSerialPropertyArea(bool access_rw, bool* fsetxattr_failed) { 69 char filename[PROP_FILENAME_MAX]; 70 int len = async_safe_format_buffer(filename, sizeof(filename), "%s/properties_serial", filename_); 71 if (len < 0 || len > PROP_FILENAME_MAX) { 72 serial_prop_area_ = nullptr; 73 return false; 74 } 75 76 if (access_rw) { 77 serial_prop_area_ = 78 prop_area::map_prop_area_rw(filename, "u:object_r:properties_serial:s0", fsetxattr_failed); 79 } else { 80 serial_prop_area_ = prop_area::map_prop_area(filename); 81 } 82 return serial_prop_area_; 83 } 84 85 bool ContextsSerialized::InitializeProperties() { 86 if (!property_info_area_file_.LoadDefaultPath()) { 87 return false; 88 } 89 90 if (!InitializeContextNodes()) { 91 FreeAndUnmap(); 92 return false; 93 } 94 95 return true; 96 } 97 98 bool ContextsSerialized::Initialize(bool writable, const char* filename, bool* fsetxattr_failed) { 99 filename_ = filename; 100 if (!InitializeProperties()) { 101 return false; 102 } 103 104 if (writable) { 105 mkdir(filename_, S_IRWXU | S_IXGRP | S_IXOTH); 106 bool open_failed = false; 107 if (fsetxattr_failed) { 108 *fsetxattr_failed = false; 109 } 110 111 for (size_t i = 0; i < num_context_nodes_; ++i) { 112 if (!context_nodes_[i].Open(true, fsetxattr_failed)) { 113 open_failed = true; 114 } 115 } 116 if (open_failed || !MapSerialPropertyArea(true, fsetxattr_failed)) { 117 FreeAndUnmap(); 118 return false; 119 } 120 } else { 121 if (!MapSerialPropertyArea(false, nullptr)) { 122 FreeAndUnmap(); 123 return false; 124 } 125 } 126 return true; 127 } 128 129 prop_area* ContextsSerialized::GetPropAreaForName(const char* name) { 130 uint32_t index; 131 property_info_area_file_->GetPropertyInfoIndexes(name, &index, nullptr); 132 if (index == ~0u || index >= num_context_nodes_) { 133 async_safe_format_log(ANDROID_LOG_ERROR, "libc", "Could not find context for property \"%s\"", 134 name); 135 return nullptr; 136 } 137 auto* context_node = &context_nodes_[index]; 138 if (!context_node->pa()) { 139 // We explicitly do not check no_access_ in this case because unlike the 140 // case of foreach(), we want to generate an selinux audit for each 141 // non-permitted property access in this function. 142 context_node->Open(false, nullptr); 143 } 144 return context_node->pa(); 145 } 146 147 void ContextsSerialized::ForEach(void (*propfn)(const prop_info* pi, void* cookie), void* cookie) { 148 for (size_t i = 0; i < num_context_nodes_; ++i) { 149 if (context_nodes_[i].CheckAccessAndOpen()) { 150 context_nodes_[i].pa()->foreach (propfn, cookie); 151 } 152 } 153 } 154 155 void ContextsSerialized::ResetAccess() { 156 for (size_t i = 0; i < num_context_nodes_; ++i) { 157 context_nodes_[i].ResetAccess(); 158 } 159 } 160 161 void ContextsSerialized::FreeAndUnmap() { 162 property_info_area_file_.Reset(); 163 if (context_nodes_ != nullptr) { 164 for (size_t i = 0; i < num_context_nodes_; ++i) { 165 context_nodes_[i].Unmap(); 166 } 167 munmap(context_nodes_, context_nodes_mmap_size_); 168 context_nodes_ = nullptr; 169 } 170 prop_area::unmap_prop_area(&serial_prop_area_); 171 serial_prop_area_ = nullptr; 172 } 173