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/file.h>
30 #include <android-base/logging.h>
31 #include <android-base/stringprintf.h>
32 #include <android-base/strings.h>
33
34 // Static allowlist of open paths that the zygote is allowed to keep open.
35 static const char* kPathAllowlist[] = {
36 "/dev/null",
37 "/dev/socket/zygote",
38 "/dev/socket/zygote_secondary",
39 "/dev/socket/usap_pool_primary",
40 "/dev/socket/usap_pool_secondary",
41 "/dev/socket/webview_zygote",
42 "/dev/socket/heapprofd",
43 "/sys/kernel/debug/tracing/trace_marker",
44 "/sys/kernel/tracing/trace_marker",
45 "/system/framework/framework-res.apk",
46 "/dev/urandom",
47 "/dev/ion",
48 "/dev/dri/renderD129", // Fixes b/31172436
49 "/dev/stune/foreground/tasks",
50 "/dev/blkio/tasks",
51 };
52
53 static const char kFdPath[] = "/proc/self/fd";
54
Get()55 FileDescriptorAllowlist* FileDescriptorAllowlist::Get() {
56 if (instance_ == nullptr) {
57 instance_ = new FileDescriptorAllowlist();
58 }
59 return instance_;
60 }
61
IsArtMemfd(const std::string & path)62 static bool IsArtMemfd(const std::string& path) {
63 return android::base::StartsWith(path, "/memfd:/boot-image-methods.art");
64 }
65
IsAllowed(const std::string & path) const66 bool FileDescriptorAllowlist::IsAllowed(const std::string& path) const {
67 // Check the static allowlist path.
68 for (const auto& allowlist_path : kPathAllowlist) {
69 if (path == allowlist_path) return true;
70 }
71
72 // Check any paths added to the dynamic allowlist.
73 for (const auto& allowlist_path : allowlist_) {
74 if (path == allowlist_path) return true;
75 }
76
77 // Framework jars are allowed.
78 static const char* kFrameworksPrefix[] = {
79 "/system/framework/",
80 "/system_ext/framework/",
81 };
82
83 static const char* kJarSuffix = ".jar";
84
85 for (const auto& frameworks_prefix : kFrameworksPrefix) {
86 if (android::base::StartsWith(path, frameworks_prefix) &&
87 android::base::EndsWith(path, kJarSuffix)) {
88 return true;
89 }
90 }
91
92 // Jars from APEXes are allowed. This matches /apex/**/javalib/*.jar.
93 static const char* kApexPrefix = "/apex/";
94 static const char* kApexJavalibPathSuffix = "/javalib";
95 if (android::base::StartsWith(path, kApexPrefix) && android::base::EndsWith(path, kJarSuffix) &&
96 android::base::EndsWith(android::base::Dirname(path), kApexJavalibPathSuffix)) {
97 return true;
98 }
99
100 // the in-memory file created by ART through memfd_create is allowed.
101 if (IsArtMemfd(path)) {
102 return true;
103 }
104
105 // Allowlist files needed for Runtime Resource Overlay, like these:
106 // /system/vendor/overlay/framework-res.apk
107 // /system/vendor/overlay-subdir/pg/framework-res.apk
108 // /vendor/overlay/framework-res.apk
109 // /vendor/overlay/PG/android-framework-runtime-resource-overlay.apk
110 // /data/resource-cache/system@vendor@overlay@framework-res.apk@idmap
111 // /data/resource-cache/system@vendor@overlay-subdir@pg@framework-res.apk@idmap
112 // See AssetManager.cpp for more details on overlay-subdir.
113 static const char* kOverlayDir = "/system/vendor/overlay/";
114 static const char* kVendorOverlayDir = "/vendor/overlay";
115 static const char* kVendorOverlaySubdir = "/system/vendor/overlay-subdir/";
116 static const char* kSystemProductOverlayDir = "/system/product/overlay/";
117 static const char* kProductOverlayDir = "/product/overlay";
118 static const char* kSystemSystemExtOverlayDir = "/system/system_ext/overlay/";
119 static const char* kSystemExtOverlayDir = "/system_ext/overlay";
120 static const char* kSystemOdmOverlayDir = "/system/odm/overlay";
121 static const char* kOdmOverlayDir = "/odm/overlay";
122 static const char* kSystemOemOverlayDir = "/system/oem/overlay";
123 static const char* kOemOverlayDir = "/oem/overlay";
124 static const char* kApkSuffix = ".apk";
125
126 if ((android::base::StartsWith(path, kOverlayDir) ||
127 android::base::StartsWith(path, kVendorOverlaySubdir) ||
128 android::base::StartsWith(path, kVendorOverlayDir) ||
129 android::base::StartsWith(path, kSystemProductOverlayDir) ||
130 android::base::StartsWith(path, kProductOverlayDir) ||
131 android::base::StartsWith(path, kSystemSystemExtOverlayDir) ||
132 android::base::StartsWith(path, kSystemExtOverlayDir) ||
133 android::base::StartsWith(path, kSystemOdmOverlayDir) ||
134 android::base::StartsWith(path, kOdmOverlayDir) ||
135 android::base::StartsWith(path, kSystemOemOverlayDir) ||
136 android::base::StartsWith(path, kOemOverlayDir)) &&
137 android::base::EndsWith(path, kApkSuffix) && path.find("/../") == std::string::npos) {
138 return true;
139 }
140
141 // Allow Runtime Resource Overlays inside APEXes.
142 static const char* kOverlayPathSuffix = "/overlay";
143 if (android::base::StartsWith(path, kApexPrefix) &&
144 android::base::EndsWith(android::base::Dirname(path), kOverlayPathSuffix) &&
145 android::base::EndsWith(path, kApkSuffix) && path.find("/../") == std::string::npos) {
146 return true;
147 }
148
149 static const char* kOverlayIdmapPrefix = "/data/resource-cache/";
150 static const char* kOverlayIdmapSuffix = ".apk@idmap";
151 if (android::base::StartsWith(path, kOverlayIdmapPrefix) &&
152 android::base::EndsWith(path, kOverlayIdmapSuffix) &&
153 path.find("/../") == std::string::npos) {
154 return true;
155 }
156
157 // All regular files that are placed under this path are allowlisted
158 // automatically. The directory name is maintained for compatibility.
159 static const char* kZygoteAllowlistPath = "/vendor/zygote_whitelist/";
160 if (android::base::StartsWith(path, kZygoteAllowlistPath) &&
161 path.find("/../") == std::string::npos) {
162 return true;
163 }
164
165 return false;
166 }
167
FileDescriptorAllowlist()168 FileDescriptorAllowlist::FileDescriptorAllowlist() : allowlist_() {}
169
170 FileDescriptorAllowlist* FileDescriptorAllowlist::instance_ = nullptr;
171
172 // Keeps track of all relevant information (flags, offset etc.) of an
173 // open zygote file descriptor.
174 class FileDescriptorInfo {
175 public:
176 // Create a FileDescriptorInfo for a given file descriptor.
177 static FileDescriptorInfo* CreateFromFd(int fd, fail_fn_t fail_fn);
178
179 // Checks whether the file descriptor associated with this object refers to
180 // the same description.
181 bool RefersToSameFile() const;
182
183 void ReopenOrDetach(fail_fn_t fail_fn) const;
184
185 const int fd;
186 const struct stat stat;
187 const std::string file_path;
188 const int open_flags;
189 const int fd_flags;
190 const int fs_flags;
191 const off_t offset;
192 const bool is_sock;
193
194 private:
195 // Constructs for sockets.
196 explicit FileDescriptorInfo(int fd);
197
198 // Constructs for non-socket file descriptors.
199 FileDescriptorInfo(struct stat stat, const std::string& file_path, int fd, int open_flags,
200 int fd_flags, int fs_flags, off_t offset);
201
202 // Returns the locally-bound name of the socket |fd|. Returns true
203 // iff. all of the following hold :
204 //
205 // - the socket's sa_family is AF_UNIX.
206 // - the length of the path is greater than zero (i.e, not an unnamed socket).
207 // - the first byte of the path isn't zero (i.e, not a socket with an abstract
208 // address).
209 static bool GetSocketName(const int fd, std::string* result);
210
211 void DetachSocket(fail_fn_t fail_fn) const;
212
213 DISALLOW_COPY_AND_ASSIGN(FileDescriptorInfo);
214 };
215
CreateFromFd(int fd,fail_fn_t fail_fn)216 FileDescriptorInfo* FileDescriptorInfo::CreateFromFd(int fd, fail_fn_t fail_fn) {
217 struct stat f_stat;
218 // This should never happen; the zygote should always have the right set
219 // of permissions required to stat all its open files.
220 if (TEMP_FAILURE_RETRY(fstat(fd, &f_stat)) == -1) {
221 fail_fn(android::base::StringPrintf("Unable to stat %d", fd));
222 }
223
224 const FileDescriptorAllowlist* allowlist = FileDescriptorAllowlist::Get();
225
226 if (S_ISSOCK(f_stat.st_mode)) {
227 std::string socket_name;
228 if (!GetSocketName(fd, &socket_name)) {
229 fail_fn("Unable to get socket name");
230 }
231
232 if (!allowlist->IsAllowed(socket_name)) {
233 fail_fn(android::base::StringPrintf("Socket name not allowlisted : %s (fd=%d)",
234 socket_name.c_str(), fd));
235 }
236
237 return new FileDescriptorInfo(fd);
238 }
239
240 // We only handle allowlisted regular files and character devices. Allowlisted
241 // character devices must provide a guarantee of sensible behaviour when
242 // reopened.
243 //
244 // S_ISDIR : Not supported. (We could if we wanted to, but it's unused).
245 // S_ISLINK : Not supported.
246 // S_ISBLK : Not supported.
247 // S_ISFIFO : Not supported. Note that the Zygote and USAPs use pipes to
248 // communicate with the child processes across forks but those should have been
249 // added to the redirection exemption list.
250 if (!S_ISCHR(f_stat.st_mode) && !S_ISREG(f_stat.st_mode)) {
251 std::string mode = "Unknown";
252
253 if (S_ISDIR(f_stat.st_mode)) {
254 mode = "DIR";
255 } else if (S_ISLNK(f_stat.st_mode)) {
256 mode = "LINK";
257 } else if (S_ISBLK(f_stat.st_mode)) {
258 mode = "BLOCK";
259 } else if (S_ISFIFO(f_stat.st_mode)) {
260 mode = "FIFO";
261 }
262
263 fail_fn(android::base::StringPrintf("Unsupported st_mode for FD %d: %s", fd, mode.c_str()));
264 }
265
266 std::string file_path;
267 const std::string fd_path = android::base::StringPrintf("/proc/self/fd/%d", fd);
268 if (!android::base::Readlink(fd_path, &file_path)) {
269 fail_fn(android::base::StringPrintf("Could not read fd link %s: %s",
270 fd_path.c_str(),
271 strerror(errno)));
272 }
273
274 if (!allowlist->IsAllowed(file_path)) {
275 fail_fn(android::base::StringPrintf("Not allowlisted (%d): %s", fd, file_path.c_str()));
276 }
277
278 // File descriptor flags : currently on FD_CLOEXEC. We can set these
279 // using F_SETFD - we're single threaded at this point of execution so
280 // there won't be any races.
281 const int fd_flags = TEMP_FAILURE_RETRY(fcntl(fd, F_GETFD));
282 if (fd_flags == -1) {
283 fail_fn(android::base::StringPrintf("Failed fcntl(%d, F_GETFD) (%s): %s",
284 fd,
285 file_path.c_str(),
286 strerror(errno)));
287 }
288
289 // File status flags :
290 // - File access mode : (O_RDONLY, O_WRONLY...) we'll pass these through
291 // to the open() call.
292 //
293 // - File creation flags : (O_CREAT, O_EXCL...) - there's not much we can
294 // do about these, since the file has already been created. We shall ignore
295 // them here.
296 //
297 // - Other flags : We'll have to set these via F_SETFL. On linux, F_SETFL
298 // can only set O_APPEND, O_ASYNC, O_DIRECT, O_NOATIME, and O_NONBLOCK.
299 // In particular, it can't set O_SYNC and O_DSYNC. We'll have to test for
300 // their presence and pass them in to open().
301 int fs_flags = TEMP_FAILURE_RETRY(fcntl(fd, F_GETFL));
302 if (fs_flags == -1) {
303 fail_fn(android::base::StringPrintf("Failed fcntl(%d, F_GETFL) (%s): %s",
304 fd,
305 file_path.c_str(),
306 strerror(errno)));
307 }
308
309 // File offset : Ignore the offset for non seekable files.
310 const off_t offset = TEMP_FAILURE_RETRY(lseek64(fd, 0, SEEK_CUR));
311
312 // We pass the flags that open accepts to open, and use F_SETFL for
313 // the rest of them.
314 static const int kOpenFlags = (O_RDONLY | O_WRONLY | O_RDWR | O_DSYNC | O_SYNC);
315 int open_flags = fs_flags & (kOpenFlags);
316 fs_flags = fs_flags & (~(kOpenFlags));
317
318 return new FileDescriptorInfo(f_stat, file_path, fd, open_flags, fd_flags, fs_flags, offset);
319 }
320
RefersToSameFile() const321 bool FileDescriptorInfo::RefersToSameFile() const {
322 struct stat f_stat;
323 if (TEMP_FAILURE_RETRY(fstat(fd, &f_stat)) == -1) {
324 PLOG(ERROR) << "Unable to restat fd " << fd;
325 return false;
326 }
327
328 return f_stat.st_ino == stat.st_ino && f_stat.st_dev == stat.st_dev;
329 }
330
ReopenOrDetach(fail_fn_t fail_fn) const331 void FileDescriptorInfo::ReopenOrDetach(fail_fn_t fail_fn) const {
332 if (is_sock) {
333 return DetachSocket(fail_fn);
334 }
335
336 // Children can directly use the in-memory file created by ART through memfd_create.
337 if (IsArtMemfd(file_path)) {
338 return;
339 }
340
341 // NOTE: This might happen if the file was unlinked after being opened.
342 // It's a common pattern in the case of temporary files and the like but
343 // we should not allow such usage from the zygote.
344 const int new_fd = TEMP_FAILURE_RETRY(open(file_path.c_str(), open_flags));
345
346 if (new_fd == -1) {
347 fail_fn(android::base::StringPrintf("Failed open(%s, %i): %s",
348 file_path.c_str(),
349 open_flags,
350 strerror(errno)));
351 }
352
353 if (TEMP_FAILURE_RETRY(fcntl(new_fd, F_SETFD, fd_flags)) == -1) {
354 close(new_fd);
355 fail_fn(android::base::StringPrintf("Failed fcntl(%d, F_SETFD, %d) (%s): %s",
356 new_fd,
357 fd_flags,
358 file_path.c_str(),
359 strerror(errno)));
360 }
361
362 if (TEMP_FAILURE_RETRY(fcntl(new_fd, F_SETFL, fs_flags)) == -1) {
363 close(new_fd);
364 fail_fn(android::base::StringPrintf("Failed fcntl(%d, F_SETFL, %d) (%s): %s",
365 new_fd,
366 fs_flags,
367 file_path.c_str(),
368 strerror(errno)));
369 }
370
371 if (offset != -1 && TEMP_FAILURE_RETRY(lseek64(new_fd, offset, SEEK_SET)) == -1) {
372 close(new_fd);
373 fail_fn(android::base::StringPrintf("Failed lseek64(%d, SEEK_SET) (%s): %s",
374 new_fd,
375 file_path.c_str(),
376 strerror(errno)));
377 }
378
379 int dup_flags = (fd_flags & FD_CLOEXEC) ? O_CLOEXEC : 0;
380 if (TEMP_FAILURE_RETRY(dup3(new_fd, fd, dup_flags)) == -1) {
381 close(new_fd);
382 fail_fn(android::base::StringPrintf("Failed dup3(%d, %d, %d) (%s): %s",
383 fd,
384 new_fd,
385 dup_flags,
386 file_path.c_str(),
387 strerror(errno)));
388 }
389
390 close(new_fd);
391 }
392
FileDescriptorInfo(int fd)393 FileDescriptorInfo::FileDescriptorInfo(int fd) :
394 fd(fd),
395 stat(),
396 open_flags(0),
397 fd_flags(0),
398 fs_flags(0),
399 offset(0),
400 is_sock(true) {
401 }
402
FileDescriptorInfo(struct stat stat,const std::string & file_path,int fd,int open_flags,int fd_flags,int fs_flags,off_t offset)403 FileDescriptorInfo::FileDescriptorInfo(struct stat stat, const std::string& file_path,
404 int fd, int open_flags, int fd_flags, int fs_flags,
405 off_t offset) :
406 fd(fd),
407 stat(stat),
408 file_path(file_path),
409 open_flags(open_flags),
410 fd_flags(fd_flags),
411 fs_flags(fs_flags),
412 offset(offset),
413 is_sock(false) {
414 }
415
GetSocketName(const int fd,std::string * result)416 bool FileDescriptorInfo::GetSocketName(const int fd, std::string* result) {
417 sockaddr_storage ss;
418 sockaddr* addr = reinterpret_cast<sockaddr*>(&ss);
419 socklen_t addr_len = sizeof(ss);
420
421 if (TEMP_FAILURE_RETRY(getsockname(fd, addr, &addr_len)) == -1) {
422 PLOG(ERROR) << "Failed getsockname(" << fd << ")";
423 return false;
424 }
425
426 if (addr->sa_family != AF_UNIX) {
427 LOG(ERROR) << "Unsupported socket (fd=" << fd << ") with family " << addr->sa_family;
428 return false;
429 }
430
431 const sockaddr_un* unix_addr = reinterpret_cast<const sockaddr_un*>(&ss);
432
433 size_t path_len = addr_len - offsetof(struct sockaddr_un, sun_path);
434 // This is an unnamed local socket, we do not accept it.
435 if (path_len == 0) {
436 LOG(ERROR) << "Unsupported AF_UNIX socket (fd=" << fd << ") with empty path.";
437 return false;
438 }
439
440 // This is a local socket with an abstract address. Remove the leading NUL byte and
441 // add a human-readable "ABSTRACT/" prefix.
442 if (unix_addr->sun_path[0] == '\0') {
443 *result = "ABSTRACT/";
444 result->append(&unix_addr->sun_path[1], path_len - 1);
445 return true;
446 }
447
448 // If we're here, sun_path must refer to a null terminated filesystem
449 // pathname (man 7 unix). Remove the terminator before assigning it to an
450 // std::string.
451 if (unix_addr->sun_path[path_len - 1] == '\0') {
452 --path_len;
453 }
454
455 result->assign(unix_addr->sun_path, path_len);
456 return true;
457 }
458
DetachSocket(fail_fn_t fail_fn) const459 void FileDescriptorInfo::DetachSocket(fail_fn_t fail_fn) const {
460 const int dev_null_fd = open("/dev/null", O_RDWR | O_CLOEXEC);
461 if (dev_null_fd < 0) {
462 fail_fn(std::string("Failed to open /dev/null: ").append(strerror(errno)));
463 }
464
465 if (dup3(dev_null_fd, fd, O_CLOEXEC) == -1) {
466 fail_fn(android::base::StringPrintf("Failed dup3 on socket descriptor %d: %s",
467 fd,
468 strerror(errno)));
469 }
470
471 if (close(dev_null_fd) == -1) {
472 fail_fn(android::base::StringPrintf("Failed close(%d): %s", dev_null_fd, strerror(errno)));
473 }
474 }
475
476 // TODO: Move the definitions here and eliminate the forward declarations. They
477 // temporarily help making code reviews easier.
478 static int ParseFd(dirent* dir_entry, int dir_fd);
479 static std::unique_ptr<std::set<int>> GetOpenFdsIgnoring(const std::vector<int>& fds_to_ignore,
480 fail_fn_t fail_fn);
481
Create(const std::vector<int> & fds_to_ignore,fail_fn_t fail_fn)482 FileDescriptorTable* FileDescriptorTable::Create(const std::vector<int>& fds_to_ignore,
483 fail_fn_t fail_fn) {
484 std::unique_ptr<std::set<int>> open_fds = GetOpenFdsIgnoring(fds_to_ignore, fail_fn);
485 std::unordered_map<int, FileDescriptorInfo*> open_fd_map;
486 for (auto fd : *open_fds) {
487 open_fd_map[fd] = FileDescriptorInfo::CreateFromFd(fd, fail_fn);
488 }
489 return new FileDescriptorTable(open_fd_map);
490 }
491
GetOpenFdsIgnoring(const std::vector<int> & fds_to_ignore,fail_fn_t fail_fn)492 static std::unique_ptr<std::set<int>> GetOpenFdsIgnoring(const std::vector<int>& fds_to_ignore,
493 fail_fn_t fail_fn) {
494 DIR* proc_fd_dir = opendir(kFdPath);
495 if (proc_fd_dir == nullptr) {
496 fail_fn(android::base::StringPrintf("Unable to open directory %s: %s",
497 kFdPath,
498 strerror(errno)));
499 }
500
501 auto result = std::make_unique<std::set<int>>();
502 int dir_fd = dirfd(proc_fd_dir);
503 dirent* dir_entry;
504 while ((dir_entry = readdir(proc_fd_dir)) != nullptr) {
505 const int fd = ParseFd(dir_entry, dir_fd);
506 if (fd == -1) {
507 continue;
508 }
509
510 if (std::find(fds_to_ignore.begin(), fds_to_ignore.end(), fd) != fds_to_ignore.end()) {
511 continue;
512 }
513
514 result->insert(fd);
515 }
516
517 if (closedir(proc_fd_dir) == -1) {
518 fail_fn(android::base::StringPrintf("Unable to close directory: %s", strerror(errno)));
519 }
520 return result;
521 }
522
GetOpenFds(fail_fn_t fail_fn)523 std::unique_ptr<std::set<int>> GetOpenFds(fail_fn_t fail_fn) {
524 const std::vector<int> nothing_to_ignore;
525 return GetOpenFdsIgnoring(nothing_to_ignore, fail_fn);
526 }
527
Restat(const std::vector<int> & fds_to_ignore,fail_fn_t fail_fn)528 void FileDescriptorTable::Restat(const std::vector<int>& fds_to_ignore, fail_fn_t fail_fn) {
529 std::unique_ptr<std::set<int>> open_fds = GetOpenFdsIgnoring(fds_to_ignore, fail_fn);
530
531 // Check that the files did not change, and leave only newly opened FDs in
532 // |open_fds|.
533 RestatInternal(*open_fds, fail_fn);
534 }
535
536 // Reopens all file descriptors that are contained in the table.
ReopenOrDetach(fail_fn_t fail_fn)537 void FileDescriptorTable::ReopenOrDetach(fail_fn_t fail_fn) {
538 std::unordered_map<int, FileDescriptorInfo*>::const_iterator it;
539 for (it = open_fd_map_.begin(); it != open_fd_map_.end(); ++it) {
540 const FileDescriptorInfo* info = it->second;
541 if (info == nullptr) {
542 return;
543 } else {
544 info->ReopenOrDetach(fail_fn);
545 }
546 }
547 }
548
FileDescriptorTable(const std::unordered_map<int,FileDescriptorInfo * > & map)549 FileDescriptorTable::FileDescriptorTable(
550 const std::unordered_map<int, FileDescriptorInfo*>& map)
551 : open_fd_map_(map) {
552 }
553
~FileDescriptorTable()554 FileDescriptorTable::~FileDescriptorTable() {
555 for (auto& it : open_fd_map_) {
556 delete it.second;
557 }
558 }
559
RestatInternal(std::set<int> & open_fds,fail_fn_t fail_fn)560 void FileDescriptorTable::RestatInternal(std::set<int>& open_fds, fail_fn_t fail_fn) {
561 // ART creates a file through memfd for optimization purposes. We make sure
562 // there is at most one being created.
563 bool art_memfd_seen = false;
564
565 // Iterate through the list of file descriptors we've already recorded
566 // and check whether :
567 //
568 // (a) they continue to be open.
569 // (b) they refer to the same file.
570 //
571 // We'll only store the last error message.
572 std::unordered_map<int, FileDescriptorInfo*>::iterator it = open_fd_map_.begin();
573 while (it != open_fd_map_.end()) {
574 std::set<int>::const_iterator element = open_fds.find(it->first);
575 if (element == open_fds.end()) {
576 // The entry from the file descriptor table is no longer in the list
577 // of open files. We warn about this condition and remove it from
578 // the list of FDs under consideration.
579 //
580 // TODO(narayan): This will be an error in a future android release.
581 // error = true;
582 // ALOGW("Zygote closed file descriptor %d.", it->first);
583 delete it->second;
584 it = open_fd_map_.erase(it);
585 } else {
586 // The entry from the file descriptor table is still open. Restat
587 // it and check whether it refers to the same file.
588 if (!it->second->RefersToSameFile()) {
589 // The file descriptor refers to a different description. We must
590 // update our entry in the table.
591 delete it->second;
592 it->second = FileDescriptorInfo::CreateFromFd(*element, fail_fn);
593 } else {
594 // It's the same file. Nothing to do here. Move on to the next open
595 // FD.
596 }
597
598 if (IsArtMemfd(it->second->file_path)) {
599 if (art_memfd_seen) {
600 fail_fn("ART fd already seen: " + it->second->file_path);
601 } else {
602 art_memfd_seen = true;
603 }
604 }
605
606 ++it;
607
608 // Finally, remove the FD from the set of open_fds. We do this last because
609 // |element| will not remain valid after a call to erase.
610 open_fds.erase(element);
611 }
612 }
613
614 if (open_fds.size() > 0) {
615 // The zygote has opened new file descriptors since our last inspection.
616 // We warn about this condition and add them to our table.
617 //
618 // TODO(narayan): This will be an error in a future android release.
619 // error = true;
620 // ALOGW("Zygote opened %zd new file descriptor(s).", open_fds.size());
621
622 // TODO(narayan): This code will be removed in a future android release.
623 std::set<int>::const_iterator it;
624 for (it = open_fds.begin(); it != open_fds.end(); ++it) {
625 const int fd = (*it);
626 open_fd_map_[fd] = FileDescriptorInfo::CreateFromFd(fd, fail_fn);
627 }
628 }
629 }
630
ParseFd(dirent * dir_entry,int dir_fd)631 static int ParseFd(dirent* dir_entry, int dir_fd) {
632 char* end;
633 const int fd = strtol(dir_entry->d_name, &end, 10);
634 if ((*end) != '\0') {
635 return -1;
636 }
637
638 // Don't bother with the standard input/output/error, they're handled
639 // specially post-fork anyway.
640 if (fd <= STDERR_FILENO || fd == dir_fd) {
641 return -1;
642 }
643
644 return fd;
645 }
646