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
92#define FAILED 1
93
94int 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 */
218int 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 */
237void 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 */
249void cleanup(void)
250{
251
252}
253
254#elif HAVE_MODIFY_LDT
255int 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
263int main(void)
264{
265	tst_resm(TINFO, "modify_ldt01 test only for ix86");
266	tst_exit();
267}
268
269#endif /* defined(__i386__) */
270