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
62std::once_flag init_path_flag;
63
64struct ctx {
65    bool initialized;
66    int fd;
67    char buf[128];
68    char *buf_ptr;
69    size_t buf_len;
70};
71
72static 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
87static 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
95static 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
105static 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
129static 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
151static 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
188static 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
202static 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
227void 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
256static 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
292int 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
321static 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
340int 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