首页 > 解决方案 > 使用适当的包装函数从 sk_buff 获取 pid

问题描述

这是从 Linux Kernel 中的 sk_buff 和 inode 获取 PID的后续问题,由于我无法在答案下发表评论,所以我在这里..

答案是skb->sk->socket->file->f_owner->pid

我之所以问是因为我有一种预感,即使用内核空间中的指针直接处理数据很容易出错。

我用谷歌搜索了这个,但没有发现任何有用的东西。

任何帮助或建议将不胜感激。

顺便说一句,内核版本是 4.4 或 3.10。基于最新内核头文件的解决方案也很好。

标签: clinuxmodulelinux-kernelkernel

解决方案


由于我本周正在使用 5.10.28 和 Debian 11,这就是您得到的解决方案。:-@) /usr/include/linux/pid.h(或 debian/linux-headers/usr/src/linux-headers-5.10.28/include/linux/pid.h,如果你愿意)的这条评论告诉它比我一个人做得更好:

/*
 * What is struct pid?
 *
 * A struct pid is the kernel's internal notion of a process identifier.
 * It refers to individual tasks, process groups, and sessions.  While
 * there are processes attached to it the struct pid lives in a hash
 * table, so it and then the processes that it refers to can be found
 * quickly from the numeric pid value.  The attached processes may be
 * quickly accessed by following pointers from struct pid.
 *
 * Storing pid_t values in the kernel and referring to them later has a
 * problem.  The process originally with that pid may have exited and the
 * pid allocator wrapped, and another process could have come along
 * and been assigned that pid.
 *
 * Referring to user space processes by holding a reference to struct
 * task_struct has a problem.  When the user space process exits
 * the now useless task_struct is still kept.  A task_struct plus a
 * stack consumes around 10K of low kernel memory.  More precisely
 * this is THREAD_SIZE + sizeof(struct task_struct).  By comparison
 * a struct pid is about 64 bytes.
 *
 * Holding a reference to struct pid solves both of these problems.
 * It is small so holding a reference does not consume a lot of
 * resources, and since a new struct pid is allocated when the numeric pid
 * value is reused (when pids wrap around) we don't mistakenly refer to new
 * processes.
 */

检查 pid.h 会显示一些对您有帮助的实用程序,如果您准备在内核空间中处理此问题(鉴于上面的黑暗警告,需要稍微了解命名空间等)。您的 sk_buff 包含一个指向struct pid的指针,而不仅仅是一个整数 pid,并且可能是一个用户空间进程,因为您在内核空间中,该进程现已消失。你最好的选择是这样的:

#include <pid.h>

struct pid *myspid;
pid_t mypid;

myspid = get_pid(skb->sk->socket->file->f_owner->pid);
if (myspid == NULL)
    /* forget it */
mypid = pid_nr(myspid);
return mypid;

但肯定不止于此。只是让你进入球场。


推荐阅读