blob: 33b26899fe817090c8c4601ea6db74cffb955c4f [file] [log] [blame]
Robert Sesek8225b7c2016-12-16 14:02:31 -05001/*
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
Narayan Kamath3879ecc2017-03-02 17:30:03 +000029#include <android-base/file.h>
Narayan Kamatha352d242017-03-02 14:44:45 +000030#include <android-base/logging.h>
Narayan Kamath3879ecc2017-03-02 17:30:03 +000031#include <android-base/stringprintf.h>
Robert Sesek8225b7c2016-12-16 14:02:31 -050032#include <android-base/strings.h>
Robert Sesek8225b7c2016-12-16 14:02:31 -050033
Robert Sesek54e387d2016-12-02 17:27:50 -050034// Static whitelist of open paths that the zygote is allowed to keep open.
Robert Sesek8225b7c2016-12-16 14:02:31 -050035static const char* kPathWhitelist[] = {
36 "/dev/null",
37 "/dev/socket/zygote",
38 "/dev/socket/zygote_secondary",
39 "/dev/socket/webview_zygote",
Florian Mayer6ce2d992018-10-16 14:30:02 +010040 "/dev/socket/heapprofd",
Robert Sesek8225b7c2016-12-16 14:02:31 -050041 "/sys/kernel/debug/tracing/trace_marker",
42 "/system/framework/framework-res.apk",
43 "/dev/urandom",
44 "/dev/ion",
45 "/dev/dri/renderD129", // Fixes b/31172436
46};
47
48static const char kFdPath[] = "/proc/self/fd";
49
50// static
Robert Sesek54e387d2016-12-02 17:27:50 -050051FileDescriptorWhitelist* FileDescriptorWhitelist::Get() {
52 if (instance_ == nullptr) {
53 instance_ = new FileDescriptorWhitelist();
54 }
55 return instance_;
56}
57
58bool FileDescriptorWhitelist::IsAllowed(const std::string& path) const {
59 // Check the static whitelist path.
60 for (const auto& whitelist_path : kPathWhitelist) {
61 if (path == whitelist_path)
62 return true;
63 }
64
65 // Check any paths added to the dynamic whitelist.
66 for (const auto& whitelist_path : whitelist_) {
67 if (path == whitelist_path)
68 return true;
69 }
70
Narayan Kamath3879ecc2017-03-02 17:30:03 +000071 static const char* kFrameworksPrefix = "/system/framework/";
72 static const char* kJarSuffix = ".jar";
73 if (android::base::StartsWith(path, kFrameworksPrefix)
74 && android::base::EndsWith(path, kJarSuffix)) {
Robert Sesek54e387d2016-12-02 17:27:50 -050075 return true;
76 }
77
78 // Whitelist files needed for Runtime Resource Overlay, like these:
79 // /system/vendor/overlay/framework-res.apk
80 // /system/vendor/overlay-subdir/pg/framework-res.apk
81 // /vendor/overlay/framework-res.apk
82 // /vendor/overlay/PG/android-framework-runtime-resource-overlay.apk
83 // /data/resource-cache/system@vendor@overlay@framework-res.apk@idmap
84 // /data/resource-cache/system@vendor@overlay-subdir@pg@framework-res.apk@idmap
85 // See AssetManager.cpp for more details on overlay-subdir.
Narayan Kamath3879ecc2017-03-02 17:30:03 +000086 static const char* kOverlayDir = "/system/vendor/overlay/";
87 static const char* kVendorOverlayDir = "/vendor/overlay";
Mårten Kongstad06a1ac82018-09-20 13:09:47 +020088 static const char* kVendorOverlaySubdir = "/system/vendor/overlay-subdir/";
Jaekyun Seok1713d9e2018-01-12 21:47:26 +090089 static const char* kSystemProductOverlayDir = "/system/product/overlay/";
90 static const char* kProductOverlayDir = "/product/overlay";
Dario Freni4ce46792018-06-01 14:02:08 +010091 static const char* kSystemProductServicesOverlayDir = "/system/product_services/overlay/";
92 static const char* kProductServicesOverlayDir = "/product_services/overlay";
Narayan Kamath3879ecc2017-03-02 17:30:03 +000093 static const char* kApkSuffix = ".apk";
Robert Sesek54e387d2016-12-02 17:27:50 -050094
Narayan Kamath3879ecc2017-03-02 17:30:03 +000095 if ((android::base::StartsWith(path, kOverlayDir)
Mårten Kongstad06a1ac82018-09-20 13:09:47 +020096 || android::base::StartsWith(path, kVendorOverlaySubdir)
Jaekyun Seok1713d9e2018-01-12 21:47:26 +090097 || android::base::StartsWith(path, kVendorOverlayDir)
98 || android::base::StartsWith(path, kSystemProductOverlayDir)
Dario Freni4ce46792018-06-01 14:02:08 +010099 || android::base::StartsWith(path, kProductOverlayDir)
100 || android::base::StartsWith(path, kSystemProductServicesOverlayDir)
101 || android::base::StartsWith(path, kProductServicesOverlayDir))
Narayan Kamath3879ecc2017-03-02 17:30:03 +0000102 && android::base::EndsWith(path, kApkSuffix)
Robert Sesek54e387d2016-12-02 17:27:50 -0500103 && path.find("/../") == std::string::npos) {
104 return true;
105 }
106
Narayan Kamath3879ecc2017-03-02 17:30:03 +0000107 static const char* kOverlayIdmapPrefix = "/data/resource-cache/";
108 static const char* kOverlayIdmapSuffix = ".apk@idmap";
109 if (android::base::StartsWith(path, kOverlayIdmapPrefix)
110 && android::base::EndsWith(path, kOverlayIdmapSuffix)
Robert Sesek54e387d2016-12-02 17:27:50 -0500111 && path.find("/../") == std::string::npos) {
112 return true;
113 }
114
115 // All regular files that are placed under this path are whitelisted automatically.
Narayan Kamath3879ecc2017-03-02 17:30:03 +0000116 static const char* kZygoteWhitelistPath = "/vendor/zygote_whitelist/";
117 if (android::base::StartsWith(path, kZygoteWhitelistPath)
118 && path.find("/../") == std::string::npos) {
Robert Sesek54e387d2016-12-02 17:27:50 -0500119 return true;
120 }
121
122 return false;
123}
124
125FileDescriptorWhitelist::FileDescriptorWhitelist()
126 : whitelist_() {
127}
128
Robert Sesek54e387d2016-12-02 17:27:50 -0500129FileDescriptorWhitelist* FileDescriptorWhitelist::instance_ = nullptr;
130
Andreas Gampe183a5d32018-03-12 14:53:34 -0700131// Keeps track of all relevant information (flags, offset etc.) of an
132// open zygote file descriptor.
133class FileDescriptorInfo {
134 public:
135 // Create a FileDescriptorInfo for a given file descriptor. Returns
136 // |NULL| if an error occurred.
137 static FileDescriptorInfo* CreateFromFd(int fd, std::string* error_msg);
138
139 // Checks whether the file descriptor associated with this object
140 // refers to the same description.
141 bool Restat() const;
142
143 bool ReopenOrDetach(std::string* error_msg) const;
144
145 const int fd;
146 const struct stat stat;
147 const std::string file_path;
148 const int open_flags;
149 const int fd_flags;
150 const int fs_flags;
151 const off_t offset;
152 const bool is_sock;
153
154 private:
155 FileDescriptorInfo(int fd);
156
157 FileDescriptorInfo(struct stat stat, const std::string& file_path, int fd, int open_flags,
158 int fd_flags, int fs_flags, off_t offset);
159
160 // Returns the locally-bound name of the socket |fd|. Returns true
161 // iff. all of the following hold :
162 //
163 // - the socket's sa_family is AF_UNIX.
164 // - the length of the path is greater than zero (i.e, not an unnamed socket).
165 // - the first byte of the path isn't zero (i.e, not a socket with an abstract
166 // address).
167 static bool GetSocketName(const int fd, std::string* result);
168
169 bool DetachSocket(std::string* error_msg) const;
170
171 DISALLOW_COPY_AND_ASSIGN(FileDescriptorInfo);
172};
173
Robert Sesek54e387d2016-12-02 17:27:50 -0500174// static
Andreas Gampe183a5d32018-03-12 14:53:34 -0700175FileDescriptorInfo* FileDescriptorInfo::CreateFromFd(int fd, std::string* error_msg) {
Robert Sesek8225b7c2016-12-16 14:02:31 -0500176 struct stat f_stat;
177 // This should never happen; the zygote should always have the right set
178 // of permissions required to stat all its open files.
179 if (TEMP_FAILURE_RETRY(fstat(fd, &f_stat)) == -1) {
Andreas Gampe183a5d32018-03-12 14:53:34 -0700180 *error_msg = android::base::StringPrintf("Unable to stat %d", fd);
181 return nullptr;
Robert Sesek8225b7c2016-12-16 14:02:31 -0500182 }
183
Robert Sesek54e387d2016-12-02 17:27:50 -0500184 const FileDescriptorWhitelist* whitelist = FileDescriptorWhitelist::Get();
185
Robert Sesek8225b7c2016-12-16 14:02:31 -0500186 if (S_ISSOCK(f_stat.st_mode)) {
187 std::string socket_name;
188 if (!GetSocketName(fd, &socket_name)) {
Andreas Gampe183a5d32018-03-12 14:53:34 -0700189 *error_msg = "Unable to get socket name";
190 return nullptr;
Robert Sesek8225b7c2016-12-16 14:02:31 -0500191 }
192
Robert Sesek54e387d2016-12-02 17:27:50 -0500193 if (!whitelist->IsAllowed(socket_name)) {
Andreas Gampe183a5d32018-03-12 14:53:34 -0700194 *error_msg = android::base::StringPrintf("Socket name not whitelisted : %s (fd=%d)",
195 socket_name.c_str(),
196 fd);
197 return nullptr;
Robert Sesek8225b7c2016-12-16 14:02:31 -0500198 }
199
200 return new FileDescriptorInfo(fd);
201 }
202
203 // We only handle whitelisted regular files and character devices. Whitelisted
204 // character devices must provide a guarantee of sensible behaviour when
205 // reopened.
206 //
207 // S_ISDIR : Not supported. (We could if we wanted to, but it's unused).
208 // S_ISLINK : Not supported.
209 // S_ISBLK : Not supported.
210 // S_ISFIFO : Not supported. Note that the zygote uses pipes to communicate
211 // with the child process across forks but those should have been closed
212 // before we got to this point.
213 if (!S_ISCHR(f_stat.st_mode) && !S_ISREG(f_stat.st_mode)) {
Andreas Gampe183a5d32018-03-12 14:53:34 -0700214 *error_msg = android::base::StringPrintf("Unsupported st_mode %u", f_stat.st_mode);
215 return nullptr;
Robert Sesek8225b7c2016-12-16 14:02:31 -0500216 }
217
218 std::string file_path;
Narayan Kamath3879ecc2017-03-02 17:30:03 +0000219 const std::string fd_path = android::base::StringPrintf("/proc/self/fd/%d", fd);
220 if (!android::base::Readlink(fd_path, &file_path)) {
Andreas Gampe183a5d32018-03-12 14:53:34 -0700221 *error_msg = android::base::StringPrintf("Could not read fd link %s: %s",
222 fd_path.c_str(),
223 strerror(errno));
224 return nullptr;
Robert Sesek8225b7c2016-12-16 14:02:31 -0500225 }
226
Robert Sesek54e387d2016-12-02 17:27:50 -0500227 if (!whitelist->IsAllowed(file_path)) {
Andreas Gampe183a5d32018-03-12 14:53:34 -0700228 *error_msg = std::string("Not whitelisted : ").append(file_path);
229 return nullptr;
Robert Sesek8225b7c2016-12-16 14:02:31 -0500230 }
231
232 // File descriptor flags : currently on FD_CLOEXEC. We can set these
233 // using F_SETFD - we're single threaded at this point of execution so
234 // there won't be any races.
235 const int fd_flags = TEMP_FAILURE_RETRY(fcntl(fd, F_GETFD));
236 if (fd_flags == -1) {
Andreas Gampe183a5d32018-03-12 14:53:34 -0700237 *error_msg = android::base::StringPrintf("Failed fcntl(%d, F_GETFD) (%s): %s",
238 fd,
239 file_path.c_str(),
240 strerror(errno));
241 return nullptr;
Robert Sesek8225b7c2016-12-16 14:02:31 -0500242 }
243
244 // File status flags :
245 // - File access mode : (O_RDONLY, O_WRONLY...) we'll pass these through
246 // to the open() call.
247 //
248 // - File creation flags : (O_CREAT, O_EXCL...) - there's not much we can
249 // do about these, since the file has already been created. We shall ignore
250 // them here.
251 //
252 // - Other flags : We'll have to set these via F_SETFL. On linux, F_SETFL
253 // can only set O_APPEND, O_ASYNC, O_DIRECT, O_NOATIME, and O_NONBLOCK.
254 // In particular, it can't set O_SYNC and O_DSYNC. We'll have to test for
255 // their presence and pass them in to open().
256 int fs_flags = TEMP_FAILURE_RETRY(fcntl(fd, F_GETFL));
257 if (fs_flags == -1) {
Andreas Gampe183a5d32018-03-12 14:53:34 -0700258 *error_msg = android::base::StringPrintf("Failed fcntl(%d, F_GETFL) (%s): %s",
259 fd,
260 file_path.c_str(),
261 strerror(errno));
262 return nullptr;
Robert Sesek8225b7c2016-12-16 14:02:31 -0500263 }
264
265 // File offset : Ignore the offset for non seekable files.
266 const off_t offset = TEMP_FAILURE_RETRY(lseek64(fd, 0, SEEK_CUR));
267
268 // We pass the flags that open accepts to open, and use F_SETFL for
269 // the rest of them.
270 static const int kOpenFlags = (O_RDONLY | O_WRONLY | O_RDWR | O_DSYNC | O_SYNC);
271 int open_flags = fs_flags & (kOpenFlags);
272 fs_flags = fs_flags & (~(kOpenFlags));
273
274 return new FileDescriptorInfo(f_stat, file_path, fd, open_flags, fd_flags, fs_flags, offset);
275}
276
277bool FileDescriptorInfo::Restat() const {
278 struct stat f_stat;
279 if (TEMP_FAILURE_RETRY(fstat(fd, &f_stat)) == -1) {
Narayan Kamatha352d242017-03-02 14:44:45 +0000280 PLOG(ERROR) << "Unable to restat fd " << fd;
Robert Sesek8225b7c2016-12-16 14:02:31 -0500281 return false;
282 }
283
284 return f_stat.st_ino == stat.st_ino && f_stat.st_dev == stat.st_dev;
285}
286
Andreas Gampe183a5d32018-03-12 14:53:34 -0700287bool FileDescriptorInfo::ReopenOrDetach(std::string* error_msg) const {
Robert Sesek8225b7c2016-12-16 14:02:31 -0500288 if (is_sock) {
Andreas Gampe183a5d32018-03-12 14:53:34 -0700289 return DetachSocket(error_msg);
Robert Sesek8225b7c2016-12-16 14:02:31 -0500290 }
291
292 // NOTE: This might happen if the file was unlinked after being opened.
293 // It's a common pattern in the case of temporary files and the like but
294 // we should not allow such usage from the zygote.
295 const int new_fd = TEMP_FAILURE_RETRY(open(file_path.c_str(), open_flags));
296
297 if (new_fd == -1) {
Andreas Gampe183a5d32018-03-12 14:53:34 -0700298 *error_msg = android::base::StringPrintf("Failed open(%s, %i): %s",
299 file_path.c_str(),
300 open_flags,
301 strerror(errno));
Robert Sesek8225b7c2016-12-16 14:02:31 -0500302 return false;
303 }
304
305 if (TEMP_FAILURE_RETRY(fcntl(new_fd, F_SETFD, fd_flags)) == -1) {
306 close(new_fd);
Andreas Gampe183a5d32018-03-12 14:53:34 -0700307 *error_msg = android::base::StringPrintf("Failed fcntl(%d, F_SETFD, %d) (%s): %s",
308 new_fd,
309 fd_flags,
310 file_path.c_str(),
311 strerror(errno));
Robert Sesek8225b7c2016-12-16 14:02:31 -0500312 return false;
313 }
314
315 if (TEMP_FAILURE_RETRY(fcntl(new_fd, F_SETFL, fs_flags)) == -1) {
316 close(new_fd);
Andreas Gampe183a5d32018-03-12 14:53:34 -0700317 *error_msg = android::base::StringPrintf("Failed fcntl(%d, F_SETFL, %d) (%s): %s",
318 new_fd,
319 fs_flags,
320 file_path.c_str(),
321 strerror(errno));
Robert Sesek8225b7c2016-12-16 14:02:31 -0500322 return false;
323 }
324
325 if (offset != -1 && TEMP_FAILURE_RETRY(lseek64(new_fd, offset, SEEK_SET)) == -1) {
326 close(new_fd);
Andreas Gampe183a5d32018-03-12 14:53:34 -0700327 *error_msg = android::base::StringPrintf("Failed lseek64(%d, SEEK_SET) (%s): %s",
328 new_fd,
329 file_path.c_str(),
330 strerror(errno));
Robert Sesek8225b7c2016-12-16 14:02:31 -0500331 return false;
332 }
333
Nick Kralevichd9765a42018-12-14 21:34:44 -0800334 int dupFlags = (fd_flags & FD_CLOEXEC) ? O_CLOEXEC : 0;
335 if (TEMP_FAILURE_RETRY(dup3(new_fd, fd, dupFlags)) == -1) {
Robert Sesek8225b7c2016-12-16 14:02:31 -0500336 close(new_fd);
Nick Kralevichd9765a42018-12-14 21:34:44 -0800337 *error_msg = android::base::StringPrintf("Failed dup3(%d, %d, %d) (%s): %s",
Andreas Gampe183a5d32018-03-12 14:53:34 -0700338 fd,
339 new_fd,
Nick Kralevichd9765a42018-12-14 21:34:44 -0800340 dupFlags,
Andreas Gampe183a5d32018-03-12 14:53:34 -0700341 file_path.c_str(),
342 strerror(errno));
Robert Sesek8225b7c2016-12-16 14:02:31 -0500343 return false;
344 }
345
346 close(new_fd);
347
348 return true;
349}
350
351FileDescriptorInfo::FileDescriptorInfo(int fd) :
352 fd(fd),
353 stat(),
354 open_flags(0),
355 fd_flags(0),
356 fs_flags(0),
357 offset(0),
358 is_sock(true) {
359}
360
361FileDescriptorInfo::FileDescriptorInfo(struct stat stat, const std::string& file_path,
362 int fd, int open_flags, int fd_flags, int fs_flags,
363 off_t offset) :
364 fd(fd),
365 stat(stat),
366 file_path(file_path),
367 open_flags(open_flags),
368 fd_flags(fd_flags),
369 fs_flags(fs_flags),
370 offset(offset),
371 is_sock(false) {
372}
373
Robert Sesek8225b7c2016-12-16 14:02:31 -0500374// static
375bool FileDescriptorInfo::GetSocketName(const int fd, std::string* result) {
376 sockaddr_storage ss;
377 sockaddr* addr = reinterpret_cast<sockaddr*>(&ss);
378 socklen_t addr_len = sizeof(ss);
379
380 if (TEMP_FAILURE_RETRY(getsockname(fd, addr, &addr_len)) == -1) {
Narayan Kamath84b55112017-03-02 17:04:08 +0000381 PLOG(ERROR) << "Failed getsockname(" << fd << ")";
Robert Sesek8225b7c2016-12-16 14:02:31 -0500382 return false;
383 }
384
385 if (addr->sa_family != AF_UNIX) {
Narayan Kamath84b55112017-03-02 17:04:08 +0000386 LOG(ERROR) << "Unsupported socket (fd=" << fd << ") with family " << addr->sa_family;
Robert Sesek8225b7c2016-12-16 14:02:31 -0500387 return false;
388 }
389
390 const sockaddr_un* unix_addr = reinterpret_cast<const sockaddr_un*>(&ss);
391
392 size_t path_len = addr_len - offsetof(struct sockaddr_un, sun_path);
393 // This is an unnamed local socket, we do not accept it.
394 if (path_len == 0) {
Narayan Kamath84b55112017-03-02 17:04:08 +0000395 LOG(ERROR) << "Unsupported AF_UNIX socket (fd=" << fd << ") with empty path.";
Robert Sesek8225b7c2016-12-16 14:02:31 -0500396 return false;
397 }
398
Robert Sesekd0a190df2018-02-12 18:46:01 -0500399 // This is a local socket with an abstract address. Remove the leading NUL byte and
400 // add a human-readable "ABSTRACT/" prefix.
Robert Sesek8225b7c2016-12-16 14:02:31 -0500401 if (unix_addr->sun_path[0] == '\0') {
Robert Sesekd0a190df2018-02-12 18:46:01 -0500402 *result = "ABSTRACT/";
403 result->append(&unix_addr->sun_path[1], path_len - 1);
404 return true;
Robert Sesek8225b7c2016-12-16 14:02:31 -0500405 }
406
407 // If we're here, sun_path must refer to a null terminated filesystem
408 // pathname (man 7 unix). Remove the terminator before assigning it to an
409 // std::string.
410 if (unix_addr->sun_path[path_len - 1] == '\0') {
411 --path_len;
412 }
413
414 result->assign(unix_addr->sun_path, path_len);
415 return true;
416}
417
Andreas Gampe183a5d32018-03-12 14:53:34 -0700418bool FileDescriptorInfo::DetachSocket(std::string* error_msg) const {
Robert Sesek8225b7c2016-12-16 14:02:31 -0500419 const int dev_null_fd = open("/dev/null", O_RDWR);
420 if (dev_null_fd < 0) {
Andreas Gampe183a5d32018-03-12 14:53:34 -0700421 *error_msg = std::string("Failed to open /dev/null: ").append(strerror(errno));
Robert Sesek8225b7c2016-12-16 14:02:31 -0500422 return false;
423 }
424
425 if (dup2(dev_null_fd, fd) == -1) {
Andreas Gampe183a5d32018-03-12 14:53:34 -0700426 *error_msg = android::base::StringPrintf("Failed dup2 on socket descriptor %d: %s",
427 fd,
428 strerror(errno));
Robert Sesek8225b7c2016-12-16 14:02:31 -0500429 return false;
430 }
431
432 if (close(dev_null_fd) == -1) {
Andreas Gampe183a5d32018-03-12 14:53:34 -0700433 *error_msg = android::base::StringPrintf("Failed close(%d): %s", dev_null_fd, strerror(errno));
Robert Sesek8225b7c2016-12-16 14:02:31 -0500434 return false;
435 }
436
437 return true;
438}
439
440// static
Andreas Gampe183a5d32018-03-12 14:53:34 -0700441FileDescriptorTable* FileDescriptorTable::Create(const std::vector<int>& fds_to_ignore,
442 std::string* error_msg) {
Robert Sesek8225b7c2016-12-16 14:02:31 -0500443 DIR* d = opendir(kFdPath);
Andreas Gampe183a5d32018-03-12 14:53:34 -0700444 if (d == nullptr) {
445 *error_msg = std::string("Unable to open directory ").append(kFdPath);
446 return nullptr;
Robert Sesek8225b7c2016-12-16 14:02:31 -0500447 }
448 int dir_fd = dirfd(d);
449 dirent* e;
450
451 std::unordered_map<int, FileDescriptorInfo*> open_fd_map;
452 while ((e = readdir(d)) != NULL) {
453 const int fd = ParseFd(e, dir_fd);
454 if (fd == -1) {
455 continue;
456 }
Andreas Gampe8dfa1782017-01-05 12:45:58 -0800457 if (std::find(fds_to_ignore.begin(), fds_to_ignore.end(), fd) != fds_to_ignore.end()) {
Narayan Kamath84b55112017-03-02 17:04:08 +0000458 LOG(INFO) << "Ignoring open file descriptor " << fd;
Andreas Gampe8dfa1782017-01-05 12:45:58 -0800459 continue;
460 }
Robert Sesek8225b7c2016-12-16 14:02:31 -0500461
Andreas Gampe183a5d32018-03-12 14:53:34 -0700462 FileDescriptorInfo* info = FileDescriptorInfo::CreateFromFd(fd, error_msg);
Robert Sesek8225b7c2016-12-16 14:02:31 -0500463 if (info == NULL) {
464 if (closedir(d) == -1) {
Narayan Kamath84b55112017-03-02 17:04:08 +0000465 PLOG(ERROR) << "Unable to close directory";
Robert Sesek8225b7c2016-12-16 14:02:31 -0500466 }
467 return NULL;
468 }
469 open_fd_map[fd] = info;
470 }
471
472 if (closedir(d) == -1) {
Andreas Gampe183a5d32018-03-12 14:53:34 -0700473 *error_msg = "Unable to close directory";
474 return nullptr;
Robert Sesek8225b7c2016-12-16 14:02:31 -0500475 }
476 return new FileDescriptorTable(open_fd_map);
477}
478
Andreas Gampe183a5d32018-03-12 14:53:34 -0700479bool FileDescriptorTable::Restat(const std::vector<int>& fds_to_ignore, std::string* error_msg) {
Robert Sesek8225b7c2016-12-16 14:02:31 -0500480 std::set<int> open_fds;
481
482 // First get the list of open descriptors.
483 DIR* d = opendir(kFdPath);
484 if (d == NULL) {
Andreas Gampe183a5d32018-03-12 14:53:34 -0700485 *error_msg = android::base::StringPrintf("Unable to open directory %s: %s",
486 kFdPath,
487 strerror(errno));
Robert Sesek8225b7c2016-12-16 14:02:31 -0500488 return false;
489 }
490
491 int dir_fd = dirfd(d);
492 dirent* e;
493 while ((e = readdir(d)) != NULL) {
494 const int fd = ParseFd(e, dir_fd);
495 if (fd == -1) {
496 continue;
497 }
Andreas Gampe8dfa1782017-01-05 12:45:58 -0800498 if (std::find(fds_to_ignore.begin(), fds_to_ignore.end(), fd) != fds_to_ignore.end()) {
Narayan Kamath84b55112017-03-02 17:04:08 +0000499 LOG(INFO) << "Ignoring open file descriptor " << fd;
Andreas Gampe8dfa1782017-01-05 12:45:58 -0800500 continue;
501 }
Robert Sesek8225b7c2016-12-16 14:02:31 -0500502
503 open_fds.insert(fd);
504 }
505
506 if (closedir(d) == -1) {
Andreas Gampe183a5d32018-03-12 14:53:34 -0700507 *error_msg = android::base::StringPrintf("Unable to close directory: %s", strerror(errno));
Robert Sesek8225b7c2016-12-16 14:02:31 -0500508 return false;
509 }
510
Andreas Gampe183a5d32018-03-12 14:53:34 -0700511 return RestatInternal(open_fds, error_msg);
Robert Sesek8225b7c2016-12-16 14:02:31 -0500512}
513
514// Reopens all file descriptors that are contained in the table. Returns true
515// if all descriptors were successfully re-opened or detached, and false if an
516// error occurred.
Andreas Gampe183a5d32018-03-12 14:53:34 -0700517bool FileDescriptorTable::ReopenOrDetach(std::string* error_msg) {
Robert Sesek8225b7c2016-12-16 14:02:31 -0500518 std::unordered_map<int, FileDescriptorInfo*>::const_iterator it;
519 for (it = open_fd_map_.begin(); it != open_fd_map_.end(); ++it) {
520 const FileDescriptorInfo* info = it->second;
Andreas Gampe183a5d32018-03-12 14:53:34 -0700521 if (info == NULL || !info->ReopenOrDetach(error_msg)) {
Robert Sesek8225b7c2016-12-16 14:02:31 -0500522 return false;
523 }
524 }
525
526 return true;
527}
528
529FileDescriptorTable::FileDescriptorTable(
530 const std::unordered_map<int, FileDescriptorInfo*>& map)
531 : open_fd_map_(map) {
532}
533
Andreas Gampe183a5d32018-03-12 14:53:34 -0700534bool FileDescriptorTable::RestatInternal(std::set<int>& open_fds, std::string* error_msg) {
Robert Sesek8225b7c2016-12-16 14:02:31 -0500535 bool error = false;
536
537 // Iterate through the list of file descriptors we've already recorded
538 // and check whether :
539 //
540 // (a) they continue to be open.
541 // (b) they refer to the same file.
Andreas Gampe183a5d32018-03-12 14:53:34 -0700542 //
543 // We'll only store the last error message.
Robert Sesek8225b7c2016-12-16 14:02:31 -0500544 std::unordered_map<int, FileDescriptorInfo*>::iterator it = open_fd_map_.begin();
545 while (it != open_fd_map_.end()) {
546 std::set<int>::const_iterator element = open_fds.find(it->first);
547 if (element == open_fds.end()) {
548 // The entry from the file descriptor table is no longer in the list
549 // of open files. We warn about this condition and remove it from
550 // the list of FDs under consideration.
551 //
552 // TODO(narayan): This will be an error in a future android release.
553 // error = true;
554 // ALOGW("Zygote closed file descriptor %d.", it->first);
555 it = open_fd_map_.erase(it);
556 } else {
557 // The entry from the file descriptor table is still open. Restat
558 // it and check whether it refers to the same file.
559 const bool same_file = it->second->Restat();
560 if (!same_file) {
561 // The file descriptor refers to a different description. We must
562 // update our entry in the table.
563 delete it->second;
Andreas Gampe183a5d32018-03-12 14:53:34 -0700564 it->second = FileDescriptorInfo::CreateFromFd(*element, error_msg);
Robert Sesek8225b7c2016-12-16 14:02:31 -0500565 if (it->second == NULL) {
566 // The descriptor no longer no longer refers to a whitelisted file.
567 // We flag an error and remove it from the list of files we're
568 // tracking.
569 error = true;
570 it = open_fd_map_.erase(it);
571 } else {
572 // Successfully restatted the file, move on to the next open FD.
573 ++it;
574 }
575 } else {
576 // It's the same file. Nothing to do here. Move on to the next open
577 // FD.
578 ++it;
579 }
580
581 // Finally, remove the FD from the set of open_fds. We do this last because
582 // |element| will not remain valid after a call to erase.
583 open_fds.erase(element);
584 }
585 }
586
587 if (open_fds.size() > 0) {
588 // The zygote has opened new file descriptors since our last inspection.
589 // We warn about this condition and add them to our table.
590 //
591 // TODO(narayan): This will be an error in a future android release.
592 // error = true;
593 // ALOGW("Zygote opened %zd new file descriptor(s).", open_fds.size());
594
595 // TODO(narayan): This code will be removed in a future android release.
596 std::set<int>::const_iterator it;
597 for (it = open_fds.begin(); it != open_fds.end(); ++it) {
598 const int fd = (*it);
Andreas Gampe183a5d32018-03-12 14:53:34 -0700599 FileDescriptorInfo* info = FileDescriptorInfo::CreateFromFd(fd, error_msg);
Robert Sesek8225b7c2016-12-16 14:02:31 -0500600 if (info == NULL) {
601 // A newly opened file is not on the whitelist. Flag an error and
602 // continue.
603 error = true;
604 } else {
605 // Track the newly opened file.
606 open_fd_map_[fd] = info;
607 }
608 }
609 }
610
611 return !error;
612}
613
614// static
615int FileDescriptorTable::ParseFd(dirent* e, int dir_fd) {
616 char* end;
617 const int fd = strtol(e->d_name, &end, 10);
618 if ((*end) != '\0') {
619 return -1;
620 }
621
622 // Don't bother with the standard input/output/error, they're handled
623 // specially post-fork anyway.
624 if (fd <= STDERR_FILENO || fd == dir_fd) {
625 return -1;
626 }
627
628 return fd;
629}