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 55TCID_DEFINE(modify_ldt01); 56int 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 63extern 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 70typedef struct user_desc modify_ldt_s; 71#elif HAVE_STRUCT_MODIFY_LDT_LDT_S 72typedef struct modify_ldt_ldt_s modify_ldt_s; 73#else 74typedef 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 88int create_segment(void *, size_t); 89void cleanup(void); 90void setup(void); 91 92int main(int ac, char **av) 93{ 94 int lc; 95 96 void *ptr; 97 int retval, func; 98 99 int seg[4]; 100 101 tst_parse_opts(ac, av, NULL, NULL); 102 103 setup(); 104 105 for (lc = 0; TEST_LOOPING(lc); lc++) { 106 107 /* reset tst_count in case we are looping */ 108 tst_count = 0; 109 110 /* 111 * Check for ENOSYS. 112 */ 113 ptr = malloc(10); 114 func = 100; 115 retval = modify_ldt(func, ptr, sizeof(ptr)); 116 if (retval < 0) { 117 if (errno != ENOSYS) { 118 tst_resm(TFAIL, "modify_ldt() set invalid " 119 "errno, expected ENOSYS, got: %d", 120 errno); 121 } else { 122 tst_resm(TPASS, 123 "modify_ldt() set expected errno"); 124 } 125 } else { 126 tst_resm(TFAIL, "modify_ldt error: " 127 "unexpected return value %d", retval); 128 } 129 130 free(ptr); 131 132 /* 133 * Check for EINVAL 134 */ 135 ptr = 0; 136 137 retval = modify_ldt(1, ptr, sizeof(ptr)); 138 if (retval < 0) { 139 if (errno != EINVAL) { 140 tst_resm(TFAIL, "modify_ldt() set invalid " 141 "errno, expected EINVAL, got: %d", 142 errno); 143 } else { 144 tst_resm(TPASS, 145 "modify_ldt() set expected errno"); 146 } 147 } else { 148 tst_resm(TFAIL, "modify_ldt error: " 149 "unexpected return value %d", retval); 150 } 151 152 /* 153 * Create a new LDT segment. 154 */ 155 if (create_segment(seg, sizeof(seg)) == -1) { 156 tst_brkm(TBROK, cleanup, "Creation of segment failed"); 157 } 158 159 /* 160 * Check for EFAULT 161 */ 162 ptr = sbrk(0); 163 164 retval = modify_ldt(0, ptr + 0xFFF, sizeof(ptr)); 165 if (retval < 0) { 166 if (errno != EFAULT) { 167 tst_resm(TFAIL, "modify_ldt() set invalid " 168 "errno, expected EFAULT, got: %d", 169 errno); 170 } else { 171 tst_resm(TPASS, 172 "modify_ldt() set expected errno"); 173 } 174 } else { 175 tst_resm(TFAIL, "modify_ldt error: " 176 "unexpected return value %d", retval); 177 } 178 } 179 cleanup(); 180 tst_exit(); 181} 182 183/* 184 * create_segment() - 185 */ 186int create_segment(void *seg, size_t size) 187{ 188 modify_ldt_s entry; 189 190 entry.entry_number = 0; 191 entry.base_addr = (unsigned long)seg; 192 entry.limit = size; 193 entry.seg_32bit = 1; 194 entry.contents = 0; 195 entry.read_exec_only = 0; 196 entry.limit_in_pages = 0; 197 entry.seg_not_present = 0; 198 199 return modify_ldt(1, &entry, sizeof(entry)); 200} 201 202void setup(void) 203{ 204 205 tst_sig(FORK, DEF_HANDLER, cleanup); 206 207 TEST_PAUSE; 208} 209 210void cleanup(void) 211{ 212 213} 214 215#elif HAVE_MODIFY_LDT 216int main(void) 217{ 218 tst_brkm(TCONF, 219 NULL, 220 "modify_ldt is available but not tested on the platform than __i386__"); 221} 222 223#else 224int main(void) 225{ 226 tst_resm(TINFO, "modify_ldt01 test only for ix86"); 227 tst_exit(); 228} 229 230#endif /* defined(__i386__) */ 231