| /* | |
| * 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 <android/fdsan.h> | |
| #include <dirent.h> | |
| #include <errno.h> | |
| #include <stdio.h> | |
| #include <stdlib.h> | |
| #include <string.h> | |
| #include <sys/types.h> | |
| #include <unistd.h> | |
| #include <string> | |
| #include <utility> | |
| #include <vector> | |
| #include <android-base/file.h> | |
| #include <log/log.h> | |
| #include <unwindstack/Memory.h> | |
| #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, int (*)(DIR*)> 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<unwindstack::Memory> 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<std::string>& path = entry.path; | |
| const std::optional<uint64_t>& 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: <MISSING> (owned by %#" PRIx64 ")\n", prefix, fd, | |
| *fdsan_owner); | |
| } else { | |
| ALOGE("OpenFilesList contains an entry (fd %d) with no path or owner", fd); | |
| } | |
| } | |
| } | |