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