1 /*
2 * Copyright (c) International Business Machines Corp., 2001
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
12 * the GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17 */
18
19 /*
20 * Testcase to test whether chroot(2) sets errno correctly.
21 *
22 * 1. Test for ENAMETOOLONG:
23 * Create a bad directory name with length more than
24 * VFS_MAXNAMELEN (Linux kernel variable), and pass it as the
25 * path to chroot(2).
26 *
27 * 2. Test for ENOENT:
28 * Attempt to chroot(2) on a non-existent directory
29 *
30 * 3. Test for ENOTDIR:
31 * Attempt to chdir(2) on a file.
32 *
33 * 4. Test for EFAULT:
34 * The pathname parameter to chroot() points to an invalid address,
35 * chroot(2) fails with EPERM.
36 *
37 * 5. Test for ELOOP:
38 * Too many symbolic links were encountered When resolving the
39 * pathname parameter.
40 *
41 * 07/2001 Ported by Wayne Boyer
42 */
43
44 #include <stdio.h>
45 #include <errno.h>
46 #include <sys/stat.h>
47 #include <sys/mman.h>
48 #include "test.h"
49 #include <fcntl.h>
50 #include "safe_macros.h"
51
52 char *TCID = "chroot03";
53
54 static int fd;
55 static char fname[255];
56 static char nonexistent_dir[100] = "testdir";
57 static char bad_dir[] = "abcdefghijklmnopqrstmnopqrstuvwxyzabcdefghijklmnopqrstmnopqrstuvwxyzabcdefghijklmnopqrstmnopqrstuvwxyzabcdefghijklmnopqrstmnopqrstuvwxyzabcdefghijklmnopqrstmnopqrstuvwxyzabcdefghijklmnopqrstmnopqrstuvwxyzabcdefghijklmnopqrstmnopqrstuvwxyzabcdefghijklmnopqrstmnopqrstuvwxyz";
58 static char symbolic_dir[] = "sym_dir1";
59
60 struct test_case_t {
61 char *dir;
62 int error;
63 } TC[] = {
64 /*
65 * to test whether chroot() is setting ENAMETOOLONG if the
66 * pathname is more than VFS_MAXNAMELEN
67 */
68 {
69 bad_dir, ENAMETOOLONG},
70 /*
71 * to test whether chroot() is setting ENOTDIR if the argument
72 * is not a directory.
73 */
74 {
75 fname, ENOTDIR},
76 /*
77 * to test whether chroot() is setting ENOENT if the directory
78 * does not exist.
79 */
80 {
81 nonexistent_dir, ENOENT},
82 #if !defined(UCLINUX)
83 /*
84 * attempt to chroot to a path pointing to an invalid address
85 * and expect EFAULT as errno
86 */
87 {
88 (char *)-1, EFAULT},
89 #endif
90 {symbolic_dir, ELOOP}
91 };
92
93 int TST_TOTAL = ARRAY_SIZE(TC);
94
95 static char *bad_addr;
96
97 static void setup(void);
98 static void cleanup(void);
99
main(int ac,char ** av)100 int main(int ac, char **av)
101 {
102 int lc;
103 int i;
104
105 tst_parse_opts(ac, av, NULL, NULL);
106
107 setup();
108
109 for (lc = 0; TEST_LOOPING(lc); lc++) {
110 tst_count = 0;
111
112 for (i = 0; i < TST_TOTAL; i++) {
113 TEST(chroot(TC[i].dir));
114
115 if (TEST_RETURN != -1) {
116 tst_resm(TFAIL, "call succeeded unexpectedly");
117 continue;
118 }
119
120 if (TEST_ERRNO == TC[i].error) {
121 tst_resm(TPASS | TTERRNO, "failed as expected");
122 } else {
123 tst_resm(TFAIL | TTERRNO,
124 "didn't fail as expected (expected errno "
125 "= %d : %s)",
126 TC[i].error, strerror(TC[i].error));
127 }
128 }
129 }
130
131 cleanup();
132 tst_exit();
133 }
134
setup(void)135 static void setup(void)
136 {
137 tst_sig(NOFORK, DEF_HANDLER, cleanup);
138 TEST_PAUSE;
139 tst_tmpdir();
140
141 /*
142 * create a file and use it to test whether chroot() is setting
143 * ENOTDIR if the argument is not a directory.
144 */
145 (void)sprintf(fname, "tfile_%d", getpid());
146 fd = SAFE_CREAT(cleanup, fname, 0777);
147
148 #if !defined(UCLINUX)
149 bad_addr = mmap(0, 1, PROT_NONE,
150 MAP_PRIVATE_EXCEPT_UCLINUX | MAP_ANONYMOUS, 0, 0);
151 if (bad_addr == MAP_FAILED)
152 tst_brkm(TBROK, cleanup, "mmap failed");
153
154 TC[3].dir = bad_addr;
155 #endif
156 /*
157 * create two symbolic directory who point to each other to
158 * test ELOOP.
159 */
160 SAFE_SYMLINK(cleanup, "sym_dir1/", "sym_dir2");
161 SAFE_SYMLINK(cleanup, "sym_dir2/", "sym_dir1");
162 }
163
cleanup(void)164 static void cleanup(void)
165 {
166 close(fd);
167 tst_rmdir();
168 }
169