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