1 /*
2  *  Copyright 2014 Google, Inc
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 //#define LOG_NDEBUG 0
18 #define LOG_TAG "libprocessgroup"
19 
20 #include <assert.h>
21 #include <dirent.h>
22 #include <errno.h>
23 #include <fcntl.h>
24 #include <inttypes.h>
25 #include <mutex>
26 #include <stdbool.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <sys/stat.h>
31 #include <sys/types.h>
32 
33 #include <log/log.h>
34 #include <private/android_filesystem_config.h>
35 
36 #include <utils/SystemClock.h>
37 
38 #include <processgroup/processgroup.h>
39 
40 // Uncomment line below use memory cgroups for keeping track of (forked) PIDs
41 // #define USE_MEMCG 1
42 
43 #define MEM_CGROUP_PATH "/dev/memcg/apps"
44 #define MEM_CGROUP_TASKS "/dev/memcg/apps/tasks"
45 #define ACCT_CGROUP_PATH "/acct"
46 
47 #define PROCESSGROUP_UID_PREFIX "uid_"
48 #define PROCESSGROUP_PID_PREFIX "pid_"
49 #define PROCESSGROUP_CGROUP_PROCS_FILE "/cgroup.procs"
50 #define PROCESSGROUP_MAX_UID_LEN 11
51 #define PROCESSGROUP_MAX_PID_LEN 11
52 #define PROCESSGROUP_MAX_PATH_LEN \
53         ((sizeof(MEM_CGROUP_PATH) > sizeof(ACCT_CGROUP_PATH) ? \
54           sizeof(MEM_CGROUP_PATH) : sizeof(ACCT_CGROUP_PATH)) + \
55          sizeof(PROCESSGROUP_UID_PREFIX) + 1 + \
56          PROCESSGROUP_MAX_UID_LEN + \
57          sizeof(PROCESSGROUP_PID_PREFIX) + 1 + \
58          PROCESSGROUP_MAX_PID_LEN + \
59          sizeof(PROCESSGROUP_CGROUP_PROCS_FILE) + \
60          1)
61 
62 std::once_flag init_path_flag;
63 
64 struct ctx {
65     bool initialized;
66     int fd;
67     char buf[128];
68     char *buf_ptr;
69     size_t buf_len;
70 };
71 
getCgroupRootPath()72 static const char* getCgroupRootPath() {
73 #ifdef USE_MEMCG
74     static const char* cgroup_root_path = NULL;
75     std::call_once(init_path_flag, [&]() {
76             // Check if mem cgroup is mounted, only then check for write-access to avoid
77             // SELinux denials
78             cgroup_root_path = access(MEM_CGROUP_TASKS, F_OK) || access(MEM_CGROUP_PATH, W_OK) ?
79                     ACCT_CGROUP_PATH : MEM_CGROUP_PATH;
80             });
81     return cgroup_root_path;
82 #else
83     return ACCT_CGROUP_PATH;
84 #endif
85 }
86 
convertUidToPath(char * path,size_t size,uid_t uid)87 static int convertUidToPath(char *path, size_t size, uid_t uid)
88 {
89     return snprintf(path, size, "%s/%s%d",
90             getCgroupRootPath(),
91             PROCESSGROUP_UID_PREFIX,
92             uid);
93 }
94 
convertUidPidToPath(char * path,size_t size,uid_t uid,int pid)95 static int convertUidPidToPath(char *path, size_t size, uid_t uid, int pid)
96 {
97     return snprintf(path, size, "%s/%s%d/%s%d",
98             getCgroupRootPath(),
99             PROCESSGROUP_UID_PREFIX,
100             uid,
101             PROCESSGROUP_PID_PREFIX,
102             pid);
103 }
104 
initCtx(uid_t uid,int pid,struct ctx * ctx)105 static int initCtx(uid_t uid, int pid, struct ctx *ctx)
106 {
107     int ret;
108     char path[PROCESSGROUP_MAX_PATH_LEN] = {0};
109     convertUidPidToPath(path, sizeof(path), uid, pid);
110     strlcat(path, PROCESSGROUP_CGROUP_PROCS_FILE, sizeof(path));
111 
112     int fd = open(path, O_RDONLY);
113     if (fd < 0) {
114         ret = -errno;
115         SLOGW("failed to open %s: %s", path, strerror(errno));
116         return ret;
117     }
118 
119     ctx->fd = fd;
120     ctx->buf_ptr = ctx->buf;
121     ctx->buf_len = 0;
122     ctx->initialized = true;
123 
124     SLOGV("Initialized context for %s", path);
125 
126     return 0;
127 }
128 
refillBuffer(struct ctx * ctx)129 static int refillBuffer(struct ctx *ctx)
130 {
131     memmove(ctx->buf, ctx->buf_ptr, ctx->buf_len);
132     ctx->buf_ptr = ctx->buf;
133 
134     ssize_t ret = read(ctx->fd, ctx->buf_ptr + ctx->buf_len,
135                 sizeof(ctx->buf) - ctx->buf_len - 1);
136     if (ret < 0) {
137         return -errno;
138     } else if (ret == 0) {
139         return 0;
140     }
141 
142     ctx->buf_len += ret;
143     ctx->buf[ctx->buf_len] = 0;
144     SLOGV("Read %zd to buffer: %s", ret, ctx->buf);
145 
146     assert(ctx->buf_len <= sizeof(ctx->buf));
147 
148     return ret;
149 }
150 
getOneAppProcess(uid_t uid,int appProcessPid,struct ctx * ctx)151 static pid_t getOneAppProcess(uid_t uid, int appProcessPid, struct ctx *ctx)
152 {
153     if (!ctx->initialized) {
154         int ret = initCtx(uid, appProcessPid, ctx);
155         if (ret < 0) {
156             return ret;
157         }
158     }
159 
160     char *eptr;
161     while ((eptr = (char *)memchr(ctx->buf_ptr, '\n', ctx->buf_len)) == NULL) {
162         int ret = refillBuffer(ctx);
163         if (ret == 0) {
164             return -ERANGE;
165         }
166         if (ret < 0) {
167             return ret;
168         }
169     }
170 
171     *eptr = '\0';
172     char *pid_eptr = NULL;
173     errno = 0;
174     long pid = strtol(ctx->buf_ptr, &pid_eptr, 10);
175     if (errno != 0) {
176         return -errno;
177     }
178     if (pid_eptr != eptr) {
179         return -EINVAL;
180     }
181 
182     ctx->buf_len -= (eptr - ctx->buf_ptr) + 1;
183     ctx->buf_ptr = eptr + 1;
184 
185     return (pid_t)pid;
186 }
187 
removeProcessGroup(uid_t uid,int pid)188 static int removeProcessGroup(uid_t uid, int pid)
189 {
190     int ret;
191     char path[PROCESSGROUP_MAX_PATH_LEN] = {0};
192 
193     convertUidPidToPath(path, sizeof(path), uid, pid);
194     ret = rmdir(path);
195 
196     convertUidToPath(path, sizeof(path), uid);
197     rmdir(path);
198 
199     return ret;
200 }
201 
removeUidProcessGroups(const char * uid_path)202 static void removeUidProcessGroups(const char *uid_path)
203 {
204     DIR *uid = opendir(uid_path);
205     if (uid != NULL) {
206         struct dirent cur;
207         struct dirent *dir;
208         while ((readdir_r(uid, &cur, &dir) == 0) && dir) {
209             char path[PROCESSGROUP_MAX_PATH_LEN];
210 
211             if (dir->d_type != DT_DIR) {
212                 continue;
213             }
214 
215             if (strncmp(dir->d_name, PROCESSGROUP_PID_PREFIX, strlen(PROCESSGROUP_PID_PREFIX))) {
216                 continue;
217             }
218 
219             snprintf(path, sizeof(path), "%s/%s", uid_path, dir->d_name);
220             SLOGV("removing %s\n", path);
221             rmdir(path);
222         }
223         closedir(uid);
224     }
225 }
226 
removeAllProcessGroups()227 void removeAllProcessGroups()
228 {
229     SLOGV("removeAllProcessGroups()");
230     const char *cgroup_root_path = getCgroupRootPath();
231     DIR *root = opendir(cgroup_root_path);
232     if (root == NULL) {
233         SLOGE("failed to open %s: %s", cgroup_root_path, strerror(errno));
234     } else {
235         struct dirent cur;
236         struct dirent *dir;
237         while ((readdir_r(root, &cur, &dir) == 0) && dir) {
238             char path[PROCESSGROUP_MAX_PATH_LEN];
239 
240             if (dir->d_type != DT_DIR) {
241                 continue;
242             }
243             if (strncmp(dir->d_name, PROCESSGROUP_UID_PREFIX, strlen(PROCESSGROUP_UID_PREFIX))) {
244                 continue;
245             }
246 
247             snprintf(path, sizeof(path), "%s/%s", cgroup_root_path, dir->d_name);
248             removeUidProcessGroups(path);
249             SLOGV("removing %s\n", path);
250             rmdir(path);
251         }
252         closedir(root);
253     }
254 }
255 
killProcessGroupOnce(uid_t uid,int initialPid,int signal)256 static int killProcessGroupOnce(uid_t uid, int initialPid, int signal)
257 {
258     int processes = 0;
259     struct ctx ctx;
260     pid_t pid;
261 
262     ctx.initialized = false;
263 
264     while ((pid = getOneAppProcess(uid, initialPid, &ctx)) >= 0) {
265         processes++;
266         if (pid == 0) {
267             // Should never happen...  but if it does, trying to kill this
268             // will boomerang right back and kill us!  Let's not let that happen.
269             SLOGW("Yikes, we've been told to kill pid 0!  How about we don't do that.");
270             continue;
271         }
272         if (pid != initialPid) {
273             // We want to be noisy about killing processes so we can understand
274             // what is going on in the log; however, don't be noisy about the base
275             // process, since that it something we always kill, and we have already
276             // logged elsewhere about killing it.
277             SLOGI("Killing pid %d in uid %d as part of process group %d", pid, uid, initialPid);
278         }
279         int ret = kill(pid, signal);
280         if (ret == -1) {
281             SLOGW("failed to kill pid %d: %s", pid, strerror(errno));
282         }
283     }
284 
285     if (ctx.initialized) {
286         close(ctx.fd);
287     }
288 
289     return processes;
290 }
291 
killProcessGroup(uid_t uid,int initialPid,int signal)292 int killProcessGroup(uid_t uid, int initialPid, int signal)
293 {
294     int processes;
295     const int sleep_us = 5 * 1000;  // 5ms
296     int64_t startTime = android::uptimeMillis();
297     int retry = 40;
298 
299     while ((processes = killProcessGroupOnce(uid, initialPid, signal)) > 0) {
300         SLOGV("killed %d processes for processgroup %d\n", processes, initialPid);
301         if (retry > 0) {
302             usleep(sleep_us);
303             --retry;
304         } else {
305             SLOGE("failed to kill %d processes for processgroup %d\n",
306                     processes, initialPid);
307             break;
308         }
309     }
310 
311     SLOGV("Killed process group uid %d pid %d in %" PRId64 "ms, %d procs remain", uid, initialPid,
312             android::uptimeMillis()-startTime, processes);
313 
314     if (processes == 0) {
315         return removeProcessGroup(uid, initialPid);
316     } else {
317         return -1;
318     }
319 }
320 
mkdirAndChown(const char * path,mode_t mode,uid_t uid,gid_t gid)321 static int mkdirAndChown(const char *path, mode_t mode, uid_t uid, gid_t gid)
322 {
323     int ret;
324 
325     ret = mkdir(path, mode);
326     if (ret < 0 && errno != EEXIST) {
327         return -errno;
328     }
329 
330     ret = chown(path, uid, gid);
331     if (ret < 0) {
332         ret = -errno;
333         rmdir(path);
334         return ret;
335     }
336 
337     return 0;
338 }
339 
createProcessGroup(uid_t uid,int initialPid)340 int createProcessGroup(uid_t uid, int initialPid)
341 {
342     char path[PROCESSGROUP_MAX_PATH_LEN] = {0};
343     int ret;
344 
345     convertUidToPath(path, sizeof(path), uid);
346 
347     ret = mkdirAndChown(path, 0750, AID_SYSTEM, AID_SYSTEM);
348     if (ret < 0) {
349         SLOGE("failed to make and chown %s: %s", path, strerror(-ret));
350         return ret;
351     }
352 
353     convertUidPidToPath(path, sizeof(path), uid, initialPid);
354 
355     ret = mkdirAndChown(path, 0750, AID_SYSTEM, AID_SYSTEM);
356     if (ret < 0) {
357         SLOGE("failed to make and chown %s: %s", path, strerror(-ret));
358         return ret;
359     }
360 
361     strlcat(path, PROCESSGROUP_CGROUP_PROCS_FILE, sizeof(path));
362 
363     int fd = open(path, O_WRONLY);
364     if (fd < 0) {
365         ret = -errno;
366         SLOGE("failed to open %s: %s", path, strerror(errno));
367         return ret;
368     }
369 
370     char pid[PROCESSGROUP_MAX_PID_LEN + 1] = {0};
371     int len = snprintf(pid, sizeof(pid), "%d", initialPid);
372 
373     ret = write(fd, pid, len);
374     if (ret < 0) {
375         ret = -errno;
376         SLOGE("failed to write '%s' to %s: %s", pid, path, strerror(errno));
377     } else {
378         ret = 0;
379     }
380 
381     close(fd);
382     return ret;
383 }
384 
385