1 /*
2 * Copyright (c) International Business Machines Corp., 2001
3 * 07/2001 Ported by Wayne Boyer
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 Foundation,
17 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19 /*
20 * Test Description:
21 * Verify that,
22 * 1) lstat(2) returns -1 and sets errno to EACCES if search permission is
23 * denied on a component of the path prefix.
24 * 2) lstat(2) returns -1 and sets errno to ENOENT if the specified file
25 * does not exists or empty string.
26 * 3) lstat(2) returns -1 and sets errno to EFAULT if pathname points
27 * outside user's accessible address space.
28 * 4) lstat(2) returns -1 and sets errno to ENAMETOOLONG if the pathname
29 * component is too long.
30 * 5) lstat(2) returns -1 and sets errno to ENOTDIR if the directory
31 * component in pathname is not a directory.
32 * 6) lstat(2) returns -1 and sets errno to ELOOP if the pathname has too
33 * many symbolic links encountered while traversing.
34 */
35
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <unistd.h>
39 #include <fcntl.h>
40 #include <errno.h>
41 #include <string.h>
42 #include <signal.h>
43 #include <sys/types.h>
44 #include <sys/stat.h>
45 #include <sys/mman.h>
46 #include <pwd.h>
47
48 #include "test.h"
49 #include "safe_macros.h"
50
51 #define MODE_RWX S_IRWXU | S_IRWXG | S_IRWXO
52 #define FILE_MODE S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH
53 #define TEST_DIR "test_dir"
54 #define TEST_EACCES TEST_DIR"/test_eacces"
55 #define TEST_ENOENT ""
56 #define TEST_ENOTDIR "test_file/test_enotdir"
57 #define TEST_ELOOP "/test_eloop"
58
59 static char longpathname[PATH_MAX + 2];
60 static char elooppathname[sizeof(TEST_ELOOP) * 43] = ".";
61
62 #if !defined(UCLINUX)
63 static void bad_addr_setup(int);
64 static void high_address_setup(int);
65 #endif
66
67 static struct test_case_t {
68 char *pathname;
69 int exp_errno;
70 void (*setup) ();
71 } test_cases[] = {
72 {TEST_EACCES, EACCES, NULL},
73 {TEST_ENOENT, ENOENT, NULL},
74 #if !defined(UCLINUX)
75 {NULL, EFAULT, bad_addr_setup},
76 {NULL, EFAULT, high_address_setup},
77 #endif
78 {longpathname, ENAMETOOLONG, NULL},
79 {TEST_ENOTDIR, ENOTDIR, NULL},
80 {elooppathname, ELOOP, NULL},
81 };
82
83 char *TCID = "lstat02";
84 int TST_TOTAL = ARRAY_SIZE(test_cases);
85
86 static void setup(void);
87 static void lstat_verify(int);
88 static void cleanup(void);
89
main(int ac,char ** av)90 int main(int ac, char **av)
91 {
92 int lc;
93 int i;
94
95 tst_parse_opts(ac, av, NULL, NULL);
96
97 setup();
98
99 for (lc = 0; TEST_LOOPING(lc); lc++) {
100 tst_count = 0;
101 for (i = 0; i < TST_TOTAL; i++)
102 lstat_verify(i);
103 }
104
105 cleanup();
106 tst_exit();
107 }
108
setup(void)109 static void setup(void)
110 {
111 int i;
112 struct passwd *ltpuser;
113
114 tst_require_root();
115
116 tst_sig(NOFORK, DEF_HANDLER, cleanup);
117
118 ltpuser = SAFE_GETPWNAM(cleanup, "nobody");
119 SAFE_SETEUID(cleanup, ltpuser->pw_uid);
120
121 TEST_PAUSE;
122
123 tst_tmpdir();
124
125 SAFE_MKDIR(cleanup, TEST_DIR, MODE_RWX);
126 SAFE_TOUCH(cleanup, TEST_EACCES, 0666, NULL);
127 if (chmod(TEST_DIR, FILE_MODE) < 0)
128 tst_brkm(TBROK, cleanup, "chmod(2) of %s failed", TEST_DIR);
129
130 SAFE_TOUCH(cleanup, "test_file", MODE_RWX, NULL);
131
132 memset(longpathname, 'a', PATH_MAX+1);
133
134 SAFE_MKDIR(cleanup, "test_eloop", MODE_RWX);
135 SAFE_SYMLINK(cleanup, "../test_eloop", "test_eloop/test_eloop");
136 /*
137 * NOTE: the ELOOP test is written based on that the consecutive
138 * symlinks limits in kernel is hardwired to 40.
139 */
140 for (i = 0; i < 43; i++)
141 strcat(elooppathname, TEST_ELOOP);
142 }
143
144 #if !defined(UCLINUX)
bad_addr_setup(int i)145 static void bad_addr_setup(int i)
146 {
147 test_cases[i].pathname = SAFE_MMAP(cleanup, 0, 1, PROT_NONE,
148 MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
149 }
150
high_address_setup(int i)151 static void high_address_setup(int i)
152 {
153 test_cases[i].pathname = (char *)get_high_address();
154 }
155 #endif
156
lstat_verify(int i)157 static void lstat_verify(int i)
158 {
159 struct stat stat_buf;
160
161 if (test_cases[i].setup != NULL)
162 test_cases[i].setup(i);
163
164 TEST(lstat(test_cases[i].pathname, &stat_buf));
165
166 if (TEST_RETURN != -1) {
167 tst_resm(TFAIL, "lstat() returned %ld, expected -1, errno=%d",
168 TEST_RETURN, test_cases[i].exp_errno);
169 return;
170 }
171
172 if (TEST_ERRNO == test_cases[i].exp_errno) {
173 tst_resm(TPASS | TTERRNO, "lstat() failed as expected");
174 } else {
175 tst_resm(TFAIL | TTERRNO,
176 "lstat() failed unexpectedly; expected: %d - %s",
177 test_cases[i].exp_errno,
178 strerror(test_cases[i].exp_errno));
179 }
180 }
181
cleanup(void)182 static void cleanup(void)
183 {
184 if (seteuid(0))
185 tst_resm(TINFO | TERRNO, "Failet to seteuid(0) before cleanup");
186
187 tst_rmdir();
188 }
189