modify_ldt02.c revision ae5eb2cbaa3d1f39876a9000b85806c5417bf25f
1/* 2 * 3 * Copyright (c) International Business Machines Corp., 2001 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 2 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See 13 * the GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program; if not, write to the Free Software 17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 */ 19 20/* 21 * NAME 22 * modify_ldt02.c 23 * 24 * DESCRIPTION 25 * Testcase to check the error conditions for modify_ldt(2) 26 * 27 * ALGORITHM 28 * block1: 29 * Create a segment at entry 0 and a valid base address. 30 * Read the contents of the segment thru' fs register. 31 * Validate the data. 32 * Write an invalid base address into entry 0. 33 * Read the contents of entry 0 in the child process. 34 * Verify that a SIGSEGV is incurred. 35 * 36 * USAGE 37 * modify_ldt02 38 * 39 * HISTORY 40 * 07/2001 Ported by Wayne Boyer 41 * 42 * RESTRICTIONS 43 * None 44 */ 45 46#include "config.h" 47#include "test.h" 48#include "usctest.h" 49 50 51TCID_DEFINE(modify_ldt02); 52int TST_TOTAL = 1; 53extern int Tst_count; 54 55 56#if defined(__i386__) && defined(HAVE_MODIFY_LDT) 57 58#ifdef HAVE_ASM_LDT_H 59#include <asm/ldt.h> 60#endif 61extern int modify_ldt(int, void*, unsigned long); 62 63 64#include <asm/unistd.h> 65#include <string.h> 66#include <sys/wait.h> 67#include <errno.h> 68 69/* Newer ldt.h files use user_desc, instead of modify_ldt_ldt_s */ 70#ifdef HAVE_STRUCT_USER_DESC 71typedef struct user_desc modify_ldt_s; 72#elif HAVE_STRUCT_MODIFY_LDT_LDT_S 73typedef struct modify_ldt_ldt_s modify_ldt_s; 74#else 75typedef struct modify_ldt_ldt_t 76{ 77 unsigned int entry_number; 78 unsigned long int base_addr; 79 unsigned int limit; 80 unsigned int seg_32bit:1; 81 unsigned int contents:2; 82 unsigned int read_exec_only:1; 83 unsigned int limit_in_pages:1; 84 unsigned int seg_not_present:1; 85 unsigned int useable:1; 86 unsigned int empty:25; 87} modify_ldt_s; 88#endif 89 90int create_segment(void *, size_t); 91int read_segment(unsigned int); 92void cleanup(void); 93void setup(void); 94 95#define FAILED 1 96 97 98int 99main(int ac, char **av) 100{ 101 int lc; /* loop counter */ 102 char *msg; /* message returned from parse_opts */ 103 104 int val, pid, status; 105 106 int flag; 107 int seg[4]; 108 109 110 /* parse standard options */ 111 if ((msg = parse_opts(ac, av, (option_t *)NULL, NULL)) != (char *)NULL){ 112 tst_brkm(TBROK, cleanup, "OPTION PARSING ERROR - %s", msg); 113 /*NOTREACHED*/ 114 } 115 116 setup(); /* global setup */ 117 118 /* The following loop checks looping state if -i option given */ 119 for (lc = 0; TEST_LOOPING(lc); lc++) { 120 121 /* reset Tst_count in case we are looping */ 122 Tst_count = 0; 123 124//block1: 125 tst_resm(TINFO, "Enter block 1"); 126 flag = 0; 127 128 seg[0] = 12345; 129 if (create_segment(seg, sizeof(seg)) == -1) { 130 tst_brkm(TINFO, cleanup, "Creation of segment failed"); 131 /*NOTREACHED*/ 132 } 133 134 val = read_segment(0); 135 136 if (val != seg[0]) { 137 tst_resm(TFAIL, "Invalid value read %d, expected %d", 138 val, seg[0]); 139 flag = FAILED; 140 } 141 142 if (flag) { 143 tst_resm(TINFO, "block 1 FAILED"); 144 } else { 145 tst_resm(TINFO, "block 1 PASSED"); 146 } 147 148 tst_resm(TINFO, "Exit block 1"); 149 150//block2: 151 tst_resm(TINFO, "Enter block 2"); 152 flag = 0; 153 154 if (create_segment(0, 10) == -1) { 155 tst_brkm(TINFO, cleanup, "Creation of segment failed"); 156 /*NOTREACHED*/ 157 } 158 159 tst_flush(); 160 if ((pid = FORK_OR_VFORK()) == 0) { 161 val = read_segment(0); 162 exit(1); 163 } 164 165 (void)waitpid(pid, &status, 0); 166 167 if (WEXITSTATUS(status) != 0) { 168 flag = FAILED; 169 tst_resm(TFAIL, "Did not generate SEGV, child returned " 170 "unexpected status"); 171 } 172 173 if (flag) { 174 tst_resm(TINFO, "block 2 FAILED"); 175 } else { 176 tst_resm(TINFO, "block 2 PASSED"); 177 } 178 } 179 cleanup(); 180 return(0); 181} 182 183int 184create_segment(void *seg, size_t size) 185{ 186 modify_ldt_s entry; 187 188 entry.entry_number = 0; 189 entry.base_addr = (unsigned long)seg; 190 entry.limit = size; 191 entry.seg_32bit = 1; 192 entry.contents = 0; 193 entry.read_exec_only = 0; 194 entry.limit_in_pages = 0; 195 entry.seg_not_present = 0; 196 197 return modify_ldt(1, &entry, sizeof(entry)); 198} 199 200int read_segment(unsigned int index) 201{ 202 int res; 203 __asm__ __volatile__("\n\ 204 push $0x0007;\n\ 205 pop %%fs;\n\ 206 movl %%fs:(%1), %0" 207 : "=r" (res) 208 : "r" (index*sizeof(int))); 209 return res; 210} 211 212void 213sigsegv_handler(int sig) 214{ 215 tst_resm(TINFO, "received signal: %d", sig); 216 exit(0); 217} 218 219/* 220 * setup() - performs all ONE TIME setup for this test 221 */ 222void 223setup(void) 224{ 225 struct sigaction act; 226 227 memset(&act, 0, sizeof(act)); 228 sigemptyset(&act.sa_mask); 229 230 /* capture signals */ 231 tst_sig(FORK, DEF_HANDLER, cleanup); 232 233 act.sa_handler = sigsegv_handler; 234 (void)sigaction(SIGSEGV, &act, NULL); 235 236 /* Pause if that option was specified */ 237 TEST_PAUSE; 238} 239 240/* 241 * cleanup() - performs all the ONE TIME cleanup for this test at completion 242 * or premature exit. 243 */ 244void 245cleanup(void) 246{ 247 /* 248 * print timing status if that option was specified. 249 * print errno log if that option was specified 250 */ 251 TEST_CLEANUP; 252 253 /* exit with return code appropriate for results */ 254 tst_exit(); 255} 256#elif HAVE_MODIFY_LDT 257int main() 258{ 259 tst_resm(TCONF, "modify_ldt is available but not tested on the platform than __i386__"); 260 return 0; 261} 262 263#else /* if defined(__i386__) */ 264 265int main() 266{ 267 tst_resm(TINFO, "modify_ldt02 test only for ix86"); 268 return 0; 269} 270 271#endif /* if defined(__i386__) */ 272