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