Home | History | Annotate | Download | only in modify_ldt
      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