1 /*
2 *
3 * Copyright (C) Bull S.A. 2001
4 * Copyright (c) International Business Machines Corp., 2001
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
14 * the GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21 /*
22 * Test Name: fstat05
23 *
24 * Test Description:
25 * Verify that,
26 * if buffer points outside user's accessible address space fstat(2)
27 * either returns -1 and sets errno to EFAULT
28 * or SIGSEGV is returned instead of EFAULT
29 *
30 * Expected Result:
31 * fstat() should fail with return value -1 and set expected errno.
32 * or
33 * fstat() should fail with SIGSEGV returned.
34 * Both results are considered as acceptable.
35 *
36 * Algorithm:
37 * Setup:
38 * Setup signal handling SIGSEGV included.
39 * Switch to nobody user.
40 * Pause for SIGUSR1 if option specified.
41 * Create temporary directory.
42 * Create a testfile under temporary directory.
43 *
44 * Test:
45 * Buffer points outside user's accessible address space.
46 * Loop if the proper options are given.
47 * Execute system call
48 * Check return code, if system call failed (return=-1)
49 * if errno set == expected errno
50 * Issue sys call fails with expected return value and errno.
51 * Otherwise,
52 * Issue sys call fails with unexpected errno.
53 * Otherwise,
54 * Issue sys call returns unexpected value.
55 *
56 * Sighandler:
57 * if signal == SIGSEGV
58 * Issue sys call fails with expected signal
59 * Otherwise,
60 * Issue sys call fails with unexpected signal.
61 *
62 * Cleanup:
63 * Print errno log and/or timing stats if options given
64 * Close the test file
65 * Delete the temporary directory(s)/file(s) created.
66 *
67 * Usage: <for command-line>
68 * fstat05 [-c n] [-e] [-i n] [-I x] [-p x] [-t]
69 * where, -c n : Run n copies concurrently.
70 * -e : Turn on errno logging.
71 * -i n : Execute test n times.
72 * -I x : Execute test for x seconds.
73 * -P x : Pause for x seconds between iterations.
74 * -t : Turn on syscall timing.
75 *
76 * History
77 * 05/2002 Jacky Malcles
78 * -Ported
79 *
80 * Restrictions:
81 * This test must be run as root.
82 */
83
84 #include <stdio.h>
85 #include <stdlib.h>
86 #include <unistd.h>
87 #include <fcntl.h>
88 #include <errno.h>
89 #include <string.h>
90 #include <signal.h>
91 #include <sys/types.h>
92 #include <sys/stat.h>
93 #include <pwd.h>
94
95 #include "test.h"
96
97 #define TEST_FILE "testfile"
98
99 char nobody_uid[] = "nobody";
100 struct passwd *ltpuser;
101
102 char *TCID = "fstat05";
103 int TST_TOTAL = 1;
104
105 int fildes; /* testfile descriptor */
106
107 void setup(); /* Main setup function for the tests */
108 void cleanup(); /* cleanup function for the test */
109 void sighandler(int sig); /* signals handler function for the test */
110
111 int siglist[] = { SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGTRAP, SIGABRT, SIGIOT,
112 SIGBUS, SIGFPE, SIGUSR1, SIGSEGV, SIGUSR2, SIGPIPE, SIGALRM,
113 SIGTERM,
114 #ifdef SIGSTKFLT
115 SIGSTKFLT,
116 #endif
117 SIGCHLD, SIGCONT, SIGTSTP, SIGTTIN,
118 SIGTTOU, SIGURG, SIGXCPU, SIGXFSZ, SIGVTALRM, SIGPROF,
119 SIGWINCH, SIGIO, SIGPWR, SIGSYS,
120 #ifdef SIGUNUSED
121 SIGUNUSED
122 #endif
123 };
124
125 int SIG_SEEN = sizeof(siglist) / sizeof(int);
126
127 #if !defined(UCLINUX)
128
main(int ac,char ** av)129 int main(int ac, char **av)
130 {
131 struct stat stat_buf; /* stat structure buffer */
132 struct stat *ptr_str;
133 int lc;
134
135 tst_parse_opts(ac, av, NULL, NULL);
136
137 /* Buffer points outside user's accessible address space. */
138 ptr_str = &stat_buf; /* if it was for conformance testing */
139 ptr_str = (void *)sbrk(0) + (4 * getpagesize());
140
141 /*
142 * Invoke setup function
143 */
144 setup();
145
146 for (lc = 0; TEST_LOOPING(lc); lc++) {
147
148 tst_count = 0;
149
150 /*
151 * Call fstat(2).
152 * verify that it fails with -1 return value and
153 * sets appropriate errno.
154 */
155 TEST(fstat(fildes, ptr_str));
156
157 /* Check return code from fstat(2) */
158 if (TEST_RETURN == -1) {
159 if (TEST_ERRNO == EFAULT)
160 tst_resm(TPASS,
161 "fstat failed with EFAULT as expected");
162 else
163 tst_resm(TFAIL | TTERRNO,
164 "fstat failed unexpectedly");
165 } else
166 tst_resm(TFAIL, "fstat() returned %ld but we wanted -1",
167 TEST_RETURN);
168
169 }
170
171 /*
172 * Invoke cleanup() to delete the test directory/file(s) created
173 * in the setup().
174 */
175 cleanup();
176 tst_exit();
177 }
178
179 #else
180
main(void)181 int main(void)
182 {
183 tst_brkm(TCONF, NULL, "test is not available on uClinux");
184 }
185
186 #endif /* if !defined(UCLINUX) */
187
188 /*
189 * void
190 * setup(void) - performs all ONE TIME setup for this test.
191 * Exit the test program on receipt of unexpected signals.
192 * Create a temporary directory and change directory to it.
193 */
setup(void)194 void setup(void)
195 {
196 int i;
197
198 tst_require_root();
199
200 /*
201 * Capture unexpected signals SIGSEGV included
202 * SIGSEGV being considered as acceptable as returned value
203 */
204 for (i = 0; i < SIG_SEEN; i++)
205 signal(siglist[i], &sighandler);
206
207 ltpuser = getpwnam(nobody_uid);
208 if (setuid(ltpuser->pw_uid) == -1)
209 tst_brkm(TBROK | TERRNO, NULL, "setuid(%d) failed",
210 ltpuser->pw_uid);
211
212 tst_tmpdir();
213
214 /* Create a testfile under temporary directory */
215 fildes = open(TEST_FILE, O_RDWR | O_CREAT, 0666);
216 if (fildes == -1)
217 tst_brkm(TBROK | TERRNO, cleanup,
218 "open(%s, O_RDWR|O_CREAT, 0666) failed", TEST_FILE);
219
220 TEST_PAUSE;
221 }
222
223 /*
224 * void
225 * cleanup() - Performs all ONE TIME cleanup for this test at
226 * completion or premature exit.
227 * Print test timing stats and errno log if test executed with options.
228 * Remove temporary directory and sub-directories/files under it
229 * created during setup().
230 * Exit the test program with normal exit code.
231 */
cleanup(void)232 void cleanup(void)
233 {
234
235 if (close(fildes) == -1)
236 tst_brkm(TBROK | TERRNO, cleanup, "close(%s) failed",
237 TEST_FILE);
238
239 tst_rmdir();
240
241 }
242
243 /*
244 * sighandler() - handle the signals
245 */
246
sighandler(int sig)247 void sighandler(int sig)
248 {
249 if (sig == SIGSEGV)
250 tst_resm(TPASS, "fstat failed as expected with SIGSEGV");
251 else
252 tst_brkm(TBROK, NULL, "Unexpected signal %d received.", sig);
253 cleanup();
254 tst_exit();
255 }
256