linux/arch/ia64/ia32/ia32_ldt.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2001, 2004 Hewlett-Packard Co
   3 *      David Mosberger-Tang <davidm@hpl.hp.com>
   4 *
   5 * Adapted from arch/i386/kernel/ldt.c
   6 */
   7
   8#include <linux/errno.h>
   9#include <linux/sched.h>
  10#include <linux/string.h>
  11#include <linux/mm.h>
  12#include <linux/smp.h>
  13#include <linux/vmalloc.h>
  14
  15#include <asm/uaccess.h>
  16
  17#include "ia32priv.h"
  18
  19/*
  20 * read_ldt() is not really atomic - this is not a problem since synchronization of reads
  21 * and writes done to the LDT has to be assured by user-space anyway. Writes are atomic,
  22 * to protect the security checks done on new descriptors.
  23 */
  24static int
  25read_ldt (void __user *ptr, unsigned long bytecount)
  26{
  27        unsigned long bytes_left, n;
  28        char __user *src, *dst;
  29        char buf[256];  /* temporary buffer (don't overflow kernel stack!) */
  30
  31        if (bytecount > IA32_LDT_ENTRIES*IA32_LDT_ENTRY_SIZE)
  32                bytecount = IA32_LDT_ENTRIES*IA32_LDT_ENTRY_SIZE;
  33
  34        bytes_left = bytecount;
  35
  36        src = (void __user *) IA32_LDT_OFFSET;
  37        dst = ptr;
  38
  39        while (bytes_left) {
  40                n = sizeof(buf);
  41                if (n > bytes_left)
  42                        n = bytes_left;
  43
  44                /*
  45                 * We know we're reading valid memory, but we still must guard against
  46                 * running out of memory.
  47                 */
  48                if (__copy_from_user(buf, src, n))
  49                        return -EFAULT;
  50
  51                if (copy_to_user(dst, buf, n))
  52                        return -EFAULT;
  53
  54                src += n;
  55                dst += n;
  56                bytes_left -= n;
  57        }
  58        return bytecount;
  59}
  60
  61static int
  62read_default_ldt (void __user * ptr, unsigned long bytecount)
  63{
  64        unsigned long size;
  65        int err;
  66
  67        /* XXX fix me: should return equivalent of default_ldt[0] */
  68        err = 0;
  69        size = 8;
  70        if (size > bytecount)
  71                size = bytecount;
  72
  73        err = size;
  74        if (clear_user(ptr, size))
  75                err = -EFAULT;
  76
  77        return err;
  78}
  79
  80static int
  81write_ldt (void __user * ptr, unsigned long bytecount, int oldmode)
  82{
  83        struct ia32_user_desc ldt_info;
  84        __u64 entry;
  85        int ret;
  86
  87        if (bytecount != sizeof(ldt_info))
  88                return -EINVAL;
  89        if (copy_from_user(&ldt_info, ptr, sizeof(ldt_info)))
  90                return -EFAULT;
  91
  92        if (ldt_info.entry_number >= IA32_LDT_ENTRIES)
  93                return -EINVAL;
  94        if (ldt_info.contents == 3) {
  95                if (oldmode)
  96                        return -EINVAL;
  97                if (ldt_info.seg_not_present == 0)
  98                        return -EINVAL;
  99        }
 100
 101        if (ldt_info.base_addr == 0 && ldt_info.limit == 0
 102            && (oldmode || (ldt_info.contents == 0 && ldt_info.read_exec_only == 1
 103                            && ldt_info.seg_32bit == 0 && ldt_info.limit_in_pages == 0
 104                            && ldt_info.seg_not_present == 1 && ldt_info.useable == 0)))
 105                /* allow LDTs to be cleared by the user */
 106                entry = 0;
 107        else
 108                /* we must set the "Accessed" bit as IVE doesn't emulate it */
 109                entry = IA32_SEG_DESCRIPTOR(ldt_info.base_addr, ldt_info.limit,
 110                                            (((ldt_info.read_exec_only ^ 1) << 1)
 111                                             | (ldt_info.contents << 2)) | 1,
 112                                            1, 3, ldt_info.seg_not_present ^ 1,
 113                                            (oldmode ? 0 : ldt_info.useable),
 114                                            ldt_info.seg_32bit,
 115                                            ldt_info.limit_in_pages);
 116        /*
 117         * Install the new entry.  We know we're accessing valid (mapped) user-level
 118         * memory, but we still need to guard against out-of-memory, hence we must use
 119         * put_user().
 120         */
 121        ret = __put_user(entry, (__u64 __user *) IA32_LDT_OFFSET + ldt_info.entry_number);
 122        ia32_load_segment_descriptors(current);
 123        return ret;
 124}
 125
 126asmlinkage int
 127sys32_modify_ldt (int func, unsigned int ptr, unsigned int bytecount)
 128{
 129        int ret = -ENOSYS;
 130
 131        switch (func) {
 132              case 0:
 133                ret = read_ldt(compat_ptr(ptr), bytecount);
 134                break;
 135              case 1:
 136                ret = write_ldt(compat_ptr(ptr), bytecount, 1);
 137                break;
 138              case 2:
 139                ret = read_default_ldt(compat_ptr(ptr), bytecount);
 140                break;
 141              case 0x11:
 142                ret = write_ldt(compat_ptr(ptr), bytecount, 0);
 143                break;
 144        }
 145        return ret;
 146}
 147