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