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 whitelist of open paths that the zygote is allowed to keep open.
35 static const char* kPathWhitelist[] = {
36 "/apex/com.android.conscrypt/javalib/conscrypt.jar",
37 "/apex/com.android.ipsec/javalib/ike.jar",
38 "/apex/com.android.i18n/javalib/core-icu4j.jar",
39 "/apex/com.android.media/javalib/updatable-media.jar",
40 "/apex/com.android.sdkext/javalib/framework-sdkextensions.jar",
41 "/apex/com.android.tethering/javalib/framework-tethering.jar",
42 "/dev/null",
43 "/dev/socket/zygote",
44 "/dev/socket/zygote_secondary",
45 "/dev/socket/usap_pool_primary",
46 "/dev/socket/usap_pool_secondary",
47 "/dev/socket/webview_zygote",
48 "/dev/socket/heapprofd",
49 "/sys/kernel/debug/tracing/trace_marker",
50 "/sys/kernel/tracing/trace_marker",
51 "/system/framework/framework-res.apk",
52 "/dev/urandom",
53 "/dev/ion",
54 "/dev/dri/renderD129", // Fixes b/31172436
55 };
56
57 static const char kFdPath[] = "/proc/self/fd";
58
59 // static
Get()60 FileDescriptorWhitelist* FileDescriptorWhitelist::Get() {
61 if (instance_ == nullptr) {
62 instance_ = new FileDescriptorWhitelist();
63 }
64 return instance_;
65 }
66
IsArtMemfd(const std::string & path)67 static bool IsArtMemfd(const std::string& path) {
68 return android::base::StartsWith(path, "/memfd:/boot-image-methods.art");
69 }
70
IsAllowed(const std::string & path) const71 bool FileDescriptorWhitelist::IsAllowed(const std::string& path) const {
72 // Check the static whitelist path.
73 for (const auto& whitelist_path : kPathWhitelist) {
74 if (path == whitelist_path)
75 return true;
76 }
77
78 // Check any paths added to the dynamic whitelist.
79 for (const auto& whitelist_path : whitelist_) {
80 if (path == whitelist_path)
81 return true;
82 }
83
84 // Framework jars are allowed.
85 static const char* kFrameworksPrefix[] = {
86 "/system/framework/",
87 "/system_ext/framework/",
88 };
89
90 static const char* kJarSuffix = ".jar";
91
92 for (const auto& frameworks_prefix : kFrameworksPrefix) {
93 if (android::base::StartsWith(path, frameworks_prefix)
94 && android::base::EndsWith(path, kJarSuffix)) {
95 return true;
96 }
97 }
98
99 // Jars from the ART APEX are allowed.
100 static const char* kArtApexPrefix = "/apex/com.android.art/javalib/";
101 if (android::base::StartsWith(path, kArtApexPrefix)
102 && android::base::EndsWith(path, kJarSuffix)) {
103 return true;
104 }
105
106 // the in-memory file created by ART through memfd_create is allowed.
107 if (IsArtMemfd(path)) {
108 return true;
109 }
110
111 // Whitelist files needed for Runtime Resource Overlay, like these:
112 // /system/vendor/overlay/framework-res.apk
113 // /system/vendor/overlay-subdir/pg/framework-res.apk
114 // /vendor/overlay/framework-res.apk
115 // /vendor/overlay/PG/android-framework-runtime-resource-overlay.apk
116 // /data/resource-cache/system@vendor@overlay@framework-res.apk@idmap
117 // /data/resource-cache/system@vendor@overlay-subdir@pg@framework-res.apk@idmap
118 // See AssetManager.cpp for more details on overlay-subdir.
119 static const char* kOverlayDir = "/system/vendor/overlay/";
120 static const char* kVendorOverlayDir = "/vendor/overlay";
121 static const char* kVendorOverlaySubdir = "/system/vendor/overlay-subdir/";
122 static const char* kSystemProductOverlayDir = "/system/product/overlay/";
123 static const char* kProductOverlayDir = "/product/overlay";
124 static const char* kSystemSystemExtOverlayDir = "/system/system_ext/overlay/";
125 static const char* kSystemExtOverlayDir = "/system_ext/overlay";
126 static const char* kSystemOdmOverlayDir = "/system/odm/overlay";
127 static const char* kOdmOverlayDir = "/odm/overlay";
128 static const char* kSystemOemOverlayDir = "/system/oem/overlay";
129 static const char* kOemOverlayDir = "/oem/overlay";
130 static const char* kApkSuffix = ".apk";
131
132 if ((android::base::StartsWith(path, kOverlayDir)
133 || android::base::StartsWith(path, kVendorOverlaySubdir)
134 || android::base::StartsWith(path, kVendorOverlayDir)
135 || android::base::StartsWith(path, kSystemProductOverlayDir)
136 || android::base::StartsWith(path, kProductOverlayDir)
137 || android::base::StartsWith(path, kSystemSystemExtOverlayDir)
138 || android::base::StartsWith(path, kSystemExtOverlayDir)
139 || android::base::StartsWith(path, kSystemOdmOverlayDir)
140 || android::base::StartsWith(path, kOdmOverlayDir)
141 || android::base::StartsWith(path, kSystemOemOverlayDir)
142 || android::base::StartsWith(path, kOemOverlayDir))
143 && android::base::EndsWith(path, kApkSuffix)
144 && path.find("/../") == std::string::npos) {
145 return true;
146 }
147
148 static const char* kOverlayIdmapPrefix = "/data/resource-cache/";
149 static const char* kOverlayIdmapSuffix = ".apk@idmap";
150 if (android::base::StartsWith(path, kOverlayIdmapPrefix)
151 && android::base::EndsWith(path, kOverlayIdmapSuffix)
152 && path.find("/../") == std::string::npos) {
153 return true;
154 }
155
156 // All regular files that are placed under this path are whitelisted automatically.
157 static const char* kZygoteWhitelistPath = "/vendor/zygote_whitelist/";
158 if (android::base::StartsWith(path, kZygoteWhitelistPath)
159 && path.find("/../") == std::string::npos) {
160 return true;
161 }
162
163 return false;
164 }
165
FileDescriptorWhitelist()166 FileDescriptorWhitelist::FileDescriptorWhitelist()
167 : whitelist_() {
168 }
169
170 FileDescriptorWhitelist* FileDescriptorWhitelist::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
180 // refers to 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 explicit FileDescriptorInfo(int fd);
196
197 FileDescriptorInfo(struct stat stat, const std::string& file_path, int fd, int open_flags,
198 int fd_flags, int fs_flags, off_t offset);
199
200 // Returns the locally-bound name of the socket |fd|. Returns true
201 // iff. all of the following hold :
202 //
203 // - the socket's sa_family is AF_UNIX.
204 // - the length of the path is greater than zero (i.e, not an unnamed socket).
205 // - the first byte of the path isn't zero (i.e, not a socket with an abstract
206 // address).
207 static bool GetSocketName(const int fd, std::string* result);
208
209 void DetachSocket(fail_fn_t fail_fn) const;
210
211 DISALLOW_COPY_AND_ASSIGN(FileDescriptorInfo);
212 };
213
214 // static
CreateFromFd(int fd,fail_fn_t fail_fn)215 FileDescriptorInfo* FileDescriptorInfo::CreateFromFd(int fd, fail_fn_t fail_fn) {
216 struct stat f_stat;
217 // This should never happen; the zygote should always have the right set
218 // of permissions required to stat all its open files.
219 if (TEMP_FAILURE_RETRY(fstat(fd, &f_stat)) == -1) {
220 fail_fn(android::base::StringPrintf("Unable to stat %d", fd));
221 }
222
223 const FileDescriptorWhitelist* whitelist = FileDescriptorWhitelist::Get();
224
225 if (S_ISSOCK(f_stat.st_mode)) {
226 std::string socket_name;
227 if (!GetSocketName(fd, &socket_name)) {
228 fail_fn("Unable to get socket name");
229 }
230
231 if (!whitelist->IsAllowed(socket_name)) {
232 fail_fn(android::base::StringPrintf("Socket name not whitelisted : %s (fd=%d)",
233 socket_name.c_str(),
234 fd));
235 }
236
237 return new FileDescriptorInfo(fd);
238 }
239
240 // We only handle whitelisted regular files and character devices. Whitelisted
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 (!whitelist->IsAllowed(file_path)) {
275 fail_fn(android::base::StringPrintf("Not whitelisted (%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 // static
Create(const std::vector<int> & fds_to_ignore,fail_fn_t fail_fn)477 FileDescriptorTable* FileDescriptorTable::Create(const std::vector<int>& fds_to_ignore,
478 fail_fn_t fail_fn) {
479 DIR* proc_fd_dir = opendir(kFdPath);
480 if (proc_fd_dir == nullptr) {
481 fail_fn(std::string("Unable to open directory ").append(kFdPath));
482 }
483
484 int dir_fd = dirfd(proc_fd_dir);
485 dirent* dir_entry;
486
487 std::unordered_map<int, FileDescriptorInfo*> open_fd_map;
488 while ((dir_entry = readdir(proc_fd_dir)) != nullptr) {
489 const int fd = ParseFd(dir_entry, dir_fd);
490 if (fd == -1) {
491 continue;
492 }
493
494 if (std::find(fds_to_ignore.begin(), fds_to_ignore.end(), fd) != fds_to_ignore.end()) {
495 continue;
496 }
497
498 open_fd_map[fd] = FileDescriptorInfo::CreateFromFd(fd, fail_fn);
499 }
500
501 if (closedir(proc_fd_dir) == -1) {
502 fail_fn("Unable to close directory");
503 }
504
505 return new FileDescriptorTable(open_fd_map);
506 }
507
Restat(const std::vector<int> & fds_to_ignore,fail_fn_t fail_fn)508 void FileDescriptorTable::Restat(const std::vector<int>& fds_to_ignore, fail_fn_t fail_fn) {
509 std::set<int> open_fds;
510
511 // First get the list of open descriptors.
512 DIR* proc_fd_dir = opendir(kFdPath);
513 if (proc_fd_dir == nullptr) {
514 fail_fn(android::base::StringPrintf("Unable to open directory %s: %s",
515 kFdPath,
516 strerror(errno)));
517 }
518
519 int dir_fd = dirfd(proc_fd_dir);
520 dirent* dir_entry;
521 while ((dir_entry = readdir(proc_fd_dir)) != nullptr) {
522 const int fd = ParseFd(dir_entry, dir_fd);
523 if (fd == -1) {
524 continue;
525 }
526
527 if (std::find(fds_to_ignore.begin(), fds_to_ignore.end(), fd) != fds_to_ignore.end()) {
528 continue;
529 }
530
531 open_fds.insert(fd);
532 }
533
534 if (closedir(proc_fd_dir) == -1) {
535 fail_fn(android::base::StringPrintf("Unable to close directory: %s", strerror(errno)));
536 }
537
538 RestatInternal(open_fds, fail_fn);
539 }
540
541 // Reopens all file descriptors that are contained in the table.
ReopenOrDetach(fail_fn_t fail_fn)542 void FileDescriptorTable::ReopenOrDetach(fail_fn_t fail_fn) {
543 std::unordered_map<int, FileDescriptorInfo*>::const_iterator it;
544 for (it = open_fd_map_.begin(); it != open_fd_map_.end(); ++it) {
545 const FileDescriptorInfo* info = it->second;
546 if (info == nullptr) {
547 return;
548 } else {
549 info->ReopenOrDetach(fail_fn);
550 }
551 }
552 }
553
FileDescriptorTable(const std::unordered_map<int,FileDescriptorInfo * > & map)554 FileDescriptorTable::FileDescriptorTable(
555 const std::unordered_map<int, FileDescriptorInfo*>& map)
556 : open_fd_map_(map) {
557 }
558
RestatInternal(std::set<int> & open_fds,fail_fn_t fail_fn)559 void FileDescriptorTable::RestatInternal(std::set<int>& open_fds, fail_fn_t fail_fn) {
560 // ART creates a file through memfd for optimization purposes. We make sure
561 // there is at most one being created.
562 bool art_memfd_seen = false;
563
564 // Iterate through the list of file descriptors we've already recorded
565 // and check whether :
566 //
567 // (a) they continue to be open.
568 // (b) they refer to the same file.
569 //
570 // We'll only store the last error message.
571 std::unordered_map<int, FileDescriptorInfo*>::iterator it = open_fd_map_.begin();
572 while (it != open_fd_map_.end()) {
573 std::set<int>::const_iterator element = open_fds.find(it->first);
574 if (element == open_fds.end()) {
575 // The entry from the file descriptor table is no longer in the list
576 // of open files. We warn about this condition and remove it from
577 // the list of FDs under consideration.
578 //
579 // TODO(narayan): This will be an error in a future android release.
580 // error = true;
581 // ALOGW("Zygote closed file descriptor %d.", it->first);
582 it = open_fd_map_.erase(it);
583 } else {
584 // The entry from the file descriptor table is still open. Restat
585 // it and check whether it refers to the same file.
586 if (!it->second->RefersToSameFile()) {
587 // The file descriptor refers to a different description. We must
588 // update our entry in the table.
589 delete it->second;
590 it->second = FileDescriptorInfo::CreateFromFd(*element, fail_fn);
591 } else {
592 // It's the same file. Nothing to do here. Move on to the next open
593 // FD.
594 }
595
596 if (IsArtMemfd(it->second->file_path)) {
597 if (art_memfd_seen) {
598 fail_fn("ART fd already seen: " + it->second->file_path);
599 } else {
600 art_memfd_seen = true;
601 }
602 }
603
604 ++it;
605
606 // Finally, remove the FD from the set of open_fds. We do this last because
607 // |element| will not remain valid after a call to erase.
608 open_fds.erase(element);
609 }
610 }
611
612 if (open_fds.size() > 0) {
613 // The zygote has opened new file descriptors since our last inspection.
614 // We warn about this condition and add them to our table.
615 //
616 // TODO(narayan): This will be an error in a future android release.
617 // error = true;
618 // ALOGW("Zygote opened %zd new file descriptor(s).", open_fds.size());
619
620 // TODO(narayan): This code will be removed in a future android release.
621 std::set<int>::const_iterator it;
622 for (it = open_fds.begin(); it != open_fds.end(); ++it) {
623 const int fd = (*it);
624 open_fd_map_[fd] = FileDescriptorInfo::CreateFromFd(fd, fail_fn);
625 }
626 }
627 }
628
629 // static
ParseFd(dirent * dir_entry,int dir_fd)630 int FileDescriptorTable::ParseFd(dirent* dir_entry, int dir_fd) {
631 char* end;
632 const int fd = strtol(dir_entry->d_name, &end, 10);
633 if ((*end) != '\0') {
634 return -1;
635 }
636
637 // Don't bother with the standard input/output/error, they're handled
638 // specially post-fork anyway.
639 if (fd <= STDERR_FILENO || fd == dir_fd) {
640 return -1;
641 }
642
643 return fd;
644 }
645