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