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 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 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 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 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 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 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 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 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 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 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 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 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