PageRenderTime 44ms CodeModel.GetById 13ms app.highlight 23ms RepoModel.GetById 2ms app.codeStats 0ms

/arch/ia64/ia32/ia32_ldt.c

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