Linux : /proc/<PID>/exe return 位于 '/home/<USER>/new/v' 的进程的可执行文件 '/bin/bash' 的路径

Linux : /proc/<PID>/exe return path to executable '/bin/bash' for process located at '/home/<USER>/new/v'

我正在尝试构建一个脚本,在新进程启动时将 PID 和路径打印到可执行文件。

我的代码如下:

#include<stdio.h>
#include<stdlib.h>
#include <limits.h>
#include<unistd.h>
#include<fcntl.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<sys/time.h>
#include<string.h>

   void pnotify(){
    int fd,resp,pid,pidbak=0;
    fd_set c;
    struct timeval tv;
    float f;
    char buf[256]="",buf2[256]="";

    fd=open("/proc/loadavg",O_RDONLY,0600);
    if(fd==-1){
        printf("Load error !\n");
        return;
    }

    tv.tv_sec=0;
    tv.tv_usec=10;

    while(1){
        FD_ZERO(&c);
        FD_SET(fd,&c);

        if((resp=select(fd+1,&c,NULL,NULL,&tv))==-1){
            printf("Error select.\n");
            exit(5);
        }
        if(resp>0){
            pidbak=pid;
            read(fd,buf,256);
            lseek(fd,0,SEEK_SET);
            sscanf(buf,"%f %f %f %s %d",&f,&f,&f,buf,&pid);
            memset(buf,0,256);
            if(pid != pidbak){
                sprintf(buf,"/proc/%d/exe",pid);
                if(readlink(buf,buf2,256)<=0){
                    perror("Readlink Error : ");
                    continue;
                }
                printf("PID : %d\tPATH : %s\n",pid,buf2);
            }
            memset(buf,0,256);
            memset(buf2,0,256);
        }
    }   
}

main(){
    pnotify();
}

此代码总体上似乎运行良好,但是,当我打开另一个新终端执行新进程时,其可执行文件位于 /home/<USER>/new/v,它提供的路径位于 /bin/bash

你能找出问题所在吗?

一切正常。 'v' 是一个 shell 脚本,而 /bin/bash 是 实际上是 运行 的可执行进程。你也许能得到 /proc/$$/cmdline(或 comm)中的更多信息,具体取决于什么 您实际要解决的问题。或者,您可以使用 监控 fork 和 exec 调用的 netlink 接口。

注意当一个新进程启动时,它有相同的可执行文件 作为其 parent.

我想通了,

每当我们 运行 来自终端的代码 (/bin/bash) if forks fork() 一个带有新 PID 的新进程(child 终端 /bin/bash 和新的 PID)然后这个 child 调用 exec() 并用 v 覆盖自己。在 fork()exec() 之间有一个很小的时间间隔,直到这段时间 /proc/PID/exe 指向 /bin/bash 并且当 v 起来 & 运行ning /proc/PID/exe 更新为指向“/home/USER/v”。

我相应地修改了代码,现在它可以正常工作了。

#include<stdio.h>
#include<stdlib.h>
#include <limits.h>
#include<unistd.h>
#include<fcntl.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<sys/time.h>
#include<string.h>

void pnotify(){
    int fd,resp,pid,pidbak=0,flag=0;
    fd_set c;
    struct timeval tv;
    float f;
    char buf[256]="",buf2[256]="";

    fd=open("/proc/loadavg",O_RDONLY,0600);
    if(fd==-1){
        printf("Load error !\n");
        return;
    }

    tv.tv_sec=0;
    tv.tv_usec=10;

    while(1){
        FD_ZERO(&c);
        FD_SET(fd,&c);

        if((resp=select(fd+1,&c,NULL,NULL,&tv))==-1){
            printf("Error select.\n");
            exit(5);
        }
        if(resp>0){
            pidbak=pid;
            read(fd,buf,256);
            lseek(fd,0,SEEK_SET);
            sscanf(buf,"%f %f %f %s %d",&f,&f,&f,buf,&pid);
            memset(buf,0,256);
            if(pid != pidbak){
                sprintf(buf,"/proc/%d/exe",pid);
                do{
                    memset(buf2,0,256);
                    if(readlink(buf,buf2,256)<=0){
                        perror("Readlink Error : ");
                        flag==1;
                        break;
                    }
                }while(strcmp(buf2,"/bin/bash")==0);
                if(flag==1)
                    continue;
                printf("PID : %d\tPATH : %s\n",pid,buf2);
            }
            memset(buf,0,256);
            memset(buf2,0,256);
        }
    }   
}

main(){
    pnotify();
}

这不能可靠地工作。您正在滥用 loadavg 中的 "last pid" 字段。在您从 select 中醒来并阅读它之间,以及在解析和使用该数字做某事之间,您有一个 window ,其中可以有大量进程来来去去,而您对此一无所知发生了。

也许有专门的设施来监控 forks/execs,我不知道。在最坏的情况下,您可以通过在 clone/execve/whatever 您真正想要监视的

上放置探测器来保证使用 systemtap 的可靠通知。