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

1.9k views Asked by At

I am trying to build a script that prints the PID & Path to executable file whenever a new process starts.

My code is as follows:

#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();
}

This code seems to work good in general, However, when i open another new terminal to execute a new process whose executable file is located at /home/<USER>/new/v it provides path at /bin/bash.

Output: Note the pid on both windows Can you please find out whats going wrong?

3

There are 3 answers

2
user464502 On BEST ANSWER

Nothing is going wrong. 'v' is a shell script, and /bin/bash is the executable process that is actually running. You might be able to get more information out of /proc/$$/cmdline (or comm), depending on what problem you're actually trying to solve. Alternatively, you might use the netlink interface to monitor fork and exec calls.

Note that when a new process starts, it has the same executable as its parent.

0
Anirban On

I figured out something,

Whenever we run a code from the terminal(/bin/bash) if forks fork() a new process with a new PID (child terminal /bin/bash with new PID) then this child calls exec() and overlays itself with v. There is minor time gap between fork() &exec() until elapse of this time /proc/PID/exe points to /bin/bash and when v is up & running /proc/PID/exe is updated t point to '/home/USER/v'.

I modified the code accrdingly and now it works as desired to.

#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();
}
0
AudioBubble On

This cannot reliably work. You are abusing the "last pid" field from loadavg. Between you being woken up from select and reading it, and between parsing and doing something with the number you have a window where a high number of processes can come (and go) and you have no clue this happened.

Maybe there is a dedicated facility to monitor forks/execs, I don't know. In worst case you can gaurantee reliable notifications with systemtap by putting a probe on clone/execve/whatever you really want to monitor.