root/arch/i386/kernel/ldt.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. read_ldt
  2. limits_ok
  3. write_ldt
  4. sys_modify_ldt

   1 /*
   2  * linux/kernel/ldt.c
   3  *
   4  * Copyright (C) 1992 Krishna Balasubramanian and Linus Torvalds
   5  */
   6 
   7 #include <linux/errno.h>
   8 #include <linux/sched.h>
   9 #include <linux/string.h>
  10 #include <linux/mm.h>
  11 #include <asm/segment.h>
  12 #include <asm/system.h>
  13 #include <linux/ldt.h>
  14 
  15 static int read_ldt(void * ptr, unsigned long bytecount)
     /* [previous][next][first][last][top][bottom][index][help] */
  16 {
  17         int error;
  18         void * address = current->ldt;
  19         unsigned long size;
  20 
  21         if (!ptr)
  22                 return -EINVAL;
  23         size = LDT_ENTRIES*LDT_ENTRY_SIZE;
  24         if (!address) {
  25                 address = &default_ldt;
  26                 size = sizeof(default_ldt);
  27         }
  28         if (size > bytecount)
  29                 size = bytecount;
  30         error = verify_area(VERIFY_WRITE, ptr, size);
  31         if (error)
  32                 return error;
  33         memcpy_tofs(ptr, address, size);
  34         return size;
  35 }
  36 
  37 static inline int limits_ok(struct modify_ldt_ldt_s *ldt_info)
     /* [previous][next][first][last][top][bottom][index][help] */
  38 {
  39         unsigned long base, limit;
  40         /* linear address of first and last accessible byte */
  41         unsigned long first, last;
  42 
  43         base = ldt_info->base_addr;
  44         limit = ldt_info->limit;
  45         if (ldt_info->limit_in_pages)
  46                 limit = limit * PAGE_SIZE + PAGE_SIZE - 1;
  47 
  48         first = base;
  49         last = limit + base;
  50 
  51         /* segment grows down? */
  52         if (ldt_info->contents == 1) {
  53                 /* data segment grows down */
  54                 first = base+limit+1;
  55                 last = base+65535;
  56                 if (ldt_info->seg_32bit)
  57                         last = base-1;
  58         }
  59         return (last >= first && last < TASK_SIZE);
  60 }
  61 
  62 static int write_ldt(void * ptr, unsigned long bytecount)
     /* [previous][next][first][last][top][bottom][index][help] */
  63 {
  64         struct modify_ldt_ldt_s ldt_info;
  65         unsigned long *lp;
  66         int error, i;
  67 
  68         if (bytecount != sizeof(ldt_info))
  69                 return -EINVAL;
  70         error = verify_area(VERIFY_READ, ptr, sizeof(ldt_info));
  71         if (error)
  72                 return error;
  73 
  74         memcpy_fromfs(&ldt_info, ptr, sizeof(ldt_info));
  75 
  76         if (ldt_info.contents == 3 || ldt_info.entry_number >= LDT_ENTRIES)
  77                 return -EINVAL;
  78 
  79         if (!limits_ok(&ldt_info))
  80                 return -EINVAL;
  81 
  82         if (!current->ldt) {
  83                 for (i=1 ; i<NR_TASKS ; i++) {
  84                         if (task[i] == current) {
  85                                 if (!(current->ldt = (struct desc_struct*) vmalloc(LDT_ENTRIES*LDT_ENTRY_SIZE)))
  86                                         return -ENOMEM;
  87                                 memset(current->ldt, 0, LDT_ENTRIES*LDT_ENTRY_SIZE);
  88                                 set_ldt_desc(gdt+(i<<1)+FIRST_LDT_ENTRY, current->ldt, LDT_ENTRIES);
  89                                 load_ldt(i);
  90                         }
  91                 }
  92         }
  93         
  94         lp = (unsigned long *) &current->ldt[ldt_info.entry_number];
  95         /* Allow LDTs to be cleared by the user. */
  96         if (ldt_info.base_addr == 0 && ldt_info.limit == 0) {
  97                 *lp = 0;
  98                 *(lp+1) = 0;
  99                 return 0;
 100         }
 101         *lp = ((ldt_info.base_addr & 0x0000ffff) << 16) |
 102                   (ldt_info.limit & 0x0ffff);
 103         *(lp+1) = (ldt_info.base_addr & 0xff000000) |
 104                   ((ldt_info.base_addr & 0x00ff0000)>>16) |
 105                   (ldt_info.limit & 0xf0000) |
 106                   (ldt_info.contents << 10) |
 107                   ((ldt_info.read_exec_only ^ 1) << 9) |
 108                   (ldt_info.seg_32bit << 22) |
 109                   (ldt_info.limit_in_pages << 23) |
 110                   ((ldt_info.seg_not_present ^1) << 15) |
 111                   0x7000;
 112         return 0;
 113 }
 114 
 115 asmlinkage int sys_modify_ldt(int func, void *ptr, unsigned long bytecount)
     /* [previous][next][first][last][top][bottom][index][help] */
 116 {
 117         if (func == 0)
 118                 return read_ldt(ptr, bytecount);
 119         if (func == 1)
 120                 return write_ldt(ptr, bytecount);
 121         return -ENOSYS;
 122 }

/* [previous][next][first][last][top][bottom][index][help] */