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