/* * Copyright (C) 2008 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "Process.h" #include "Utils.h" using android::base::StringPrintf; namespace android { namespace vold { static bool checkMaps(const std::string& path, const std::string& prefix) { bool found = false; auto file = std::unique_ptr{fopen(path.c_str(), "re"), fclose}; if (!file) { return false; } char* buf = nullptr; size_t len = 0; while (getline(&buf, &len, file.get()) != -1) { std::string line(buf); std::string::size_type pos = line.find('/'); if (pos != std::string::npos) { line = line.substr(pos); if (android::base::StartsWith(line, prefix)) { LOG(WARNING) << "Found map " << path << " referencing " << line; found = true; break; } } } free(buf); return found; } static bool checkSymlink(const std::string& path, const std::string& prefix) { std::string res; if (android::base::Readlink(path, &res)) { if (android::base::StartsWith(res, prefix)) { LOG(WARNING) << "Found symlink " << path << " referencing " << res; return true; } } return false; } // TODO: Refactor the code with KillProcessesWithOpenFiles(). int KillProcessesWithMounts(const std::string& prefix, int signal) { std::unordered_set pids; auto proc_d = std::unique_ptr(opendir("/proc"), closedir); if (!proc_d) { PLOG(ERROR) << "Failed to open proc"; return -1; } struct dirent* proc_de; while ((proc_de = readdir(proc_d.get())) != nullptr) { // We only care about valid PIDs pid_t pid; if (proc_de->d_type != DT_DIR) continue; if (!android::base::ParseInt(proc_de->d_name, &pid)) continue; // Look for references to prefix std::string mounts_file(StringPrintf("/proc/%d/mounts", pid)); auto fp = std::unique_ptr( setmntent(mounts_file.c_str(), "r"), endmntent); if (!fp) { PLOG(WARNING) << "Failed to open " << mounts_file; continue; } // Check if obb directory is mounted, and get all packages of mounted app data directory. mntent* mentry; while ((mentry = getmntent(fp.get())) != nullptr) { if (android::base::StartsWith(mentry->mnt_dir, prefix)) { pids.insert(pid); break; } } } if (signal != 0) { for (const auto& pid : pids) { LOG(WARNING) << "Killing pid "<< pid << " with signal " << strsignal(signal) << " because it has a mount with prefix " << prefix; kill(pid, signal); } } return pids.size(); } int KillProcessesWithOpenFiles(const std::string& prefix, int signal, bool killFuseDaemon) { std::unordered_set pids; auto proc_d = std::unique_ptr(opendir("/proc"), closedir); if (!proc_d) { PLOG(ERROR) << "Failed to open proc"; return -1; } struct dirent* proc_de; while ((proc_de = readdir(proc_d.get())) != nullptr) { // We only care about valid PIDs pid_t pid; if (proc_de->d_type != DT_DIR) continue; if (!android::base::ParseInt(proc_de->d_name, &pid)) continue; // Look for references to prefix bool found = false; auto path = StringPrintf("/proc/%d", pid); found |= checkMaps(path + "/maps", prefix); found |= checkSymlink(path + "/cwd", prefix); found |= checkSymlink(path + "/root", prefix); found |= checkSymlink(path + "/exe", prefix); auto fd_path = path + "/fd"; auto fd_d = std::unique_ptr(opendir(fd_path.c_str()), closedir); if (!fd_d) { PLOG(WARNING) << "Failed to open " << fd_path; } else { struct dirent* fd_de; while ((fd_de = readdir(fd_d.get())) != nullptr) { if (fd_de->d_type != DT_LNK) continue; found |= checkSymlink(fd_path + "/" + fd_de->d_name, prefix); } } if (found) { if (!IsFuseDaemon(pid) || killFuseDaemon) { pids.insert(pid); } else { LOG(WARNING) << "Found FUSE daemon with open file. Skipping..."; } } } if (signal != 0) { for (const auto& pid : pids) { LOG(WARNING) << "Sending " << strsignal(signal) << " to " << pid; kill(pid, signal); } } return pids.size(); } } // namespace vold } // namespace android