【问题标题】:How to use proc_pid_cmdline in kernel module如何在内核模块中使用 proc_pid_cmdline
【发布时间】:2014-08-30 10:40:10
【问题描述】:

我正在编写一个内核模块来获取具有完整进程名称的 pid 列表。 proc_pid_cmdline() 给出完整的进程名称;使用相同的函数/proc/*/cmdline 得到完整的进程名称。 (struct task_struct) -> comm 提示它是什么进程,但不是完整路径。

我已经包含了函数名,但它给出了错误,因为它不知道在哪里可以找到函数。

如何在模块中使用proc_pid_cmdline()

【问题讨论】:

  • 您必须定义什么是进程名称,因为 Linux(和 Unix)根本不使用进程名称。

标签: linux kernel


【解决方案1】:

你不应该打电话给proc_pid_cmdline()

fs/proc/base.c中的non-public function

static int proc_pid_cmdline(struct seq_file *m, struct pid_namespace *ns,
                            struct pid *pid, struct task_struct *task)

不过,它的作用很简单:

get_cmdline(task, m->buf, PAGE_SIZE);

这不太可能返回完整路径,并且不可能在每种情况下都确定完整路径。 arg[0] 值可能会被覆盖,文件可能会被删除或移动等。进程可能会 exec() 以掩盖原始命令行的方式以及各种其他问题。

扫描我的 Fedora 20 系统 /proc/*/cmdline 会发现各种无用的结果:

-F
BUG:
WARNING: at
WARNING: CPU:
INFO: possible recursive locking detecte
ernel BUG at
list_del corruption
list_add corruption
do_IRQ: stack overflow:
ear stack overflow (cur:
eneral protection fault
nable to handle kernel
ouble fault:
RTNL: assertion failed
eek! page_mapcount(page) went negative!
adness at
NETDEV WATCHDOG
ysctl table check failed
: nobody cared
IRQ handler type mismatch
Machine Check Exception:
Machine check events logged
divide error:
bounds:
coprocessor segment overrun:
invalid TSS:
segment not present:
invalid opcode:
alignment check:
stack segment:
fpu exception:
simd exception:
iret exception:
/var/log/messages
--
/usr/bin/abrt-dump-oops
-xtD

【讨论】:

  • 在 openSUSE 13.2 中为我工作:for I in /proc/*/cmdline; do echo $I; cat $I | tr '\000' ' '; echo; done
  • 我目前正在查看 proc_exe_link 中的源代码,它返回进程可执行文件的文件结构。我同意上面的 cmd 可以伪造。伪造 mm->exe_file 有多容易,因为它似乎是原始原始二进制文件的内存映射?
【解决方案2】:

我已经设法解决了这个问题的一个版本。我想访问所有 PID 的cmdline,但在内核本身内(与问题所述的 内核模块 相反),但也许这些原则也可以应用于内核模块?

我所做的是,我将以下函数添加到fs/proc/base.c

int proc_get_cmdline(struct task_struct *task, char * buffer) {
    int i;
    int ret = proc_pid_cmdline(task, buffer);

    for(i = 0; i < ret - 1; i++) {
           if(buffer[i] == '\0')
                   buffer[i] = ' ';
   }
    return 0;
}

然后我在include/linux/proc_fs.h
int proc_get_cmdline(struct task_struct *, char *); 中添加了声明

此时,我可以访问内核中所有进程的cmdline。 要访问task_struct,也许您可​​以参考kernel: efficient way to find task_struct by pid?

拥有task_struct 后,您应该能够执行以下操作:

char cmdline[256];    
proc_get_cmdline(task, cmdline);
if(strlen(cmdline) > 0)
    printk("  cmdline :%s\n", cmdline);
else
    printk("  cmdline :%s\n", task->comm);

我可以通过这种方式获取所有进程的命令行。

【讨论】:

    【解决方案3】:

    获取进程后面的二进制文件的完整路径。

    char * exepathp;
    
    struct file * exe_file;
    struct mm_struct *mm;
    char exe_path [1000];
    
    //straight up stolen from get_mm_exe_file   
    mm = get_task_mm(current);
    down_read(&mm->mmap_sem); //lock read
    exe_file = mm->exe_file;
    if (exe_file) get_file(exe_file);
    up_read(&mm->mmap_sem); //unlock read
    
    //reduce exe path to a string
    exepathp = d_path( &(exe_file->f_path), exe_path, 1000*sizeof(char) );
    

    其中 current 是您感兴趣的进程的任务结构。变量 exepathp 获取完整路径的字符串。这与进程 cmd 略有不同,这是为启动进程而加载的二进制文件的路径。将此路径与进程 cmd 结合起来应该会为您提供完整路径。

    【讨论】:

      猜你喜欢
      • 2011-05-23
      • 1970-01-01
      • 1970-01-01
      • 2018-08-07
      • 2014-04-22
      • 1970-01-01
      • 2012-01-31
      • 2012-09-27
      • 2013-01-17
      相关资源
      最近更新 更多