processgroup.cpp revision 32375c23284704a7d044ed79060c4431468b4b4e
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 <stdio.h>
26#include <stdlib.h>
27#include <string.h>
28#include <sys/stat.h>
29#include <sys/types.h>
30#include <unistd.h>
31
32#include <chrono>
33#include <memory>
34#include <mutex>
35#include <set>
36#include <thread>
37
38#include <android-base/logging.h>
39#include <android-base/unique_fd.h>
40#include <private/android_filesystem_config.h>
41
42#include <processgroup/processgroup.h>
43
44using namespace std::chrono_literals;
45
46#define MEM_CGROUP_PATH "/dev/memcg/apps"
47#define MEM_CGROUP_TASKS "/dev/memcg/apps/tasks"
48#define ACCT_CGROUP_PATH "/acct"
49
50#define PROCESSGROUP_UID_PREFIX "uid_"
51#define PROCESSGROUP_PID_PREFIX "pid_"
52#define PROCESSGROUP_CGROUP_PROCS_FILE "/cgroup.procs"
53#define PROCESSGROUP_MAX_UID_LEN 11
54#define PROCESSGROUP_MAX_PID_LEN 11
55#define PROCESSGROUP_MAX_PATH_LEN \
56        ((sizeof(MEM_CGROUP_PATH) > sizeof(ACCT_CGROUP_PATH) ? \
57          sizeof(MEM_CGROUP_PATH) : sizeof(ACCT_CGROUP_PATH)) + \
58         sizeof(PROCESSGROUP_UID_PREFIX) + 1 + \
59         PROCESSGROUP_MAX_UID_LEN + \
60         sizeof(PROCESSGROUP_PID_PREFIX) + 1 + \
61         PROCESSGROUP_MAX_PID_LEN + \
62         sizeof(PROCESSGROUP_CGROUP_PROCS_FILE) + \
63         1)
64
65std::once_flag init_path_flag;
66
67class ProcessGroup {
68  public:
69    ProcessGroup() : buf_ptr_(buf_), buf_len_(0) {}
70
71    bool Open(uid_t uid, int pid);
72
73    // Return positive number and sets *pid = next pid in process cgroup on success
74    // Returns 0 if there are no pids left in the process cgroup
75    // Returns -errno if an error was encountered
76    int GetOneAppProcess(pid_t* pid);
77
78  private:
79    // Returns positive number of bytes filled on success
80    // Returns 0 if there was nothing to read
81    // Returns -errno if an error was encountered
82    int RefillBuffer();
83
84    android::base::unique_fd fd_;
85    char buf_[128];
86    char* buf_ptr_;
87    size_t buf_len_;
88};
89
90static const char* getCgroupRootPath() {
91    static const char* cgroup_root_path = NULL;
92    std::call_once(init_path_flag, [&]() {
93            // Check if mem cgroup is mounted, only then check for write-access to avoid
94            // SELinux denials
95            cgroup_root_path = access(MEM_CGROUP_TASKS, F_OK) || access(MEM_CGROUP_PATH, W_OK) ?
96                    ACCT_CGROUP_PATH : MEM_CGROUP_PATH;
97            });
98    return cgroup_root_path;
99}
100
101static int convertUidToPath(char *path, size_t size, uid_t uid)
102{
103    return snprintf(path, size, "%s/%s%d",
104            getCgroupRootPath(),
105            PROCESSGROUP_UID_PREFIX,
106            uid);
107}
108
109static int convertUidPidToPath(char *path, size_t size, uid_t uid, int pid)
110{
111    return snprintf(path, size, "%s/%s%d/%s%d",
112            getCgroupRootPath(),
113            PROCESSGROUP_UID_PREFIX,
114            uid,
115            PROCESSGROUP_PID_PREFIX,
116            pid);
117}
118
119bool ProcessGroup::Open(uid_t uid, int pid) {
120    char path[PROCESSGROUP_MAX_PATH_LEN] = {0};
121    convertUidPidToPath(path, sizeof(path), uid, pid);
122    strlcat(path, PROCESSGROUP_CGROUP_PROCS_FILE, sizeof(path));
123
124    int fd = open(path, O_RDONLY);
125    if (fd < 0) return false;
126
127    fd_.reset(fd);
128
129    LOG(VERBOSE) << "Initialized context for " << path;
130
131    return true;
132}
133
134int ProcessGroup::RefillBuffer() {
135    memmove(buf_, buf_ptr_, buf_len_);
136    buf_ptr_ = buf_;
137
138    ssize_t ret = read(fd_, buf_ptr_ + buf_len_, sizeof(buf_) - buf_len_ - 1);
139    if (ret < 0) {
140        return -errno;
141    } else if (ret == 0) {
142        return 0;
143    }
144
145    buf_len_ += ret;
146    buf_[buf_len_] = 0;
147    LOG(VERBOSE) << "Read " << ret << " to buffer: " << buf_;
148
149    assert(buf_len_ <= sizeof(buf_));
150
151    return ret;
152}
153
154int ProcessGroup::GetOneAppProcess(pid_t* out_pid) {
155    *out_pid = 0;
156
157    char* eptr;
158    while ((eptr = static_cast<char*>(memchr(buf_ptr_, '\n', buf_len_))) == nullptr) {
159        int ret = RefillBuffer();
160        if (ret <= 0) return ret;
161    }
162
163    *eptr = '\0';
164    char* pid_eptr = nullptr;
165    errno = 0;
166    long pid = strtol(buf_ptr_, &pid_eptr, 10);
167    if (errno != 0) {
168        return -errno;
169    }
170    if (pid_eptr != eptr) {
171        errno = EINVAL;
172        return -errno;
173    }
174
175    buf_len_ -= (eptr - buf_ptr_) + 1;
176    buf_ptr_ = eptr + 1;
177
178    *out_pid = static_cast<pid_t>(pid);
179    return 1;
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        dirent* dir;
201        while ((dir = readdir(uid.get())) != nullptr) {
202            char path[PROCESSGROUP_MAX_PATH_LEN];
203
204            if (dir->d_type != DT_DIR) {
205                continue;
206            }
207
208            if (strncmp(dir->d_name, PROCESSGROUP_PID_PREFIX, strlen(PROCESSGROUP_PID_PREFIX))) {
209                continue;
210            }
211
212            snprintf(path, sizeof(path), "%s/%s", uid_path, dir->d_name);
213            LOG(VERBOSE) << "Removing " << path;
214            if (rmdir(path) == -1) PLOG(WARNING) << "Failed to remove " << path;
215        }
216    }
217}
218
219void removeAllProcessGroups()
220{
221    LOG(VERBOSE) << "removeAllProcessGroups()";
222    const char* cgroup_root_path = getCgroupRootPath();
223    std::unique_ptr<DIR, decltype(&closedir)> root(opendir(cgroup_root_path), closedir);
224    if (root == NULL) {
225        PLOG(ERROR) << "Failed to open " << cgroup_root_path;
226    } else {
227        dirent* dir;
228        while ((dir = readdir(root.get())) != nullptr) {
229            char path[PROCESSGROUP_MAX_PATH_LEN];
230
231            if (dir->d_type != DT_DIR) {
232                continue;
233            }
234            if (strncmp(dir->d_name, PROCESSGROUP_UID_PREFIX, strlen(PROCESSGROUP_UID_PREFIX))) {
235                continue;
236            }
237
238            snprintf(path, sizeof(path), "%s/%s", cgroup_root_path, dir->d_name);
239            removeUidProcessGroups(path);
240            LOG(VERBOSE) << "Removing " << path;
241            if (rmdir(path) == -1) PLOG(WARNING) << "Failed to remove " << path;
242        }
243    }
244}
245
246// Returns number of processes killed on success
247// Returns 0 if there are no processes in the process cgroup left to kill
248// Returns -errno on error
249static int doKillProcessGroupOnce(uid_t uid, int initialPid, int signal) {
250    ProcessGroup process_group;
251    if (!process_group.Open(uid, initialPid)) {
252        PLOG(WARNING) << "Failed to open process cgroup uid " << uid << " pid " << initialPid;
253        return -errno;
254    }
255
256    // We separate all of the pids in the cgroup into those pids that are also the leaders of
257    // process groups (stored in the pgids set) and those that are not (stored in the pids set).
258    std::set<pid_t> pgids;
259    pgids.emplace(initialPid);
260    std::set<pid_t> pids;
261
262    int ret;
263    pid_t pid;
264    int processes = 0;
265    while ((ret = process_group.GetOneAppProcess(&pid)) > 0 && pid >= 0) {
266        processes++;
267        if (pid == 0) {
268            // Should never happen...  but if it does, trying to kill this
269            // will boomerang right back and kill us!  Let's not let that happen.
270            LOG(WARNING) << "Yikes, we've been told to kill pid 0!  How about we don't do that?";
271            continue;
272        }
273        pid_t pgid = getpgid(pid);
274        if (pgid == -1) PLOG(ERROR) << "getpgid(" << pid << ") failed";
275        if (pgid == pid) {
276            pgids.emplace(pid);
277        } else {
278            pids.emplace(pid);
279        }
280    }
281
282    // Erase all pids that will be killed when we kill the process groups.
283    for (auto it = pids.begin(); it != pids.end();) {
284        pid_t pgid = getpgid(pid);
285        if (pgids.count(pgid) == 1) {
286            it = pids.erase(it);
287        } else {
288            ++it;
289        }
290    }
291
292    // Kill all process groups.
293    for (const auto pgid : pgids) {
294        LOG(VERBOSE) << "Killing process group " << -pgid << " in uid " << uid
295                     << " as part of process cgroup " << initialPid;
296
297        if (kill(-pgid, signal) == -1) {
298            PLOG(WARNING) << "kill(" << -pgid << ", " << signal << ") failed";
299        }
300    }
301
302    // Kill remaining pids.
303    for (const auto pid : pids) {
304        LOG(VERBOSE) << "Killing pid " << pid << " in uid " << uid << " as part of process cgroup "
305                     << initialPid;
306
307        if (kill(pid, signal) == -1) {
308            PLOG(WARNING) << "kill(" << pid << ", " << signal << ") failed";
309        }
310    }
311
312    return ret >= 0 ? processes : ret;
313}
314
315static int killProcessGroup(uid_t uid, int initialPid, int signal, int retries) {
316    std::chrono::steady_clock::time_point start = std::chrono::steady_clock::now();
317
318    int retry = retries;
319    int processes;
320    while ((processes = doKillProcessGroupOnce(uid, initialPid, signal)) > 0) {
321        LOG(VERBOSE) << "Killed " << processes << " processes for processgroup " << initialPid;
322        if (retry > 0) {
323            std::this_thread::sleep_for(5ms);
324            --retry;
325        } else {
326            break;
327        }
328    }
329
330    if (processes < 0) {
331        PLOG(ERROR) << "Error encountered killing process cgroup uid " << uid << " pid "
332                    << initialPid;
333        return -1;
334    }
335
336    std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now();
337    auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count();
338
339    // We only calculate the number of 'processes' when killing the processes.
340    // In the retries == 0 case, we only kill the processes once and therefore
341    // will not have waited then recalculated how many processes are remaining
342    // after the first signals have been sent.
343    // Logging anything regarding the number of 'processes' here does not make sense.
344
345    if (processes == 0) {
346        if (retries > 0) {
347            LOG(INFO) << "Successfully killed process cgroup uid " << uid << " pid " << initialPid
348                      << " in " << static_cast<int>(ms) << "ms";
349        }
350        return removeProcessGroup(uid, initialPid);
351    } else {
352        if (retries > 0) {
353            LOG(ERROR) << "Failed to kill process cgroup uid " << uid << " pid " << initialPid
354                       << " in " << static_cast<int>(ms) << "ms, " << processes
355                       << " processes remain";
356        }
357        return -1;
358    }
359}
360
361int killProcessGroup(uid_t uid, int initialPid, int signal) {
362    return killProcessGroup(uid, initialPid, signal, 40 /*retries*/);
363}
364
365int killProcessGroupOnce(uid_t uid, int initialPid, int signal) {
366    return killProcessGroup(uid, initialPid, signal, 0 /*retries*/);
367}
368
369static bool mkdirAndChown(const char *path, mode_t mode, uid_t uid, gid_t gid)
370{
371    if (mkdir(path, mode) == -1 && errno != EEXIST) {
372        return false;
373    }
374
375    if (chown(path, uid, gid) == -1) {
376        int saved_errno = errno;
377        rmdir(path);
378        errno = saved_errno;
379        return false;
380    }
381
382    return true;
383}
384
385int createProcessGroup(uid_t uid, int initialPid)
386{
387    char path[PROCESSGROUP_MAX_PATH_LEN] = {0};
388
389    convertUidToPath(path, sizeof(path), uid);
390
391    if (!mkdirAndChown(path, 0750, AID_SYSTEM, AID_SYSTEM)) {
392        PLOG(ERROR) << "Failed to make and chown " << path;
393        return -errno;
394    }
395
396    convertUidPidToPath(path, sizeof(path), uid, initialPid);
397
398    if (!mkdirAndChown(path, 0750, AID_SYSTEM, AID_SYSTEM)) {
399        PLOG(ERROR) << "Failed to make and chown " << path;
400        return -errno;
401    }
402
403    strlcat(path, PROCESSGROUP_CGROUP_PROCS_FILE, sizeof(path));
404
405    int fd = open(path, O_WRONLY);
406    if (fd == -1) {
407        int ret = -errno;
408        PLOG(ERROR) << "Failed to open " << path;
409        return ret;
410    }
411
412    char pid[PROCESSGROUP_MAX_PID_LEN + 1] = {0};
413    int len = snprintf(pid, sizeof(pid), "%d", initialPid);
414
415    int ret = 0;
416    if (write(fd, pid, len) < 0) {
417        ret = -errno;
418        PLOG(ERROR) << "Failed to write '" << pid << "' to " << path;
419    }
420
421    close(fd);
422    return ret;
423}
424