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