mirror of
https://github.com/lucannez64/darling-lol.git
synced 2026-10-26 19:47:42 +00:00
Implement proc_listpids in the kernel emulation
proc_info callnum 1 (proc_listpids) previously fell through to the unsupported-callnum path and returned ENOTSUP, so process enumeration (e.g. the Riot client's Vanguard kext probe) logged 'sys_proc_info(): Unsupported callnum: 1'. Walk /proc like _sysctl_proc and _proc_pidinfo_listthreads already do and mirror XNU's filter semantics for PROC_ALL_PIDS, PROC_PGRP_ONLY, PROC_PPID_ONLY, PROC_TTY_ONLY, PROC_UID_ONLY and PROC_RUID_ONLY, with XNU's size-query, ENOMEM and truncation contracts.
This commit is contained in:
1 parent
7bb4554e8f
commit
ac4a832ebc
1 file changed
+162
-2
+162
-2
@@ -3221,10 +3221,18 @@ index 0000000..479294a
|
||||
+ return -ENOSYS;
|
||||
+}
|
||||
diff --git a/darling/src/libsystem_kernel/emulation/src/xnu_syscall/bsd/impl/misc/proc_info.c b/darling/src/libsystem_kernel/emulation/src/xnu_syscall/bsd/impl/misc/proc_info.c
|
||||
index c2f70fb..af904ed 100644
|
||||
index c2f70fb..73c2a5a 100644
|
||||
--- a/darling/src/libsystem_kernel/emulation/src/xnu_syscall/bsd/impl/misc/proc_info.c
|
||||
+++ b/darling/src/libsystem_kernel/emulation/src/xnu_syscall/bsd/impl/misc/proc_info.c
|
||||
@@ -83,6 +83,38 @@ long sys_proc_info(uint32_t callnum, int32_t pid, uint32_t flavor,
|
||||
@@ -35,6 +35,7 @@
|
||||
#define LINUX_PR_SET_NAME 15
|
||||
|
||||
static long _proc_pidinfo(int32_t pid, uint32_t flavor, uint64_t arg, void* buffer, int32_t bufsize);
|
||||
+static long _proc_listpids(uint32_t type, uint32_t typeinfo, void* buffer, int32_t bufsize);
|
||||
|
||||
extern __SIZE_TYPE__ strlen(const char *s);
|
||||
extern void *memset(void *s, int c, __SIZE_TYPE__ n);
|
||||
@@ -83,7 +84,42 @@ long sys_proc_info(uint32_t callnum, int32_t pid, uint32_t flavor,
|
||||
case 2: // proc_pidinfo
|
||||
return _proc_pidinfo(pid, flavor, arg, buffer, bufsize);
|
||||
case 3: // proc_pidfdinfo
|
||||
@@ -3261,8 +3269,160 @@ index c2f70fb..af904ed 100644
|
||||
+ return -ENOTSUP;
|
||||
+ }
|
||||
case 1: // proc_listpids
|
||||
+ // `pid` carries the process type and `flavor` carries the type
|
||||
+ // info (e.g. the pgid, ppid or uid to match).
|
||||
+ return _proc_listpids(pid, flavor, buffer, bufsize);
|
||||
default:
|
||||
__simple_printf("sys_proc_info(): Unsupported callnum: %d\n",
|
||||
callnum);
|
||||
@@ -827,3 +863,147 @@ bail:
|
||||
close_internal(fd);
|
||||
return count * sizeof(uint64_t);
|
||||
}
|
||||
+
|
||||
+// Returns whether `pid` should be included in a proc_listpids() query of the
|
||||
+// given `type`, matching the semantics of XNU's bsd/kern/proc_info.c.
|
||||
+static bool _proc_listpids_match(uint32_t type, uint32_t typeinfo, int32_t pid,
|
||||
+ int32_t uid)
|
||||
+{
|
||||
+ char path[64], stat[1024];
|
||||
+ char* statptr;
|
||||
+ const char* elem;
|
||||
+ int32_t ppid, pgrp, tty;
|
||||
+
|
||||
+ switch (type)
|
||||
+ {
|
||||
+ case PROC_ALL_PIDS:
|
||||
+ return true;
|
||||
+
|
||||
+ case PROC_UID_ONLY:
|
||||
+ case PROC_RUID_ONLY:
|
||||
+ // Darling's container runs every guest process as our own
|
||||
+ // user, which is also what _sysctl_proc() reports.
|
||||
+ return typeinfo == (uint32_t) uid;
|
||||
+
|
||||
+ case PROC_PGRP_ONLY:
|
||||
+ case PROC_PPID_ONLY:
|
||||
+ case PROC_TTY_ONLY:
|
||||
+ break;
|
||||
+
|
||||
+ default:
|
||||
+ // PROC_KDBG_ONLY and anything else: no process carries the
|
||||
+ // corresponding state under Darling.
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
+ __simple_sprintf(path, "/proc/%d/stat", pid);
|
||||
+ if (!read_string(path, stat, sizeof(stat)))
|
||||
+ return false;
|
||||
+
|
||||
+ statptr = stat;
|
||||
+ skip_stat_elems(&statptr, 1); // pid
|
||||
+
|
||||
+ if (!(elem = next_stat_elem(&statptr)))
|
||||
+ return false;
|
||||
+ // comm
|
||||
+
|
||||
+ if (!(elem = next_stat_elem(&statptr)))
|
||||
+ return false;
|
||||
+ // state
|
||||
+
|
||||
+ if (!(elem = next_stat_elem(&statptr)))
|
||||
+ return false;
|
||||
+ ppid = __simple_atoi(elem, NULL);
|
||||
+
|
||||
+ if (!(elem = next_stat_elem(&statptr)))
|
||||
+ return false;
|
||||
+ pgrp = __simple_atoi(elem, NULL);
|
||||
+
|
||||
+ if (type == PROC_PPID_ONLY)
|
||||
+ return ppid == (int32_t) typeinfo;
|
||||
+
|
||||
+ if (type == PROC_PGRP_ONLY)
|
||||
+ return pgrp == (int32_t) typeinfo;
|
||||
+
|
||||
+ // PROC_TTY_ONLY: the (Linux-encoded) controlling terminal device.
|
||||
+ if (!(elem = next_stat_elem(&statptr)))
|
||||
+ return false;
|
||||
+ // session
|
||||
+
|
||||
+ if (!(elem = next_stat_elem(&statptr)))
|
||||
+ return false;
|
||||
+ tty = __simple_atoi(elem, NULL);
|
||||
+
|
||||
+ return tty != 0 && (uint32_t) tty == typeinfo;
|
||||
+}
|
||||
+
|
||||
+// Emulates XNU's proc_listpids(), i.e. proc_info(PROC_INFO_CALL_LISTPIDS).
|
||||
+// Guest pids are Linux pids, so walking /proc gives the same set that the
|
||||
+// other proc_info flavors and sysctl(KERN_PROC_*) already operate on.
|
||||
+static long _proc_listpids(uint32_t type, uint32_t typeinfo, void* buffer, int32_t bufsize)
|
||||
+{
|
||||
+ char dents[256];
|
||||
+ long basep = 0;
|
||||
+ int fd, ret;
|
||||
+ int32_t maxpids, count = 0;
|
||||
+ static int uid = -1;
|
||||
+
|
||||
+ if (type != PROC_ALL_PIDS && type != PROC_PGRP_ONLY && type != PROC_TTY_ONLY &&
|
||||
+ type != PROC_UID_ONLY && type != PROC_RUID_ONLY &&
|
||||
+ type != PROC_PPID_ONLY && type != PROC_KDBG_ONLY)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ if (buffer && bufsize < (int32_t) sizeof(int))
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ // A null buffer asks for the size a caller should allocate.
|
||||
+ maxpids = buffer ? (bufsize / (int32_t) sizeof(int)) : 0;
|
||||
+
|
||||
+ if (uid == -1)
|
||||
+ uid = sys_getuid();
|
||||
+
|
||||
+ fd = sys_open_nocancel("/proc", BSD_O_RDONLY | BSD_O_DIRECTORY, 0);
|
||||
+ if (fd < 0)
|
||||
+ return fd;
|
||||
+
|
||||
+ while ((ret = sys_getdirentries(fd, (char*) dents, sizeof(dents), &basep)) > 0)
|
||||
+ {
|
||||
+ int pos = 0;
|
||||
+
|
||||
+ while (pos < ret)
|
||||
+ {
|
||||
+ struct bsd_dirent* dent = (struct bsd_dirent*) &dents[pos];
|
||||
+
|
||||
+ pos += dent->d_reclen;
|
||||
+
|
||||
+ if (dent->d_type != DT_DIR || !isdigit(dent->d_name[0]))
|
||||
+ continue;
|
||||
+
|
||||
+ int pid = __simple_atoi(dent->d_name, NULL);
|
||||
+
|
||||
+ if (!_proc_listpids_match(type, typeinfo, pid, uid))
|
||||
+ continue;
|
||||
+
|
||||
+ if (buffer)
|
||||
+ {
|
||||
+ // Truncate rather than overflow, like XNU does.
|
||||
+ if (count >= maxpids)
|
||||
+ goto bail;
|
||||
+
|
||||
+ ((int*) buffer)[count] = pid;
|
||||
+ }
|
||||
+
|
||||
+ ++count;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+bail:
|
||||
+ close_internal(fd);
|
||||
+
|
||||
+ // XNU reports a little extra headroom so that a size query followed by a
|
||||
+ // fill call cannot come up short when processes appear in between.
|
||||
+ if (!buffer)
|
||||
+ return (long)(count + 20) * sizeof(int);
|
||||
+
|
||||
+ return (long) count * sizeof(int);
|
||||
+}
|
||||
diff --git a/darling/src/libsystem_kernel/emulation/src/xnu_syscall/bsd/impl/misc/ptrace.c b/darling/src/libsystem_kernel/emulation/src/xnu_syscall/bsd/impl/misc/ptrace.c
|
||||
index 0a8f1e4..55aadbe 100644
|
||||
--- a/darling/src/libsystem_kernel/emulation/src/xnu_syscall/bsd/impl/misc/ptrace.c
|
||||
|
||||
Reference in new issue
Block a user