无法在 WSL2 中获得正确的 pid

Can not get correct pid in WSL2

我正在学习 Linux 编程。
当我尝试编写一个简单的模块来获取进程系列时,我发现我无法获取进程及其父进程的当前 pid。如何解决?
这是我的代码的一部分。

static pid_t pid = 1;
module_param(pid, int, 0644);

static int hello_init(void) {
    struct task_struct *p;
    struct list_head *pp;
    struct task_struct *psibling;
    struct pid *kpid;

    kpid = find_get_pid(pid);
    p = pid_task(kpid, PIDTYPE_PID);
    printk("me: %d %s\n", pid, p->comm);
    if (p->parent == NULL) {
        printk("No Parent\n");
    }
    else {
        printk("Parent: %d %s\n", p->parent->pid, p->parent->comm);
    }
    list_for_each(pp, &p->parent->children) {
        psibling = list_entry(pp, struct task_struct, sibling);
        printk("sibling %d %s \n", psibling->pid, psibling->comm);
    }
    list_for_each(pp, &p->children) {
        psibling = list_entry(pp, struct task_struct, sibling);
        printk("children %d %s \n", psibling->pid, psibling->comm);
    }
    return 0;
}

结果:

sudo insmod module.ko pid=1
dmesg
[ 6396.170631] me: 237 systemd
[ 6396.170633] Parent: 235 unshare
[ 6396.170633] sibling 237 systemd
[ 6396.170633] children 286 systemd-journal
[ 6396.170634] children 306 systemd-udevd
[ 6396.170635] children 314 systemd-network
[ 6396.170635] children 501 snapfuse
[ 6396.170636] children 508 dbus-daemon
[ 6396.170636] children 509 NetworkManager
[ 6396.170637] children 632 systemd-logind
[ 6396.170637] children 639 systemd
[ 6396.170638] children 665 rtkit-daemon
[ 6396.170638] children 671 polkitd
[ 6396.170638] children 711 udisksd
[ 6396.170639] children 761 upowerd

我不是 Linux 系统开发专家,但我会根据您的尝试尝试提供帮助。

首先,您没有在问题中提及它,但您显然 运行正在启用某种 Systemd。如您所知,WSL 通常不支持 Systemd。在高层次上,在 WSL 上启用 Systemd 的脚本都有两个基本功能:

  • 创建一个新的 PID 命名空间,其中 Systemd 运行宁作为 PID1。在最基本的层面上,这可以通过以下方式完成:

    sudo -b unshare --pid --fork --mount-proc /lib/systemd/systemd --system-unit=basic.target
    

    我们可以在返回的进程列表中看到 unshare,所以它至少被调用了。

  • 等待Systemd完全启动,然后进入上面创建的命名空间。这通常类似于:

    sudo -E nsenter --all -t $(pgrep -xo systemd) $SHELL
    

    为了处理多个 shells、分布等,实际的脚本通常要复杂一些。它们还试图在命名空间内保留更多的 WSL 环境,以启用互操作功能比如运行ning Windows .exes。但核心概念始终相同。

所以,在这里猜测(同样,作为一个非系统开发人员),似乎是:

  • kpid=find_get_pid(1) 正在返回命名空间

    内的 systemd 进程
  • pid_task(kpid, PIDTYPE_PID) 正在从根名称空间返回“真实”进程信息。

    在我看来,代码必须 运行ning 在名称空间之外,因为您将 unshare 视为其中的一部分。在命名空间中,unshare 不存在。您可以使用 ps -ef | grep unshare.

    验证这一点(在命名空间内)

至少有两种可能的解决方案:

  • 如果这不是问题(从评论来看,它不是),那么只需 运行 来自根 pid 命名空间的代码。我假设您的 Systemd 脚本是 运行ning 通过您的 shell 启动文件,因此您应该能够通过使用 wsl ~ -e bash --noprofile --norc 之类的东西启动来返回到根命名空间。这将在没有任何启动脚本的情况下启动 shell。

    当然,您使用的任何脚本都可能记录了其他禁用 Systemd 脚本的技术。

  • 如果您确实希望您的代码在 PID 命名空间内正常工作,那么您可能需要找到命名空间(我将从 lsns 的源开始一个例子)。 然后在该命名空间中找到任务结构(可能 find_task_by_pid_ns?)。