• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2008 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 /*
18 ** mountd process killer
19 */
20 
21 #include "vold.h"
22 
23 #include <stdio.h>
24 #include <unistd.h>
25 #include <string.h>
26 #include <fcntl.h>
27 #include <dirent.h>
28 #include <ctype.h>
29 #include <pwd.h>
30 #include <stdlib.h>
31 #include <poll.h>
32 #include <sys/stat.h>
33 
34 
ReadSymLink(const char * path,char * link)35 static boolean ReadSymLink(const char* path, char* link)
36 {
37     struct stat s;
38     int length;
39 
40     if (lstat(path, &s) < 0)
41         return false;
42     if ((s.st_mode & S_IFMT) != S_IFLNK)
43         return false;
44 
45     // we have a symlink
46     length = readlink(path, link, PATH_MAX - 1);
47     if (length <= 0)
48         return false;
49     link[length] = 0;
50     return true;
51 }
52 
PathMatchesMountPoint(const char * path,const char * mountPoint)53 static boolean PathMatchesMountPoint(const char* path, const char* mountPoint)
54 {
55     int length = strlen(mountPoint);
56     if (length > 1 && strncmp(path, mountPoint, length) == 0)
57     {
58         // we need to do extra checking if mountPoint does not end in a '/'
59         if (mountPoint[length - 1] == '/')
60             return true;
61         // if mountPoint does not have a trailing slash, we need to make sure
62         // there is one in the path to avoid partial matches.
63         return (path[length] == 0 || path[length] == '/');
64     }
65 
66     return false;
67 }
68 
GetProcessName(int pid,char buffer[PATH_MAX])69 static void GetProcessName(int pid, char buffer[PATH_MAX])
70 {
71     int fd;
72     sprintf(buffer, "/proc/%d/cmdline", pid);
73     fd = open(buffer, O_RDONLY);
74     if (fd < 0) {
75         strcpy(buffer, "???");
76     } else {
77         int length = read(fd, buffer, PATH_MAX - 1);
78         buffer[length] = 0;
79         close(fd);
80     }
81 }
82 
CheckFileDescriptorSymLinks(int pid,const char * mountPoint)83 static boolean CheckFileDescriptorSymLinks(int pid, const char* mountPoint)
84 {
85     DIR*    dir;
86     struct dirent* de;
87     boolean fileOpen = false;
88     char    path[PATH_MAX];
89     char    link[PATH_MAX];
90     int     parent_length;
91 
92     // compute path to process's directory of open files
93     sprintf(path, "/proc/%d/fd", pid);
94     dir = opendir(path);
95     if (!dir)
96         return false;
97 
98     // remember length of the path
99     parent_length = strlen(path);
100     // append a trailing '/'
101     path[parent_length++] = '/';
102 
103     while ((de = readdir(dir)) != 0 && !fileOpen) {
104         if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."))
105             continue;
106 
107         // append the file name, after truncating to parent directory
108         path[parent_length] = 0;
109         strcat(path, de->d_name);
110 
111         if (ReadSymLink(path, link) && PathMatchesMountPoint(link, mountPoint))
112         {
113             char    name[PATH_MAX];
114             GetProcessName(pid, name);
115             LOG_ERROR("process %s (%d) has open file %s", name, pid, link);
116             fileOpen = true;
117         }
118     }
119 
120     closedir(dir);
121     return fileOpen;
122 }
123 
CheckFileMaps(int pid,const char * mountPoint)124 static boolean CheckFileMaps(int pid, const char* mountPoint)
125 {
126     FILE*   file;
127     char    buffer[PATH_MAX + 100];
128     boolean mapOpen = false;
129 
130     sprintf(buffer, "/proc/%d/maps", pid);
131     file = fopen(buffer, "r");
132     if (!file)
133         return false;
134 
135     while (!mapOpen && fgets(buffer, sizeof(buffer), file))
136     {
137         // skip to the path
138         const char* path = strchr(buffer, '/');
139         if (path && PathMatchesMountPoint(path, mountPoint))
140         {
141             char    name[PATH_MAX];
142             GetProcessName(pid, name);
143             LOG_ERROR("process %s (%d) has open file map for %s", name, pid, path);
144             mapOpen = true;
145         }
146     }
147 
148     fclose(file);
149     return mapOpen;
150 }
151 
CheckSymLink(int pid,const char * mountPoint,const char * name,const char * message)152 static boolean CheckSymLink(int pid, const char* mountPoint, const char* name, const char* message)
153 {
154     char    path[PATH_MAX];
155     char    link[PATH_MAX];
156 
157     sprintf(path, "/proc/%d/%s", pid, name);
158     if (ReadSymLink(path, link) && PathMatchesMountPoint(link, mountPoint))
159     {
160         char    name[PATH_MAX];
161         GetProcessName(pid, name);
162         LOG_ERROR("process %s (%d) has %s in %s", name, pid, message, mountPoint);
163         return true;
164     }
165     else
166         return false;
167 }
168 
get_pid(const char * s)169 static int get_pid(const char* s)
170 {
171     int result = 0;
172     while (*s) {
173         if (!isdigit(*s)) return -1;
174         result = 10 * result + (*s++ - '0');
175     }
176     return result;
177 }
178 
179 // hunt down and kill processes that have files open on the given mount point
KillProcessesWithOpenFiles(const char * mountPoint,boolean sigkill,int * excluded,int num_excluded)180 void KillProcessesWithOpenFiles(const char* mountPoint, boolean sigkill, int *excluded, int num_excluded)
181 {
182     DIR*    dir;
183     struct dirent* de;
184 
185     LOG_ERROR("KillProcessesWithOpenFiles %s", mountPoint);
186     dir = opendir("/proc");
187     if (!dir) return;
188 
189     while ((de = readdir(dir)) != 0)
190     {
191         boolean killed = false;
192         // does the name look like a process ID?
193         int pid = get_pid(de->d_name);
194         if (pid == -1) continue;
195 
196         if (CheckFileDescriptorSymLinks(pid, mountPoint)    // check for open files
197                 || CheckFileMaps(pid, mountPoint)           // check for mmap()
198                 || CheckSymLink(pid, mountPoint, "cwd", "working directory")    // check working directory
199                 || CheckSymLink(pid, mountPoint, "root", "chroot")              // check for chroot()
200                 || CheckSymLink(pid, mountPoint, "exe", "executable path")      // check executable path
201             )
202         {
203             int i;
204             boolean hit = false;
205 
206             for (i = 0; i < num_excluded; i++) {
207                 if (pid == excluded[i]) {
208                     LOG_ERROR("I just need a little more TIME captain!");
209                     hit = true;
210                     break;
211                 }
212             }
213 
214             if (!hit) {
215                 LOG_ERROR("Killing process %d", pid);
216                 kill(pid, (sigkill ? SIGKILL : SIGTERM));
217             }
218         }
219     }
220 
221     closedir(dir);
222 }
223