modify_ldt02.c revision 605fa3362fd7cef0baa2131be32cf44661783d3e
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 50TCID_DEFINE(modify_ldt02); 51int TST_TOTAL = 1; 52 53#if defined(__i386__) && defined(HAVE_MODIFY_LDT) 54 55#ifdef HAVE_ASM_LDT_H 56#include <asm/ldt.h> 57#endif 58extern int modify_ldt(int, void *, unsigned long); 59 60#include <asm/unistd.h> 61#include <string.h> 62#include <sys/wait.h> 63#include <errno.h> 64 65/* Newer ldt.h files use user_desc, instead of modify_ldt_ldt_s */ 66#ifdef HAVE_STRUCT_USER_DESC 67typedef struct user_desc modify_ldt_s; 68#elif HAVE_STRUCT_MODIFY_LDT_LDT_S 69typedef struct modify_ldt_ldt_s modify_ldt_s; 70#else 71typedef struct modify_ldt_ldt_t { 72 unsigned int entry_number; 73 unsigned long int base_addr; 74 unsigned int limit; 75 unsigned int seg_32bit:1; 76 unsigned int contents:2; 77 unsigned int read_exec_only:1; 78 unsigned int limit_in_pages:1; 79 unsigned int seg_not_present:1; 80 unsigned int useable:1; 81 unsigned int empty:25; 82} modify_ldt_s; 83#endif 84 85int create_segment(void *, size_t); 86int read_segment(unsigned int); 87void cleanup(void); 88void setup(void); 89 90#define FAILED 1 91 92int main(int ac, char **av) 93{ 94 int lc; 95 const char *msg; 96 97 int val, pid, status; 98 99 int flag; 100 int seg[4]; 101 102 if ((msg = parse_opts(ac, av, NULL, NULL)) != NULL) { 103 tst_brkm(TBROK, NULL, "OPTION PARSING ERROR - %s", msg); 104 } 105 106 setup(); /* global setup */ 107 108 /* The following loop checks looping state if -i option given */ 109 for (lc = 0; TEST_LOOPING(lc); lc++) { 110 111 /* reset tst_count in case we are looping */ 112 tst_count = 0; 113 114//block1: 115 tst_resm(TINFO, "Enter block 1"); 116 flag = 0; 117 118 seg[0] = 12345; 119 if (create_segment(seg, sizeof(seg)) == -1) { 120 tst_brkm(TINFO, cleanup, "Creation of segment failed"); 121 } 122 123 val = read_segment(0); 124 125 if (val != seg[0]) { 126 tst_resm(TFAIL, "Invalid value read %d, expected %d", 127 val, seg[0]); 128 flag = FAILED; 129 } 130 131 if (flag) { 132 tst_resm(TINFO, "block 1 FAILED"); 133 } else { 134 tst_resm(TINFO, "block 1 PASSED"); 135 } 136 137 tst_resm(TINFO, "Exit block 1"); 138 139//block2: 140 tst_resm(TINFO, "Enter block 2"); 141 flag = 0; 142 143 if (create_segment(0, 10) == -1) { 144 tst_brkm(TINFO, cleanup, "Creation of segment failed"); 145 } 146 147 tst_flush(); 148 if ((pid = FORK_OR_VFORK()) == 0) { 149 val = read_segment(0); 150 exit(1); 151 } 152 153 (void)waitpid(pid, &status, 0); 154 155 if (WEXITSTATUS(status) != 0) { 156 flag = FAILED; 157 tst_resm(TFAIL, "Did not generate SEGV, child returned " 158 "unexpected status"); 159 } 160 161 if (flag) { 162 tst_resm(TINFO, "block 2 FAILED"); 163 } else { 164 tst_resm(TINFO, "block 2 PASSED"); 165 } 166 } 167 cleanup(); 168 tst_exit(); 169 170} 171 172int create_segment(void *seg, size_t size) 173{ 174 modify_ldt_s entry; 175 176 entry.entry_number = 0; 177 entry.base_addr = (unsigned long)seg; 178 entry.limit = size; 179 entry.seg_32bit = 1; 180 entry.contents = 0; 181 entry.read_exec_only = 0; 182 entry.limit_in_pages = 0; 183 entry.seg_not_present = 0; 184 185 return modify_ldt(1, &entry, sizeof(entry)); 186} 187 188int read_segment(unsigned int index) 189{ 190 int res; 191 __asm__ __volatile__("\n\ 192 push $0x0007;\n\ 193 pop %%fs;\n\ 194 movl %%fs:(%1), %0":"=r"(res) 195 :"r"(index * sizeof(int))); 196 return res; 197} 198 199void sigsegv_handler(int sig) 200{ 201 tst_resm(TINFO, "received signal: %d", sig); 202 exit(0); 203} 204 205/* 206 * setup() - performs all ONE TIME setup for this test 207 */ 208void setup(void) 209{ 210 struct sigaction act; 211 212 memset(&act, 0, sizeof(act)); 213 sigemptyset(&act.sa_mask); 214 215 tst_sig(FORK, DEF_HANDLER, cleanup); 216 217 act.sa_handler = sigsegv_handler; 218 (void)sigaction(SIGSEGV, &act, NULL); 219 220 TEST_PAUSE; 221} 222 223/* 224 * cleanup() - performs all the ONE TIME cleanup for this test at completion 225 * or premature exit. 226 */ 227void cleanup(void) 228{ 229 230} 231#elif HAVE_MODIFY_LDT 232int main(void) 233{ 234 tst_brkm(TCONF, 235 NULL, 236 "modify_ldt is available but not tested on the platform than __i386__"); 237} 238 239#else /* if defined(__i386__) */ 240 241int main(void) 242{ 243 tst_resm(TINFO, "modify_ldt02 test only for ix86"); 244 tst_exit(); 245} 246 247#endif /* if defined(__i386__) */ 248