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