0

I am creating an ebpf program that has a tracepoint on the syscall read().

The purpose of the program is to count how many times a file is read.

My current method to trace this is as follows:

  1. When the tracepoint for read() hits, it has access to the file descriptor (fd) and process id (pid). My c callback code gets executed with this information.
  2. The code gets the inode from each file in /proc/{pid}/fd. If the inode matches the specific file(s) to monitor I increment the count. This all happens before the read() syscall finishes.

This works fine and dandy sometimes... However I noticed something odd...

  1. Smaller files (e.g. 2 lines total) don't typically get picked up this way, but larger files do.

For instance:

cat small.txt = Missed

cat big.txt = Seen

  1. If I add the strace command before the cat call it works

For instance:

strace -q cat small.txt = Seen

The ebpf code that handles this can be seen here:

void handle_event(void *ctx, void *data, unsigned int data_sz)
{
    //struct that holds data like pid, and fd
    struct data_t *m = data;
//get /proc/pid/fd as string
char path_str[100];
sprintf(path_str, "/proc/%d/fd", m->pid);


//for traversing the proc dir
DIR *mydir;
struct dirent *myfile;
struct stat mystat;

//traverse /proc/pid/fd
char buf[512];
mydir = opendir(path_str);
if(mydir != NULL){

    while((myfile = readdir(mydir)) != NULL)
    {
        //stat each file
        sprintf(buf, "%s/%s", path_str, myfile->d_name);
        stat(buf, &mystat);

        //check if inode matches from list
        if(mystat.st_ino == 1396301 || mystat.st_ino == 1319264 || mystat.st_ino == 5768513 || mystat.st_ino == 1318781){
            //alert message to signify file was read
            printf("Read file!\n");
            printf("inode = %d \n", mystat.st_ino);
        }


    }
}
//close the dir
if(mydir != NULL){
    closedir(mydir);
}


}

What I noticed is that cat big.txt always has an fd in /proc/pid/fd for big.txt, as does strace -q small.txt for small.txt.

However for cat small.txt it never seems to have an fd.

I am presuming this has something to do with caching, but I can't seem to figure out how the file is being accessed in the case of cat small.txt, because even if it accesses the file through a cache wouldn't it also produce an fd, and update /proc/pid/fd?

If not, why not? And what mechanism would be used to access the file contents instead?

Any help would be much appreciated.

Logan
  • 21

1 Answers1

2

Thank you @user1686 for asking your question. This helped me to figure out that essentially nothing is ensuring that my tracepoint callback (which executes in userspace) will finish before the read() syscall which executes in kernel space.

Therefore what's likely happening is the process closes the file before my callback can access /proc/pid/fd and so the normal behavior that an fd gets added to /proc/pid/fd is happening as expected.

Logan
  • 21