• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <string>
18 #include <unordered_map>
19 #include <set>
20 #include <vector>
21 #include <algorithm>
22 
23 #include <android-base/strings.h>
24 #include <dirent.h>
25 #include <fcntl.h>
26 #include <grp.h>
27 #include <inttypes.h>
28 #include <stdlib.h>
29 #include <sys/socket.h>
30 #include <sys/stat.h>
31 #include <sys/types.h>
32 #include <sys/un.h>
33 #include <unistd.h>
34 
35 #include <cutils/log.h>
36 #include "JNIHelp.h"
37 #include "ScopedPrimitiveArray.h"
38 
39 // Whitelist of open paths that the zygote is allowed to keep open.
40 //
41 // In addition to the paths listed here, all files ending with
42 // ".jar" under /system/framework" are whitelisted. See
43 // FileDescriptorInfo::IsWhitelisted for the canonical definition.
44 //
45 // If the whitelisted path is associated with a regular file or a
46 // character device, the file is reopened after a fork with the same
47 // offset and mode. If the whilelisted  path is associated with a
48 // AF_UNIX socket, the socket will refer to /dev/null after each
49 // fork, and all operations on it will fail.
50 static const char* kPathWhitelist[] = {
51   "/dev/null",
52   "/dev/socket/zygote",
53   "/dev/socket/zygote_secondary",
54   "/sys/kernel/debug/tracing/trace_marker",
55   "/system/framework/framework-res.apk",
56   "/dev/urandom",
57   "/dev/ion",
58   "/dev/dri/renderD129", // Fixes b/31172436
59 };
60 
61 static const char* kFdPath = "/proc/self/fd";
62 
63 // Keeps track of all relevant information (flags, offset etc.) of an
64 // open zygote file descriptor.
65 class FileDescriptorInfo {
66  public:
67   // Create a FileDescriptorInfo for a given file descriptor. Returns
68   // |NULL| if an error occurred.
createFromFd(int fd)69   static FileDescriptorInfo* createFromFd(int fd) {
70     struct stat f_stat;
71     // This should never happen; the zygote should always have the right set
72     // of permissions required to stat all its open files.
73     if (TEMP_FAILURE_RETRY(fstat(fd, &f_stat)) == -1) {
74       ALOGE("Unable to stat fd %d : %s", fd, strerror(errno));
75       return NULL;
76     }
77 
78     if (S_ISSOCK(f_stat.st_mode)) {
79       std::string socket_name;
80       if (!GetSocketName(fd, &socket_name)) {
81         return NULL;
82       }
83 
84       if (!IsWhitelisted(socket_name)) {
85         ALOGE("Socket name not whitelisted : %s (fd=%d)", socket_name.c_str(), fd);
86         return NULL;
87       }
88 
89       return new FileDescriptorInfo(fd);
90     }
91 
92     // We only handle whitelisted regular files and character devices. Whitelisted
93     // character devices must provide a guarantee of sensible behaviour when
94     // reopened.
95     //
96     // S_ISDIR : Not supported. (We could if we wanted to, but it's unused).
97     // S_ISLINK : Not supported.
98     // S_ISBLK : Not supported.
99     // S_ISFIFO : Not supported. Note that the zygote uses pipes to communicate
100     // with the child process across forks but those should have been closed
101     // before we got to this point.
102     if (!S_ISCHR(f_stat.st_mode) && !S_ISREG(f_stat.st_mode)) {
103       ALOGE("Unsupported st_mode %d", f_stat.st_mode);
104       return NULL;
105     }
106 
107     std::string file_path;
108     if (!Readlink(fd, &file_path)) {
109       return NULL;
110     }
111 
112     if (!IsWhitelisted(file_path)) {
113       ALOGE("Not whitelisted : %s", file_path.c_str());
114       return NULL;
115     }
116 
117     // File descriptor flags : currently on FD_CLOEXEC. We can set these
118     // using F_SETFD - we're single threaded at this point of execution so
119     // there won't be any races.
120     const int fd_flags = TEMP_FAILURE_RETRY(fcntl(fd, F_GETFD));
121     if (fd_flags == -1) {
122       ALOGE("Failed fcntl(%d, F_GETFD) : %s", fd, strerror(errno));
123       return NULL;
124     }
125 
126     // File status flags :
127     // - File access mode : (O_RDONLY, O_WRONLY...) we'll pass these through
128     //   to the open() call.
129     //
130     // - File creation flags : (O_CREAT, O_EXCL...) - there's not much we can
131     //   do about these, since the file has already been created. We shall ignore
132     //   them here.
133     //
134     // - Other flags : We'll have to set these via F_SETFL. On linux, F_SETFL
135     //   can only set O_APPEND, O_ASYNC, O_DIRECT, O_NOATIME, and O_NONBLOCK.
136     //   In particular, it can't set O_SYNC and O_DSYNC. We'll have to test for
137     //   their presence and pass them in to open().
138     int fs_flags = TEMP_FAILURE_RETRY(fcntl(fd, F_GETFL));
139     if (fs_flags == -1) {
140       ALOGE("Failed fcntl(%d, F_GETFL) : %s", fd, strerror(errno));
141       return NULL;
142     }
143 
144     // File offset : Ignore the offset for non seekable files.
145     const off_t offset = TEMP_FAILURE_RETRY(lseek64(fd, 0, SEEK_CUR));
146 
147     // We pass the flags that open accepts to open, and use F_SETFL for
148     // the rest of them.
149     static const int kOpenFlags = (O_RDONLY | O_WRONLY | O_RDWR | O_DSYNC | O_SYNC);
150     int open_flags = fs_flags & (kOpenFlags);
151     fs_flags = fs_flags & (~(kOpenFlags));
152 
153     return new FileDescriptorInfo(f_stat, file_path, fd, open_flags, fd_flags, fs_flags, offset);
154   }
155 
156   // Checks whether the file descriptor associated with this object
157   // refers to the same description.
Restat()158   bool Restat() const {
159     struct stat f_stat;
160     if (TEMP_FAILURE_RETRY(fstat(fd, &f_stat)) == -1) {
161       return false;
162     }
163 
164     return f_stat.st_ino == stat.st_ino && f_stat.st_dev == stat.st_dev;
165   }
166 
ReopenOrDetach()167   bool ReopenOrDetach() const {
168     if (is_sock) {
169       return DetachSocket();
170     }
171 
172     // NOTE: This might happen if the file was unlinked after being opened.
173     // It's a common pattern in the case of temporary files and the like but
174     // we should not allow such usage from the zygote.
175     const int new_fd = TEMP_FAILURE_RETRY(open(file_path.c_str(), open_flags));
176 
177     if (new_fd == -1) {
178       ALOGE("Failed open(%s, %d) : %s", file_path.c_str(), open_flags, strerror(errno));
179       return false;
180     }
181 
182     if (TEMP_FAILURE_RETRY(fcntl(new_fd, F_SETFD, fd_flags)) == -1) {
183       close(new_fd);
184       ALOGE("Failed fcntl(%d, F_SETFD, %x) : %s", new_fd, fd_flags, strerror(errno));
185       return false;
186     }
187 
188     if (TEMP_FAILURE_RETRY(fcntl(new_fd, F_SETFL, fs_flags)) == -1) {
189       close(new_fd);
190       ALOGE("Failed fcntl(%d, F_SETFL, %x) : %s", new_fd, fs_flags, strerror(errno));
191       return false;
192     }
193 
194     if (offset != -1 && TEMP_FAILURE_RETRY(lseek64(new_fd, offset, SEEK_SET)) == -1) {
195       close(new_fd);
196       ALOGE("Failed lseek64(%d, SEEK_SET) : %s", new_fd, strerror(errno));
197       return false;
198     }
199 
200     if (TEMP_FAILURE_RETRY(dup2(new_fd, fd)) == -1) {
201       close(new_fd);
202       ALOGE("Failed dup2(%d, %d) : %s", fd, new_fd, strerror(errno));
203       return false;
204     }
205 
206     close(new_fd);
207 
208     return true;
209   }
210 
211   const int fd;
212   const struct stat stat;
213   const std::string file_path;
214   const int open_flags;
215   const int fd_flags;
216   const int fs_flags;
217   const off_t offset;
218   const bool is_sock;
219 
220  private:
FileDescriptorInfo(int fd)221   FileDescriptorInfo(int fd) :
222     fd(fd),
223     stat(),
224     open_flags(0),
225     fd_flags(0),
226     fs_flags(0),
227     offset(0),
228     is_sock(true) {
229   }
230 
FileDescriptorInfo(struct stat stat,const std::string & file_path,int fd,int open_flags,int fd_flags,int fs_flags,off_t offset)231   FileDescriptorInfo(struct stat stat, const std::string& file_path, int fd, int open_flags,
232                      int fd_flags, int fs_flags, off_t offset) :
233     fd(fd),
234     stat(stat),
235     file_path(file_path),
236     open_flags(open_flags),
237     fd_flags(fd_flags),
238     fs_flags(fs_flags),
239     offset(offset),
240     is_sock(false) {
241   }
242 
StartsWith(const std::string & str,const std::string & prefix)243   static bool StartsWith(const std::string& str, const std::string& prefix) {
244     return str.compare(0, prefix.size(), prefix) == 0;
245   }
246 
EndsWith(const std::string & str,const std::string & suffix)247   static bool EndsWith(const std::string& str, const std::string& suffix) {
248     if (suffix.size() > str.size()) {
249       return false;
250     }
251 
252     return str.compare(str.size() - suffix.size(), suffix.size(), suffix) == 0;
253   }
254 
255   // Returns true iff. a given path is whitelisted. A path is whitelisted
256   // if it belongs to the whitelist (see kPathWhitelist) or if it's a path
257   // under /system/framework that ends with ".jar" or if it is a system
258   // framework overlay.
IsWhitelisted(const std::string & path)259   static bool IsWhitelisted(const std::string& path) {
260     for (size_t i = 0; i < (sizeof(kPathWhitelist) / sizeof(kPathWhitelist[0])); ++i) {
261       if (kPathWhitelist[i] == path) {
262         return true;
263       }
264     }
265 
266     static const std::string kFrameworksPrefix = "/system/framework/";
267     static const std::string kJarSuffix = ".jar";
268     if (StartsWith(path, kFrameworksPrefix) && EndsWith(path, kJarSuffix)) {
269       return true;
270     }
271 
272     // Whitelist files needed for Runtime Resource Overlay, like these:
273     // /system/vendor/overlay/framework-res.apk
274     // /system/vendor/overlay-subdir/pg/framework-res.apk
275     // /data/resource-cache/system@vendor@overlay@framework-res.apk@idmap
276     // /data/resource-cache/system@vendor@overlay-subdir@pg@framework-res.apk@idmap
277     // See AssetManager.cpp for more details on overlay-subdir.
278     static const std::string kOverlayDir = "/system/vendor/overlay/";
279     static const std::string kVendorOverlayDir = "/vendor/overlay";
280     static const std::string kOverlaySubdir = "/system/vendor/overlay-subdir/";
281     static const std::string kApkSuffix = ".apk";
282 
283     if ((StartsWith(path, kOverlayDir) || StartsWith(path, kOverlaySubdir)
284          || StartsWith(path, kVendorOverlayDir))
285         && EndsWith(path, kApkSuffix)
286         && path.find("/../") == std::string::npos) {
287       return true;
288     }
289 
290     static const std::string kOverlayIdmapPrefix = "/data/resource-cache/";
291     static const std::string kOverlayIdmapSuffix = ".apk@idmap";
292     if (StartsWith(path, kOverlayIdmapPrefix) && EndsWith(path, kOverlayIdmapSuffix)
293         && path.find("/../") == std::string::npos) {
294       return true;
295     }
296 
297     // All regular files that are placed under this path are whitelisted automatically.
298     static const std::string kZygoteWhitelistPath = "/vendor/zygote_whitelist/";
299     if (StartsWith(path, kZygoteWhitelistPath) && path.find("/../") == std::string::npos) {
300       return true;
301     }
302 
303     return false;
304   }
305 
306   // TODO: Call android::base::Readlink instead of copying the code here.
Readlink(const int fd,std::string * result)307   static bool Readlink(const int fd, std::string* result) {
308     char path[64];
309     snprintf(path, sizeof(path), "/proc/self/fd/%d", fd);
310 
311     // Code copied from android::base::Readlink starts here :
312 
313     // Annoyingly, the readlink system call returns EINVAL for a zero-sized buffer,
314     // and truncates to whatever size you do supply, so it can't be used to query.
315     // We could call lstat first, but that would introduce a race condition that
316     // we couldn't detect.
317     // ext2 and ext4 both have PAGE_SIZE limitations, so we assume that here.
318     char buf[4096];
319     ssize_t len = readlink(path, buf, sizeof(buf));
320     if (len == -1) return false;
321 
322     result->assign(buf, len);
323     return true;
324   }
325 
326   // Returns the locally-bound name of the socket |fd|. Returns true
327   // iff. all of the following hold :
328   //
329   // - the socket's sa_family is AF_UNIX.
330   // - the length of the path is greater than zero (i.e, not an unnamed socket).
331   // - the first byte of the path isn't zero (i.e, not a socket with an abstract
332   //   address).
GetSocketName(const int fd,std::string * result)333   static bool GetSocketName(const int fd, std::string* result) {
334     sockaddr_storage ss;
335     sockaddr* addr = reinterpret_cast<sockaddr*>(&ss);
336     socklen_t addr_len = sizeof(ss);
337 
338     if (TEMP_FAILURE_RETRY(getsockname(fd, addr, &addr_len)) == -1) {
339       ALOGE("Failed getsockname(%d) : %s", fd, strerror(errno));
340       return false;
341     }
342 
343     if (addr->sa_family != AF_UNIX) {
344       ALOGE("Unsupported socket (fd=%d) with family %d", fd, addr->sa_family);
345       return false;
346     }
347 
348     const sockaddr_un* unix_addr = reinterpret_cast<const sockaddr_un*>(&ss);
349 
350     size_t path_len = addr_len - offsetof(struct sockaddr_un, sun_path);
351     // This is an unnamed local socket, we do not accept it.
352     if (path_len == 0) {
353       ALOGE("Unsupported AF_UNIX socket (fd=%d) with empty path.", fd);
354       return false;
355     }
356 
357     // This is a local socket with an abstract address, we do not accept it.
358     if (unix_addr->sun_path[0] == '\0') {
359       ALOGE("Unsupported AF_UNIX socket (fd=%d) with abstract address.", fd);
360       return false;
361     }
362 
363     // If we're here, sun_path must refer to a null terminated filesystem
364     // pathname (man 7 unix). Remove the terminator before assigning it to an
365     // std::string.
366     if (unix_addr->sun_path[path_len - 1] ==  '\0') {
367       --path_len;
368     }
369 
370     result->assign(unix_addr->sun_path, path_len);
371     return true;
372   }
373 
DetachSocket()374   bool DetachSocket() const {
375     const int dev_null_fd = open("/dev/null", O_RDWR);
376     if (dev_null_fd < 0) {
377       ALOGE("Failed to open /dev/null : %s", strerror(errno));
378       return false;
379     }
380 
381     if (dup2(dev_null_fd, fd) == -1) {
382       ALOGE("Failed dup2 on socket descriptor %d : %s", fd, strerror(errno));
383       return false;
384     }
385 
386     if (close(dev_null_fd) == -1) {
387       ALOGE("Failed close(%d) : %s", dev_null_fd, strerror(errno));
388       return false;
389     }
390 
391     return true;
392   }
393 
394   DISALLOW_COPY_AND_ASSIGN(FileDescriptorInfo);
395 };
396 
397 // A FileDescriptorTable is a collection of FileDescriptorInfo objects
398 // keyed by their FDs.
399 class FileDescriptorTable {
400  public:
401   // Creates a new FileDescriptorTable. This function scans
402   // /proc/self/fd for the list of open file descriptors and collects
403   // information about them. Returns NULL if an error occurs.
Create()404   static FileDescriptorTable* Create() {
405     DIR* d = opendir(kFdPath);
406     if (d == NULL) {
407       ALOGE("Unable to open directory %s: %s", kFdPath, strerror(errno));
408       return NULL;
409     }
410     int dir_fd = dirfd(d);
411     dirent* e;
412 
413     std::unordered_map<int, FileDescriptorInfo*> open_fd_map;
414     while ((e = readdir(d)) != NULL) {
415       const int fd = ParseFd(e, dir_fd);
416       if (fd == -1) {
417         continue;
418       }
419 
420       FileDescriptorInfo* info = FileDescriptorInfo::createFromFd(fd);
421       if (info == NULL) {
422         if (closedir(d) == -1) {
423           ALOGE("Unable to close directory : %s", strerror(errno));
424         }
425         return NULL;
426       }
427       open_fd_map[fd] = info;
428     }
429 
430     if (closedir(d) == -1) {
431       ALOGE("Unable to close directory : %s", strerror(errno));
432       return NULL;
433     }
434     return new FileDescriptorTable(open_fd_map);
435   }
436 
Restat()437   bool Restat() {
438     std::set<int> open_fds;
439 
440     // First get the list of open descriptors.
441     DIR* d = opendir(kFdPath);
442     if (d == NULL) {
443       ALOGE("Unable to open directory %s: %s", kFdPath, strerror(errno));
444       return false;
445     }
446 
447     int dir_fd = dirfd(d);
448     dirent* e;
449     while ((e = readdir(d)) != NULL) {
450       const int fd = ParseFd(e, dir_fd);
451       if (fd == -1) {
452         continue;
453       }
454 
455       open_fds.insert(fd);
456     }
457 
458     if (closedir(d) == -1) {
459       ALOGE("Unable to close directory : %s", strerror(errno));
460       return false;
461     }
462 
463     return RestatInternal(open_fds);
464   }
465 
466   // Reopens all file descriptors that are contained in the table. Returns true
467   // if all descriptors were successfully re-opened or detached, and false if an
468   // error occurred.
ReopenOrDetach()469   bool ReopenOrDetach() {
470     std::unordered_map<int, FileDescriptorInfo*>::const_iterator it;
471     for (it = open_fd_map_.begin(); it != open_fd_map_.end(); ++it) {
472       const FileDescriptorInfo* info = it->second;
473       if (info == NULL || !info->ReopenOrDetach()) {
474         return false;
475       }
476     }
477 
478     return true;
479   }
480 
481  private:
FileDescriptorTable(const std::unordered_map<int,FileDescriptorInfo * > & map)482   FileDescriptorTable(const std::unordered_map<int, FileDescriptorInfo*>& map)
483       : open_fd_map_(map) {
484   }
485 
RestatInternal(std::set<int> & open_fds)486   bool RestatInternal(std::set<int>& open_fds) {
487     bool error = false;
488 
489     // Iterate through the list of file descriptors we've already recorded
490     // and check whether :
491     //
492     // (a) they continue to be open.
493     // (b) they refer to the same file.
494     std::unordered_map<int, FileDescriptorInfo*>::iterator it = open_fd_map_.begin();
495     while (it != open_fd_map_.end()) {
496       std::set<int>::const_iterator element = open_fds.find(it->first);
497       if (element == open_fds.end()) {
498         // The entry from the file descriptor table is no longer in the list
499         // of open files. We warn about this condition and remove it from
500         // the list of FDs under consideration.
501         //
502         // TODO(narayan): This will be an error in a future android release.
503         // error = true;
504         // ALOGW("Zygote closed file descriptor %d.", it->first);
505         it = open_fd_map_.erase(it);
506       } else {
507         // The entry from the file descriptor table is still open. Restat
508         // it and check whether it refers to the same file.
509         const bool same_file = it->second->Restat();
510         if (!same_file) {
511           // The file descriptor refers to a different description. We must
512           // update our entry in the table.
513           delete it->second;
514           it->second = FileDescriptorInfo::createFromFd(*element);
515           if (it->second == NULL) {
516             // The descriptor no longer no longer refers to a whitelisted file.
517             // We flag an error and remove it from the list of files we're
518             // tracking.
519             error = true;
520             it = open_fd_map_.erase(it);
521           } else {
522             // Successfully restatted the file, move on to the next open FD.
523             ++it;
524           }
525         } else {
526           // It's the same file. Nothing to do here. Move on to the next open
527           // FD.
528           ++it;
529         }
530 
531         // Finally, remove the FD from the set of open_fds. We do this last because
532         // |element| will not remain valid after a call to erase.
533         open_fds.erase(element);
534       }
535     }
536 
537     if (open_fds.size() > 0) {
538       // The zygote has opened new file descriptors since our last inspection.
539       // We warn about this condition and add them to our table.
540       //
541       // TODO(narayan): This will be an error in a future android release.
542       // error = true;
543       // ALOGW("Zygote opened %zd new file descriptor(s).", open_fds.size());
544 
545       // TODO(narayan): This code will be removed in a future android release.
546       std::set<int>::const_iterator it;
547       for (it = open_fds.begin(); it != open_fds.end(); ++it) {
548         const int fd = (*it);
549         FileDescriptorInfo* info = FileDescriptorInfo::createFromFd(fd);
550         if (info == NULL) {
551           // A newly opened file is not on the whitelist. Flag an error and
552           // continue.
553           error = true;
554         } else {
555           // Track the newly opened file.
556           open_fd_map_[fd] = info;
557         }
558       }
559     }
560 
561     return !error;
562   }
563 
ParseFd(dirent * e,int dir_fd)564   static int ParseFd(dirent* e, int dir_fd) {
565     char* end;
566     const int fd = strtol(e->d_name, &end, 10);
567     if ((*end) != '\0') {
568       return -1;
569     }
570 
571     // Don't bother with the standard input/output/error, they're handled
572     // specially post-fork anyway.
573     if (fd <= STDERR_FILENO || fd == dir_fd) {
574       return -1;
575     }
576 
577     return fd;
578   }
579 
580   // Invariant: All values in this unordered_map are non-NULL.
581   std::unordered_map<int, FileDescriptorInfo*> open_fd_map_;
582 
583   DISALLOW_COPY_AND_ASSIGN(FileDescriptorTable);
584 };
585