t_chroot.c revision 272458
122347Spst/* $NetBSD: t_chroot.c,v 1.1 2011/07/07 06:57:53 jruoho Exp $ */
222347Spst
322347Spst/*-
429964Sache * Copyright (c) 2011 The NetBSD Foundation, Inc.
592906Smarkm * All rights reserved.
622347Spst *
722347Spst * This code is derived from software contributed to The NetBSD Foundation
822347Spst * by Jukka Ruohonen.
922347Spst *
1022347Spst * Redistribution and use in source and binary forms, with or without
1122347Spst * modification, are permitted provided that the following conditions
1222347Spst * are met:
1322347Spst * 1. Redistributions of source code must retain the above copyright
1422347Spst *    notice, this list of conditions and the following disclaimer.
1522347Spst * 2. Redistributions in binary form must reproduce the above copyright
1622347Spst *    notice, this list of conditions and the following disclaimer in the
1722347Spst *    documentation and/or other materials provided with the distribution.
1829964Sache *
1922347Spst * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
2022347Spst * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
2122347Spst * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
2222347Spst * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
2322347Spst * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2422347Spst * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2522347Spst * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2622347Spst * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2722347Spst * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2822347Spst * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
2922347Spst * POSSIBILITY OF SUCH DAMAGE.
3022347Spst */
3122347Spst#include <sys/cdefs.h>
3222347Spst__RCSID("$NetBSD: t_chroot.c,v 1.1 2011/07/07 06:57:53 jruoho Exp $");
3322347Spst
3429964Sache#include <sys/wait.h>
3529964Sache
3629964Sache#include <atf-c.h>
3722347Spst#include <errno.h>
3822347Spst#include <fcntl.h>
3922347Spst#include <limits.h>
4022347Spst#include <pwd.h>
4122347Spst#include <stdlib.h>
4222347Spst#include <string.h>
4322347Spst#include <unistd.h>
4422347Spst
4522347SpstATF_TC(chroot_basic);
4622347SpstATF_TC_HEAD(chroot_basic, tc)
4722347Spst{
4822347Spst	atf_tc_set_md_var(tc, "descr", "A basic test of chroot(2)");
4922347Spst	atf_tc_set_md_var(tc, "require.user", "root");
5022347Spst}
5192906Smarkm
5222347SpstATF_TC_BODY(chroot_basic, tc)
5322347Spst{
5422347Spst	char buf[PATH_MAX];
5522347Spst	int fd, sta;
5622347Spst	pid_t pid;
5722347Spst
5822347Spst	(void)memset(buf, '\0', sizeof(buf));
5922347Spst	(void)getcwd(buf, sizeof(buf));
6022347Spst	(void)strlcat(buf, "/dir", sizeof(buf));
6122347Spst
6222347Spst	ATF_REQUIRE(mkdir(buf, 0500) == 0);
6322347Spst	ATF_REQUIRE(chdir(buf) == 0);
6422347Spst
6522347Spst	pid = fork();
6622347Spst	ATF_REQUIRE(pid >= 0);
6722347Spst
6822347Spst	if (pid == 0) {
6922347Spst
7022347Spst		if (chroot(buf) != 0)
7122347Spst			_exit(EXIT_FAILURE);
7222347Spst
7322347Spst		errno = 0;
7422347Spst
7522347Spst		if (chroot("/root") != -1)
7622347Spst			_exit(EXIT_FAILURE);
7722347Spst
7822347Spst		if (errno != ENOENT)
7922347Spst			_exit(EXIT_FAILURE);
8022347Spst
8122347Spst		fd = open("file", O_RDONLY | O_CREAT, 0600);
8222347Spst
8322347Spst		if (fd < 0)
8422347Spst			_exit(EXIT_FAILURE);
8522347Spst
8622347Spst		if (close(fd) != 0)
8722347Spst			_exit(EXIT_FAILURE);
8822347Spst
8922347Spst		_exit(EXIT_SUCCESS);
9022347Spst	}
9122347Spst
9222347Spst	(void)wait(&sta);
9322347Spst
9422347Spst	if (WIFEXITED(sta) == 0 || WEXITSTATUS(sta) != EXIT_SUCCESS)
9522347Spst		atf_tc_fail("chroot(2) failed");
9622347Spst
9722347Spst	(void)chdir("/");
9822347Spst	(void)strlcat(buf, "/file", sizeof(buf));
9922347Spst
10022347Spst	fd = open(buf, O_RDONLY);
10122347Spst
10222347Spst	if (fd < 0)
10322347Spst		atf_tc_fail("chroot(2) did not change the root directory");
10422347Spst
10522347Spst	ATF_REQUIRE(close(fd) == 0);
10622347Spst	ATF_REQUIRE(unlink(buf) == 0);
10722347Spst}
10822347Spst
10922347SpstATF_TC(chroot_err);
11022347SpstATF_TC_HEAD(chroot_err, tc)
11122347Spst{
11222347Spst	atf_tc_set_md_var(tc, "descr", "Test error conditions of chroot(2)");
11322347Spst	atf_tc_set_md_var(tc, "require.user", "root");
11422347Spst}
11522347Spst
11622347SpstATF_TC_BODY(chroot_err, tc)
11722347Spst{
11822347Spst	char buf[PATH_MAX + 1];
11922347Spst
12022347Spst	(void)memset(buf, 'x', sizeof(buf));
12122347Spst
12222347Spst	errno = 0;
12322347Spst	ATF_REQUIRE_ERRNO(ENAMETOOLONG, chroot(buf) == -1);
12422347Spst
12522347Spst	errno = 0;
12622347Spst	ATF_REQUIRE_ERRNO(EFAULT, chroot((void *)-1) == -1);
12722347Spst
12822347Spst	errno = 0;
12922347Spst	ATF_REQUIRE_ERRNO(ENOENT, chroot("/a/b/c/d/e/f/g/h/i/j") == -1);
13022347Spst}
13122347Spst
13222347SpstATF_TC(chroot_perm);
13322347SpstATF_TC_HEAD(chroot_perm, tc)
13422347Spst{
13522347Spst	atf_tc_set_md_var(tc, "descr", "Test permissions with chroot(2)");
13622347Spst	atf_tc_set_md_var(tc, "require.user", "unprivileged");
13722347Spst}
13822347Spst
13922347SpstATF_TC_BODY(chroot_perm, tc)
14022347Spst{
14122347Spst	static char buf[LINE_MAX];
14222347Spst	pid_t pid;
14322347Spst	int sta;
14422347Spst
14522347Spst	(void)memset(buf, '\0', sizeof(buf));
14622347Spst	ATF_REQUIRE(getcwd(buf, sizeof(buf)) != NULL);
14722347Spst
14822347Spst	pid = fork();
14922347Spst	ATF_REQUIRE(pid >= 0);
15022347Spst
15122347Spst	if (pid == 0) {
15222347Spst
15322347Spst		errno = 0;
15422347Spst
15522347Spst		if (chroot(buf) != -1)
15622347Spst			_exit(EXIT_FAILURE);
15722347Spst
15822347Spst		if (errno != EPERM)
15922347Spst			_exit(EXIT_FAILURE);
16022347Spst
16122347Spst		_exit(EXIT_SUCCESS);
16222347Spst	}
16322347Spst
16422347Spst	(void)wait(&sta);
16522347Spst
16622347Spst	if (WIFEXITED(sta) == 0 || WEXITSTATUS(sta) != EXIT_SUCCESS)
16722347Spst		atf_tc_fail("chroot(2) succeeded as unprivileged user");
168}
169
170ATF_TC(fchroot_basic);
171ATF_TC_HEAD(fchroot_basic, tc)
172{
173	atf_tc_set_md_var(tc, "descr", "A basic test of fchroot(2)");
174	atf_tc_set_md_var(tc, "require.user", "root");
175}
176
177ATF_TC_BODY(fchroot_basic, tc)
178{
179	char buf[PATH_MAX];
180	int fd, sta;
181	pid_t pid;
182
183	(void)memset(buf, '\0', sizeof(buf));
184	(void)getcwd(buf, sizeof(buf));
185	(void)strlcat(buf, "/dir", sizeof(buf));
186
187	ATF_REQUIRE(mkdir(buf, 0500) == 0);
188	ATF_REQUIRE(chdir(buf) == 0);
189
190	fd = open(buf, O_RDONLY);
191	ATF_REQUIRE(fd >= 0);
192
193	pid = fork();
194	ATF_REQUIRE(pid >= 0);
195
196	if (pid == 0) {
197
198		if (fchroot(fd) != 0)
199			_exit(EXIT_FAILURE);
200
201		if (close(fd) != 0)
202			_exit(EXIT_FAILURE);
203
204		fd = open("file", O_RDONLY | O_CREAT, 0600);
205
206		if (fd < 0)
207			_exit(EXIT_FAILURE);
208
209		if (close(fd) != 0)
210			_exit(EXIT_FAILURE);
211
212		_exit(EXIT_SUCCESS);
213	}
214
215	(void)wait(&sta);
216
217	if (WIFEXITED(sta) == 0 || WEXITSTATUS(sta) != EXIT_SUCCESS)
218		atf_tc_fail("fchroot(2) failed");
219
220	(void)chdir("/");
221	(void)strlcat(buf, "/file", sizeof(buf));
222
223	fd = open(buf, O_RDONLY);
224
225	if (fd < 0)
226		atf_tc_fail("fchroot(2) did not change the root directory");
227
228	ATF_REQUIRE(close(fd) == 0);
229	ATF_REQUIRE(unlink(buf) == 0);
230}
231
232ATF_TC(fchroot_err);
233ATF_TC_HEAD(fchroot_err, tc)
234{
235	atf_tc_set_md_var(tc, "descr", "Test error conditions of fchroot(2)");
236	atf_tc_set_md_var(tc, "require.user", "root");
237}
238
239ATF_TC_BODY(fchroot_err, tc)
240{
241	int fd;
242
243	fd = open("/etc/passwd", O_RDONLY);
244	ATF_REQUIRE(fd >= 0);
245
246	errno = 0;
247	ATF_REQUIRE_ERRNO(EBADF, fchroot(-1) == -1);
248
249	errno = 0;
250	ATF_REQUIRE_ERRNO(ENOTDIR, fchroot(fd) == -1);
251
252	ATF_REQUIRE(close(fd) == 0);
253}
254
255ATF_TC(fchroot_perm);
256ATF_TC_HEAD(fchroot_perm, tc)
257{
258	atf_tc_set_md_var(tc, "descr", "Test permissions with fchroot(2)");
259	atf_tc_set_md_var(tc, "require.user", "root");
260}
261
262ATF_TC_BODY(fchroot_perm, tc)
263{
264	static char buf[LINE_MAX];
265	struct passwd *pw;
266	int fd, sta;
267	pid_t pid;
268
269	(void)memset(buf, '\0', sizeof(buf));
270	ATF_REQUIRE(getcwd(buf, sizeof(buf)) != NULL);
271
272	pw = getpwnam("nobody");
273	fd = open(buf, O_RDONLY);
274
275	ATF_REQUIRE(fd >= 0);
276	ATF_REQUIRE(pw != NULL);
277
278	pid = fork();
279	ATF_REQUIRE(pid >= 0);
280
281	if (pid == 0) {
282
283		(void)setuid(pw->pw_uid);
284
285		errno = 0;
286
287		if (fchroot(fd) != -1)
288			_exit(EXIT_FAILURE);
289
290		if (errno != EPERM)
291			_exit(EXIT_FAILURE);
292
293		_exit(EXIT_SUCCESS);
294	}
295
296	(void)wait(&sta);
297
298	if (WIFEXITED(sta) == 0 || WEXITSTATUS(sta) != EXIT_SUCCESS)
299		atf_tc_fail("fchroot(2) succeeded as unprivileged user");
300}
301
302ATF_TP_ADD_TCS(tp)
303{
304
305	ATF_TP_ADD_TC(tp, chroot_basic);
306	ATF_TP_ADD_TC(tp, chroot_err);
307	ATF_TP_ADD_TC(tp, chroot_perm);
308	ATF_TP_ADD_TC(tp, fchroot_basic);
309	ATF_TP_ADD_TC(tp, fchroot_err);
310	ATF_TP_ADD_TC(tp, fchroot_perm);
311
312	return atf_no_error();
313}
314