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