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
main(int ac,char ** av)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 */
create_segment(void * seg,size_t size)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 */
setup(void)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 */
cleanup(void)249 void cleanup(void)
250 {
251
252 }
253
254 #elif HAVE_MODIFY_LDT
main(void)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
main(void)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