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