/* * Copyright (C) 2016 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. */ #define LOG_TAG "DEBUG" #include "libdebuggerd/open_files_list.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "libdebuggerd/utility.h" #include "private/bionic_fdsan.h" void populate_open_files_list(OpenFilesList* list, pid_t pid) { std::string fd_dir_name = "/proc/" + std::to_string(pid) + "/fd"; std::unique_ptr dir(opendir(fd_dir_name.c_str()), closedir); if (dir == nullptr) { ALOGE("failed to open directory %s: %s", fd_dir_name.c_str(), strerror(errno)); return; } struct dirent* de; while ((de = readdir(dir.get())) != nullptr) { if (*de->d_name == '.') { continue; } int fd = atoi(de->d_name); std::string path = fd_dir_name + "/" + std::string(de->d_name); std::string target; if (android::base::Readlink(path, &target)) { (*list)[fd].path = target; } else { (*list)[fd].path = "???"; ALOGE("failed to readlink %s: %s", path.c_str(), strerror(errno)); } } } void populate_fdsan_table(OpenFilesList* list, std::shared_ptr memory, uint64_t fdsan_table_address) { constexpr size_t inline_fds = sizeof(FdTable::entries) / sizeof(*FdTable::entries); static_assert(inline_fds == 128); size_t entry_offset = offsetof(FdTable, entries); for (size_t i = 0; i < inline_fds; ++i) { uint64_t address = fdsan_table_address + entry_offset + sizeof(FdEntry) * i; FdEntry entry; if (!memory->Read(address, &entry, sizeof(entry))) { ALOGE("failed to read fdsan table entry %zu: %s", i, strerror(errno)); return; } if (entry.close_tag) { (*list)[i].fdsan_owner = entry.close_tag.load(); } } size_t overflow_offset = offsetof(FdTable, overflow); uintptr_t overflow = 0; if (!memory->Read(fdsan_table_address + overflow_offset, &overflow, sizeof(overflow))) { ALOGE("failed to read fdsan table overflow pointer: %s", strerror(errno)); return; } if (!overflow) { return; } size_t overflow_length; if (!memory->Read(overflow, &overflow_length, sizeof(overflow_length))) { ALOGE("failed to read fdsan overflow table length: %s", strerror(errno)); return; } if (overflow_length > 131072) { ALOGE("unreasonable large fdsan overflow table size %zu, bailing out", overflow_length); return; } for (size_t i = 0; i < overflow_length; ++i) { int fd = i + inline_fds; uint64_t address = overflow + offsetof(FdTableOverflow, entries) + i * sizeof(FdEntry); FdEntry entry; if (!memory->Read(address, &entry, sizeof(entry))) { ALOGE("failed to read fdsan overflow entry for fd %d: %s", fd, strerror(errno)); return; } if (entry.close_tag) { (*list)[fd].fdsan_owner = entry.close_tag; } } return; } void dump_open_files_list(log_t* log, const OpenFilesList& files, const char* prefix) { for (auto& [fd, entry] : files) { const std::optional& path = entry.path; const std::optional& fdsan_owner = entry.fdsan_owner; if (path && fdsan_owner) { const char* type = android_fdsan_get_tag_type(*fdsan_owner); uint64_t value = android_fdsan_get_tag_value(*fdsan_owner); _LOG(log, logtype::OPEN_FILES, "%sfd %i: %s (owned by %s %#" PRIx64 ")\n", prefix, fd, path->c_str(), type, value); } else if (path && !fdsan_owner) { _LOG(log, logtype::OPEN_FILES, "%sfd %i: %s (unowned)\n", prefix, fd, path->c_str()); } else if (!path && fdsan_owner) { _LOG(log, logtype::OPEN_FILES, "%sfd %i: (owned by %#" PRIx64 ")\n", prefix, fd, *fdsan_owner); } else { ALOGE("OpenFilesList contains an entry (fd %d) with no path or owner", fd); } } }