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 err = 0; 68 size = 8; 69 if (size > bytecount) 70 size = bytecount; 71 72 err = size; 73 if (clear_user(ptr, size)) 74 err = -EFAULT; 75 76 return err; 77} 78 79static int 80write_ldt (void __user * ptr, unsigned long bytecount, int oldmode) 81{ 82 struct ia32_user_desc ldt_info; 83 __u64 entry; 84 int ret; 85 86 if (bytecount != sizeof(ldt_info)) 87 return -EINVAL; 88 if (copy_from_user(&ldt_info, ptr, sizeof(ldt_info))) 89 return -EFAULT; 90 91 if (ldt_info.entry_number >= IA32_LDT_ENTRIES) 92 return -EINVAL; 93 if (ldt_info.contents == 3) { 94 if (oldmode) 95 return -EINVAL; 96 if (ldt_info.seg_not_present == 0) 97 return -EINVAL; 98 } 99 100 if (ldt_info.base_addr == 0 && ldt_info.limit == 0 101 && (oldmode || (ldt_info.contents == 0 && ldt_info.read_exec_only == 1 102 && ldt_info.seg_32bit == 0 && ldt_info.limit_in_pages == 0 103 && ldt_info.seg_not_present == 1 && ldt_info.useable == 0))) 104 /* allow LDTs to be cleared by the user */ 105 entry = 0; 106 else 107 /* we must set the "Accessed" bit as IVE doesn't emulate it */ 108 entry = IA32_SEG_DESCRIPTOR(ldt_info.base_addr, ldt_info.limit, 109 (((ldt_info.read_exec_only ^ 1) << 1) 110 | (ldt_info.contents << 2)) | 1, 111 1, 3, ldt_info.seg_not_present ^ 1, 112 (oldmode ? 0 : ldt_info.useable), 113 ldt_info.seg_32bit, 114 ldt_info.limit_in_pages); 115 /* 116 * Install the new entry. We know we're accessing valid (mapped) user-level 117 * memory, but we still need to guard against out-of-memory, hence we must use 118 * put_user(). 119 */ 120 ret = __put_user(entry, (__u64 __user *) IA32_LDT_OFFSET + ldt_info.entry_number); 121 ia32_load_segment_descriptors(current); 122 return ret; 123} 124 125asmlinkage int 126sys32_modify_ldt (int func, unsigned int ptr, unsigned int bytecount) 127{ 128 int ret = -ENOSYS; 129 130 switch (func) { 131 case 0: 132 ret = read_ldt(compat_ptr(ptr), bytecount); 133 break; 134 case 1: 135 ret = write_ldt(compat_ptr(ptr), bytecount, 1); 136 break; 137 case 2: 138 ret = read_default_ldt(compat_ptr(ptr), bytecount); 139 break; 140 case 0x11: 141 ret = write_ldt(compat_ptr(ptr), bytecount, 0); 142 break; 143 } 144 return ret; 145} 146