diff --git a/tools/regression/security/access/Makefile b/tools/regression/security/access/Makefile new file mode 100644 index 000000000000..4b8039fc1c5d --- /dev/null +++ b/tools/regression/security/access/Makefile @@ -0,0 +1,9 @@ +# $FreeBSD$ + +PROG= testaccess +NOMAN= yes + +SRCS= testaccess.c +CFLAGS += -Wall + +.include diff --git a/tools/regression/security/access/testaccess.c b/tools/regression/security/access/testaccess.c new file mode 100644 index 000000000000..bd6945e2aee5 --- /dev/null +++ b/tools/regression/security/access/testaccess.c @@ -0,0 +1,360 @@ +/*- + * Copyright (c) 2001 Networks Associates Technologies, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * Written at NAI Labs at Network Associates by Robert Watson for the + * TrustedBSD Project. + * + * Work sponsored by Defense Advanced Research Projects Agency under the + * CHATS research program, CBOSS project. + * + * $FreeBSD$ + */ + +#include + +#include +#include +#include +#include +#include + +/* + * Regression test to check some basic cases and see if access() and + * eaccess() are using the correct portions of the process credential. + * This test relies on running with privilege, and on UFS file system + * semantics. Running the test in other environments may result + * in incorrect failure identification. + * + * Note that this may also break if file system access control is + * broken, or if the ability to check and set credentials is broken. + * + * Note that this test uses two hard-coded non-root UIDs; on multi-user + * systems, these UIDs may be in use by an untrusted user, in which + * case those users could interfere with the test. + */ + +#define ROOT_UID (uid_t)0 +#define WHEEL_GID (gid_t)0 +#define TEST_UID_ONE (uid_t)500 +#define TEST_GID_ONE (gid_t)500 +#define TEST_UID_TWO (uid_t)501 +#define TEST_GID_TWO (gid_t)501 + +struct file_description { + char *fd_name; + uid_t fd_owner; + gid_t fd_group; + mode_t fd_mode; +}; + +static struct file_description fd_list[] = { +{"test1", ROOT_UID, WHEEL_GID, 0400}, +{"test2", TEST_UID_ONE, WHEEL_GID,0400}, +{"test3", TEST_UID_TWO, WHEEL_GID, 0400}, +{"test4", ROOT_UID, WHEEL_GID, 0040}, +{"test5", ROOT_UID, TEST_GID_ONE, 0040}, +{"test6", ROOT_UID, TEST_GID_TWO, 0040}}; + +static int fd_list_count = sizeof(fd_list) / + sizeof(struct file_description); + +int +setup(void) +{ + int i, error; + + for (i = 0; i < fd_list_count; i++) { + error = open(fd_list[i].fd_name, O_CREAT | O_EXCL, fd_list[i].fd_mode); + if (error == -1) { + perror("open"); + return (error); + } + close(error); + error = chown(fd_list[i].fd_name, fd_list[i].fd_owner, + fd_list[i].fd_group); + if (error) { + perror("chown"); + return (error); + } + } + return (0); +} + +int +restoreprivilege(void) +{ + int error; + + error = setreuid(ROOT_UID, ROOT_UID); + if (error) + return (error); + + error = setregid(WHEEL_GID, WHEEL_GID); + if (error) + return (error); + + return (0); +} + +int +reportprivilege(char *message) +{ + uid_t euid, ruid, suid; + gid_t egid, rgid, sgid; + int error; + + error = getresuid(&ruid, &euid, &suid); + if (error) { + perror("getresuid"); + return (error); + } + + error = getresgid(&rgid, &egid, &sgid); + if (error) { + perror("getresgid"); + return (error); + } + + if (message) + printf("%s: ", message); + printf("ruid: %d, euid: %d, suid: %d, ", ruid, euid, suid); + printf("rgid: %d, egid: %d, sgid: %d\n", rgid, egid, sgid); + + return (0); +} + +int +cleanup(void) +{ + int i, error; + + error = restoreprivilege(); + if (error) { + perror("restoreprivilege"); + return (error); + } + + for (i = 0; i < fd_list_count; i++) { + error = unlink(fd_list[i].fd_name); + if (error) + return (error); + } + + return (0); +} + +int +main(int argc, char *argv[]) +{ + int error, errorseen; + + if (geteuid() != 0) { + fprintf(stderr, "testaccess must run as root.\n"); + exit (EXIT_FAILURE); + } + + error = setup(); + if (error) { + cleanup(); + exit (EXIT_FAILURE); + } + + /* Make sure saved uid is set appropriately. */ + error = setresuid(ROOT_UID, ROOT_UID, ROOT_UID); + if (error) { + perror("setresuid"); + cleanup(); + } + + /* Clear out additional groups. */ + error = setgroups(0, NULL); + if (error) { + perror("setgroups"); + cleanup(); + } + + /* Make sure saved gid is set appropriately. */ + error = setresgid(WHEEL_GID, WHEEL_GID, WHEEL_GID); + if (error) { + perror("setresgid"); + cleanup(); + } + + /* + * UID-only tests. + */ + + /* Check that saved uid is not used */ + error = setresuid(TEST_UID_ONE, TEST_UID_ONE, ROOT_UID); + if (error) { + perror("setresuid.1"); + cleanup(); + exit (EXIT_FAILURE); + } + + errorseen = 0; + + error = access("test1", R_OK); + if (!error) { + fprintf(stderr, "saved uid used instead of real uid\n"); + errorseen++; + } + +#ifdef EACCESS_AVAILABLE + error = eaccess("test2", R_OK); + if (!error) { + fprintf(stderr, "saved uid used instead of effective uid\n"); + errorseen++; + } +#endif + + error = restoreprivilege(); + if (error) { + perror("restoreprivilege"); + cleanup(); + exit (EXIT_FAILURE); + } + + error = setresuid(TEST_UID_ONE, TEST_UID_TWO, ROOT_UID); + if (error) { + perror("setresid.2"); + cleanup(); + exit (EXIT_FAILURE); + } + + /* Check that the real uid is used, not the effective uid */ + error = access("test2", R_OK); + if (error) { + fprintf(stderr, "Effective uid was used instead of real uid in access().\n"); + errorseen++; + } + +#ifdef EACCESS_AVAILABLE + /* Check that the effective uid is used, not the real uid */ + error = eaccess("test3", R_OK); + if (error) { + fprintf(stderr, "Real uid was used instead of effective uid in eaccess().\n"); + errorseen++; + } +#endif + + /* Check that the real uid is used, not the effective uid */ + error = access("test3", R_OK); + if (!error) { + fprintf(stderr, "Effective uid was used instead of real uid in access().\n"); + errorseen++; + } + +#ifdef EACCESS_AVAILABLE + /* Check that the effective uid is used, not the real uid */ + error = eaccess("test2", R_OK); + if (error) { + fprintf(stderr, "Real uid was used instead of effective uid in eaccess().\n"); + errorseen++; + } +#endif + + error = restoreprivilege(); + if (error) { + perror("restoreprivilege"); + cleanup(); + exit (EXIT_FAILURE); + } + + error = setresgid(TEST_GID_ONE, TEST_GID_TWO, WHEEL_GID); + if (error) { + perror("setresgid.1"); + cleanup(); + exit (EXIT_FAILURE); + } + + /* Set non-root effective uid to avoid excess privilege. */ + error = setresuid(TEST_UID_ONE, TEST_UID_ONE, ROOT_UID); + if (error) { + perror("setresuid.3"); + cleanup(); + exit (EXIT_FAILURE); + } + + /* Check that the saved gid is not used */ + error = access("test4", R_OK); + if (!error) { + fprintf(stderr, "saved gid used instead of real gid\n"); + } + +#ifdef EACCESS_AVAILABLE + error = eaccess("test4", R_OK); + if (!error) { + fprintf(stderr, "saved gid used instead of effective gid\n"); + errorseen++; + } +#endif + + /* Check that the real gid is used, not the effective gid */ + error = access("test5", R_OK); + if (error) { + fprintf(stderr, "Effective gid was used instead of real gid in access().\n"); + errorseen++; + } + +#ifdef EACCESS_AVAILABLE + /* Check that the effective gid is used, not the real gid */ + error = eaccess("test6", R_OK); + if (error) { + fprintf(stderr, "Real gid was used instead of effective gid in eaccess().\n"); + errorseen++; + } +#endif + + /* Check that the real gid is used, not the effective gid */ + error = access("test6", R_OK); + if (!error) { + fprintf(stderr, "Effective gid was used instead of real gid in access().\n"); + errorseen++; + } + +#ifdef EACCESS_AVAILABLE + /* Check that the effective gid is used, not the real gid */ + error = eaccess("test5", R_OK); + if (!error) { + fprintf(stderr, "Real gid was used instead of effective gid in eaccess().\n"); + errorseen++; + } +#endif + + fprintf(stderr, "%d errors seen.\n", errorseen); + + /* + * All tests done, restore and clean up + */ + + error = cleanup(); + if (error) { + perror("cleanup"); + exit (EXIT_FAILURE); + } + + exit (EXIT_SUCCESS); +}