00001
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "ldt_keeper.h"
00022
00023 #include <string.h>
00024 #include <stdlib.h>
00025 #include <errno.h>
00026 #include <fcntl.h>
00027 #include <sys/mman.h>
00028 #include <sys/types.h>
00029 #include <stdio.h>
00030 #include <unistd.h>
00031 #ifdef __linux__
00032 #include <asm/unistd.h>
00033 #include <asm/ldt.h>
00034
00035 #include <linux/version.h>
00036 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,47)
00037 #define modify_ldt_ldt_s user_desc
00038 #endif
00039
00040 #ifdef __cplusplus
00041 extern "C" {
00042 #endif
00043
00044 #if defined(__GLIBC__) && (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ == 0))
00045 _syscall3( int, modify_ldt, int, func, void *, ptr, unsigned long, bytecount );
00046 #else
00047 int modify_ldt(int func, void *ptr, unsigned long bytecount);
00048 #endif
00049 #ifdef __cplusplus
00050 }
00051 #endif
00052 #else
00053 #if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
00054 #include <machine/segments.h>
00055 #include <machine/sysarch.h>
00056 #endif
00057
00058 #ifdef __svr4__
00059 #include <sys/segment.h>
00060 #include <sys/sysi86.h>
00061
00062
00063 #ifdef __cplusplus
00064 extern "C" {
00065 #endif
00066 int sysi86(int, void*);
00067 #ifdef __cplusplus
00068 }
00069 #endif
00070
00071 #ifndef NUMSYSLDTS
00072 #define NUMSYSLDTS 6
00073 #endif
00074
00075 #define TEB_SEL_IDX NUMSYSLDTS
00076 #endif
00077
00078 #define LDT_ENTRIES 8192
00079 #define LDT_ENTRY_SIZE 8
00080 #pragma pack(4)
00081 struct modify_ldt_ldt_s {
00082 unsigned int entry_number;
00083 unsigned long base_addr;
00084 unsigned int limit;
00085 unsigned int seg_32bit:1;
00086 unsigned int contents:2;
00087 unsigned int read_exec_only:1;
00088 unsigned int limit_in_pages:1;
00089 unsigned int seg_not_present:1;
00090 unsigned int useable:1;
00091 };
00092
00093 #define MODIFY_LDT_CONTENTS_DATA 0
00094 #define MODIFY_LDT_CONTENTS_STACK 1
00095 #define MODIFY_LDT_CONTENTS_CODE 2
00096 #endif
00097
00098
00099
00100 #define LDT_SEL(idx) ((idx) << 3 | 1 << 2 | 3)
00101
00102
00103 #if defined(__FreeBSD__) && defined(LDT_AUTO_ALLOC)
00104 #define TEB_SEL_IDX LDT_AUTO_ALLOC
00105 #endif
00106
00107 #ifndef TEB_SEL_IDX
00108 #define TEB_SEL_IDX 17
00109 #endif
00110
00111 static unsigned int fs_ldt = TEB_SEL_IDX;
00112
00113
00119 #ifdef __cplusplus
00120 extern "C"
00121 #endif
00122 void Setup_FS_Segment(void)
00123 {
00124 unsigned int ldt_desc = LDT_SEL(fs_ldt);
00125
00126 __asm__ __volatile__(
00127 "movl %0,%%eax; movw %%ax, %%fs" : : "r" (ldt_desc)
00128 :"eax"
00129 );
00130 }
00131
00132
00133 #if 0
00134 #ifdef __linux__
00135
00136
00137 static int LDT_Modify( int func, struct modify_ldt_ldt_s *ptr,
00138 unsigned long count )
00139 {
00140 int res;
00141 #ifdef __PIC__
00142 __asm__ __volatile__( "pushl %%ebx\n\t"
00143 "movl %2,%%ebx\n\t"
00144 "int $0x80\n\t"
00145 "popl %%ebx"
00146 : "=a" (res)
00147 : "0" (__NR_modify_ldt),
00148 "r" (func),
00149 "c" (ptr),
00150 "d"(16)
00151 :"esi" );
00152 #else
00153 __asm__ __volatile__("int $0x80"
00154 : "=a" (res)
00155 : "0" (__NR_modify_ldt),
00156 "b" (func),
00157 "c" (ptr),
00158 "d"(16)
00159 :"esi");
00160 #endif
00161 if (res >= 0) return res;
00162 errno = -res;
00163 return -1;
00164 }
00165 #endif
00166 #endif
00167
00168 #if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
00169 static void LDT_EntryToBytes( unsigned long *buffer, const struct modify_ldt_ldt_s *content )
00170 {
00171 *buffer++ = ((content->base_addr & 0x0000ffff) << 16) |
00172 (content->limit & 0x0ffff);
00173 *buffer = (content->base_addr & 0xff000000) |
00174 ((content->base_addr & 0x00ff0000)>>16) |
00175 (content->limit & 0xf0000) |
00176 (content->contents << 10) |
00177 ((content->read_exec_only == 0) << 9) |
00178 ((content->seg_32bit != 0) << 22) |
00179 ((content->limit_in_pages != 0) << 23) |
00180 0xf000;
00181 }
00182 #endif
00183
00184 void* fs_seg=0;
00185
00186 ldt_fs_t* Setup_LDT_Keeper(void)
00187 {
00188 struct modify_ldt_ldt_s array;
00189 int ret;
00190 ldt_fs_t* ldt_fs = (ldt_fs_t*) malloc(sizeof(ldt_fs_t));
00191
00192 if (!ldt_fs)
00193 return NULL;
00194
00195 ldt_fs->fd = open("/dev/zero", O_RDWR);
00196 if(ldt_fs->fd<0){
00197 perror( "Cannot open /dev/zero for READ+WRITE. Check permissions! error: ");
00198 return NULL;
00199 }
00200 fs_seg=
00201 ldt_fs->fs_seg = mmap(NULL, getpagesize(), PROT_READ | PROT_WRITE, MAP_PRIVATE,
00202 ldt_fs->fd, 0);
00203 if (ldt_fs->fs_seg == (void*)-1)
00204 {
00205 perror("ERROR: Couldn't allocate memory for fs segment");
00206 close(ldt_fs->fd);
00207 free(ldt_fs);
00208 return NULL;
00209 }
00210 *(void**)((char*)ldt_fs->fs_seg+0x18) = ldt_fs->fs_seg;
00211 memset(&array, 0, sizeof(array));
00212 array.base_addr=(int)ldt_fs->fs_seg;
00213 array.entry_number=TEB_SEL_IDX;
00214 array.limit=array.base_addr+getpagesize()-1;
00215 array.seg_32bit=1;
00216 array.read_exec_only=0;
00217 array.seg_not_present=0;
00218 array.contents=MODIFY_LDT_CONTENTS_DATA;
00219 array.limit_in_pages=0;
00220 #ifdef __linux__
00221
00222 ret=modify_ldt(0x1, &array, sizeof(struct modify_ldt_ldt_s));
00223 if(ret<0)
00224 {
00225 perror("install_fs");
00226 printf("Couldn't install fs segment, expect segfault\n");
00227 }
00228 #endif
00229
00230 #if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
00231 {
00232 unsigned long d[2];
00233
00234 LDT_EntryToBytes( d, &array );
00235 #if defined(__FreeBSD__) && defined(LDT_AUTO_ALLOC)
00236 ret = i386_set_ldt(LDT_AUTO_ALLOC, (union descriptor *)d, 1);
00237 array.entry_number = ret;
00238 fs_ldt = ret;
00239 #else
00240 ret = i386_set_ldt(array.entry_number, (union descriptor *)d, 1);
00241 #endif
00242 if (ret < 0)
00243 {
00244 perror("install_fs");
00245 printf("Couldn't install fs segment, expect segfault\n");
00246 printf("Did you reconfigure the kernel with \"options USER_LDT\"?\n");
00247 }
00248 }
00249 #endif
00250
00251 #if defined(__svr4__)
00252 {
00253 struct ssd ssd;
00254 ssd.sel = LDT_SEL(TEB_SEL_IDX);
00255 ssd.bo = array.base_addr;
00256 ssd.ls = array.limit - array.base_addr;
00257 ssd.acc1 = ((array.read_exec_only == 0) << 1) |
00258 (array.contents << 2) |
00259 0xf0;
00260 ssd.acc2 = 0x4;
00261 if (sysi86(SI86DSCR, &ssd) < 0) {
00262 perror("sysi86(SI86DSCR)");
00263 printf("Couldn't install fs segment, expect segfault\n");
00264 }
00265 }
00266 #endif
00267
00268 Setup_FS_Segment();
00269
00270 ldt_fs->prev_struct = (char*)malloc(sizeof(char) * 8);
00271 *(void**)array.base_addr = ldt_fs->prev_struct;
00272
00273 return ldt_fs;
00274 }
00275
00276 void Restore_LDT_Keeper(ldt_fs_t* ldt_fs)
00277 {
00278 if (ldt_fs == NULL || ldt_fs->fs_seg == 0)
00279 return;
00280 if (ldt_fs->prev_struct)
00281 free(ldt_fs->prev_struct);
00282 munmap((char*)ldt_fs->fs_seg, getpagesize());
00283 ldt_fs->fs_seg = 0;
00284 close(ldt_fs->fd);
00285 free(ldt_fs);
00286 }