# HG changeset patch # User Paper # Date 1712963630 14400 # Node ID 0718f538c5f91bc5f1fc9106a21065bc34018401 # Parent 3efac054115112c68a7c2fe45d6fe70f6fd6e978 dep/animone: filter open files by access mode diff -r 3efac0541151 -r 0718f538c5f9 dep/animone/configure.ac --- a/dep/animone/configure.ac Fri Apr 12 05:23:45 2024 -0400 +++ b/dep/animone/configure.ac Fri Apr 12 19:13:50 2024 -0400 @@ -42,18 +42,15 @@ ;; *) dnl BSDs - build_bsd=yes - AC_DEFINE([BSD]) AC_CHECK_LIB([util], [kinfo_getfile], [build_libutil=yes], [build_libutil=no]) - - dnl if we have this function it means kvm_openfiles likely also supports NULL values, - dnl i.e., loading the currently running kernel AC_CHECK_LIB([kvm], [kvm_getfiles], [build_kvm=yes], [build_kvm=no]) if test "x$build_kvm" = "xyes"; then AC_DEFINE([LIBKVM]) + AC_DEFINE([BSD]) elif test "x$build_libutil" = "xyes"; then AC_DEFINE([LIBUTIL]) + AC_DEFINE([BSD]) fi ;; esac diff -r 3efac0541151 -r 0718f538c5f9 dep/animone/src/fd/bsd.cc --- a/dep/animone/src/fd/bsd.cc Fri Apr 12 05:23:45 2024 -0400 +++ b/dep/animone/src/fd/bsd.cc Fri Apr 12 19:13:50 2024 -0400 @@ -13,6 +13,7 @@ #ifdef HAVE_KVM_GETFILES # include +# include #elif defined(LIBUTIL) # include #endif @@ -110,10 +111,8 @@ return false; /* actually get our results */ - if (sysctl((const int*)mib, (sizeof(mib) / sizeof(*mib)) - 1, result.get(), &length, NULL, 0) == ENOMEM) { - result.reset(); - throw std::bad_alloc(); - } + if (sysctl((const int*)mib, (sizeof(mib) / sizeof(*mib)) - 1, result.get(), &length, NULL, 0) == ENOMEM) + return false; if (length < sizeof(struct kinfo_proc)) return false; @@ -126,10 +125,47 @@ #endif } +#ifdef HAVE_KVM_GETFILES +static bool GetOpenFileName(const struct kinfo_file& file, std::string& name) { + /* OpenBSD doesn't provide a native API for this, so we have + * to do it ourselves */ + static constexpr std::string_view root = "/"; + + FTS* file_system = fts_open(root.data(), FTS_COMFOLLOW | FTS_NOCHDIR, nullptr); + if (!file_system) + return false; + + /* Search through the filesystem for a file that matches our + * kinfo_file structure */ + FTSENT* parent = nullptr; + while ((parent = fts_read(file_system))) { + FTSENT* child = fts_children(file_system, 0); + while (child && child->fts_link) { + child = child->fts_link; + if (!S_ISREG(child->fts_statp->st_mode) || !S_ISLNK(child->fts_statp->st_mode)) + continue; + + if (child->fts_statp->st_dev != file->va_fsid) + continue; + + if (child->fts_statp->st_ino != file->va_fileid) + continue; + + name = std::string(child->fts_path) + child->fts_name; + fts_close(file_system); + return true; + } + } + + fts_close(filesystem); + return false; +} +#endif /* HAVE_KVM_GETFILES */ + bool EnumerateOpenFiles(const std::set& pids, open_file_proc_t open_file_proc) { #ifdef HAVE_KVM_GETFILES char errbuf[_POSIX2_LINE_MAX]; - kvm_t* kernel = kvm_openfiles(NULL, NULL, NULL, O_RDONLY, errbuf); + kvm_t* kernel = kvm_openfiles(nullptr, nullptr, nullptr, O_RDONLY, errbuf); if (!kernel) return false; @@ -142,7 +178,15 @@ } for (int i = 0; i < cnt; i++) { - if (!open_file_proc({pid, kfile[i].kf_path})) { + uint32_t oflags = kfile[i].kf_flags & O_ACCMODE; + if (oflags == O_WRONLY || oflags == O_RDWR) + continue; + + std::string name; + if (!GetOpenFileName(kfile[i], name)) + continue; + + if (!open_file_proc({pid, name})) { kvm_close(kernel); return false; } @@ -150,10 +194,8 @@ } kvm_close(kernel); - return true; #elif defined(LIBUTIL) - /* does this code even work? */ for (const auto& pid : pids) { int cnt; std::unique_ptr files(kinfo_getfile(pid, &cnt)); @@ -162,7 +204,11 @@ for (int i = 0; i < cnt; i++) { const struct kinfo_file& current = files[i]; - if (current.kf_vnode_type != KF_VTYPE_VREG) + if (current.kf_vnode_type != KF_VTYPE_VREG || current.kf_vnode_type != KF_VTYPE_VLNK) + continue; + + const int oflags = current.kf_flags & O_ACCMODE; + if (oflags == O_WRONLY || oflags == O_RDWR) continue; if (!open_file_proc({pid, current.kf_path})) @@ -172,29 +218,8 @@ return true; #else - for (const auto& pid : pids) { - int mib[6] = {CTL_KERN, KERN_FILE2, KERN_FILE_BYPID, pid, sizeof(struct kinfo_file), 0}; - - size_t len = 0; - if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), NULL, &len, NULL, 0) == -1) - return false; - - mib[5] = len / sizeof(struct kinfo_file); - - std::unique_ptr buf(new struct kinfo_file[mib[5]]); - if (!buf) - return false; - - if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), buf.get(), &len, NULL, 0) == -1) - return false; - - /* TODO: check kfile[i].ki_ofileflags */ - for (size_t i = 0; i < mib[5]; i++) - if (!open_file_proc({pid, kfile[i].kf_path})) - return false; - } - - return true; + /* NetBSD doesn't even provide a real API for this */ + return false; #endif } diff -r 3efac0541151 -r 0718f538c5f9 dep/animone/src/fd/proc.cc --- a/dep/animone/src/fd/proc.cc Fri Apr 12 05:23:45 2024 -0400 +++ b/dep/animone/src/fd/proc.cc Fri Apr 12 19:13:50 2024 -0400 @@ -36,7 +36,9 @@ if (line.find("flags:", 0) == 0) flags = util::StringToInt(line.substr(line.find_last_not_of("0123456789") + 1)); - if (flags & O_WRONLY || flags & O_RDWR) + /* check if the file was opened in a write mode */ + int accflags = flags & O_ACCMODE; + if (accflags == O_WRONLY || accflags == O_RDWR) return false; return true; @@ -65,11 +67,9 @@ static constexpr std::array invalid_paths = {"/boot", "/dev", "/bin", "/usr", "/opt", "/proc", "/var", "/etc", "/dev"}; - for (const auto& invalid_path : invalid_paths) { - if (!path.rfind(invalid_path, 0)) { + for (const auto& invalid_path : invalid_paths) + if (!path.rfind(invalid_path, 0)) return true; - } - } return false; } diff -r 3efac0541151 -r 0718f538c5f9 dep/animone/src/fd/xnu.cc --- a/dep/animone/src/fd/xnu.cc Fri Apr 12 05:23:45 2024 -0400 +++ b/dep/animone/src/fd/xnu.cc Fri Apr 12 19:13:50 2024 -0400 @@ -14,6 +14,18 @@ #include #include +/* you may be asking: WTF is FWRITE? + * well, from bsd/sys/fcntl.h in the XNU kernel: + * + * Kernel encoding of open mode; separate read and write bits that are + * independently testable: 1 greater than [O_RDONLY and O_WRONLY]. + * + * It's just how the kernel defines write mode. +*/ +#ifndef FWRITE +#define FWRITE 0x0002 +#endif + namespace animone::internal::xnu { bool EnumerateOpenProcesses(process_proc_t process_proc) { @@ -66,11 +78,9 @@ if (sz != PROC_PIDFDVNODEPATHINFO_SIZE) return false; - // This doesn't work (for unknown reasons). I assume somethings fucked up with - // my assumptions; I don't care enough to look into it tbh - // - // if (vnodeInfo.pfi.fi_openflags & O_WRONLY || vnodeInfo.pfi.fi_openflags & O_RDWR) - // continue; + /* why would a media player open a file in write mode? */ + if (vnodeInfo.pfi.fi_openflags & FWRITE) + continue; if (!open_file_proc({pid, vnodeInfo.pvip.vip_path})) return false;