fd_utils.cpp revision 54e387ddbe6a0462bc8e9e15c7c7b3463adfcb24
1/* 2 * Copyright (C) 2016 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#include "fd_utils.h" 18 19#include <algorithm> 20 21#include <fcntl.h> 22#include <grp.h> 23#include <stdlib.h> 24#include <sys/socket.h> 25#include <sys/types.h> 26#include <sys/un.h> 27#include <unistd.h> 28 29#include <android-base/strings.h> 30#include <cutils/log.h> 31 32// Static whitelist of open paths that the zygote is allowed to keep open. 33static const char* kPathWhitelist[] = { 34 "/dev/null", 35 "/dev/socket/zygote", 36 "/dev/socket/zygote_secondary", 37 "/dev/socket/webview_zygote", 38 "/sys/kernel/debug/tracing/trace_marker", 39 "/system/framework/framework-res.apk", 40 "/dev/urandom", 41 "/dev/ion", 42 "/dev/dri/renderD129", // Fixes b/31172436 43}; 44 45static const char kFdPath[] = "/proc/self/fd"; 46 47// static 48FileDescriptorWhitelist* FileDescriptorWhitelist::Get() { 49 if (instance_ == nullptr) { 50 instance_ = new FileDescriptorWhitelist(); 51 } 52 return instance_; 53} 54 55bool FileDescriptorWhitelist::IsAllowed(const std::string& path) const { 56 // Check the static whitelist path. 57 for (const auto& whitelist_path : kPathWhitelist) { 58 if (path == whitelist_path) 59 return true; 60 } 61 62 // Check any paths added to the dynamic whitelist. 63 for (const auto& whitelist_path : whitelist_) { 64 if (path == whitelist_path) 65 return true; 66 } 67 68 static const std::string kFrameworksPrefix = "/system/framework/"; 69 static const std::string kJarSuffix = ".jar"; 70 if (StartsWith(path, kFrameworksPrefix) && EndsWith(path, kJarSuffix)) { 71 return true; 72 } 73 74 // Whitelist files needed for Runtime Resource Overlay, like these: 75 // /system/vendor/overlay/framework-res.apk 76 // /system/vendor/overlay-subdir/pg/framework-res.apk 77 // /vendor/overlay/framework-res.apk 78 // /vendor/overlay/PG/android-framework-runtime-resource-overlay.apk 79 // /data/resource-cache/system@vendor@overlay@framework-res.apk@idmap 80 // /data/resource-cache/system@vendor@overlay-subdir@pg@framework-res.apk@idmap 81 // See AssetManager.cpp for more details on overlay-subdir. 82 static const std::string kOverlayDir = "/system/vendor/overlay/"; 83 static const std::string kVendorOverlayDir = "/vendor/overlay"; 84 static const std::string kOverlaySubdir = "/system/vendor/overlay-subdir/"; 85 static const std::string kApkSuffix = ".apk"; 86 87 if ((StartsWith(path, kOverlayDir) || StartsWith(path, kOverlaySubdir) 88 || StartsWith(path, kVendorOverlayDir)) 89 && EndsWith(path, kApkSuffix) 90 && path.find("/../") == std::string::npos) { 91 return true; 92 } 93 94 static const std::string kOverlayIdmapPrefix = "/data/resource-cache/"; 95 static const std::string kOverlayIdmapSuffix = ".apk@idmap"; 96 if (StartsWith(path, kOverlayIdmapPrefix) && EndsWith(path, kOverlayIdmapSuffix) 97 && path.find("/../") == std::string::npos) { 98 return true; 99 } 100 101 // All regular files that are placed under this path are whitelisted automatically. 102 static const std::string kZygoteWhitelistPath = "/vendor/zygote_whitelist/"; 103 if (StartsWith(path, kZygoteWhitelistPath) && path.find("/../") == std::string::npos) { 104 return true; 105 } 106 107 return false; 108} 109 110FileDescriptorWhitelist::FileDescriptorWhitelist() 111 : whitelist_() { 112} 113 114// TODO: Call android::base::StartsWith instead of copying the code here. 115// static 116bool FileDescriptorWhitelist::StartsWith(const std::string& str, 117 const std::string& prefix) { 118 return str.compare(0, prefix.size(), prefix) == 0; 119} 120 121// TODO: Call android::base::EndsWith instead of copying the code here. 122// static 123bool FileDescriptorWhitelist::EndsWith(const std::string& str, 124 const std::string& suffix) { 125 if (suffix.size() > str.size()) { 126 return false; 127 } 128 129 return str.compare(str.size() - suffix.size(), suffix.size(), suffix) == 0; 130} 131 132FileDescriptorWhitelist* FileDescriptorWhitelist::instance_ = nullptr; 133 134// static 135FileDescriptorInfo* FileDescriptorInfo::CreateFromFd(int fd) { 136 struct stat f_stat; 137 // This should never happen; the zygote should always have the right set 138 // of permissions required to stat all its open files. 139 if (TEMP_FAILURE_RETRY(fstat(fd, &f_stat)) == -1) { 140 ALOGE("Unable to stat fd %d : %s", fd, strerror(errno)); 141 return NULL; 142 } 143 144 const FileDescriptorWhitelist* whitelist = FileDescriptorWhitelist::Get(); 145 146 if (S_ISSOCK(f_stat.st_mode)) { 147 std::string socket_name; 148 if (!GetSocketName(fd, &socket_name)) { 149 return NULL; 150 } 151 152 if (!whitelist->IsAllowed(socket_name)) { 153 ALOGE("Socket name not whitelisted : %s (fd=%d)", socket_name.c_str(), fd); 154 return NULL; 155 } 156 157 return new FileDescriptorInfo(fd); 158 } 159 160 // We only handle whitelisted regular files and character devices. Whitelisted 161 // character devices must provide a guarantee of sensible behaviour when 162 // reopened. 163 // 164 // S_ISDIR : Not supported. (We could if we wanted to, but it's unused). 165 // S_ISLINK : Not supported. 166 // S_ISBLK : Not supported. 167 // S_ISFIFO : Not supported. Note that the zygote uses pipes to communicate 168 // with the child process across forks but those should have been closed 169 // before we got to this point. 170 if (!S_ISCHR(f_stat.st_mode) && !S_ISREG(f_stat.st_mode)) { 171 ALOGE("Unsupported st_mode %d", f_stat.st_mode); 172 return NULL; 173 } 174 175 std::string file_path; 176 if (!Readlink(fd, &file_path)) { 177 return NULL; 178 } 179 180 if (!whitelist->IsAllowed(file_path)) { 181 ALOGE("Not whitelisted : %s", file_path.c_str()); 182 return NULL; 183 } 184 185 // File descriptor flags : currently on FD_CLOEXEC. We can set these 186 // using F_SETFD - we're single threaded at this point of execution so 187 // there won't be any races. 188 const int fd_flags = TEMP_FAILURE_RETRY(fcntl(fd, F_GETFD)); 189 if (fd_flags == -1) { 190 ALOGE("Failed fcntl(%d, F_GETFD) : %s", fd, strerror(errno)); 191 return NULL; 192 } 193 194 // File status flags : 195 // - File access mode : (O_RDONLY, O_WRONLY...) we'll pass these through 196 // to the open() call. 197 // 198 // - File creation flags : (O_CREAT, O_EXCL...) - there's not much we can 199 // do about these, since the file has already been created. We shall ignore 200 // them here. 201 // 202 // - Other flags : We'll have to set these via F_SETFL. On linux, F_SETFL 203 // can only set O_APPEND, O_ASYNC, O_DIRECT, O_NOATIME, and O_NONBLOCK. 204 // In particular, it can't set O_SYNC and O_DSYNC. We'll have to test for 205 // their presence and pass them in to open(). 206 int fs_flags = TEMP_FAILURE_RETRY(fcntl(fd, F_GETFL)); 207 if (fs_flags == -1) { 208 ALOGE("Failed fcntl(%d, F_GETFL) : %s", fd, strerror(errno)); 209 return NULL; 210 } 211 212 // File offset : Ignore the offset for non seekable files. 213 const off_t offset = TEMP_FAILURE_RETRY(lseek64(fd, 0, SEEK_CUR)); 214 215 // We pass the flags that open accepts to open, and use F_SETFL for 216 // the rest of them. 217 static const int kOpenFlags = (O_RDONLY | O_WRONLY | O_RDWR | O_DSYNC | O_SYNC); 218 int open_flags = fs_flags & (kOpenFlags); 219 fs_flags = fs_flags & (~(kOpenFlags)); 220 221 return new FileDescriptorInfo(f_stat, file_path, fd, open_flags, fd_flags, fs_flags, offset); 222} 223 224bool FileDescriptorInfo::Restat() const { 225 struct stat f_stat; 226 if (TEMP_FAILURE_RETRY(fstat(fd, &f_stat)) == -1) { 227 return false; 228 } 229 230 return f_stat.st_ino == stat.st_ino && f_stat.st_dev == stat.st_dev; 231} 232 233bool FileDescriptorInfo::ReopenOrDetach() const { 234 if (is_sock) { 235 return DetachSocket(); 236 } 237 238 // NOTE: This might happen if the file was unlinked after being opened. 239 // It's a common pattern in the case of temporary files and the like but 240 // we should not allow such usage from the zygote. 241 const int new_fd = TEMP_FAILURE_RETRY(open(file_path.c_str(), open_flags)); 242 243 if (new_fd == -1) { 244 ALOGE("Failed open(%s, %d) : %s", file_path.c_str(), open_flags, strerror(errno)); 245 return false; 246 } 247 248 if (TEMP_FAILURE_RETRY(fcntl(new_fd, F_SETFD, fd_flags)) == -1) { 249 close(new_fd); 250 ALOGE("Failed fcntl(%d, F_SETFD, %x) : %s", new_fd, fd_flags, strerror(errno)); 251 return false; 252 } 253 254 if (TEMP_FAILURE_RETRY(fcntl(new_fd, F_SETFL, fs_flags)) == -1) { 255 close(new_fd); 256 ALOGE("Failed fcntl(%d, F_SETFL, %x) : %s", new_fd, fs_flags, strerror(errno)); 257 return false; 258 } 259 260 if (offset != -1 && TEMP_FAILURE_RETRY(lseek64(new_fd, offset, SEEK_SET)) == -1) { 261 close(new_fd); 262 ALOGE("Failed lseek64(%d, SEEK_SET) : %s", new_fd, strerror(errno)); 263 return false; 264 } 265 266 if (TEMP_FAILURE_RETRY(dup2(new_fd, fd)) == -1) { 267 close(new_fd); 268 ALOGE("Failed dup2(%d, %d) : %s", fd, new_fd, strerror(errno)); 269 return false; 270 } 271 272 close(new_fd); 273 274 return true; 275} 276 277FileDescriptorInfo::FileDescriptorInfo(int fd) : 278 fd(fd), 279 stat(), 280 open_flags(0), 281 fd_flags(0), 282 fs_flags(0), 283 offset(0), 284 is_sock(true) { 285} 286 287FileDescriptorInfo::FileDescriptorInfo(struct stat stat, const std::string& file_path, 288 int fd, int open_flags, int fd_flags, int fs_flags, 289 off_t offset) : 290 fd(fd), 291 stat(stat), 292 file_path(file_path), 293 open_flags(open_flags), 294 fd_flags(fd_flags), 295 fs_flags(fs_flags), 296 offset(offset), 297 is_sock(false) { 298} 299 300// TODO: Call android::base::Readlink instead of copying the code here. 301// static 302bool FileDescriptorInfo::Readlink(const int fd, std::string* result) { 303 char path[64]; 304 snprintf(path, sizeof(path), "/proc/self/fd/%d", fd); 305 306 // Code copied from android::base::Readlink starts here : 307 308 // Annoyingly, the readlink system call returns EINVAL for a zero-sized buffer, 309 // and truncates to whatever size you do supply, so it can't be used to query. 310 // We could call lstat first, but that would introduce a race condition that 311 // we couldn't detect. 312 // ext2 and ext4 both have PAGE_SIZE limitations, so we assume that here. 313 char buf[4096]; 314 ssize_t len = readlink(path, buf, sizeof(buf)); 315 if (len == -1) return false; 316 317 result->assign(buf, len); 318 return true; 319} 320 321// static 322bool FileDescriptorInfo::GetSocketName(const int fd, std::string* result) { 323 sockaddr_storage ss; 324 sockaddr* addr = reinterpret_cast<sockaddr*>(&ss); 325 socklen_t addr_len = sizeof(ss); 326 327 if (TEMP_FAILURE_RETRY(getsockname(fd, addr, &addr_len)) == -1) { 328 ALOGE("Failed getsockname(%d) : %s", fd, strerror(errno)); 329 return false; 330 } 331 332 if (addr->sa_family != AF_UNIX) { 333 ALOGE("Unsupported socket (fd=%d) with family %d", fd, addr->sa_family); 334 return false; 335 } 336 337 const sockaddr_un* unix_addr = reinterpret_cast<const sockaddr_un*>(&ss); 338 339 size_t path_len = addr_len - offsetof(struct sockaddr_un, sun_path); 340 // This is an unnamed local socket, we do not accept it. 341 if (path_len == 0) { 342 ALOGE("Unsupported AF_UNIX socket (fd=%d) with empty path.", fd); 343 return false; 344 } 345 346 // This is a local socket with an abstract address, we do not accept it. 347 if (unix_addr->sun_path[0] == '\0') { 348 ALOGE("Unsupported AF_UNIX socket (fd=%d) with abstract address.", fd); 349 return false; 350 } 351 352 // If we're here, sun_path must refer to a null terminated filesystem 353 // pathname (man 7 unix). Remove the terminator before assigning it to an 354 // std::string. 355 if (unix_addr->sun_path[path_len - 1] == '\0') { 356 --path_len; 357 } 358 359 result->assign(unix_addr->sun_path, path_len); 360 return true; 361} 362 363bool FileDescriptorInfo::DetachSocket() const { 364 const int dev_null_fd = open("/dev/null", O_RDWR); 365 if (dev_null_fd < 0) { 366 ALOGE("Failed to open /dev/null : %s", strerror(errno)); 367 return false; 368 } 369 370 if (dup2(dev_null_fd, fd) == -1) { 371 ALOGE("Failed dup2 on socket descriptor %d : %s", fd, strerror(errno)); 372 return false; 373 } 374 375 if (close(dev_null_fd) == -1) { 376 ALOGE("Failed close(%d) : %s", dev_null_fd, strerror(errno)); 377 return false; 378 } 379 380 return true; 381} 382 383// static 384FileDescriptorTable* FileDescriptorTable::Create() { 385 DIR* d = opendir(kFdPath); 386 if (d == NULL) { 387 ALOGE("Unable to open directory %s: %s", kFdPath, strerror(errno)); 388 return NULL; 389 } 390 int dir_fd = dirfd(d); 391 dirent* e; 392 393 std::unordered_map<int, FileDescriptorInfo*> open_fd_map; 394 while ((e = readdir(d)) != NULL) { 395 const int fd = ParseFd(e, dir_fd); 396 if (fd == -1) { 397 continue; 398 } 399 400 FileDescriptorInfo* info = FileDescriptorInfo::CreateFromFd(fd); 401 if (info == NULL) { 402 if (closedir(d) == -1) { 403 ALOGE("Unable to close directory : %s", strerror(errno)); 404 } 405 return NULL; 406 } 407 open_fd_map[fd] = info; 408 } 409 410 if (closedir(d) == -1) { 411 ALOGE("Unable to close directory : %s", strerror(errno)); 412 return NULL; 413 } 414 return new FileDescriptorTable(open_fd_map); 415} 416 417bool FileDescriptorTable::Restat() { 418 std::set<int> open_fds; 419 420 // First get the list of open descriptors. 421 DIR* d = opendir(kFdPath); 422 if (d == NULL) { 423 ALOGE("Unable to open directory %s: %s", kFdPath, strerror(errno)); 424 return false; 425 } 426 427 int dir_fd = dirfd(d); 428 dirent* e; 429 while ((e = readdir(d)) != NULL) { 430 const int fd = ParseFd(e, dir_fd); 431 if (fd == -1) { 432 continue; 433 } 434 435 open_fds.insert(fd); 436 } 437 438 if (closedir(d) == -1) { 439 ALOGE("Unable to close directory : %s", strerror(errno)); 440 return false; 441 } 442 443 return RestatInternal(open_fds); 444} 445 446// Reopens all file descriptors that are contained in the table. Returns true 447// if all descriptors were successfully re-opened or detached, and false if an 448// error occurred. 449bool FileDescriptorTable::ReopenOrDetach() { 450 std::unordered_map<int, FileDescriptorInfo*>::const_iterator it; 451 for (it = open_fd_map_.begin(); it != open_fd_map_.end(); ++it) { 452 const FileDescriptorInfo* info = it->second; 453 if (info == NULL || !info->ReopenOrDetach()) { 454 return false; 455 } 456 } 457 458 return true; 459} 460 461FileDescriptorTable::FileDescriptorTable( 462 const std::unordered_map<int, FileDescriptorInfo*>& map) 463 : open_fd_map_(map) { 464} 465 466bool FileDescriptorTable::RestatInternal(std::set<int>& open_fds) { 467 bool error = false; 468 469 // Iterate through the list of file descriptors we've already recorded 470 // and check whether : 471 // 472 // (a) they continue to be open. 473 // (b) they refer to the same file. 474 std::unordered_map<int, FileDescriptorInfo*>::iterator it = open_fd_map_.begin(); 475 while (it != open_fd_map_.end()) { 476 std::set<int>::const_iterator element = open_fds.find(it->first); 477 if (element == open_fds.end()) { 478 // The entry from the file descriptor table is no longer in the list 479 // of open files. We warn about this condition and remove it from 480 // the list of FDs under consideration. 481 // 482 // TODO(narayan): This will be an error in a future android release. 483 // error = true; 484 // ALOGW("Zygote closed file descriptor %d.", it->first); 485 it = open_fd_map_.erase(it); 486 } else { 487 // The entry from the file descriptor table is still open. Restat 488 // it and check whether it refers to the same file. 489 const bool same_file = it->second->Restat(); 490 if (!same_file) { 491 // The file descriptor refers to a different description. We must 492 // update our entry in the table. 493 delete it->second; 494 it->second = FileDescriptorInfo::CreateFromFd(*element); 495 if (it->second == NULL) { 496 // The descriptor no longer no longer refers to a whitelisted file. 497 // We flag an error and remove it from the list of files we're 498 // tracking. 499 error = true; 500 it = open_fd_map_.erase(it); 501 } else { 502 // Successfully restatted the file, move on to the next open FD. 503 ++it; 504 } 505 } else { 506 // It's the same file. Nothing to do here. Move on to the next open 507 // FD. 508 ++it; 509 } 510 511 // Finally, remove the FD from the set of open_fds. We do this last because 512 // |element| will not remain valid after a call to erase. 513 open_fds.erase(element); 514 } 515 } 516 517 if (open_fds.size() > 0) { 518 // The zygote has opened new file descriptors since our last inspection. 519 // We warn about this condition and add them to our table. 520 // 521 // TODO(narayan): This will be an error in a future android release. 522 // error = true; 523 // ALOGW("Zygote opened %zd new file descriptor(s).", open_fds.size()); 524 525 // TODO(narayan): This code will be removed in a future android release. 526 std::set<int>::const_iterator it; 527 for (it = open_fds.begin(); it != open_fds.end(); ++it) { 528 const int fd = (*it); 529 FileDescriptorInfo* info = FileDescriptorInfo::CreateFromFd(fd); 530 if (info == NULL) { 531 // A newly opened file is not on the whitelist. Flag an error and 532 // continue. 533 error = true; 534 } else { 535 // Track the newly opened file. 536 open_fd_map_[fd] = info; 537 } 538 } 539 } 540 541 return !error; 542} 543 544// static 545int FileDescriptorTable::ParseFd(dirent* e, int dir_fd) { 546 char* end; 547 const int fd = strtol(e->d_name, &end, 10); 548 if ((*end) != '\0') { 549 return -1; 550 } 551 552 // Don't bother with the standard input/output/error, they're handled 553 // specially post-fork anyway. 554 if (fd <= STDERR_FILENO || fd == dir_fd) { 555 return -1; 556 } 557 558 return fd; 559} 560