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_ldt01.c 23 * 24 * DESCRIPTION 25 * Testcase to check the error conditions for modify_ldt(2) 26 * 27 * CALLS 28 * modify_ldt() 29 * 30 * ALGORITHM 31 * block1: 32 * Invoke modify_ldt() with a func value which is neither 33 * 0 or 1. Verify that ENOSYS is set. 34 * block2: 35 * Invoke mprotect() with ptr == NULL. Verify that EINVAL 36 * is set. 37 * block3: 38 * Create an LDT segment. 39 * Try to read from an invalid pointer. 40 * Verify that EFAULT is set. 41 * 42 * USAGE 43 * modify_ldt01 44 * 45 * HISTORY 46 * 07/2001 Ported by Wayne Boyer 47 * 48 * RESTRICTIONS 49 * None 50 */ 51 52 #include "config.h" 53 #include "test.h" 54 55 TCID_DEFINE(modify_ldt01); 56 int TST_TOTAL = 1; 57 58 #if defined(__i386__) && defined(HAVE_MODIFY_LDT) 59 60 #ifdef HAVE_ASM_LDT_H 61 #include <asm/ldt.h> 62 #endif 63 extern int modify_ldt(int, void *, unsigned long); 64 65 #include <asm/unistd.h> 66 #include <errno.h> 67 68 /* Newer ldt.h files use user_desc, instead of modify_ldt_ldt_s */ 69 #ifdef HAVE_STRUCT_USER_DESC 70 typedef struct user_desc modify_ldt_s; 71 #elif HAVE_STRUCT_MODIFY_LDT_LDT_S 72 typedef struct modify_ldt_ldt_s modify_ldt_s; 73 #else 74 typedef struct modify_ldt_ldt_t { 75 unsigned int entry_number; 76 unsigned long int base_addr; 77 unsigned int limit; 78 unsigned int seg_32bit:1; 79 unsigned int contents:2; 80 unsigned int read_exec_only:1; 81 unsigned int limit_in_pages:1; 82 unsigned int seg_not_present:1; 83 unsigned int useable:1; 84 unsigned int empty:25; 85 } modify_ldt_s; 86 #endif 87 88 int create_segment(void *, size_t); 89 void cleanup(void); 90 void setup(void); 91 92 #define FAILED 1 93 94 int main(int ac, char **av) 95 { 96 int lc; 97 98 void *ptr; 99 int retval, func; 100 101 int flag; 102 int seg[4]; 103 104 tst_parse_opts(ac, av, NULL, NULL); 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 /* 116 * Check for ENOSYS. 117 */ 118 tst_resm(TINFO, "Enter block 1"); 119 flag = 0; 120 ptr = malloc(10); 121 func = 100; 122 retval = modify_ldt(func, ptr, sizeof(ptr)); 123 if (retval < 0) { 124 if (errno != ENOSYS) { 125 tst_resm(TFAIL, "modify_ldt() set invalid " 126 "errno, expected ENOSYS, got: %d", 127 errno); 128 flag = FAILED; 129 } 130 } else { 131 tst_resm(TFAIL, "modify_ldt error: " 132 "unexpected return value %d", retval); 133 flag = FAILED; 134 } 135 136 if (flag) { 137 tst_resm(TINFO, "block 1 FAILED"); 138 } else { 139 tst_resm(TINFO, "block 1 PASSED"); 140 } 141 tst_resm(TINFO, "Exit block 1"); 142 free(ptr); 143 144 //block2: 145 /* 146 * Check for EINVAL 147 */ 148 tst_resm(TINFO, "Enter block 2"); 149 flag = 0; 150 151 ptr = 0; 152 153 retval = modify_ldt(1, ptr, sizeof(ptr)); 154 if (retval < 0) { 155 if (errno != EINVAL) { 156 tst_resm(TFAIL, "modify_ldt() set invalid " 157 "errno, expected EINVAL, got: %d", 158 errno); 159 flag = FAILED; 160 } 161 } else { 162 tst_resm(TFAIL, "modify_ldt error: " 163 "unexpected return value %d", retval); 164 flag = FAILED; 165 } 166 167 if (flag) { 168 tst_resm(TINFO, "block 2 FAILED"); 169 } else { 170 tst_resm(TINFO, "block 2 PASSED"); 171 } 172 tst_resm(TINFO, "Exit block 2"); 173 174 //block3: 175 176 /* 177 * Create a new LDT segment. 178 */ 179 if (create_segment(seg, sizeof(seg)) == -1) { 180 tst_brkm(TINFO, cleanup, "Creation of segment failed"); 181 } 182 183 /* 184 * Check for EFAULT 185 */ 186 ptr = sbrk(0); 187 188 retval = modify_ldt(0, ptr + 0xFFF, sizeof(ptr)); 189 if (retval < 0) { 190 if (errno != EFAULT) { 191 tst_resm(TFAIL, "modify_ldt() set invalid " 192 "errno, expected EFAULT, got: %d", 193 errno); 194 flag = FAILED; 195 } 196 } else { 197 tst_resm(TFAIL, "modify_ldt error: " 198 "unexpected return value %d", retval); 199 flag = FAILED; 200 } 201 202 if (flag) { 203 tst_resm(TINFO, "block 3 FAILED"); 204 } else { 205 tst_resm(TINFO, "block 3 PASSED"); 206 } 207 tst_resm(TINFO, "Exit block 3"); 208 209 } 210 cleanup(); 211 tst_exit(); 212 213 } 214 215 /* 216 * create_segment() - 217 */ 218 int create_segment(void *seg, size_t size) 219 { 220 modify_ldt_s entry; 221 222 entry.entry_number = 0; 223 entry.base_addr = (unsigned long)seg; 224 entry.limit = size; 225 entry.seg_32bit = 1; 226 entry.contents = 0; 227 entry.read_exec_only = 0; 228 entry.limit_in_pages = 0; 229 entry.seg_not_present = 0; 230 231 return modify_ldt(1, &entry, sizeof(entry)); 232 } 233 234 /* 235 * setup() - performs all ONE TIME setup for this test 236 */ 237 void setup(void) 238 { 239 240 tst_sig(FORK, DEF_HANDLER, cleanup); 241 242 TEST_PAUSE; 243 } 244 245 /* 246 * cleanup() - performs all the ONE TIME cleanup for this test at completion 247 * or premature exit. 248 */ 249 void cleanup(void) 250 { 251 252 } 253 254 #elif HAVE_MODIFY_LDT 255 int main(void) 256 { 257 tst_brkm(TCONF, 258 NULL, 259 "modify_ldt is available but not tested on the platform than __i386__"); 260 } 261 262 #else 263 int main(void) 264 { 265 tst_resm(TINFO, "modify_ldt01 test only for ix86"); 266 tst_exit(); 267 } 268 269 #endif /* defined(__i386__) */ 270