struct dir *dir_openat(struct dir *top_dir, const char *dirname) { struct dir *dir = _dir_new(top_dir->db, top_dir->pathname, dirname); dir->dir = opendirat(top_dir->dir, dirname); int r = (dir->dir != NULL) ? 0 : -1; DIRTRACE(dir, r, "opendirat(\"%s\")", dir->pathname); if (r == -1) { r = mkdirat(dirfd(top_dir->dir), dirname, 0700); DIRTRACE(dir, r, "mkdirat(\"%s\")", dir->pathname); if (r == 0) { dir->dir = opendirat(top_dir->dir, dirname); r = (dir->dir != NULL) ? 0 : -1; DIRTRACE(dir, r, "opendirat(\"%s\")", dir->pathname); } if (r == -1) { dir_free(dir); return NULL; } } return dir; }
bool FindProcessHoldingSocket(pid_t* pid_out, ino_t socket_inode) { bool already_found = false; DIR* proc = opendir("/proc"); if (!proc) return false; const uid_t uid = getuid(); struct dirent* dent; while ((dent = readdir(proc))) { char* endptr = NULL; errno = 0; const unsigned long int pid_ul = strtoul(dent->d_name, &endptr, 10); if (pid_ul == ULONG_MAX || !endptr || *endptr || errno != 0) continue; // We have this setuid code here because the zygote and its children have // /proc/$pid/fd owned by root. While scanning through /proc, we add this // extra check so users cannot accidentally gain information about other // users' processes. To determine process ownership, we use the property // that if user foo owns process N, then /proc/N is owned by foo. int proc_pid_fd = -1; { char buf[256]; struct stat statbuf; snprintf(buf, sizeof(buf), "/proc/%lu", pid_ul); proc_pid_fd = open(buf, O_RDONLY | O_DIRECTORY); if (proc_pid_fd < 0) continue; if (fstat(proc_pid_fd, &statbuf) < 0 || uid != statbuf.st_uid) { close(proc_pid_fd); continue; } } DIR* fd = opendirat(proc_pid_fd, "fd"); if (!fd) { close(proc_pid_fd); continue; } while ((dent = readdir(fd))) { char buf[256]; int printed = snprintf(buf, sizeof(buf), "fd/%s", dent->d_name); if (printed < 0 || printed >= (int)(sizeof(buf) - 1)) { continue; } ino_t fd_inode; if (ProcPathGetInodeAt(&fd_inode, proc_pid_fd, buf)) { if (fd_inode == socket_inode) { if (already_found) { closedir(fd); close(proc_pid_fd); closedir(proc); return false; } already_found = true; *pid_out = pid_ul; break; } } } closedir(fd); close(proc_pid_fd); } closedir(proc); return already_found; }