diff options
author | gjb <gjb@FreeBSD.org> | 2014-10-14 15:37:19 +0000 |
---|---|---|
committer | gjb <gjb@FreeBSD.org> | 2014-10-14 15:37:19 +0000 |
commit | 49bc9d1f7ffccd05cb04d7cb7b41a1ee2f39b46d (patch) | |
tree | acfa7870dec8e734f823d6db57d1b0799de03ad1 /contrib/netbsd-tests/lib/libc/sys | |
parent | 8521a45a5518d0da7ec2b53f2abb0f433d612a61 (diff) | |
parent | 594c54630f7d35d5f8feece66ae5ef818703cd18 (diff) | |
download | FreeBSD-src-49bc9d1f7ffccd05cb04d7cb7b41a1ee2f39b46d.zip FreeBSD-src-49bc9d1f7ffccd05cb04d7cb7b41a1ee2f39b46d.tar.gz |
Reintegrate head@r273095
Sponsored by: The FreeBSD Foundation
Diffstat (limited to 'contrib/netbsd-tests/lib/libc/sys')
57 files changed, 12488 insertions, 0 deletions
diff --git a/contrib/netbsd-tests/lib/libc/sys/t_access.c b/contrib/netbsd-tests/lib/libc/sys/t_access.c new file mode 100644 index 0000000..f15afc2 --- /dev/null +++ b/contrib/netbsd-tests/lib/libc/sys/t_access.c @@ -0,0 +1,210 @@ +/* $NetBSD: t_access.c,v 1.1 2011/07/07 06:57:53 jruoho Exp $ */ + +/*- + * Copyright (c) 2011 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jukka Ruohonen. + * + * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ +#include <sys/cdefs.h> +__RCSID("$NetBSD: t_access.c,v 1.1 2011/07/07 06:57:53 jruoho Exp $"); + +#include <errno.h> +#include <fcntl.h> +#include <limits.h> +#include <stdint.h> +#include <stdlib.h> +#include <unistd.h> + +#include <atf-c.h> + +static const char path[] = "access"; +static const int mode[4] = { R_OK, W_OK, X_OK, F_OK }; + +ATF_TC_WITH_CLEANUP(access_access); +ATF_TC_HEAD(access_access, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test access(2) for EACCES"); + atf_tc_set_md_var(tc, "require.user", "unprivileged"); +} + +ATF_TC_BODY(access_access, tc) +{ + const int perm[3] = { 0200, 0400, 0000 }; + size_t i; + int fd; + + fd = open(path, O_RDONLY | O_CREAT); + + if (fd < 0) + return; + + for (i = 0; i < __arraycount(mode) - 1; i++) { + + ATF_REQUIRE(fchmod(fd, perm[i]) == 0); + + errno = 0; + + ATF_REQUIRE(access(path, mode[i]) != 0); + ATF_REQUIRE(errno == EACCES); + } + + ATF_REQUIRE(close(fd) == 0); +} + +ATF_TC_CLEANUP(access_access, tc) +{ + (void)unlink(path); +} + +ATF_TC(access_fault); +ATF_TC_HEAD(access_fault, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test access(2) for EFAULT"); +} + +ATF_TC_BODY(access_fault, tc) +{ + size_t i; + + for (i = 0; i < __arraycount(mode); i++) { + + errno = 0; + + ATF_REQUIRE(access(NULL, mode[i]) != 0); + ATF_REQUIRE(errno == EFAULT); + + errno = 0; + + ATF_REQUIRE(access((char *)-1, mode[i]) != 0); + ATF_REQUIRE(errno == EFAULT); + } +} + +ATF_TC(access_inval); +ATF_TC_HEAD(access_inval, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test access(2) for EINVAL"); +} + +ATF_TC_BODY(access_inval, tc) +{ + + errno = 0; + + ATF_REQUIRE(access("/usr", -1) != 0); + ATF_REQUIRE(errno == EINVAL); +} + +ATF_TC(access_notdir); +ATF_TC_HEAD(access_notdir, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test access(2) for ENOTDIR"); +} + +ATF_TC_BODY(access_notdir, tc) +{ + size_t i; + + for (i = 0; i < __arraycount(mode); i++) { + + errno = 0; + + /* + * IEEE Std 1003.1-2008 about ENOTDIR: + * + * "A component of the path prefix is not a directory, + * or the path argument contains at least one non-<slash> + * character and ends with one or more trailing <slash> + * characters and the last pathname component names an + * existing file that is neither a directory nor a symbolic + * link to a directory." + */ + ATF_REQUIRE(access("/etc/passwd//", mode[i]) != 0); + ATF_REQUIRE(errno == ENOTDIR); + } +} + +ATF_TC(access_notexist); +ATF_TC_HEAD(access_notexist, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test access(2) for ENOENT"); +} + +ATF_TC_BODY(access_notexist, tc) +{ + size_t i; + + for (i = 0; i < __arraycount(mode); i++) { + + errno = 0; + + ATF_REQUIRE(access("", mode[i]) != 0); + ATF_REQUIRE(errno == ENOENT); + } +} + +ATF_TC(access_toolong); +ATF_TC_HEAD(access_toolong, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test access(2) for ENAMETOOLONG"); +} + +ATF_TC_BODY(access_toolong, tc) +{ + char *buf; + size_t i; + + buf = malloc(PATH_MAX); + + if (buf == NULL) + return; + + for (i = 0; i < PATH_MAX; i++) + buf[i] = 'x'; + + for (i = 0; i < __arraycount(mode); i++) { + + errno = 0; + + ATF_REQUIRE(access(buf, mode[i]) != 0); + ATF_REQUIRE(errno == ENAMETOOLONG); + } + + free(buf); +} + +ATF_TP_ADD_TCS(tp) +{ + + ATF_TP_ADD_TC(tp, access_access); + ATF_TP_ADD_TC(tp, access_fault); + ATF_TP_ADD_TC(tp, access_inval); + ATF_TP_ADD_TC(tp, access_notdir); + ATF_TP_ADD_TC(tp, access_notexist); + ATF_TP_ADD_TC(tp, access_toolong); + + return atf_no_error(); +} diff --git a/contrib/netbsd-tests/lib/libc/sys/t_chroot.c b/contrib/netbsd-tests/lib/libc/sys/t_chroot.c new file mode 100644 index 0000000..ce71708 --- /dev/null +++ b/contrib/netbsd-tests/lib/libc/sys/t_chroot.c @@ -0,0 +1,313 @@ +/* $NetBSD: t_chroot.c,v 1.1 2011/07/07 06:57:53 jruoho Exp $ */ + +/*- + * Copyright (c) 2011 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jukka Ruohonen. + * + * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ +#include <sys/cdefs.h> +__RCSID("$NetBSD: t_chroot.c,v 1.1 2011/07/07 06:57:53 jruoho Exp $"); + +#include <sys/wait.h> + +#include <atf-c.h> +#include <errno.h> +#include <fcntl.h> +#include <limits.h> +#include <pwd.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +ATF_TC(chroot_basic); +ATF_TC_HEAD(chroot_basic, tc) +{ + atf_tc_set_md_var(tc, "descr", "A basic test of chroot(2)"); + atf_tc_set_md_var(tc, "require.user", "root"); +} + +ATF_TC_BODY(chroot_basic, tc) +{ + char buf[PATH_MAX]; + int fd, sta; + pid_t pid; + + (void)memset(buf, '\0', sizeof(buf)); + (void)getcwd(buf, sizeof(buf)); + (void)strlcat(buf, "/dir", sizeof(buf)); + + ATF_REQUIRE(mkdir(buf, 0500) == 0); + ATF_REQUIRE(chdir(buf) == 0); + + pid = fork(); + ATF_REQUIRE(pid >= 0); + + if (pid == 0) { + + if (chroot(buf) != 0) + _exit(EXIT_FAILURE); + + errno = 0; + + if (chroot("/root") != -1) + _exit(EXIT_FAILURE); + + if (errno != ENOENT) + _exit(EXIT_FAILURE); + + fd = open("file", O_RDONLY | O_CREAT, 0600); + + if (fd < 0) + _exit(EXIT_FAILURE); + + if (close(fd) != 0) + _exit(EXIT_FAILURE); + + _exit(EXIT_SUCCESS); + } + + (void)wait(&sta); + + if (WIFEXITED(sta) == 0 || WEXITSTATUS(sta) != EXIT_SUCCESS) + atf_tc_fail("chroot(2) failed"); + + (void)chdir("/"); + (void)strlcat(buf, "/file", sizeof(buf)); + + fd = open(buf, O_RDONLY); + + if (fd < 0) + atf_tc_fail("chroot(2) did not change the root directory"); + + ATF_REQUIRE(close(fd) == 0); + ATF_REQUIRE(unlink(buf) == 0); +} + +ATF_TC(chroot_err); +ATF_TC_HEAD(chroot_err, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test error conditions of chroot(2)"); + atf_tc_set_md_var(tc, "require.user", "root"); +} + +ATF_TC_BODY(chroot_err, tc) +{ + char buf[PATH_MAX + 1]; + + (void)memset(buf, 'x', sizeof(buf)); + + errno = 0; + ATF_REQUIRE_ERRNO(ENAMETOOLONG, chroot(buf) == -1); + + errno = 0; + ATF_REQUIRE_ERRNO(EFAULT, chroot((void *)-1) == -1); + + errno = 0; + ATF_REQUIRE_ERRNO(ENOENT, chroot("/a/b/c/d/e/f/g/h/i/j") == -1); +} + +ATF_TC(chroot_perm); +ATF_TC_HEAD(chroot_perm, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test permissions with chroot(2)"); + atf_tc_set_md_var(tc, "require.user", "unprivileged"); +} + +ATF_TC_BODY(chroot_perm, tc) +{ + static char buf[LINE_MAX]; + pid_t pid; + int sta; + + (void)memset(buf, '\0', sizeof(buf)); + ATF_REQUIRE(getcwd(buf, sizeof(buf)) != NULL); + + pid = fork(); + ATF_REQUIRE(pid >= 0); + + if (pid == 0) { + + errno = 0; + + if (chroot(buf) != -1) + _exit(EXIT_FAILURE); + + if (errno != EPERM) + _exit(EXIT_FAILURE); + + _exit(EXIT_SUCCESS); + } + + (void)wait(&sta); + + if (WIFEXITED(sta) == 0 || WEXITSTATUS(sta) != EXIT_SUCCESS) + atf_tc_fail("chroot(2) succeeded as unprivileged user"); +} + +ATF_TC(fchroot_basic); +ATF_TC_HEAD(fchroot_basic, tc) +{ + atf_tc_set_md_var(tc, "descr", "A basic test of fchroot(2)"); + atf_tc_set_md_var(tc, "require.user", "root"); +} + +ATF_TC_BODY(fchroot_basic, tc) +{ + char buf[PATH_MAX]; + int fd, sta; + pid_t pid; + + (void)memset(buf, '\0', sizeof(buf)); + (void)getcwd(buf, sizeof(buf)); + (void)strlcat(buf, "/dir", sizeof(buf)); + + ATF_REQUIRE(mkdir(buf, 0500) == 0); + ATF_REQUIRE(chdir(buf) == 0); + + fd = open(buf, O_RDONLY); + ATF_REQUIRE(fd >= 0); + + pid = fork(); + ATF_REQUIRE(pid >= 0); + + if (pid == 0) { + + if (fchroot(fd) != 0) + _exit(EXIT_FAILURE); + + if (close(fd) != 0) + _exit(EXIT_FAILURE); + + fd = open("file", O_RDONLY | O_CREAT, 0600); + + if (fd < 0) + _exit(EXIT_FAILURE); + + if (close(fd) != 0) + _exit(EXIT_FAILURE); + + _exit(EXIT_SUCCESS); + } + + (void)wait(&sta); + + if (WIFEXITED(sta) == 0 || WEXITSTATUS(sta) != EXIT_SUCCESS) + atf_tc_fail("fchroot(2) failed"); + + (void)chdir("/"); + (void)strlcat(buf, "/file", sizeof(buf)); + + fd = open(buf, O_RDONLY); + + if (fd < 0) + atf_tc_fail("fchroot(2) did not change the root directory"); + + ATF_REQUIRE(close(fd) == 0); + ATF_REQUIRE(unlink(buf) == 0); +} + +ATF_TC(fchroot_err); +ATF_TC_HEAD(fchroot_err, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test error conditions of fchroot(2)"); + atf_tc_set_md_var(tc, "require.user", "root"); +} + +ATF_TC_BODY(fchroot_err, tc) +{ + int fd; + + fd = open("/etc/passwd", O_RDONLY); + ATF_REQUIRE(fd >= 0); + + errno = 0; + ATF_REQUIRE_ERRNO(EBADF, fchroot(-1) == -1); + + errno = 0; + ATF_REQUIRE_ERRNO(ENOTDIR, fchroot(fd) == -1); + + ATF_REQUIRE(close(fd) == 0); +} + +ATF_TC(fchroot_perm); +ATF_TC_HEAD(fchroot_perm, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test permissions with fchroot(2)"); + atf_tc_set_md_var(tc, "require.user", "root"); +} + +ATF_TC_BODY(fchroot_perm, tc) +{ + static char buf[LINE_MAX]; + struct passwd *pw; + int fd, sta; + pid_t pid; + + (void)memset(buf, '\0', sizeof(buf)); + ATF_REQUIRE(getcwd(buf, sizeof(buf)) != NULL); + + pw = getpwnam("nobody"); + fd = open(buf, O_RDONLY); + + ATF_REQUIRE(fd >= 0); + ATF_REQUIRE(pw != NULL); + + pid = fork(); + ATF_REQUIRE(pid >= 0); + + if (pid == 0) { + + (void)setuid(pw->pw_uid); + + errno = 0; + + if (fchroot(fd) != -1) + _exit(EXIT_FAILURE); + + if (errno != EPERM) + _exit(EXIT_FAILURE); + + _exit(EXIT_SUCCESS); + } + + (void)wait(&sta); + + if (WIFEXITED(sta) == 0 || WEXITSTATUS(sta) != EXIT_SUCCESS) + atf_tc_fail("fchroot(2) succeeded as unprivileged user"); +} + +ATF_TP_ADD_TCS(tp) +{ + + ATF_TP_ADD_TC(tp, chroot_basic); + ATF_TP_ADD_TC(tp, chroot_err); + ATF_TP_ADD_TC(tp, chroot_perm); + ATF_TP_ADD_TC(tp, fchroot_basic); + ATF_TP_ADD_TC(tp, fchroot_err); + ATF_TP_ADD_TC(tp, fchroot_perm); + + return atf_no_error(); +} diff --git a/contrib/netbsd-tests/lib/libc/sys/t_clock_gettime.c b/contrib/netbsd-tests/lib/libc/sys/t_clock_gettime.c new file mode 100644 index 0000000..69890fd --- /dev/null +++ b/contrib/netbsd-tests/lib/libc/sys/t_clock_gettime.c @@ -0,0 +1,212 @@ +/* $NetBSD: t_clock_gettime.c,v 1.1 2011/10/15 06:42:16 jruoho Exp $ */ + +/*- + * Copyright (c) 2008 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Frank Kardel. + * + * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ + +/*- + * Copyright (c) 2006 Frank Kardel + * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ + +#include <sys/cdefs.h> +__COPYRIGHT("@(#) Copyright (c) 2008\ + The NetBSD Foundation, inc. All rights reserved."); +__RCSID("$NetBSD: t_clock_gettime.c,v 1.1 2011/10/15 06:42:16 jruoho Exp $"); + +#include <sys/param.h> +#include <sys/sysctl.h> + +#include <machine/int_limits.h> + +#include <atf-c.h> +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include <unistd.h> + +#include "../../../h_macros.h" + +#define MINPOSDIFF 15000000 /* 15 ms for now */ +#define TIMEOUT 5 + +#define TC_HARDWARE "kern.timecounter.hardware" +#define TC_CHOICE "kern.timecounter.choice" + +static void +check_timecounter(void) +{ + struct timespec tsa, tsb, tsl, res; + long long mindiff = INTMAX_MAX; + time_t endlimit; + +#define CL(x) \ + do { \ + if ((x) != -1) \ + break; \ + atf_tc_fail_nonfatal("%s: %s", #x, strerror(errno)); \ + return; \ + } while (0) + + CL(clock_gettime(CLOCK_REALTIME, &tsa)); + tsl = tsa; + + CL(time(&endlimit)); + endlimit += TIMEOUT + 1; + + while ((time_t)tsa.tv_sec < endlimit) { + long long diff; + + CL(clock_gettime(CLOCK_REALTIME, &tsb)); + diff = 1000000000LL * (tsb.tv_sec - tsa.tv_sec) + + tsb.tv_nsec - tsa.tv_nsec; + + if (diff > 0 && mindiff > diff) + mindiff = diff; + + if (diff < 0 || diff > MINPOSDIFF) { + long long elapsed; + (void)printf("%stime TSA: 0x%jx.%08jx, TSB: 0x%jx.%08jx, " + "diff = %lld nsec, ", (diff < 0) ? "BAD " : "", + (uintmax_t)tsa.tv_sec, (uintmax_t)tsa.tv_nsec, + (uintmax_t)tsb.tv_sec, (uintmax_t)tsb.tv_nsec, diff); + + elapsed = 1000000000LL * (tsb.tv_sec - tsl.tv_sec) + + tsb.tv_nsec - tsl.tv_nsec; + + + (void)printf("%lld nsec\n", elapsed); + tsl = tsb; + + ATF_CHECK(diff >= 0); + if (diff < 0) + return; + } + + tsa.tv_sec = tsb.tv_sec; + tsa.tv_nsec = tsb.tv_nsec; + } + + if (clock_getres(CLOCK_REALTIME, &res) == 0) { + long long r = res.tv_sec * 1000000000 + res.tv_nsec; + + (void)printf("Claimed resolution: %lld nsec (%f Hz) or " + "better\n", r, 1.0 / r * 1e9); + (void)printf("Observed minimum non zero delta: %lld " + "nsec\n", mindiff); + } + +#undef CL +} + +ATF_TC(clock_gettime_real); +ATF_TC_HEAD(clock_gettime_real, tc) +{ + atf_tc_set_md_var(tc, "require.user", "root"); + atf_tc_set_md_var(tc, "descr", + "Checks the monotonicity of the CLOCK_REALTIME implementation"); + atf_tc_set_md_var(tc, "timeout", "300"); +} + +ATF_TC_BODY(clock_gettime_real, tc) +{ + char name[128], cbuf[512], ctrbuf[10240]; + size_t cbufsiz = sizeof(cbuf); + size_t ctrbufsiz = sizeof(ctrbuf); + const char *p; + char *save; + int quality, n; + + if (sysctlbyname(TC_HARDWARE, cbuf, &cbufsiz, NULL, 0) != 0) { + (void)printf("\nChecking legacy time implementation " + "for %d seconds\n", TIMEOUT); + check_timecounter(); + return; + /* NOTREACHED */ + } + (void)printf("%s = %s\n", TC_HARDWARE, cbuf); + REQUIRE_LIBC(save = strdup(cbuf), NULL); + + RL(sysctlbyname(TC_CHOICE, ctrbuf, &ctrbufsiz, NULL, 0)); + (void)printf("%s = %s\n", TC_CHOICE, ctrbuf); + + for (p = ctrbuf, n = 0; sscanf(p, "%127[^(](q=%d, f=%*u Hz)%*[ ]%n", + name, &quality, &n) == 2; p += n) { + struct timespec ts; + int ret; + + if (quality < 0) + continue; + + (void)printf("\nChecking %s for %d seconds\n", name, TIMEOUT); + CHECK_LIBC(ret = sysctlbyname(TC_HARDWARE, NULL, 0, + name, strlen(name)), -1); + if (ret == -1) + continue; + + /* wait a bit to select new counter in clockinterrupt */ + ts.tv_sec = 0; + ts.tv_nsec = 100000000; + (void)nanosleep(&ts, NULL); + + check_timecounter(); + } + + RL(sysctlbyname(TC_HARDWARE, NULL, 0, save, strlen(save))); +} + +ATF_TP_ADD_TCS(tp) +{ + + ATF_TP_ADD_TC(tp, clock_gettime_real); + + return atf_no_error(); +} diff --git a/contrib/netbsd-tests/lib/libc/sys/t_clone.c b/contrib/netbsd-tests/lib/libc/sys/t_clone.c new file mode 100644 index 0000000..ea33f32 --- /dev/null +++ b/contrib/netbsd-tests/lib/libc/sys/t_clone.c @@ -0,0 +1,252 @@ +/* $NetBSD: t_clone.c,v 1.3 2011/12/12 20:55:44 joerg Exp $ */ + +/*- + * Copyright (c) 2008 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jason R. Thorpe. + * + * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ + +#include <sys/cdefs.h> +__COPYRIGHT("@(#) Copyright (c) 2008\ + The NetBSD Foundation, inc. All rights reserved."); +__RCSID("$NetBSD: t_clone.c,v 1.3 2011/12/12 20:55:44 joerg Exp $"); + +#include <sys/mman.h> +#include <sys/resource.h> +#include <sys/types.h> +#include <sys/wait.h> + +#include <errno.h> +#include <sched.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include <atf-c.h> + +#define STACKSIZE (8 * 1024) +#define FROBVAL 41973 +#define CHILDEXIT 0xa5 + +static int +dummy(void *arg) +{ + + return 0; +} + +static int +clone_func(void *arg) +{ + long *frobp = arg, diff; + + printf("child: stack ~= %p, frobme = %p\n", &frobp, frobp); + fflush(stdout); + + if (frobp[0] != getppid()) + return 1; + + if (frobp[0] == getpid()) + return 2; + + diff = labs(frobp[1] - (long) &frobp); + + if (diff > 1024) + return 3; + + frobp[1] = FROBVAL; + + return (CHILDEXIT); +} + +ATF_TC(clone_basic); +ATF_TC_HEAD(clone_basic, tc) +{ + + atf_tc_set_md_var(tc, "descr", "Checks clone(2)"); +} + +ATF_TC_BODY(clone_basic, tc) +{ + sigset_t mask; + void *allocstack, *stack; + pid_t pid; + volatile long frobme[2]; + int stat; + + allocstack = mmap(NULL, STACKSIZE, PROT_READ|PROT_WRITE|PROT_EXEC, + MAP_PRIVATE|MAP_ANON, -1, (off_t) 0); + + ATF_REQUIRE_ERRNO(errno, allocstack != MAP_FAILED); + + stack = allocstack; +#ifndef __MACHINE_STACK_GROWS_UP + stack = (char *)stack + STACKSIZE; +#endif + + printf("parent: stack = %p, frobme = %p\n", stack, frobme); + fflush(stdout); + + frobme[0] = (long)getpid(); + frobme[1] = (long)stack; + + sigemptyset(&mask); + sigaddset(&mask, SIGUSR1); + + ATF_REQUIRE_ERRNO(errno, sigprocmask(SIG_BLOCK, &mask, NULL) != -1); + + switch (pid = __clone(clone_func, stack, + CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|SIGUSR1, + __UNVOLATILE(frobme))) { + case 0: + atf_tc_fail("clone() returned 0"); + /*NOTREACHED*/ + case -1: + atf_tc_fail("clone() failed: %s", strerror(errno)); + /*NOTREACHED*/ + default: + while (waitpid(pid, &stat, __WCLONE) != pid) + continue; + } + + ATF_REQUIRE_MSG(WIFEXITED(stat) != 0, "child didn't exit"); + + printf("parent: childexit = 0x%x, frobme = %ld\n", + WEXITSTATUS(stat), frobme[1]); + + switch (WEXITSTATUS(stat)) { + case CHILDEXIT: + ATF_REQUIRE_EQ(frobme[1], FROBVAL); + break; + case 1: + atf_tc_fail("child: argument does not contain parent's pid"); + /*NOTREACHED*/ + case 2: + atf_tc_fail("child: called in parent's pid"); + /*NOTREACHED*/ + case 3: + atf_tc_fail("child: called with bad stack"); + /*NOTREACHED*/ + default: + atf_tc_fail("child returned unknown code: %d", + WEXITSTATUS(stat)); + /*NOTREACHED*/ + } + + ATF_REQUIRE_ERRNO(errno, munmap(allocstack, STACKSIZE) != -1); +} + +ATF_TC(clone_null_stack); +ATF_TC_HEAD(clone_null_stack, tc) +{ + + atf_tc_set_md_var(tc, "descr", + "Checks that clone(2) fails when stack pointer is NULL"); +} + +ATF_TC_BODY(clone_null_stack, tc) +{ + int rv; + + rv = __clone(dummy, NULL, + CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|SIGCHLD, NULL); + + ATF_REQUIRE_EQ(rv, -1); + ATF_REQUIRE_EQ(errno, EINVAL); +} + +ATF_TC(clone_null_func); +ATF_TC_HEAD(clone_null_func, tc) +{ + + atf_tc_set_md_var(tc, "descr", + "Checks that clone(2) fails when function pointer is NULL"); +} + +ATF_TC_BODY(clone_null_func, tc) +{ + void *allocstack, *stack; + int rv; + + allocstack = mmap(NULL, STACKSIZE, PROT_READ|PROT_WRITE|PROT_EXEC, + MAP_PRIVATE|MAP_ANON, -1, (off_t) 0); + ATF_REQUIRE_ERRNO(errno, allocstack != MAP_FAILED); + stack = allocstack; +#ifndef __MACHINE_STACK_GROWS_UP + stack = (char *)stack + STACKSIZE; +#endif + + errno = 0; + rv = __clone(0, stack, + CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|SIGCHLD, NULL); + + ATF_REQUIRE_EQ(rv, -1); + ATF_REQUIRE_EQ(errno, EINVAL); + + ATF_REQUIRE_ERRNO(errno, munmap(allocstack, STACKSIZE) != -1); +} + +ATF_TC(clone_out_of_proc); +ATF_TC_HEAD(clone_out_of_proc, tc) +{ + + atf_tc_set_md_var(tc, "descr", + "Checks that clone(2) fails when running out of processes"); + atf_tc_set_md_var(tc, "require.user", "unprivileged"); +} + +ATF_TC_BODY(clone_out_of_proc, tc) +{ + struct rlimit rl; + int rv; + + ATF_REQUIRE_ERRNO(errno, getrlimit(RLIMIT_NPROC, &rl) != -1); + + rl.rlim_cur = 0; + rl.rlim_max = 0; + + ATF_REQUIRE_ERRNO(errno, setrlimit(RLIMIT_NPROC, &rl) != -1); + + errno = 0; + rv = __clone(dummy, malloc(10240), + CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|SIGCHLD, (void *)&rl); + + ATF_REQUIRE_EQ(rv, -1); + ATF_REQUIRE_EQ(errno, EAGAIN); +} + +ATF_TP_ADD_TCS(tp) +{ + + ATF_TP_ADD_TC(tp, clone_basic); + ATF_TP_ADD_TC(tp, clone_null_stack); + ATF_TP_ADD_TC(tp, clone_null_func); + ATF_TP_ADD_TC(tp, clone_out_of_proc); + + return atf_no_error(); +} diff --git a/contrib/netbsd-tests/lib/libc/sys/t_connect.c b/contrib/netbsd-tests/lib/libc/sys/t_connect.c new file mode 100644 index 0000000..d161ee3 --- /dev/null +++ b/contrib/netbsd-tests/lib/libc/sys/t_connect.c @@ -0,0 +1,99 @@ +/* $NetBSD: t_connect.c,v 1.1 2011/11/05 18:19:02 jruoho Exp $ */ +/* + * Copyright (c) 2007, 2008 The NetBSD Foundation, 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ + +#include <err.h> +#include <errno.h> +#include <string.h> +#include <unistd.h> + +#include <arpa/inet.h> +#include <netinet/in.h> + +#include <atf-c.h> + +ATF_TC(connect_low_port); +ATF_TC_HEAD(connect_low_port, tc) +{ + atf_tc_set_md_var(tc, "descr", "Checks that low-port allocation " + "works"); + atf_tc_set_md_var(tc, "require.user", "root"); +} +ATF_TC_BODY(connect_low_port, tc) +{ + struct sockaddr_in sin, sinlist; + int sd, val, slist; + socklen_t slen; + + slist = socket(AF_INET, SOCK_STREAM, 0); + sd = socket(AF_INET, SOCK_STREAM, 0); + + /* bind listening socket */ + memset(&sinlist, 0, sizeof(sinlist)); + sinlist.sin_family = AF_INET; + sinlist.sin_port = htons(31522); + sinlist.sin_addr.s_addr = inet_addr("127.0.0.1"); + + ATF_REQUIRE_EQ(bind(slist, + (struct sockaddr *)&sinlist, sizeof(sinlist)), 0); + ATF_REQUIRE_EQ(listen(slist, 1), 0); + + val = IP_PORTRANGE_LOW; + if (setsockopt(sd, IPPROTO_IP, IP_PORTRANGE, &val, + sizeof(val)) == -1) + atf_tc_fail("setsockopt failed: %s", strerror(errno)); + + memset(&sin, 0, sizeof(sin)); + + sin.sin_port = htons(31522); + sin.sin_addr.s_addr = inet_addr("127.0.0.1"); + sin.sin_family = AF_INET; + + if (connect(sd, (struct sockaddr *)&sin, sizeof(sin)) == -1) { + int serrno = errno; + atf_tc_fail("connect failed: %s%s", + strerror(serrno), + serrno != EACCES ? "" : + " (see http://mail-index.netbsd.org/" + "source-changes/2007/12/16/0011.html)"); + } + + slen = sizeof(sin); + ATF_REQUIRE_EQ(getsockname(sd, (struct sockaddr *)&sin, &slen), 0); + ATF_REQUIRE_EQ(slen, sizeof(sin)); + ATF_REQUIRE(ntohs(sin.sin_port) <= IPPORT_RESERVEDMAX); + + close(sd); +} + +ATF_TP_ADD_TCS(tp) +{ + + ATF_TP_ADD_TC(tp, connect_low_port); + + return atf_no_error(); +} diff --git a/contrib/netbsd-tests/lib/libc/sys/t_dup.c b/contrib/netbsd-tests/lib/libc/sys/t_dup.c new file mode 100644 index 0000000..a2623c0 --- /dev/null +++ b/contrib/netbsd-tests/lib/libc/sys/t_dup.c @@ -0,0 +1,385 @@ +/* $NetBSD: t_dup.c,v 1.8 2012/03/18 07:00:51 jruoho Exp $ */ + +/*- + * Copyright (c) 2011 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jukka Ruohonen. + * + * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ +#include <sys/cdefs.h> +__RCSID("$NetBSD: t_dup.c,v 1.8 2012/03/18 07:00:51 jruoho Exp $"); + +#include <sys/resource.h> +#include <sys/stat.h> +#include <sys/wait.h> + +#include <atf-c.h> +#include <errno.h> +#include <fcntl.h> +#include <limits.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sysexits.h> + +static char path[] = "dup"; +static void check_mode(bool, bool, bool); + +static void +check_mode(bool _dup, bool _dup2, bool _dup3) +{ + int mode[3] = { O_RDONLY, O_WRONLY, O_RDWR }; + int perm[5] = { 0700, 0400, 0600, 0444, 0666 }; + struct stat st, st1; + int fd, fd1, fd2; + size_t i, j; + + /* + * Check that a duplicated descriptor + * retains the mode of the original file. + */ + for (i = 0; i < __arraycount(mode); i++) { + + for (j = 0; j < __arraycount(perm); j++) { + + fd1 = open(path, mode[i] | O_CREAT, perm[j]); + fd2 = open("/etc/passwd", O_RDONLY); + + ATF_REQUIRE(fd1 >= 0); + ATF_REQUIRE(fd2 >= 0); + + if (_dup != false) + fd = dup(fd1); + else if (_dup2 != false) + fd = dup2(fd1, fd2); + else if (_dup3 != false) + fd = dup3(fd1, fd2, O_CLOEXEC); + else { + fd = -1; + } + + ATF_REQUIRE(fd >= 0); + + (void)memset(&st, 0, sizeof(struct stat)); + (void)memset(&st1, 0, sizeof(struct stat)); + + ATF_REQUIRE(fstat(fd, &st) == 0); + ATF_REQUIRE(fstat(fd1, &st1) == 0); + + if (st.st_mode != st1.st_mode) + atf_tc_fail("invalid mode"); + + (void)close(fd); + (void)close(fd1); + (void)close(fd2); + (void)unlink(path); + } + } +} + +ATF_TC(dup2_basic); +ATF_TC_HEAD(dup2_basic, tc) +{ + atf_tc_set_md_var(tc, "descr", "A basic test of dup2(2)"); +} + +ATF_TC_BODY(dup2_basic, tc) +{ + int fd, fd1, fd2; + + fd1 = open("/etc/passwd", O_RDONLY); + fd2 = open("/etc/passwd", O_RDONLY); + + ATF_REQUIRE(fd1 >= 0); + ATF_REQUIRE(fd2 >= 0); + + fd = dup2(fd1, fd2); + ATF_REQUIRE(fd >= 0); + + if (fd != fd2) + atf_tc_fail("invalid descriptor"); + + (void)close(fd); + (void)close(fd1); + + ATF_REQUIRE(close(fd2) != 0); +} + +ATF_TC(dup2_err); +ATF_TC_HEAD(dup2_err, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test error conditions of dup2(2)"); +} + +ATF_TC_BODY(dup2_err, tc) +{ + int fd; + + fd = open("/etc/passwd", O_RDONLY); + ATF_REQUIRE(fd >= 0); + + errno = 0; + ATF_REQUIRE_ERRNO(EBADF, dup2(-1, -1) == -1); + + errno = 0; + ATF_REQUIRE_ERRNO(EBADF, dup2(fd, -1) == -1); + + errno = 0; + ATF_REQUIRE_ERRNO(EBADF, dup2(-1, fd) == -1); + + /* + * Note that this should not fail with EINVAL. + */ + ATF_REQUIRE(dup2(fd, fd) != -1); + + (void)close(fd); +} + +ATF_TC(dup2_max); +ATF_TC_HEAD(dup2_max, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test dup2(2) against limits"); +} + +ATF_TC_BODY(dup2_max, tc) +{ + struct rlimit res; + + (void)memset(&res, 0, sizeof(struct rlimit)); + (void)getrlimit(RLIMIT_NOFILE, &res); + + errno = 0; + ATF_REQUIRE_ERRNO(EBADF, dup2(STDERR_FILENO, res.rlim_cur + 1) == -1); +} + +ATF_TC_WITH_CLEANUP(dup2_mode); +ATF_TC_HEAD(dup2_mode, tc) +{ + atf_tc_set_md_var(tc, "descr", "A basic test of dup2(2)"); +} + +ATF_TC_BODY(dup2_mode, tc) +{ + check_mode(false, true, false); +} + +ATF_TC_CLEANUP(dup2_mode, tc) +{ + (void)unlink(path); +} + + +ATF_TC(dup3_err); +ATF_TC_HEAD(dup3_err, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Test error conditions of dup3(2) (PR lib/45148)"); +} + +ATF_TC_BODY(dup3_err, tc) +{ + int fd; + + fd = open("/etc/passwd", O_RDONLY); + ATF_REQUIRE(fd >= 0); + + errno = 0; + ATF_REQUIRE(dup3(fd, fd, O_CLOEXEC) != -1); + + errno = 0; + ATF_REQUIRE_ERRNO(EBADF, dup3(-1, -1, O_CLOEXEC) == -1); + + errno = 0; + ATF_REQUIRE_ERRNO(EBADF, dup3(fd, -1, O_CLOEXEC) == -1); + + errno = 0; + ATF_REQUIRE_ERRNO(EBADF, dup3(-1, fd, O_CLOEXEC) == -1); + + errno = 0; + ATF_REQUIRE_ERRNO(EINVAL, dup3(fd, 1, O_NOFOLLOW) == -1); + + (void)close(fd); +} + +ATF_TC(dup3_max); +ATF_TC_HEAD(dup3_max, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test dup3(2) against limits"); +} + +ATF_TC_BODY(dup3_max, tc) +{ + struct rlimit res; + + (void)memset(&res, 0, sizeof(struct rlimit)); + (void)getrlimit(RLIMIT_NOFILE, &res); + + errno = 0; + ATF_REQUIRE_ERRNO(EBADF, dup3(STDERR_FILENO, + res.rlim_cur + 1, O_CLOEXEC) == -1); +} + +ATF_TC_WITH_CLEANUP(dup3_mode); +ATF_TC_HEAD(dup3_mode, tc) +{ + atf_tc_set_md_var(tc, "descr", "A basic test of dup3(2)"); +} + +ATF_TC_BODY(dup3_mode, tc) +{ + check_mode(false, false, true); +} + +ATF_TC_CLEANUP(dup3_mode, tc) +{ + (void)unlink(path); +} + +ATF_TC(dup_err); +ATF_TC_HEAD(dup_err, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test error conditions of dup(2)"); +} + +ATF_TC_BODY(dup_err, tc) +{ + + errno = 0; + ATF_REQUIRE_ERRNO(EBADF, dup(-1) == -1); +} + +ATF_TC_WITH_CLEANUP(dup_max); +ATF_TC_HEAD(dup_max, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test dup(2) against limits"); +} + +ATF_TC_BODY(dup_max, tc) +{ + struct rlimit res; + int *buf, fd, sta; + size_t i, n; + pid_t pid; + + pid = fork(); + ATF_REQUIRE(pid >= 0); + + if (pid == 0) { + + /* + * Open a temporary file until the + * maximum number of open files is + * reached. Ater that dup(2) family + * should fail with EMFILE. + */ + (void)closefrom(0); + (void)memset(&res, 0, sizeof(struct rlimit)); + + n = 10; + res.rlim_cur = res.rlim_max = n; + if (setrlimit(RLIMIT_NOFILE, &res) != 0) + _exit(EX_OSERR); + + buf = calloc(n, sizeof(int)); + + if (buf == NULL) + _exit(EX_OSERR); + + buf[0] = mkstemp(path); + + if (buf[0] < 0) + _exit(EX_OSERR); + + for (i = 1; i < n; i++) { + + buf[i] = open(path, O_RDONLY); + + if (buf[i] < 0) + _exit(EX_OSERR); + } + + errno = 0; + fd = dup(buf[0]); + + if (fd != -1 || errno != EMFILE) + _exit(EX_DATAERR); + + _exit(EXIT_SUCCESS); + } + + (void)wait(&sta); + + if (WIFEXITED(sta) == 0 || WEXITSTATUS(sta) != EXIT_SUCCESS) { + + if (WEXITSTATUS(sta) == EX_OSERR) + atf_tc_fail("system call error"); + + if (WEXITSTATUS(sta) == EX_DATAERR) + atf_tc_fail("dup(2) dupped more than RLIMIT_NOFILE"); + + atf_tc_fail("unknown error"); + } + + (void)unlink(path); +} + +ATF_TC_CLEANUP(dup_max, tc) +{ + (void)unlink(path); +} + +ATF_TC_WITH_CLEANUP(dup_mode); +ATF_TC_HEAD(dup_mode, tc) +{ + atf_tc_set_md_var(tc, "descr", "A basic test of dup(2)"); +} + +ATF_TC_BODY(dup_mode, tc) +{ + check_mode(true, false, false); +} + +ATF_TC_CLEANUP(dup_mode, tc) +{ + (void)unlink(path); +} + +ATF_TP_ADD_TCS(tp) +{ + + ATF_TP_ADD_TC(tp, dup2_basic); + ATF_TP_ADD_TC(tp, dup2_err); + ATF_TP_ADD_TC(tp, dup2_max); + ATF_TP_ADD_TC(tp, dup2_mode); + ATF_TP_ADD_TC(tp, dup3_err); + ATF_TP_ADD_TC(tp, dup3_max); + ATF_TP_ADD_TC(tp, dup3_mode); + ATF_TP_ADD_TC(tp, dup_err); + ATF_TP_ADD_TC(tp, dup_max); + ATF_TP_ADD_TC(tp, dup_mode); + + return atf_no_error(); +} diff --git a/contrib/netbsd-tests/lib/libc/sys/t_fsync.c b/contrib/netbsd-tests/lib/libc/sys/t_fsync.c new file mode 100644 index 0000000..e61ea7e --- /dev/null +++ b/contrib/netbsd-tests/lib/libc/sys/t_fsync.c @@ -0,0 +1,120 @@ +/* $NetBSD: t_fsync.c,v 1.2 2012/03/18 07:00:52 jruoho Exp $ */ + +/*- + * Copyright (c) 2011 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jukka Ruohonen. + * + * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ +#include <sys/cdefs.h> +__RCSID("$NetBSD: t_fsync.c,v 1.2 2012/03/18 07:00:52 jruoho Exp $"); + +#include <errno.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include <atf-c.h> + +ATF_TC(fsync_err); +ATF_TC_HEAD(fsync_err, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Test error conditions of fsync(2) (PR kern/30)"); +} + +ATF_TC_BODY(fsync_err, tc) +{ + int i, fd[2]; + + /* + * The fsync(2) call should fail with EBADF + * when the 'fd' is not a valid descriptor. + */ + for (i = 1; i < 1024; i = i + 128) { + + errno = 0; + + ATF_REQUIRE(fsync(-i) == -1); + ATF_REQUIRE(errno == EBADF); + } + + /* + * On the other hand, EINVAL should follow + * if the operation is not possible with + * the file descriptor. + */ + ATF_REQUIRE(pipe(fd) == 0); + + errno = 0; + + ATF_REQUIRE(fsync(fd[0]) == -1); + ATF_REQUIRE(errno == EINVAL); + + errno = 0; + + ATF_REQUIRE(fsync(fd[1]) == -1); + ATF_REQUIRE(errno == EINVAL); + + ATF_REQUIRE(close(fd[0]) == 0); + ATF_REQUIRE(close(fd[1]) == 0); +} + +ATF_TC(fsync_sync); +ATF_TC_HEAD(fsync_sync, tc) +{ + atf_tc_set_md_var(tc, "descr", "A basic test of fsync(2)"); +} + +ATF_TC_BODY(fsync_sync, tc) +{ + char buf[128]; + int fd, i; + + for (i = 0; i < 10; i++) { + + (void)snprintf(buf, sizeof(buf), "t_fsync-%d", i); + + fd = mkstemp(buf); + + ATF_REQUIRE(fd != -1); + ATF_REQUIRE(write(fd, "0", 1) == 1); + ATF_REQUIRE(fsync(fd) == 0); + + ATF_REQUIRE(unlink(buf) == 0); + ATF_REQUIRE(close(fd) == 0); + } +} + +ATF_TP_ADD_TCS(tp) +{ + + ATF_TP_ADD_TC(tp, fsync_err); + ATF_TP_ADD_TC(tp, fsync_sync); + + return atf_no_error(); +} diff --git a/contrib/netbsd-tests/lib/libc/sys/t_getcontext.c b/contrib/netbsd-tests/lib/libc/sys/t_getcontext.c new file mode 100644 index 0000000..3a2d9f7 --- /dev/null +++ b/contrib/netbsd-tests/lib/libc/sys/t_getcontext.c @@ -0,0 +1,129 @@ +/* $NetBSD: t_getcontext.c,v 1.3 2011/07/14 04:59:14 jruoho Exp $ */ + +/*- + * Copyright (c) 2008 The NetBSD Foundation, 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ + +#include <sys/cdefs.h> +__COPYRIGHT("@(#) Copyright (c) 2008\ + The NetBSD Foundation, inc. All rights reserved."); +__RCSID("$NetBSD: t_getcontext.c,v 1.3 2011/07/14 04:59:14 jruoho Exp $"); + +#include <atf-c.h> +#include <errno.h> +#include <stdarg.h> +#include <stdlib.h> +#include <ucontext.h> + +#define STACKSZ (10*1024) +#define DEPTH 3 + +static int calls; + +static void +run(int n, ...) +{ + va_list va; + int i, ia; + + ATF_REQUIRE_EQ(n, DEPTH - calls - 1); + + va_start(va, n); + for (i = 0; i < 9; i++) { + ia = va_arg(va, int); + ATF_REQUIRE_EQ(i, ia); + } + va_end(va); + + calls++; +} + +ATF_TC(getcontext_err); +ATF_TC_HEAD(getcontext_err, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test errors from getcontext(2)"); +} + +ATF_TC_BODY(getcontext_err, tc) +{ + + errno = 0; + ATF_REQUIRE_ERRNO(EFAULT, getcontext((void *)-1) == -1); +} + +ATF_TC(setcontext_err); +ATF_TC_HEAD(setcontext_err, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test errors from setcontext(2)"); +} + +ATF_TC_BODY(setcontext_err, tc) +{ + + errno = 0; + ATF_REQUIRE_ERRNO(EFAULT, setcontext((void *)-1) == -1); +} + +ATF_TC(setcontext_link); +ATF_TC_HEAD(setcontext_link, tc) +{ + + atf_tc_set_md_var(tc, "descr", + "Checks get/make/setcontext(), context linking via uc_link(), " + "and argument passing to the new context"); +} + +ATF_TC_BODY(setcontext_link, tc) +{ + ucontext_t uc[DEPTH]; + ucontext_t save; + volatile int i = 0; /* avoid longjmp clobbering */ + + for (i = 0; i < DEPTH; ++i) { + ATF_REQUIRE_EQ(getcontext(&uc[i]), 0); + + uc[i].uc_stack.ss_sp = malloc(STACKSZ); + uc[i].uc_stack.ss_size = STACKSZ; + uc[i].uc_link = (i > 0) ? &uc[i - 1] : &save; + + makecontext(&uc[i], (void *)run, 10, i, + 0, 1, 2, 3, 4, 5, 6, 7, 8); + } + + ATF_REQUIRE_EQ(getcontext(&save), 0); + + if (calls == 0) + ATF_REQUIRE_EQ(setcontext(&uc[DEPTH-1]), 0); +} + +ATF_TP_ADD_TCS(tp) +{ + + ATF_TP_ADD_TC(tp, getcontext_err); + ATF_TP_ADD_TC(tp, setcontext_err); + ATF_TP_ADD_TC(tp, setcontext_link); + + return atf_no_error(); +} diff --git a/contrib/netbsd-tests/lib/libc/sys/t_getgroups.c b/contrib/netbsd-tests/lib/libc/sys/t_getgroups.c new file mode 100644 index 0000000..9a8ec8e --- /dev/null +++ b/contrib/netbsd-tests/lib/libc/sys/t_getgroups.c @@ -0,0 +1,171 @@ +/* $NetBSD: t_getgroups.c,v 1.1 2011/07/07 06:57:53 jruoho Exp $ */ + +/*- + * Copyright (c) 2011 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jukka Ruohonen. + * + * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ +#include <sys/cdefs.h> +__RCSID("$NetBSD: t_getgroups.c,v 1.1 2011/07/07 06:57:53 jruoho Exp $"); + +#include <sys/wait.h> + +#include <atf-c.h> +#include <errno.h> +#include <limits.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +ATF_TC(getgroups_err); +ATF_TC_HEAD(getgroups_err, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test errors in getgroups(2)"); +} + +ATF_TC_BODY(getgroups_err, tc) +{ + gid_t gidset[NGROUPS_MAX]; + + errno = 0; + + ATF_REQUIRE(getgroups(10, (gid_t *)-1) == -1); + ATF_REQUIRE(errno == EFAULT); + + errno = 0; + + ATF_REQUIRE(getgroups(-1, gidset) == -1); + ATF_REQUIRE(errno == EINVAL); +} + +ATF_TC(getgroups_getgid); +ATF_TC_HEAD(getgroups_getgid, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test getgid(2) from getgroups(2)"); +} + +ATF_TC_BODY(getgroups_getgid, tc) +{ + gid_t gidset[NGROUPS_MAX]; + gid_t gid = getgid(); + int i, n; + + /* + * Check that getgid(2) is found from + * the GIDs returned by getgroups(2). + */ + n = getgroups(NGROUPS_MAX, gidset); + + for (i = 0; i < n; i++) { + + if (gidset[i] == gid) + return; + } + + atf_tc_fail("getgid(2) not found from getgroups(2)"); +} + +ATF_TC(getgroups_setgid); +ATF_TC_HEAD(getgroups_setgid, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test setgid(2) from getgroups(2)"); + atf_tc_set_md_var(tc, "require.user", "root"); +} + +ATF_TC_BODY(getgroups_setgid, tc) +{ + gid_t gidset[NGROUPS_MAX]; + int i, n, rv, sta; + pid_t pid; + + /* + * Check that we can setgid(2) + * to the returned group IDs. + */ + n = getgroups(NGROUPS_MAX, gidset); + ATF_REQUIRE(n >= 0); + + for (i = 0; i < n; i++) { + + pid = fork(); + ATF_REQUIRE(pid >= 0); + + if (pid == 0) { + + rv = setgid(gidset[i]); + + if (rv != 0) + _exit(EXIT_FAILURE); + + _exit(EXIT_SUCCESS); + } + + (void)wait(&sta); + + if (WIFEXITED(sta) == 0 || WEXITSTATUS(sta) != EXIT_SUCCESS) + atf_tc_fail("getgroups(2) is inconsistent"); + } +} + +ATF_TC(getgroups_zero); +ATF_TC_HEAD(getgroups_zero, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test getgroups(2) with zero param"); +} + +ATF_TC_BODY(getgroups_zero, tc) +{ + const gid_t val = 123456789; + gid_t gidset[NGROUPS_MAX]; + size_t i; + + /* + * If the first parameter is zero, the number + * of groups should be returned but the supplied + * buffer should remain intact. + */ + for (i = 0; i < __arraycount(gidset); i++) + gidset[i] = val; + + ATF_REQUIRE(getgroups(0, gidset) >= 0); + + for (i = 0; i < __arraycount(gidset); i++) { + + if (gidset[i] != val) + atf_tc_fail("getgroups(2) modified the buffer"); + } +} + +ATF_TP_ADD_TCS(tp) +{ + + ATF_TP_ADD_TC(tp, getgroups_err); + ATF_TP_ADD_TC(tp, getgroups_getgid); + ATF_TP_ADD_TC(tp, getgroups_setgid); + ATF_TP_ADD_TC(tp, getgroups_zero); + + return atf_no_error(); +} diff --git a/contrib/netbsd-tests/lib/libc/sys/t_getitimer.c b/contrib/netbsd-tests/lib/libc/sys/t_getitimer.c new file mode 100644 index 0000000..b384541 --- /dev/null +++ b/contrib/netbsd-tests/lib/libc/sys/t_getitimer.c @@ -0,0 +1,211 @@ +/* $NetBSD: t_getitimer.c,v 1.2 2012/03/22 18:20:46 christos Exp $ */ + +/*- + * Copyright (c) 2011 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jukka Ruohonen. + * + * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ +#include <sys/cdefs.h> +__RCSID("$NetBSD: t_getitimer.c,v 1.2 2012/03/22 18:20:46 christos Exp $"); + +#include <sys/time.h> + +#include <atf-c.h> +#include <errno.h> +#include <limits.h> +#include <signal.h> +#include <string.h> +#include <unistd.h> + +static bool fail; +static void sighandler(int); + +static void +sighandler(int signo) +{ + + if (signo == SIGALRM || signo == SIGVTALRM) + fail = false; +} + +ATF_TC(getitimer_empty); +ATF_TC_HEAD(getitimer_empty, tc) +{ + atf_tc_set_md_var(tc, "descr", "getitimer(2) before setitimer(2)"); +} + +ATF_TC_BODY(getitimer_empty, tc) +{ + struct itimerval it; + + /* + * Verify that the passed structure remains + * empty after calling getitimer(2) but before + * actually arming the timer with setitimer(2). + */ + (void)memset(&it, 0, sizeof(struct itimerval)); + + ATF_REQUIRE(getitimer(ITIMER_REAL, &it) == 0); + + if (it.it_value.tv_sec != 0 || it.it_value.tv_usec != 0) + goto fail; + + ATF_REQUIRE(getitimer(ITIMER_VIRTUAL, &it) == 0); + + if (it.it_value.tv_sec != 0 || it.it_value.tv_usec != 0) + goto fail; + + ATF_REQUIRE(getitimer(ITIMER_PROF, &it) == 0); + + if (it.it_value.tv_sec != 0 || it.it_value.tv_usec != 0) + goto fail; + + return; + +fail: + atf_tc_fail("getitimer(2) modfied the timer before it was armed"); +} + +ATF_TC(getitimer_err); +ATF_TC_HEAD(getitimer_err, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test errors from getitimer(2)"); +} + +ATF_TC_BODY(getitimer_err, tc) +{ + struct itimerval it; + + errno = 0; + ATF_REQUIRE_ERRNO(EINVAL, getitimer(-1, &it) == -1); + + errno = 0; + ATF_REQUIRE_ERRNO(EINVAL, getitimer(INT_MAX, &it) == -1); + + errno = 0; + ATF_REQUIRE_ERRNO(EFAULT, getitimer(ITIMER_REAL, (void *)-1) == -1); +} + +ATF_TC(setitimer_basic); +ATF_TC_HEAD(setitimer_basic, tc) +{ + atf_tc_set_md_var(tc, "descr", "A basic test of setitimer(2)"); +} + +ATF_TC_BODY(setitimer_basic, tc) +{ + struct itimerval it; + + it.it_value.tv_sec = 0; + it.it_value.tv_usec = 100; + + it.it_interval.tv_sec = 0; + it.it_interval.tv_usec = 0; + + fail = true; + + ATF_REQUIRE(signal(SIGALRM, sighandler) != SIG_ERR); + ATF_REQUIRE(setitimer(ITIMER_REAL, &it, NULL) == 0); + + /* + * Although the interaction between + * setitimer(2) and sleep(3) can be + * unspecified, it is assumed that one + * second suspension will be enough for + * the timer to fire. + */ + (void)sleep(1); + + if (fail != false) + atf_tc_fail("timer did not fire"); +} + +ATF_TC(setitimer_err); +ATF_TC_HEAD(setitimer_err, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test errors from setitimer(2)" + " (PR standards/44927)"); +} + +ATF_TC_BODY(setitimer_err, tc) +{ + struct itimerval it, ot; + + errno = 0; + ATF_REQUIRE_ERRNO(EINVAL, setitimer(-1, &it, &ot) == -1); + + errno = 0; + ATF_REQUIRE_ERRNO(EINVAL, setitimer(INT_MAX, &it, &ot) == -1); + + errno = 0; + ATF_REQUIRE_ERRNO(EFAULT, setitimer(ITIMER_REAL,(void*)-1, &ot) == -1); +} + +ATF_TC(setitimer_old); +ATF_TC_HEAD(setitimer_old, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test old values from setitimer(2)"); +} + +ATF_TC_BODY(setitimer_old, tc) +{ + struct itimerval it, ot; + + /* + * Make two calls; the second one + * should store the old values. + */ + it.it_value.tv_sec = 4; + it.it_value.tv_usec = 3; + + it.it_interval.tv_sec = 0; + it.it_interval.tv_usec = 0; + + ATF_REQUIRE(setitimer(ITIMER_REAL, &it, &ot) == 0); + + it.it_value.tv_sec = 2; + it.it_value.tv_usec = 1; + + it.it_interval.tv_sec = 0; + it.it_interval.tv_usec = 0; + + ATF_REQUIRE(setitimer(ITIMER_REAL, &it, &ot) == 0); + + if (ot.it_value.tv_sec != 4 || ot.it_value.tv_usec != 3) + atf_tc_fail("setitimer(2) did not store old values"); +} + +ATF_TP_ADD_TCS(tp) +{ + + ATF_TP_ADD_TC(tp, getitimer_empty); + ATF_TP_ADD_TC(tp, getitimer_err); + ATF_TP_ADD_TC(tp, setitimer_basic); + ATF_TP_ADD_TC(tp, setitimer_err); + ATF_TP_ADD_TC(tp, setitimer_old); + + return atf_no_error(); +} diff --git a/contrib/netbsd-tests/lib/libc/sys/t_getlogin.c b/contrib/netbsd-tests/lib/libc/sys/t_getlogin.c new file mode 100644 index 0000000..8c2b199 --- /dev/null +++ b/contrib/netbsd-tests/lib/libc/sys/t_getlogin.c @@ -0,0 +1,237 @@ +/* $NetBSD: t_getlogin.c,v 1.1 2011/07/07 06:57:53 jruoho Exp $ */ + +/*- + * Copyright (c) 2011 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jukka Ruohonen. + * + * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ +#include <sys/cdefs.h> +__RCSID("$NetBSD: t_getlogin.c,v 1.1 2011/07/07 06:57:53 jruoho Exp $"); + +#include <sys/param.h> +#include <sys/wait.h> + +#include <atf-c.h> +#include <errno.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +ATF_TC(getlogin_r_err); +ATF_TC_HEAD(getlogin_r_err, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test errors from getlogin_r(2)"); +} + +ATF_TC_BODY(getlogin_r_err, tc) +{ + char small[0]; + + ATF_REQUIRE(getlogin_r(small, sizeof(small)) == ERANGE); +} + +ATF_TC(getlogin_same); +ATF_TC_HEAD(getlogin_same, tc) +{ + atf_tc_set_md_var(tc, "descr", "getlogin(2) vs. getlogin_r(2)"); +} + +ATF_TC_BODY(getlogin_same, tc) +{ + char buf[MAXLOGNAME]; + char *str; + + str = getlogin(); + + if (str == NULL) + return; + + ATF_REQUIRE(getlogin_r(buf, sizeof(buf)) == 0); + + if (strcmp(str, buf) != 0) + atf_tc_fail("getlogin(2) and getlogin_r(2) differ"); +} + +ATF_TC(setlogin_basic); +ATF_TC_HEAD(setlogin_basic, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test that setlogin(2) works"); + atf_tc_set_md_var(tc, "require.user", "root"); +} + +ATF_TC_BODY(setlogin_basic, tc) +{ + char *name; + pid_t pid; + int sta; + + pid = fork(); + ATF_REQUIRE(pid >= 0); + + if (pid == 0) { + + (void)setsid(); + + if (setlogin("foobar") != 0) + _exit(EXIT_FAILURE); + + name = getlogin(); + + if (name == NULL) + _exit(EXIT_FAILURE); + + if (strcmp(name, "foobar") != 0) + _exit(EXIT_FAILURE); + + _exit(EXIT_SUCCESS); + } + + (void)wait(&sta); + + if (WIFEXITED(sta) == 0 || WEXITSTATUS(sta) != EXIT_SUCCESS) + atf_tc_fail("setlogin(2) failed to set login name"); +} + +ATF_TC(setlogin_err); +ATF_TC_HEAD(setlogin_err, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test errors from setlogin(2)"); + atf_tc_set_md_var(tc, "require.user", "root"); +} + +ATF_TC_BODY(setlogin_err, tc) +{ + char buf[MAXLOGNAME + 1]; + char *name; + pid_t pid; + int sta; + + pid = fork(); + ATF_REQUIRE(pid >= 0); + + (void)memset(buf, 'x', sizeof(buf)); + + if (pid == 0) { + + (void)setsid(); + + errno = 0; + + if (setlogin(buf) != -1) + _exit(EINVAL); + + if (errno != EINVAL) + _exit(EINVAL); + + errno = 0; + + if (setlogin((void *)-1) != -1) + _exit(EFAULT); + + if (errno != EFAULT) + _exit(EFAULT); + + name = getlogin(); + + if (name == NULL) + _exit(EXIT_FAILURE); + + if (strcmp(name, "foobar") == 0) + _exit(EXIT_FAILURE); + + _exit(EXIT_SUCCESS); + } + + (void)wait(&sta); + + if (WIFEXITED(sta) == 0 || WEXITSTATUS(sta) != EXIT_SUCCESS) { + + if (WEXITSTATUS(sta) == EFAULT) + atf_tc_fail("expected EFAULT, but the call succeeded"); + + if (WEXITSTATUS(sta) == EINVAL) + atf_tc_fail("expected EINVAL, but the call succeeded"); + + atf_tc_fail("setlogin(2) failed, but login name was set"); + } +} + +ATF_TC(setlogin_perm); +ATF_TC_HEAD(setlogin_perm, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test setlogin(2) as normal user"); + atf_tc_set_md_var(tc, "require.user", "unprivileged"); +} + +ATF_TC_BODY(setlogin_perm, tc) +{ + char *name; + pid_t pid; + int sta; + + pid = fork(); + ATF_REQUIRE(pid >= 0); + + if (pid == 0) { + + (void)setsid(); + + errno = 0; + + if (setlogin("foobar") != -1) + _exit(EXIT_FAILURE); + + if (errno != EPERM) + _exit(EXIT_FAILURE); + + name = getlogin(); + + if (name == NULL) + _exit(EXIT_FAILURE); + + if (strcmp(name, "foobar") == 0) + _exit(EXIT_FAILURE); + + _exit(EXIT_SUCCESS); + } + + (void)wait(&sta); + + if (WIFEXITED(sta) == 0 || WEXITSTATUS(sta) != EXIT_SUCCESS) + atf_tc_fail("login name was set as an unprivileged user"); +} + +ATF_TP_ADD_TCS(tp) +{ + + ATF_TP_ADD_TC(tp, getlogin_r_err); + ATF_TP_ADD_TC(tp, getlogin_same); + ATF_TP_ADD_TC(tp, setlogin_basic); + ATF_TP_ADD_TC(tp, setlogin_err); + ATF_TP_ADD_TC(tp, setlogin_perm); + + return atf_no_error(); +} diff --git a/contrib/netbsd-tests/lib/libc/sys/t_getpid.c b/contrib/netbsd-tests/lib/libc/sys/t_getpid.c new file mode 100644 index 0000000..b3ed393 --- /dev/null +++ b/contrib/netbsd-tests/lib/libc/sys/t_getpid.c @@ -0,0 +1,134 @@ +/* $NetBSD: t_getpid.c,v 1.1 2011/07/07 06:57:53 jruoho Exp $ */ + +/*- + * Copyright (c) 2011 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jukka Ruohonen. + * + * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ +#include <sys/cdefs.h> +__RCSID("$NetBSD: t_getpid.c,v 1.1 2011/07/07 06:57:53 jruoho Exp $"); + +#include <sys/wait.h> + +#include <stdlib.h> +#include <pthread.h> +#include <unistd.h> + +#include <atf-c.h> + +static int maxiter = 10; +static void *threadfunc(void *); + +static void * +threadfunc(void *arg) +{ + *(pid_t *)arg = getpid(); + + return NULL; +} + +ATF_TC(getpid_process); +ATF_TC_HEAD(getpid_process, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test getpid(2) with processes"); +} + +ATF_TC_BODY(getpid_process, tc) +{ + pid_t ppid, fpid, cpid, tpid, wpid; + int i, sta; + + for (i = 0; i < maxiter; i++) { + + tpid = getpid(); + fpid = fork(); + + ATF_REQUIRE(fpid >= 0); + + if (fpid == 0) { + + cpid = getpid(); + ppid = getppid(); + + if (tpid != ppid) + _exit(EXIT_FAILURE); + + if (cpid == ppid) + _exit(EXIT_FAILURE); + + if (tpid == fpid) + _exit(EXIT_FAILURE); + + _exit(EXIT_SUCCESS); + } + + wpid = wait(&sta); + + if (wpid != fpid) + atf_tc_fail("PID mismatch"); + + ATF_REQUIRE(WIFEXITED(sta) != 0); + + if (WEXITSTATUS(sta) != EXIT_SUCCESS) + atf_tc_fail("PID mismatch"); + } +} + +ATF_TC(getpid_thread); +ATF_TC_HEAD(getpid_thread, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test getpid(2) with threads"); +} + +ATF_TC_BODY(getpid_thread, tc) +{ + pid_t pid, tpid; + pthread_t tid; + int i, rv; + + for (i = 0; i < maxiter; i++) { + + pid = getpid(); + + rv = pthread_create(&tid, NULL, threadfunc, &tpid); + ATF_REQUIRE(rv == 0); + + rv = pthread_join(tid, NULL); + ATF_REQUIRE(rv == 0); + + if (pid != tpid) + atf_tc_fail("Unequal PIDs"); + } +} + +ATF_TP_ADD_TCS(tp) +{ + + ATF_TP_ADD_TC(tp, getpid_process); + ATF_TP_ADD_TC(tp, getpid_thread); + + return atf_no_error(); +} diff --git a/contrib/netbsd-tests/lib/libc/sys/t_getrusage.c b/contrib/netbsd-tests/lib/libc/sys/t_getrusage.c new file mode 100644 index 0000000..6c4218a --- /dev/null +++ b/contrib/netbsd-tests/lib/libc/sys/t_getrusage.c @@ -0,0 +1,197 @@ +/* $NetBSD: t_getrusage.c,v 1.3 2014/09/03 19:24:12 matt Exp $ */ + +/*- + * Copyright (c) 2011 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jukka Ruohonen. + * + * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ +#include <sys/cdefs.h> +__RCSID("$NetBSD: t_getrusage.c,v 1.3 2014/09/03 19:24:12 matt Exp $"); + +#include <sys/resource.h> +#include <sys/time.h> + +#include <atf-c.h> +#include <errno.h> +#include <limits.h> +#include <signal.h> +#include <stdint.h> +#include <string.h> + +static void work(void); +static void sighandler(int); + +static const size_t maxiter = 2000; + +static void +sighandler(int signo) +{ + /* Nothing. */ +} + +static void +work(void) +{ + size_t n = UINT16_MAX * 10; + + while (n > 0) { +#ifdef __or1k__ + asm volatile("l.nop"); /* Do something. */ +#else + asm volatile("nop"); /* Do something. */ +#endif + n--; + } +} + +ATF_TC(getrusage_err); +ATF_TC_HEAD(getrusage_err, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test error conditions"); +} + +ATF_TC_BODY(getrusage_err, tc) +{ + struct rusage ru; + + errno = 0; + + ATF_REQUIRE(getrusage(INT_MAX, &ru) != 0); + ATF_REQUIRE(errno == EINVAL); + + errno = 0; + + ATF_REQUIRE(getrusage(RUSAGE_SELF, (void *)0) != 0); + ATF_REQUIRE(errno == EFAULT); +} + +ATF_TC(getrusage_sig); +ATF_TC_HEAD(getrusage_sig, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test signal count with getrusage(2)"); +} + +ATF_TC_BODY(getrusage_sig, tc) +{ + struct rusage ru; + const long n = 5; + int i; + + /* + * Test that signals are recorded. + */ + ATF_REQUIRE(signal(SIGUSR1, sighandler) != SIG_ERR); + + for (i = 0; i < n; i++) + ATF_REQUIRE(raise(SIGUSR1) == 0); + + (void)memset(&ru, 0, sizeof(struct rusage)); + ATF_REQUIRE(getrusage(RUSAGE_SELF, &ru) == 0); + + if (n != ru.ru_nsignals) + atf_tc_fail("getrusage(2) did not record signals"); +} + +ATF_TC(getrusage_utime_back); +ATF_TC_HEAD(getrusage_utime_back, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test bogus values from getrusage(2)"); +} + +ATF_TC_BODY(getrusage_utime_back, tc) +{ + struct rusage ru1, ru2; + size_t i; + + /* + * Test that two consecutive calls are sane. + */ + atf_tc_expect_fail("PR kern/30115"); + + for (i = 0; i < maxiter; i++) { + + (void)memset(&ru1, 0, sizeof(struct rusage)); + (void)memset(&ru2, 0, sizeof(struct rusage)); + + work(); + + ATF_REQUIRE(getrusage(RUSAGE_SELF, &ru1) == 0); + + work(); + + ATF_REQUIRE(getrusage(RUSAGE_SELF, &ru2) == 0); + + if (timercmp(&ru2.ru_utime, &ru1.ru_utime, <) != 0) + atf_tc_fail("user time went backwards"); + } + + atf_tc_fail("anticipated error did not occur"); +} + +ATF_TC(getrusage_utime_zero); +ATF_TC_HEAD(getrusage_utime_zero, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test zero utime from getrusage(2)"); +} + +ATF_TC_BODY(getrusage_utime_zero, tc) +{ + struct rusage ru; + size_t i; + + /* + * Test that getrusage(2) does not return + * zero user time for the calling process. + * + * See also (duplicate) PR port-amd64/41734. + */ + atf_tc_expect_fail("PR kern/30115"); + + for (i = 0; i < maxiter; i++) { + + work(); + + (void)memset(&ru, 0, sizeof(struct rusage)); + + ATF_REQUIRE(getrusage(RUSAGE_SELF, &ru) == 0); + + if (ru.ru_utime.tv_sec == 0 && ru.ru_utime.tv_usec == 0) + atf_tc_fail("zero user time from getrusage(2)"); + } + + atf_tc_fail("anticipated error did not occur"); +} + +ATF_TP_ADD_TCS(tp) +{ + + ATF_TP_ADD_TC(tp, getrusage_err); + ATF_TP_ADD_TC(tp, getrusage_sig); + ATF_TP_ADD_TC(tp, getrusage_utime_back); + ATF_TP_ADD_TC(tp, getrusage_utime_zero); + + return atf_no_error(); +} diff --git a/contrib/netbsd-tests/lib/libc/sys/t_getsid.c b/contrib/netbsd-tests/lib/libc/sys/t_getsid.c new file mode 100644 index 0000000..76b54ab --- /dev/null +++ b/contrib/netbsd-tests/lib/libc/sys/t_getsid.c @@ -0,0 +1,119 @@ +/* $NetBSD: t_getsid.c,v 1.1 2011/07/07 06:57:53 jruoho Exp $ */ + +/*- + * Copyright (c) 2011 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jukka Ruohonen. + * + * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ +#include <sys/cdefs.h> +__RCSID("$NetBSD: t_getsid.c,v 1.1 2011/07/07 06:57:53 jruoho Exp $"); + +#include <sys/wait.h> + +#include <errno.h> +#include <stdlib.h> +#include <unistd.h> + +#include <atf-c.h> + +ATF_TC(getsid_current); +ATF_TC_HEAD(getsid_current, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test getsid(0)"); +} + +ATF_TC_BODY(getsid_current, tc) +{ + pid_t sid; + + sid = getsid(0); + ATF_REQUIRE(sid != -1); + + if (sid != getsid(getpid())) + atf_tc_fail("getsid(0) did not match the calling process"); +} + +ATF_TC(getsid_err); +ATF_TC_HEAD(getsid_err, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test error conditions in getsid(2)"); +} + +ATF_TC_BODY(getsid_err, tc) +{ + + errno = 0; + + ATF_REQUIRE(getsid(-1) == -1); + ATF_REQUIRE(errno == ESRCH); +} + +ATF_TC(getsid_process); +ATF_TC_HEAD(getsid_process, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test getsid(2) with processes"); +} + +ATF_TC_BODY(getsid_process, tc) +{ + pid_t csid, pid, ppid, sid; + int sta; + + sid = getsid(0); + pid = fork(); + + ATF_REQUIRE(pid >= 0); + ATF_REQUIRE(sid != -1); + + if (pid == 0) { + + csid = getsid(0); + ppid = getppid(); + + if (sid != csid) + _exit(EXIT_FAILURE); + + if (getsid(ppid) != csid) + _exit(EXIT_FAILURE); + + _exit(EXIT_SUCCESS); + } + + (void)wait(&sta); + + if (WIFEXITED(sta) == 0 || WEXITSTATUS(sta) != EXIT_SUCCESS) + atf_tc_fail("invalid session ID"); +} + +ATF_TP_ADD_TCS(tp) +{ + + ATF_TP_ADD_TC(tp, getsid_current); + ATF_TP_ADD_TC(tp, getsid_err); + ATF_TP_ADD_TC(tp, getsid_process); + + return atf_no_error(); +} diff --git a/contrib/netbsd-tests/lib/libc/sys/t_gettimeofday.c b/contrib/netbsd-tests/lib/libc/sys/t_gettimeofday.c new file mode 100644 index 0000000..1cf303b --- /dev/null +++ b/contrib/netbsd-tests/lib/libc/sys/t_gettimeofday.c @@ -0,0 +1,86 @@ +/* $NetBSD: t_gettimeofday.c,v 1.1 2011/07/07 06:57:53 jruoho Exp $ */ + +/*- + * Copyright (c) 2011 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jukka Ruohonen. + * + * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ +#include <sys/cdefs.h> +__RCSID("$NetBSD: t_gettimeofday.c,v 1.1 2011/07/07 06:57:53 jruoho Exp $"); + +#include <sys/time.h> + +#include <atf-c.h> +#include <errno.h> +#include <string.h> + +ATF_TC(gettimeofday_err); +ATF_TC_HEAD(gettimeofday_err, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test errors from gettimeofday(2)"); +} + +ATF_TC_BODY(gettimeofday_err, tc) +{ + + errno = 0; + + ATF_REQUIRE_ERRNO(EFAULT, gettimeofday((void *)-1, NULL) != 0); +} + +ATF_TC(gettimeofday_mono); +ATF_TC_HEAD(gettimeofday_mono, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test monotonicity of gettimeofday(2)"); +} + +ATF_TC_BODY(gettimeofday_mono, tc) +{ + static const size_t maxiter = 100; + struct timeval tv1, tv2; + size_t i; + + for (i = 0; i < maxiter; i++) { + + (void)memset(&tv1, 0, sizeof(struct timeval)); + (void)memset(&tv2, 0, sizeof(struct timeval)); + + ATF_REQUIRE(gettimeofday(&tv1, NULL) == 0); + ATF_REQUIRE(gettimeofday(&tv2, NULL) == 0); + + if (timercmp(&tv2, &tv1, <) != 0) + atf_tc_fail("time went backwards"); + } +} + +ATF_TP_ADD_TCS(tp) +{ + + ATF_TP_ADD_TC(tp, gettimeofday_err); + ATF_TP_ADD_TC(tp, gettimeofday_mono); + + return atf_no_error(); +} diff --git a/contrib/netbsd-tests/lib/libc/sys/t_issetugid.c b/contrib/netbsd-tests/lib/libc/sys/t_issetugid.c new file mode 100644 index 0000000..b76ba39 --- /dev/null +++ b/contrib/netbsd-tests/lib/libc/sys/t_issetugid.c @@ -0,0 +1,148 @@ +/* $NetBSD: t_issetugid.c,v 1.1 2011/07/07 06:57:53 jruoho Exp $ */ + +/*- + * Copyright (c) 2011 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jukka Ruohonen. + * + * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ +#include <sys/cdefs.h> +__RCSID("$NetBSD: t_issetugid.c,v 1.1 2011/07/07 06:57:53 jruoho Exp $"); + +#include <sys/wait.h> + +#include <atf-c.h> +#include <errno.h> +#include <pwd.h> +#include <stdlib.h> +#include <unistd.h> + +static bool check(int (*fuid)(uid_t), int (*fgid)(gid_t)); + +static bool +check(int (*fuid)(uid_t), int (*fgid)(gid_t)) +{ + struct passwd *pw; + pid_t pid; + int sta; + + pw = getpwnam("nobody"); + + if (pw == NULL) + return false; + + pid = fork(); + + if (pid < 0) + return false; + + if (pid == 0) { + + if (fuid != NULL && (*fuid)(pw->pw_uid) != 0) + _exit(EXIT_FAILURE); + + if (fgid != NULL && (*fgid)(pw->pw_gid) != 0) + _exit(EXIT_FAILURE); + + if (issetugid() != 1) + _exit(EXIT_FAILURE); + + _exit(EXIT_SUCCESS); + } + + (void)wait(&sta); + + if (WIFEXITED(sta) == 0 || WEXITSTATUS(sta) != EXIT_SUCCESS) + return false; + + return true; +} + +ATF_TC(issetugid_egid); +ATF_TC_HEAD(issetugid_egid, tc) +{ + atf_tc_set_md_var(tc, "descr", "A test of issetugid(2), eff. GID"); + atf_tc_set_md_var(tc, "require.user", "root"); +} + +ATF_TC_BODY(issetugid_egid, tc) +{ + + if (check(NULL, setegid) != true) + atf_tc_fail("issetugid(2) failed with effective GID"); +} + +ATF_TC(issetugid_euid); +ATF_TC_HEAD(issetugid_euid, tc) +{ + atf_tc_set_md_var(tc, "descr", "A test of issetugid(2), eff. UID"); + atf_tc_set_md_var(tc, "require.user", "root"); +} + +ATF_TC_BODY(issetugid_euid, tc) +{ + + if (check(seteuid, NULL) != true) + atf_tc_fail("issetugid(2) failed with effective UID"); +} + +ATF_TC(issetugid_rgid); +ATF_TC_HEAD(issetugid_rgid, tc) +{ + atf_tc_set_md_var(tc, "descr", "A test of issetugid(2), real GID"); + atf_tc_set_md_var(tc, "require.user", "root"); +} + +ATF_TC_BODY(issetugid_rgid, tc) +{ + + if (check(NULL, setgid) != true) + atf_tc_fail("issetugid(2) failed with real GID"); +} + +ATF_TC(issetugid_ruid); +ATF_TC_HEAD(issetugid_ruid, tc) +{ + atf_tc_set_md_var(tc, "descr", "A test of issetugid(2), real UID"); + atf_tc_set_md_var(tc, "require.user", "root"); +} + +ATF_TC_BODY(issetugid_ruid, tc) +{ + + if (check(setuid, NULL) != true) + atf_tc_fail("issetugid(2) failed with real UID"); +} + +ATF_TP_ADD_TCS(tp) +{ + + ATF_TP_ADD_TC(tp, issetugid_egid); + ATF_TP_ADD_TC(tp, issetugid_euid); + ATF_TP_ADD_TC(tp, issetugid_rgid); + ATF_TP_ADD_TC(tp, issetugid_ruid); + + return atf_no_error(); +} diff --git a/contrib/netbsd-tests/lib/libc/sys/t_kevent.c b/contrib/netbsd-tests/lib/libc/sys/t_kevent.c new file mode 100644 index 0000000..73ffbf8 --- /dev/null +++ b/contrib/netbsd-tests/lib/libc/sys/t_kevent.c @@ -0,0 +1,180 @@ +/* $NetBSD: t_kevent.c,v 1.6 2012/11/29 09:13:44 martin Exp $ */ + +/*- + * Copyright (c) 2011 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundatiom + * by Christos Zoulas. + * + * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ +#include <sys/cdefs.h> +__RCSID("$NetBSD: t_kevent.c,v 1.6 2012/11/29 09:13:44 martin Exp $"); + +#include <sys/types.h> +#include <sys/event.h> + +#include <atf-c.h> +#include <errno.h> +#include <time.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <fcntl.h> +#include <err.h> +#include <sys/drvctlio.h> +#include <sys/event.h> +#include <sys/time.h> +#include <sys/socket.h> +#include <sys/wait.h> + +ATF_TC(kevent_zerotimer); +ATF_TC_HEAD(kevent_zerotimer, tc) +{ + atf_tc_set_md_var(tc, "descr", "Checks that kevent with a 0 timer " + "does not crash the system (PR lib/45618)"); +} + +ATF_TC_BODY(kevent_zerotimer, tc) +{ + struct kevent ev; + int kq; + + ATF_REQUIRE((kq = kqueue()) != -1); + EV_SET(&ev, 1, EVFILT_TIMER, EV_ADD|EV_ENABLE, 0, 1, 0); + ATF_REQUIRE(kevent(kq, &ev, 1, NULL, 0, NULL) != -1); + ATF_REQUIRE(kevent(kq, NULL, 0, &ev, 1, NULL) == 1); +} + +ATF_TC(kqueue_desc_passing); +ATF_TC_HEAD(kqueue_desc_passing, tc) +{ + atf_tc_set_md_var(tc, "descr", "Checks that passing a kqueue to " + "another process does not crash the kernel (PR 46463)"); +} + +ATF_TC_BODY(kqueue_desc_passing, tc) +{ + pid_t child; + int s[2], storage, status, kq; + struct cmsghdr *msg; + struct iovec iov; + struct msghdr m; + struct kevent ev; + + ATF_REQUIRE((kq = kqueue()) != -1); + + // atf_tc_skip("crashes kernel (PR 46463)"); + + ATF_REQUIRE(socketpair(AF_LOCAL, SOCK_STREAM, 0, s) != -1); + msg = malloc(CMSG_SPACE(sizeof(int))); + m.msg_iov = &iov; + m.msg_iovlen = 1; + m.msg_name = NULL; + m.msg_namelen = 0; + m.msg_control = msg; + m.msg_controllen = CMSG_SPACE(sizeof(int)); + + child = fork(); + if (child == 0) { + close(s[0]); + + iov.iov_base = &storage; + iov.iov_len = sizeof(int); + m.msg_iov = &iov; + m.msg_iovlen = 1; + + if (recvmsg(s[1], &m, 0) == -1) + err(1, "child: could not recvmsg"); + + kq = *(int *)CMSG_DATA(msg); + printf("child (pid %d): received kq fd %d\n", getpid(), kq); + exit(0); + } + + close(s[1]); + + iov.iov_base = &storage; + iov.iov_len = sizeof(int); + + msg->cmsg_level = SOL_SOCKET; + msg->cmsg_type = SCM_RIGHTS; + msg->cmsg_len = CMSG_LEN(sizeof(int)); + + *(int *)CMSG_DATA(msg) = kq; + + EV_SET(&ev, 1, EVFILT_TIMER, EV_ADD|EV_ENABLE, 0, 1, 0); + ATF_CHECK(kevent(kq, &ev, 1, NULL, 0, NULL) != -1); + + printf("parent (pid %d): sending kq fd %d\n", getpid(), kq); + if (sendmsg(s[0], &m, 0) == -1) { + ATF_REQUIRE_EQ_MSG(errno, EBADF, "errno is %d", errno); + atf_tc_skip("PR kern/46523"); + } + + close(kq); + + waitpid(child, &status, 0); + ATF_CHECK(WIFEXITED(status) && WEXITSTATUS(status)==0); +} + +ATF_TC(kqueue_unsupported_fd); +ATF_TC_HEAD(kqueue_unsupported_fd, tc) +{ + atf_tc_set_md_var(tc, "descr", "Checks that watching an fd whose" + " type is not supported does not crash the kernel"); +} + +ATF_TC_BODY(kqueue_unsupported_fd, tc) +{ + /* mqueue and semaphore use fnullop_kqueue also */ + int fd, kq; + struct kevent ev; + + fd = open(DRVCTLDEV, O_RDONLY); + if (fd == -1 && errno == ENOENT) + atf_tc_skip("no " DRVCTLDEV " available for testing"); + ATF_REQUIRE(fd != -1); + ATF_REQUIRE((kq = kqueue()) != -1); + + EV_SET(&ev, fd, EVFILT_VNODE, EV_ADD | EV_ENABLE | EV_CLEAR, + NOTE_DELETE|NOTE_WRITE|NOTE_EXTEND|NOTE_ATTRIB|NOTE_LINK| + NOTE_RENAME|NOTE_REVOKE, 0, 0); + + ATF_REQUIRE(kevent(kq, &ev, 1, NULL, 0, NULL) == -1); + ATF_REQUIRE_ERRNO(EOPNOTSUPP, true); + + (void)close(fd); +} + + +ATF_TP_ADD_TCS(tp) +{ + + ATF_TP_ADD_TC(tp, kevent_zerotimer); + ATF_TP_ADD_TC(tp, kqueue_desc_passing); + ATF_TP_ADD_TC(tp, kqueue_unsupported_fd); + + return atf_no_error(); +} diff --git a/contrib/netbsd-tests/lib/libc/sys/t_kill.c b/contrib/netbsd-tests/lib/libc/sys/t_kill.c new file mode 100644 index 0000000..2f42862 --- /dev/null +++ b/contrib/netbsd-tests/lib/libc/sys/t_kill.c @@ -0,0 +1,312 @@ +/* $NetBSD: t_kill.c,v 1.1 2011/07/07 06:57:53 jruoho Exp $ */ + +/*- + * Copyright (c) 2011 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jukka Ruohonen. + * + * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ +#include <sys/cdefs.h> +__RCSID("$NetBSD: t_kill.c,v 1.1 2011/07/07 06:57:53 jruoho Exp $"); + +#include <sys/wait.h> + +#include <errno.h> +#include <limits.h> +#include <pwd.h> +#include <signal.h> +#include <stdlib.h> +#include <unistd.h> + +#include <atf-c.h> + +ATF_TC(kill_basic); +ATF_TC_HEAD(kill_basic, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test that kill(2) works"); +} + +ATF_TC_BODY(kill_basic, tc) +{ + const int sig[] = { SIGHUP, SIGINT, SIGKILL, SIGTERM }; + pid_t pid; + size_t i; + int sta; + + for (i = 0; i < __arraycount(sig); i++) { + + pid = fork(); + ATF_REQUIRE(pid >= 0); + + switch (pid) { + + case 0: + pause(); + break; + + default: + ATF_REQUIRE(kill(pid, sig[i]) == 0); + } + + (void)wait(&sta); + + if (WIFSIGNALED(sta) == 0 || WTERMSIG(sta) != sig[i]) + atf_tc_fail("kill(2) failed to kill child"); + } +} + +ATF_TC(kill_err); +ATF_TC_HEAD(kill_err, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test error conditions of kill(2)"); +} + +ATF_TC_BODY(kill_err, tc) +{ + int rv, sta; + pid_t pid; + + pid = fork(); + ATF_REQUIRE(pid >= 0); + + if (pid == 0) { + + errno = 0; + rv = kill(getpid(), -1); + + if (rv == 0 || errno != EINVAL) + _exit(EINVAL); + + errno = 0; + rv = kill(INT_MAX, SIGUSR1); + + if (rv == 0 || errno != ESRCH) + _exit(ESRCH); + + _exit(EXIT_SUCCESS); + } + + (void)wait(&sta); + + if (WIFEXITED(sta) == 0 || WEXITSTATUS(sta) != EXIT_SUCCESS) { + + if (WEXITSTATUS(sta) == EINVAL) + atf_tc_fail("expected EINVAL, but kill(2) succeeded"); + + if (WEXITSTATUS(sta) == ESRCH) + atf_tc_fail("expected ESRCH, but kill(2) succeeded"); + + atf_tc_fail("unknown error from kill(2)"); + } +} + +ATF_TC(kill_perm); +ATF_TC_HEAD(kill_perm, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test kill(2) permissions"); + atf_tc_set_md_var(tc, "require.user", "root"); +} + +ATF_TC_BODY(kill_perm, tc) +{ + struct passwd *pw; + pid_t cpid, ppid; + uid_t cuid = 0; + uid_t puid = 0; + int sta; + + /* + * Test that kill(2) fails when called + * for a PID owned by another user. + */ + pw = getpwnam("operator"); + + if (pw != NULL) + cuid = pw->pw_uid; + + pw = getpwnam("nobody"); + + if (pw != NULL) + puid = pw->pw_uid; + + if (cuid == 0 || puid == 0 || cuid == puid) + atf_tc_fail("getpwnam(3) failed"); + + ppid = fork(); + + if (ppid < 0) + _exit(EXIT_FAILURE); + + if (ppid == 0) { + + cpid = fork(); + + if (cpid < 0) + _exit(EXIT_FAILURE); + + if (cpid == 0) { + + if (setuid(cuid) < 0) + _exit(EXIT_FAILURE); + else { + (void)sleep(1); + } + + _exit(EXIT_SUCCESS); + } + + /* + * Try to kill the child after having + * set the real and effective UID. + */ + if (setuid(puid) != 0) + _exit(EXIT_FAILURE); + + errno = 0; + + if (kill(cpid, SIGKILL) == 0) + _exit(EPERM); + + if (errno != EPERM) + _exit(EPERM); + + (void)waitpid(cpid, &sta, 0); + + _exit(EXIT_SUCCESS); + } + + (void)waitpid(ppid, &sta, 0); + + if (WIFEXITED(sta) == 0 || WEXITSTATUS(sta) == EPERM) + atf_tc_fail("killed a process of another user"); + + if (WIFEXITED(sta) == 0 || WEXITSTATUS(sta) != EXIT_SUCCESS) + atf_tc_fail("unknown error from kill(2)"); +} + +ATF_TC(kill_pgrp_neg); +ATF_TC_HEAD(kill_pgrp_neg, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test kill(2) with process group, #2"); +} + +ATF_TC_BODY(kill_pgrp_neg, tc) +{ + const int maxiter = 3; + pid_t cpid, ppid; + int i, sta; + + ppid = fork(); + ATF_REQUIRE(ppid >= 0); + + if (ppid == 0) { + + ATF_REQUIRE(setpgid(0, 0) == 0); + + for (i = 0; i < maxiter; i++) { + + cpid = fork(); + ATF_REQUIRE(cpid >= 0); + + if (cpid == 0) + pause(); + } + + /* + * Test the variant of killpg(3); if the process number + * is negative but not -1, the signal should be sent to + * all processes whose process group ID is equal to the + * absolute value of the process number. + */ + ATF_REQUIRE(kill(-getpgrp(), SIGKILL) == 0); + + (void)sleep(1); + + _exit(EXIT_SUCCESS); + } + + (void)waitpid(ppid, &sta, 0); + + if (WIFSIGNALED(sta) == 0 || WTERMSIG(sta) != SIGKILL) + atf_tc_fail("failed to kill(2) a process group"); +} + +ATF_TC(kill_pgrp_zero); +ATF_TC_HEAD(kill_pgrp_zero, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test kill(2) with process group, #1"); +} + +ATF_TC_BODY(kill_pgrp_zero, tc) +{ + const int maxiter = 3; + pid_t cpid, ppid; + int i, sta; + + ppid = fork(); + ATF_REQUIRE(ppid >= 0); + + if (ppid == 0) { + + ATF_REQUIRE(setpgid(0, 0) == 0); + + for (i = 0; i < maxiter; i++) { + + cpid = fork(); + ATF_REQUIRE(cpid >= 0); + + if (cpid == 0) + pause(); + } + + /* + * If the supplied process number is zero, + * the signal should be sent to all processes + * under the current process group. + */ + ATF_REQUIRE(kill(0, SIGKILL) == 0); + + (void)sleep(1); + + _exit(EXIT_SUCCESS); + } + + (void)waitpid(ppid, &sta, 0); + + if (WIFSIGNALED(sta) == 0 || WTERMSIG(sta) != SIGKILL) + atf_tc_fail("failed to kill(2) a process group"); +} + +ATF_TP_ADD_TCS(tp) +{ + + ATF_TP_ADD_TC(tp, kill_basic); + ATF_TP_ADD_TC(tp, kill_err); + ATF_TP_ADD_TC(tp, kill_perm); + ATF_TP_ADD_TC(tp, kill_pgrp_neg); + ATF_TP_ADD_TC(tp, kill_pgrp_zero); + + return atf_no_error(); +} diff --git a/contrib/netbsd-tests/lib/libc/sys/t_link.c b/contrib/netbsd-tests/lib/libc/sys/t_link.c new file mode 100644 index 0000000..b58c4c9 --- /dev/null +++ b/contrib/netbsd-tests/lib/libc/sys/t_link.c @@ -0,0 +1,229 @@ +/* $NetBSD: t_link.c,v 1.2 2014/04/21 14:39:36 martin Exp $ */ + +/*- + * Copyright (c) 2011 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jukka Ruohonen. + * + * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ +#include <sys/cdefs.h> +__RCSID("$NetBSD: t_link.c,v 1.2 2014/04/21 14:39:36 martin Exp $"); + +#include <sys/param.h> +#include <sys/stat.h> + +#include <atf-c.h> +#include <errno.h> +#include <fcntl.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> + +static const char *getpath(void); +static char path[] = "link"; +static const char *pathl; + +static const char * +getpath(void) +{ + static char buf[LINE_MAX]; + + (void)memset(buf, '\0', sizeof(buf)); + + if (getcwd(buf, sizeof(buf)) == NULL) + return NULL; + + (void)strlcat(buf, path, sizeof(buf)); + (void)strlcat(buf, ".link", sizeof(buf)); + + return buf; +} + +ATF_TC_WITH_CLEANUP(link_count); +ATF_TC_HEAD(link_count, tc) +{ + atf_tc_set_md_var(tc, "descr", "link(2) counts are incremented?"); +} + +ATF_TC_BODY(link_count, tc) +{ + struct stat sa, sb; + int fd; + + (void)memset(&sa, 0, sizeof(struct stat)); + (void)memset(&sb, 0, sizeof(struct stat)); + + pathl = getpath(); + fd = open(path, O_RDWR | O_CREAT, 0600); + + ATF_REQUIRE(fd >= 0); + ATF_REQUIRE(pathl != NULL); + + ATF_REQUIRE(stat(path, &sa) == 0); + ATF_REQUIRE(link(path, pathl) == 0); + ATF_REQUIRE(stat(path, &sb) == 0); + + if (sa.st_nlink != sb.st_nlink - 1) + atf_tc_fail("incorrect link(2) count"); + + ATF_REQUIRE(close(fd) == 0); + ATF_REQUIRE(unlink(path) == 0); + ATF_REQUIRE(unlink(pathl) == 0); +} + +ATF_TC_CLEANUP(link_count, tc) +{ + (void)unlink(path); + (void)unlink(pathl); +} + +ATF_TC_WITH_CLEANUP(link_err); +ATF_TC_HEAD(link_err, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test error conditions of link(2)"); +} + +ATF_TC_BODY(link_err, tc) +{ + char buf[MAXPATHLEN + 1]; + int fd; + + (void)memset(buf, 'x', sizeof(buf)); + + pathl = getpath(); + fd = open(path, O_RDWR | O_CREAT, 0600); + + ATF_REQUIRE(fd >= 0); + ATF_REQUIRE(pathl != NULL); + + errno = 0; + ATF_REQUIRE(link(path, pathl) == 0); + ATF_REQUIRE_ERRNO(EEXIST, link(path, pathl) == -1); + + errno = 0; + ATF_REQUIRE_ERRNO(ENAMETOOLONG, link(buf, "xxx") == -1); + + errno = 0; + ATF_REQUIRE_ERRNO(ENOENT, link(path, "/d/c/b/a") == -1); + + errno = 0; + ATF_REQUIRE_ERRNO(ENOENT, link("/a/b/c/d", path) == -1); + + errno = 0; + ATF_REQUIRE_ERRNO(ENOENT, link("/a/b/c/d", "/d/c/b/a") == -1); + + errno = 0; + ATF_REQUIRE_ERRNO(EFAULT, link(path, (const char *)-1) == -1); + + errno = 0; + ATF_REQUIRE_ERRNO(EFAULT, link((const char *)-1, "xxx") == -1); + + ATF_REQUIRE(close(fd) == 0); + ATF_REQUIRE(unlink(path) == 0); + ATF_REQUIRE(unlink(pathl) == 0); +} + +ATF_TC_CLEANUP(link_err, tc) +{ + (void)unlink(path); + (void)unlink(pathl); +} + +ATF_TC(link_perm); +ATF_TC_HEAD(link_perm, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test permissions with link(2)"); + atf_tc_set_md_var(tc, "require.user", "unprivileged"); +} + +ATF_TC_BODY(link_perm, tc) +{ + int rv; + + errno = 0; + rv = link("/root", "/root.link"); + ATF_REQUIRE_MSG(rv == -1 && (errno == EACCES || errno == EPERM), + "link to a directory did not fail with EPERM or EACCESS; link() " + "returned %d, errno %d", rv, errno); + + errno = 0; + ATF_REQUIRE_ERRNO(EACCES, + link("/root/.profile", "/root/.profile.link") == -1); +} + +ATF_TC_WITH_CLEANUP(link_stat); +ATF_TC_HEAD(link_stat, tc) +{ + atf_tc_set_md_var(tc, "descr", "Check stat(2) of a linked file"); +} + +ATF_TC_BODY(link_stat, tc) +{ + struct stat sa, sb; + int fd; + + (void)memset(&sa, 0, sizeof(struct stat)); + (void)memset(&sb, 0, sizeof(struct stat)); + + pathl = getpath(); + fd = open(path, O_RDWR | O_CREAT, 0600); + + ATF_REQUIRE(fd >= 0); + ATF_REQUIRE(pathl != NULL); + + ATF_REQUIRE(link(path, pathl) == 0); + ATF_REQUIRE(stat(path, &sa) == 0); + ATF_REQUIRE(lstat(pathl, &sb) == 0); + + if (sa.st_uid != sb.st_uid) + atf_tc_fail("unequal UIDs"); + + if (sa.st_mode != sb.st_mode) + atf_tc_fail("unequal modes"); + + if (sa.st_ino != sb.st_ino) + atf_tc_fail("unequal inodes"); + + ATF_REQUIRE(close(fd) == 0); + ATF_REQUIRE(unlink(path) == 0); + ATF_REQUIRE(unlink(pathl) == 0); +} + +ATF_TC_CLEANUP(link_stat, tc) +{ + (void)unlink(path); + (void)unlink(pathl); +} + +ATF_TP_ADD_TCS(tp) +{ + + ATF_TP_ADD_TC(tp, link_count); + ATF_TP_ADD_TC(tp, link_err); + ATF_TP_ADD_TC(tp, link_perm); + ATF_TP_ADD_TC(tp, link_stat); + + return atf_no_error(); +} diff --git a/contrib/netbsd-tests/lib/libc/sys/t_listen.c b/contrib/netbsd-tests/lib/libc/sys/t_listen.c new file mode 100644 index 0000000..71201d3 --- /dev/null +++ b/contrib/netbsd-tests/lib/libc/sys/t_listen.c @@ -0,0 +1,134 @@ +/* $NetBSD: t_listen.c,v 1.4 2012/03/18 07:00:52 jruoho Exp $ */ +/* + * Copyright (c) 2007 The NetBSD Foundation, 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ + +#include <atf-c.h> +#include <err.h> +#include <errno.h> +#include <fcntl.h> +#include <string.h> +#include <unistd.h> + +#include <arpa/inet.h> +#include <netinet/in.h> + +static const char *path = "listen"; + +ATF_TC_WITH_CLEANUP(listen_err); +ATF_TC_HEAD(listen_err, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Checks errors from listen(2) (PR standards/46150)"); +} + +ATF_TC_BODY(listen_err, tc) +{ + static const size_t siz = sizeof(struct sockaddr_in); + struct sockaddr_in sina, sinb; + int fda, fdb, fdc; + + (void)memset(&sina, 0, sizeof(struct sockaddr_in)); + (void)memset(&sinb, 0, sizeof(struct sockaddr_in)); + + sina.sin_family = AF_INET; + sina.sin_port = htons(31522); + sina.sin_addr.s_addr = inet_addr("127.0.0.1"); + + sinb.sin_family = AF_INET; + sinb.sin_port = htons(31522); + sinb.sin_addr.s_addr = inet_addr("127.0.0.1"); + + fda = socket(AF_INET, SOCK_STREAM, 0); + fdb = socket(AF_INET, SOCK_STREAM, 0); + fdc = open("listen", O_RDWR | O_CREAT, 0600); + + ATF_REQUIRE(fda >= 0 && fdb >= 0 && fdc >= 0); + ATF_REQUIRE_ERRNO(ENOTSOCK, listen(fdc, 1) == -1); + + (void)close(fdc); + (void)unlink(path); + + ATF_REQUIRE(bind(fda, (struct sockaddr *)&sina, siz) == 0); + ATF_REQUIRE(listen(fda, 1) == 0); + + /* + * According to IEEE Std 1003.1-2008: if the socket is + * already connected, the call should fail with EINVAL. + */ + ATF_REQUIRE(connect(fdb, (struct sockaddr *)&sinb, siz) == 0); + ATF_REQUIRE_ERRNO(EINVAL, listen(fdb, 1) == -1); + + (void)close(fda); + (void)close(fdb); + + ATF_REQUIRE_ERRNO(EBADF, connect(fdb, + (struct sockaddr *)&sinb, siz) == -1); +} + +ATF_TC_CLEANUP(listen_err, tc) +{ + (void)unlink(path); +} + +ATF_TC(listen_low_port); +ATF_TC_HEAD(listen_low_port, tc) +{ + atf_tc_set_md_var(tc, "descr", "Does low-port allocation work?"); + atf_tc_set_md_var(tc, "require.user", "root"); +} + +ATF_TC_BODY(listen_low_port, tc) +{ + int sd, val; + + sd = socket(AF_INET, SOCK_STREAM, 0); + + val = IP_PORTRANGE_LOW; + if (setsockopt(sd, IPPROTO_IP, IP_PORTRANGE, &val, + sizeof(val)) == -1) + atf_tc_fail("setsockopt failed: %s", strerror(errno)); + + if (listen(sd, 5) == -1) { + int serrno = errno; + atf_tc_fail("listen failed: %s%s", + strerror(serrno), + serrno != EACCES ? "" : + " (see http://mail-index.netbsd.org/" + "source-changes/2007/12/16/0011.html)"); + } + + close(sd); +} + +ATF_TP_ADD_TCS(tp) +{ + + ATF_TP_ADD_TC(tp, listen_err); + ATF_TP_ADD_TC(tp, listen_low_port); + + return 0; +} diff --git a/contrib/netbsd-tests/lib/libc/sys/t_lwp_create.c b/contrib/netbsd-tests/lib/libc/sys/t_lwp_create.c new file mode 100644 index 0000000..02545fe --- /dev/null +++ b/contrib/netbsd-tests/lib/libc/sys/t_lwp_create.c @@ -0,0 +1,247 @@ +/* $NetBSD: t_lwp_create.c,v 1.2 2012/05/22 09:23:39 martin Exp $ */ + +/*- + * Copyright (c) 2012 The NetBSD Foundation, 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ + +/* + * This code is partly based on code by Joel Sing <joel at sing.id.au> + */ + +#include <atf-c.h> +#include <lwp.h> +#include <stdio.h> +#include <stdlib.h> +#include <ucontext.h> +#include <inttypes.h> +#include <errno.h> + +#ifdef __alpha__ +#include <machine/alpha_cpu.h> +#endif +#ifdef __amd64__ +#include <machine/vmparam.h> +#include <machine/psl.h> +#endif +#ifdef __hppa__ +#include <machine/psl.h> +#endif +#ifdef __i386__ +#include <machine/segments.h> +#include <machine/psl.h> +#endif +#if defined(__m68k__) || defined(__sh3__) || defined __vax__ +#include <machine/psl.h> +#endif + +volatile lwpid_t the_lwp_id = 0; + +static void lwp_main_func(void* arg) +{ + the_lwp_id = _lwp_self(); + _lwp_exit(); +} + +/* + * Hard to document - see usage examples below. + */ +#define INVALID_UCONTEXT(ARCH,NAME,DESC) \ +static void ARCH##_##NAME(ucontext_t *); \ +ATF_TC(lwp_create_##ARCH##_fail_##NAME); \ +ATF_TC_HEAD(lwp_create_##ARCH##_fail_##NAME, tc) \ +{ \ + atf_tc_set_md_var(tc, "descr", "verify rejection of invalid ucontext " \ + "on " #ARCH " due to " DESC); \ +} \ + \ +ATF_TC_BODY(lwp_create_##ARCH##_fail_##NAME, tc) \ +{ \ + ucontext_t uc; \ + lwpid_t lid; \ + int error; \ + \ + getcontext(&uc); \ + uc.uc_flags = _UC_CPU; \ + ARCH##_##NAME(&uc); \ + \ + error = _lwp_create(&uc, 0, &lid); \ + ATF_REQUIRE(error != 0 && errno == EINVAL); \ +} \ +static void ARCH##_##NAME(ucontext_t *uc) \ +{ + + +ATF_TC(lwp_create_works); +ATF_TC_HEAD(lwp_create_works, tc) +{ + atf_tc_set_md_var(tc, "descr", "Verify creation of a lwp and waiting" + " for it to finish"); +} + +ATF_TC_BODY(lwp_create_works, tc) +{ + ucontext_t uc; + lwpid_t lid; + int error; + void *stack; + static const size_t ssize = 16*1024; + + stack = malloc(ssize); + _lwp_makecontext(&uc, lwp_main_func, NULL, NULL, stack, ssize); + + error = _lwp_create(&uc, 0, &lid); + ATF_REQUIRE(error == 0); + + error = _lwp_wait(lid, NULL); + ATF_REQUIRE(error == 0); + ATF_REQUIRE(lid == the_lwp_id); +} + +INVALID_UCONTEXT(generic, no_uc_cpu, "not setting cpu registers") + uc->uc_flags &= ~_UC_CPU; +} + +#ifdef __alpha__ +INVALID_UCONTEXT(alpha, pslset, "trying to clear the USERMODE flag") + uc->uc_mcontext.__gregs[_REG_PS] &= ~ALPHA_PSL_USERMODE; +} +INVALID_UCONTEXT(alpha, pslclr, "trying to set a 'must be zero' flag") + uc->uc_mcontext.__gregs[_REG_PS] |= ALPHA_PSL_IPL_HIGH; +} +#endif +#ifdef __amd64__ +INVALID_UCONTEXT(amd64, untouchable_rflags, "forbidden rflags changed") + uc->uc_mcontext.__gregs[_REG_RFLAGS] |= PSL_MBZ; +} +/* + * XXX: add invalid GS/DS selector tests + */ +INVALID_UCONTEXT(amd64, pc_too_high, + "instruction pointer outside userland address space") + uc->uc_mcontext.__gregs[_REG_RIP] = VM_MAXUSER_ADDRESS; +} +#endif +#ifdef __arm__ +INVALID_UCONTEXT(arm, invalid_mode, "psr or r15 set to non-user-mode") + uc->uc_mcontext.__gregs[_REG_PC] |= 0x1f /*PSR_SYS32_MODE*/; + uc->uc_mcontext.__gregs[_REG_CPSR] |= 0x03 /*R15_MODE_SVC*/; +} +#endif +#ifdef __hppa__ +INVALID_UCONTEXT(hppa, invalid_1, "set illegal bits in psw") + uc->uc_mcontext.__gregs[_REG_PSW] |= PSW_MBZ; +} +INVALID_UCONTEXT(hppa, invalid_0, "clear illegal bits in psw") + uc->uc_mcontext.__gregs[_REG_PSW] &= ~PSW_MBS; +} +#endif +#ifdef __i386__ +INVALID_UCONTEXT(i386, untouchable_eflags, "changing forbidden eflags") + uc->uc_mcontext.__gregs[_REG_EFL] |= PSL_IOPL; +} +INVALID_UCONTEXT(i386, priv_escalation, "modifying priviledge level") + uc->uc_mcontext.__gregs[_REG_CS] &= ~SEL_RPL; +} +#endif +#ifdef __m68k__ +INVALID_UCONTEXT(m68k, invalid_ps_bits, + "setting forbidden bits in the ps register") + uc->uc_mcontext.__gregs[_REG_PS] |= (PSL_MBZ|PSL_IPL|PSL_S); +} +#endif +#ifdef __sh3__ +INVALID_UCONTEXT(sh3, modify_userstatic, + "modifying illegal bits in the status register") + uc->uc_mcontext.__gregs[_REG_SR] |= PSL_MD; +} +#endif +#ifdef __sparc__ +INVALID_UCONTEXT(sparc, pc_odd, "mis-aligned instruction pointer") + uc->uc_mcontext.__gregs[_REG_PC] = 0x100002; +} +INVALID_UCONTEXT(sparc, npc_odd, "mis-aligned next instruction pointer") + uc->uc_mcontext.__gregs[_REG_nPC] = 0x100002; +} +INVALID_UCONTEXT(sparc, pc_null, "NULL instruction pointer") + uc->uc_mcontext.__gregs[_REG_PC] = 0; +} +INVALID_UCONTEXT(sparc, npc_null, "NULL next instruction pointer") + uc->uc_mcontext.__gregs[_REG_nPC] = 0; +} +#endif +#ifdef __vax__ +INVALID_UCONTEXT(vax, psl_0, "clearing forbidden bits in psl") + uc->uc_mcontext.__gregs[_REG_PSL] &= ~(PSL_U | PSL_PREVU); +} +INVALID_UCONTEXT(vax, psl_1, "setting forbidden bits in psl") + uc->uc_mcontext.__gregs[_REG_PSL] |= PSL_IPL | PSL_IS; +} +INVALID_UCONTEXT(vax, psl_cm, "setting CM bit in psl") + uc->uc_mcontext.__gregs[_REG_PSL] |= PSL_CM; +} +#endif + +ATF_TP_ADD_TCS(tp) +{ + ATF_TP_ADD_TC(tp, lwp_create_works); + ATF_TP_ADD_TC(tp, lwp_create_generic_fail_no_uc_cpu); +#ifdef __alpha__ + ATF_TP_ADD_TC(tp, lwp_create_alpha_fail_pslset); + ATF_TP_ADD_TC(tp, lwp_create_alpha_fail_pslclr); +#endif +#ifdef __amd64__ + ATF_TP_ADD_TC(tp, lwp_create_amd64_fail_untouchable_rflags); + ATF_TP_ADD_TC(tp, lwp_create_amd64_fail_pc_too_high); +#endif +#ifdef __arm__ + ATF_TP_ADD_TC(tp, lwp_create_arm_fail_invalid_mode); +#endif +#ifdef __hppa__ + ATF_TP_ADD_TC(tp, lwp_create_hppa_fail_invalid_1); + ATF_TP_ADD_TC(tp, lwp_create_hppa_fail_invalid_0); +#endif +#ifdef __i386__ + ATF_TP_ADD_TC(tp, lwp_create_i386_fail_untouchable_eflags); + ATF_TP_ADD_TC(tp, lwp_create_i386_fail_priv_escalation); +#endif +#ifdef __m68k__ + ATF_TP_ADD_TC(tp, lwp_create_m68k_fail_invalid_ps_bits); +#endif +#ifdef __sh3__ + ATF_TP_ADD_TC(tp, lwp_create_sh3_fail_modify_userstatic); +#endif +#ifdef __sparc__ + ATF_TP_ADD_TC(tp, lwp_create_sparc_fail_pc_odd); + ATF_TP_ADD_TC(tp, lwp_create_sparc_fail_npc_odd); + ATF_TP_ADD_TC(tp, lwp_create_sparc_fail_pc_null); + ATF_TP_ADD_TC(tp, lwp_create_sparc_fail_npc_null); +#endif +#ifdef __vax__ + ATF_TP_ADD_TC(tp, lwp_create_vax_fail_psl_0); + ATF_TP_ADD_TC(tp, lwp_create_vax_fail_psl_1); + ATF_TP_ADD_TC(tp, lwp_create_vax_fail_psl_cm); +#endif + return atf_no_error(); +} diff --git a/contrib/netbsd-tests/lib/libc/sys/t_lwp_ctl.c b/contrib/netbsd-tests/lib/libc/sys/t_lwp_ctl.c new file mode 100644 index 0000000..1b28f75 --- /dev/null +++ b/contrib/netbsd-tests/lib/libc/sys/t_lwp_ctl.c @@ -0,0 +1,74 @@ +/* $NetBSD: t_lwp_ctl.c,v 1.2 2012/03/18 06:20:51 jruoho Exp $ */ + +/*- + * Copyright (c) 2008 The NetBSD Foundation, 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ + +#include <sys/cdefs.h> +__COPYRIGHT("@(#) Copyright (c) 2008\ + The NetBSD Foundation, inc. All rights reserved."); +__RCSID("$NetBSD: t_lwp_ctl.c,v 1.2 2012/03/18 06:20:51 jruoho Exp $"); + +#include <sys/lwpctl.h> + +#include <atf-c.h> +#include <lwp.h> +#include <stdio.h> +#include <time.h> + +ATF_TC(lwpctl_counter); +ATF_TC_HEAD(lwpctl_counter, tc) +{ + atf_tc_set_md_var(tc, "descr", "Checks lwpctl preemption counter"); +} + +ATF_TC_BODY(lwpctl_counter, tc) +{ + lwpctl_t *lc; + struct timespec ts; + int ctr1, ctr2; + + ATF_REQUIRE(_lwp_ctl(LWPCTL_FEATURE_PCTR, &lc) == 0); + + /* Ensure that preemption is reported. */ + ctr1 = lc->lc_pctr; + (void)printf("pctr = %d\n", ctr1); + ts.tv_nsec = 10*1000000; + ts.tv_sec = 0; + + ATF_REQUIRE(nanosleep(&ts, 0) != -1); + + ctr2 = lc->lc_pctr; + (void)printf("pctr = %d\n", ctr2); + + ATF_REQUIRE_MSG(ctr1 != ctr2, "counters match"); +} + +ATF_TP_ADD_TCS(tp) +{ + ATF_TP_ADD_TC(tp, lwpctl_counter); + + return atf_no_error(); +} diff --git a/contrib/netbsd-tests/lib/libc/sys/t_mincore.c b/contrib/netbsd-tests/lib/libc/sys/t_mincore.c new file mode 100644 index 0000000..553207a --- /dev/null +++ b/contrib/netbsd-tests/lib/libc/sys/t_mincore.c @@ -0,0 +1,318 @@ +/* $NetBSD: t_mincore.c,v 1.8 2012/06/08 07:18:58 martin Exp $ */ + +/*- + * Copyright (c) 2011 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jukka Ruohonen. + * + * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ + +/*- + * Copyright (c) 1999 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, + * NASA Ames Research Center. + * + * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ +#include <sys/cdefs.h> +__RCSID("$NetBSD: t_mincore.c,v 1.8 2012/06/08 07:18:58 martin Exp $"); + +#include <sys/mman.h> +#include <sys/shm.h> + +#include <atf-c.h> +#include <errno.h> +#include <fcntl.h> +#include <kvm.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/resource.h> + +static long page = 0; +static const char path[] = "mincore"; +static size_t check_residency(void *, size_t); + +static size_t +check_residency(void *addr, size_t npgs) +{ + size_t i, resident; + char *vec; + + vec = malloc(npgs); + + ATF_REQUIRE(vec != NULL); + ATF_REQUIRE(mincore(addr, npgs * page, vec) == 0); + + for (i = resident = 0; i < npgs; i++) { + + if (vec[i] != 0) + resident++; + +#if 0 + (void)fprintf(stderr, "page 0x%p is %sresident\n", + (char *)addr + (i * page), vec[i] ? "" : "not "); +#endif + } + + free(vec); + + return resident; +} + +ATF_TC(mincore_err); +ATF_TC_HEAD(mincore_err, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test errors from mincore(2)"); +} + +ATF_TC_BODY(mincore_err, tc) +{ + char *map, *vec; + + map = mmap(NULL, page, PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0); + vec = malloc(page); + + ATF_REQUIRE(vec != NULL); + ATF_REQUIRE(map != MAP_FAILED); + + errno = 0; + ATF_REQUIRE_ERRNO(EINVAL, mincore(map, 0, vec) == -1); + + errno = 0; + ATF_REQUIRE_ERRNO(ENOMEM, mincore(0, page, vec) == -1); + + errno = 0; + ATF_REQUIRE_ERRNO(EFAULT, mincore(map, page, (void *)-1) == -1); + + free(vec); + ATF_REQUIRE(munmap(map, page) == 0); +} + +ATF_TC_WITH_CLEANUP(mincore_resid); +ATF_TC_HEAD(mincore_resid, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test page residency with mincore(2)"); +} + +ATF_TC_BODY(mincore_resid, tc) +{ + void *addr, *addr2, *addr3, *buf; + size_t npgs = 0, resident; + struct stat st; + int fd, rv; + struct rlimit rlim; + + ATF_REQUIRE(getrlimit(RLIMIT_MEMLOCK, &rlim) == 0); + rlim.rlim_cur = rlim.rlim_max; + ATF_REQUIRE(setrlimit(RLIMIT_MEMLOCK, &rlim) == 0); + + (void)memset(&st, 0, sizeof(struct stat)); + + fd = open(path, O_RDWR | O_CREAT, 0700); + buf = malloc(page * 5); + + ATF_REQUIRE(fd >= 0); + ATF_REQUIRE(buf != NULL); + + rv = write(fd, buf, page * 5); + ATF_REQUIRE(rv >= 0); + + ATF_REQUIRE(fd >= 0); + ATF_REQUIRE(fstat(fd, &st) == 0); + + addr = mmap(NULL, (size_t)st.st_size, PROT_READ, + MAP_FILE | MAP_SHARED, fd, (off_t) 0); + + ATF_REQUIRE(addr != MAP_FAILED); + + (void)close(fd); + + npgs = st.st_size / page; + + if (st.st_size % page != 0) + npgs++; + + (void)check_residency(addr, npgs); + + rv = mlock(addr, npgs * page); + if (rv == -1 && errno == EAGAIN) + atf_tc_skip("hit process resource limits"); + ATF_REQUIRE(munmap(addr, st.st_size) == 0); + + npgs = 128; + + addr = mmap(NULL, npgs * page, PROT_READ | PROT_WRITE, + MAP_ANON | MAP_PRIVATE | MAP_WIRED, -1, (off_t)0); + + if (addr == MAP_FAILED) + atf_tc_skip("could not mmap wired anonymous test area, system " + "might be low on memory"); + + ATF_REQUIRE(check_residency(addr, npgs) == npgs); + ATF_REQUIRE(munmap(addr, npgs * page) == 0); + + npgs = 128; + + addr = mmap(NULL, npgs * page, PROT_READ | PROT_WRITE, + MAP_ANON | MAP_PRIVATE, -1, (off_t)0); + + ATF_REQUIRE(addr != MAP_FAILED); + + /* + * Check that the in-core pages match the locked pages. + */ + ATF_REQUIRE(check_residency(addr, npgs) == 0); + + errno = 0; + if (mlockall(MCL_CURRENT|MCL_FUTURE) != 0 && errno != ENOMEM) + atf_tc_fail("mlockall(2) failed"); + if (errno == ENOMEM) + atf_tc_skip("mlockall() exceeded process resource limits"); + + resident = check_residency(addr, npgs); + if (resident < npgs) + atf_tc_fail("mlockall(MCL_FUTURE) succeeded, still only " + "%zu pages of the newly mapped %zu pages are resident", + resident, npgs); + + addr2 = mmap(NULL, npgs * page, PROT_READ, MAP_ANON, -1, (off_t)0); + addr3 = mmap(NULL, npgs * page, PROT_NONE, MAP_ANON, -1, (off_t)0); + + if (addr2 == MAP_FAILED || addr3 == MAP_FAILED) + atf_tc_skip("could not mmap more anonymous test pages with " + "mlockall(MCL_FUTURE) in effect, system " + "might be low on memory"); + + ATF_REQUIRE(check_residency(addr2, npgs) == npgs); + ATF_REQUIRE(check_residency(addr3, npgs) == 0); + ATF_REQUIRE(mprotect(addr3, npgs * page, PROT_READ) == 0); + ATF_REQUIRE(check_residency(addr, npgs) == npgs); + ATF_REQUIRE(check_residency(addr2, npgs) == npgs); + + (void)munlockall(); + + ATF_REQUIRE(madvise(addr2, npgs * page, MADV_FREE) == 0); + ATF_REQUIRE(check_residency(addr2, npgs) == 0); + + (void)memset(addr, 0, npgs * page); + + ATF_REQUIRE(madvise(addr, npgs * page, MADV_FREE) == 0); + ATF_REQUIRE(check_residency(addr, npgs) == 0); + + (void)munmap(addr, npgs * page); + (void)munmap(addr2, npgs * page); + (void)munmap(addr3, npgs * page); + (void)unlink(path); +} + +ATF_TC_CLEANUP(mincore_resid, tc) +{ + (void)unlink(path); +} + +ATF_TC(mincore_shmseg); +ATF_TC_HEAD(mincore_shmseg, tc) +{ + atf_tc_set_md_var(tc, "descr", "residency of shared memory"); +} + +ATF_TC_BODY(mincore_shmseg, tc) +{ + size_t npgs = 128; + void *addr = NULL; + int shmid; + + shmid = shmget(IPC_PRIVATE, npgs * page, + IPC_CREAT | S_IRUSR | S_IWUSR); + + ATF_REQUIRE(shmid != -1); + + addr = shmat(shmid, NULL, 0); + + ATF_REQUIRE(addr != NULL); + ATF_REQUIRE(check_residency(addr, npgs) == 0); + + (void)memset(addr, 0xff, npgs * page); + + ATF_REQUIRE(check_residency(addr, npgs) == npgs); + ATF_REQUIRE(madvise(addr, npgs * page, MADV_FREE) == 0); + + /* + * NOTE! Even though we have MADV_FREE'd the range, + * there is another reference (the kernel's) to the + * object which owns the pages. In this case, the + * kernel does not simply free the pages, as haphazardly + * freeing pages when there are still references to + * an object can cause data corruption (say, the other + * referencer doesn't expect the pages to be freed, + * and is surprised by the subsequent ZFOD). + * + * Because of this, we simply report the number of + * pages still resident, for information only. + */ + npgs = check_residency(addr, npgs); + + (void)fprintf(stderr, "%zu pages still resident\n", npgs); + + ATF_REQUIRE(shmdt(addr) == 0); + ATF_REQUIRE(shmctl(shmid, IPC_RMID, NULL) == 0); +} + +ATF_TP_ADD_TCS(tp) +{ + + page = sysconf(_SC_PAGESIZE); + ATF_REQUIRE(page >= 0); + + ATF_TP_ADD_TC(tp, mincore_err); + ATF_TP_ADD_TC(tp, mincore_resid); + ATF_TP_ADD_TC(tp, mincore_shmseg); + + return atf_no_error(); +} diff --git a/contrib/netbsd-tests/lib/libc/sys/t_minherit.c b/contrib/netbsd-tests/lib/libc/sys/t_minherit.c new file mode 100644 index 0000000..0bdf6bc --- /dev/null +++ b/contrib/netbsd-tests/lib/libc/sys/t_minherit.c @@ -0,0 +1,200 @@ +/* $NetBSD: t_minherit.c,v 1.1 2014/07/18 12:34:52 christos Exp $ */ + +/*- + * Copyright (c) 2014 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Christos Zoulas + * + * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ +#include <sys/cdefs.h> +__RCSID("$NetBSD: t_minherit.c,v 1.1 2014/07/18 12:34:52 christos Exp $"); + +#include <sys/param.h> +#include <sys/mman.h> +#include <sys/sysctl.h> +#include <sys/wait.h> + +#include <errno.h> +#include <fcntl.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include <atf-c.h> + +static long page; + +static void * +makemap(int v, int f) { + void *map = mmap(NULL, page, PROT_READ|PROT_WRITE, + MAP_SHARED|MAP_ANON, -1, 0); + ATF_REQUIRE(map != MAP_FAILED); + memset(map, v, page); + if (f != 666) + ATF_REQUIRE(minherit(map, page, f) == 0); + else + ATF_REQUIRE(minherit(map, page, f) == -1); + return map; +} + +ATF_TC(minherit_copy); +ATF_TC_HEAD(minherit_copy, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Test for MAP_INHERIT_COPY from minherit(2)"); +} + +ATF_TC_BODY(minherit_copy, tc) +{ + void *map1 = makemap(1, MAP_INHERIT_COPY); + void *map2 = makemap(1, MAP_INHERIT_COPY); + switch (fork()) { + default: + ATF_REQUIRE(wait(NULL) != -1); + ATF_REQUIRE(memcmp(map1, map2, page) == 0); + break; + case -1: + ATF_REQUIRE(0); + break; + case 0: + ATF_REQUIRE(memcmp(map1, map2, page) == 0); + memset(map1, 0, page); + exit(0); + } +} + +ATF_TC(minherit_share); +ATF_TC_HEAD(minherit_share, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Test for MAP_INHERIT_SHARE from minherit(2)"); +} + +ATF_TC_BODY(minherit_share, tc) +{ + void *map1 = makemap(1, MAP_INHERIT_SHARE); + void *map2 = makemap(1, MAP_INHERIT_SHARE); + + switch (fork()) { + default: + ATF_REQUIRE(wait(NULL) != -1); + memset(map2, 0, page); + ATF_REQUIRE(memcmp(map1, map2, page) == 0); + break; + case -1: + ATF_REQUIRE(0); + break; + case 0: + ATF_REQUIRE(memcmp(map1, map2, page) == 0); + memset(map1, 0, page); + exit(0); + } +} + +static void +segv(int n) { + _exit(n); +} + +ATF_TC(minherit_none); +ATF_TC_HEAD(minherit_none, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Test for MAP_INHERIT_NONE from minherit(2)"); +} + +ATF_TC_BODY(minherit_none, tc) +{ + void *map1 = makemap(0, MAP_INHERIT_NONE); + int status; + + switch (fork()) { + default: + ATF_REQUIRE(wait(&status) != -1); + ATF_REQUIRE(WEXITSTATUS(status) == SIGSEGV); + break; + case -1: + ATF_REQUIRE(0); + break; + case 0: + ATF_REQUIRE(signal(SIGSEGV, segv) != SIG_ERR); + memset(map1, 0, page); + exit(0); + } +} + +ATF_TC(minherit_zero); +ATF_TC_HEAD(minherit_zero, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Test for MAP_INHERIT_ZERO from minherit(2)"); +} + +ATF_TC_BODY(minherit_zero, tc) +{ + void *map1 = makemap(1, MAP_INHERIT_ZERO); + void *map2 = makemap(0, MAP_INHERIT_SHARE); + + switch (fork()) { + default: + ATF_REQUIRE(wait(NULL) != -1); + memset(map2, 1, page); + ATF_REQUIRE(memcmp(map1, map2, page) == 0); + break; + case -1: + ATF_REQUIRE(0); + break; + case 0: + ATF_REQUIRE(memcmp(map1, map2, page) == 0); + memset(map1, 2, page); + exit(0); + } +} + +ATF_TC(minherit_bad); +ATF_TC_HEAD(minherit_bad, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Test for bad minherit(2)"); +} + +ATF_TC_BODY(minherit_bad, tc) +{ + (void)makemap(0, 666); +} + +ATF_TP_ADD_TCS(tp) +{ + page = sysconf(_SC_PAGESIZE); + ATF_REQUIRE(page >= 0); + + ATF_TP_ADD_TC(tp, minherit_copy); + ATF_TP_ADD_TC(tp, minherit_share); + ATF_TP_ADD_TC(tp, minherit_none); + ATF_TP_ADD_TC(tp, minherit_zero); + ATF_TP_ADD_TC(tp, minherit_bad); + + return atf_no_error(); +} diff --git a/contrib/netbsd-tests/lib/libc/sys/t_mkdir.c b/contrib/netbsd-tests/lib/libc/sys/t_mkdir.c new file mode 100644 index 0000000..d97a20b --- /dev/null +++ b/contrib/netbsd-tests/lib/libc/sys/t_mkdir.c @@ -0,0 +1,210 @@ +/* $NetBSD: t_mkdir.c,v 1.2 2011/10/15 07:38:31 jruoho Exp $ */ + +/*- + * Copyright (c) 2008, 2011 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jason R. Thorpe and Jukka Ruohonen. + * + * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ + +#include <sys/cdefs.h> +__COPYRIGHT("@(#) Copyright (c) 2008\ + The NetBSD Foundation, inc. All rights reserved."); +__RCSID("$NetBSD: t_mkdir.c,v 1.2 2011/10/15 07:38:31 jruoho Exp $"); + +#include <sys/stat.h> +#include <sys/wait.h> + +#include <atf-c.h> +#include <errno.h> +#include <fcntl.h> +#include <limits.h> +#include <pwd.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +ATF_TC(mkdir_err); +ATF_TC_HEAD(mkdir_err, tc) +{ + atf_tc_set_md_var(tc, "descr", "Checks errors from mkdir(2)"); +} + +ATF_TC_BODY(mkdir_err, tc) +{ + char buf[PATH_MAX + 1]; + int fd; + + (void)memset(buf, 'x', sizeof(buf)); + + fd = open("/etc", O_RDONLY); + + if (fd >= 0) { + + (void)close(fd); + + errno = 0; + ATF_REQUIRE_ERRNO(EEXIST, mkdir("/etc", 0500) == -1); + } + + errno = 0; + ATF_REQUIRE_ERRNO(EFAULT, mkdir((void *)-1, 0500) == -1); + + errno = 0; + ATF_REQUIRE_ERRNO(ENAMETOOLONG, mkdir(buf, 0500) == -1); + + errno = 0; + ATF_REQUIRE_ERRNO(ENOENT, mkdir("/a/b/c/d/e/f/g/h/i/j/k", 0500) == -1); +} + +ATF_TC_WITH_CLEANUP(mkdir_perm); +ATF_TC_HEAD(mkdir_perm, tc) +{ + atf_tc_set_md_var(tc, "descr", "Checks permissions with mkdir(2)"); + atf_tc_set_md_var(tc, "require.user", "unprivileged"); +} + +ATF_TC_BODY(mkdir_perm, tc) +{ + errno = 0; + ATF_REQUIRE_ERRNO(EACCES, mkdir("/usr/__nonexistent__", 0500) == -1); +} + +ATF_TC_CLEANUP(mkdir_perm, tc) +{ + (void)rmdir("/usr/__nonexistent__"); +} + +ATF_TC_WITH_CLEANUP(mkdir_mode); +ATF_TC_HEAD(mkdir_mode, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test that UIDs and GIDs are right " + "for a directory created with mkdir(2)"); + atf_tc_set_md_var(tc, "require.user", "root"); +} + +ATF_TC_BODY(mkdir_mode, tc) +{ + static const char *path = "/tmp/mkdir"; + struct stat st_a, st_b; + struct passwd *pw; + pid_t pid; + int sta; + + (void)memset(&st_a, 0, sizeof(struct stat)); + (void)memset(&st_b, 0, sizeof(struct stat)); + + pw = getpwnam("nobody"); + + ATF_REQUIRE(pw != NULL); + ATF_REQUIRE(stat("/tmp", &st_a) == 0); + + pid = fork(); + ATF_REQUIRE(pid >= 0); + + if (pid == 0) { + + if (setuid(pw->pw_uid) != 0) + _exit(EXIT_FAILURE); + + if (mkdir(path, 0500) != 0) + _exit(EXIT_FAILURE); + + _exit(EXIT_SUCCESS); + } + + (void)sleep(1); + (void)wait(&sta); + + if (WIFEXITED(sta) == 0 || WEXITSTATUS(sta) != EXIT_SUCCESS) + atf_tc_fail("failed to create '%s'", path); + + ATF_REQUIRE(stat(path, &st_b) == 0); + ATF_REQUIRE(rmdir(path) == 0); + + /* + * The directory's owner ID should be set to the + * effective UID, whereas the group ID should be + * set to that of the parent directory. + */ + if (st_b.st_uid != pw->pw_uid) + atf_tc_fail("invalid UID for '%s'", path); + + if (st_b.st_gid != st_a.st_gid) + atf_tc_fail("GID did not follow the parent directory"); +} + +ATF_TC_CLEANUP(mkdir_mode, tc) +{ + (void)rmdir("/tmp/mkdir"); +} + +ATF_TC(mkdir_trail); +ATF_TC_HEAD(mkdir_trail, tc) +{ + atf_tc_set_md_var(tc, "descr", "Checks mkdir(2) for trailing slashes"); +} + +ATF_TC_BODY(mkdir_trail, tc) +{ + const char *tests[] = { + /* + * IEEE 1003.1 second ed. 2.2.2.78: + * + * If the pathname refers to a directory, it may also have + * one or more trailing slashes. Multiple successive slashes + * are considered to be the same as one slash. + */ + "dir1/", + "dir2//", + + NULL, + }; + + const char **test; + + for (test = &tests[0]; *test != NULL; ++test) { + + (void)printf("Checking \"%s\"\n", *test); + (void)rmdir(*test); + + ATF_REQUIRE(mkdir(*test, 0777) == 0); + ATF_REQUIRE(rename(*test, "foo") == 0); + ATF_REQUIRE(rename("foo/", *test) == 0); + ATF_REQUIRE(rmdir(*test) == 0); + } +} + +ATF_TP_ADD_TCS(tp) +{ + + ATF_TP_ADD_TC(tp, mkdir_err); + ATF_TP_ADD_TC(tp, mkdir_perm); + ATF_TP_ADD_TC(tp, mkdir_mode); + ATF_TP_ADD_TC(tp, mkdir_trail); + + return atf_no_error(); +} diff --git a/contrib/netbsd-tests/lib/libc/sys/t_mkfifo.c b/contrib/netbsd-tests/lib/libc/sys/t_mkfifo.c new file mode 100644 index 0000000..56bc4c8 --- /dev/null +++ b/contrib/netbsd-tests/lib/libc/sys/t_mkfifo.c @@ -0,0 +1,276 @@ +/* $NetBSD: t_mkfifo.c,v 1.2 2011/11/02 06:04:48 jruoho Exp $ */ + +/*- + * Copyright (c) 2011 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jukka Ruohonen. + * + * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ +#include <sys/cdefs.h> +__RCSID("$NetBSD: t_mkfifo.c,v 1.2 2011/11/02 06:04:48 jruoho Exp $"); + +#include <sys/stat.h> +#include <sys/wait.h> + +#include <atf-c.h> +#include <errno.h> +#include <fcntl.h> +#include <limits.h> +#include <stdlib.h> +#include <signal.h> +#include <string.h> +#include <unistd.h> + +static const char path[] = "fifo"; +static void support(void); + +static void +support(void) +{ + + errno = 0; + + if (mkfifo(path, 0600) == 0) { + ATF_REQUIRE(unlink(path) == 0); + return; + } + + if (errno == EOPNOTSUPP) + atf_tc_skip("the kernel does not support FIFOs"); + else { + atf_tc_fail("mkfifo(2) failed"); + } +} + +ATF_TC_WITH_CLEANUP(mkfifo_block); +ATF_TC_HEAD(mkfifo_block, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test that FIFOs block"); +} + +ATF_TC_BODY(mkfifo_block, tc) +{ + int sta, fd = -1; + pid_t pid; + + support(); + + ATF_REQUIRE(mkfifo(path, 0600) == 0); + + pid = fork(); + ATF_REQUIRE(pid >= 0); + + if (pid == 0) { + + /* + * If we open the FIFO as read-only (write-only), + * the call should block until another process + * opens the FIFO for writing (reading). + */ + fd = open(path, O_RDONLY); + + _exit(EXIT_FAILURE); /* NOTREACHED */ + } + + (void)sleep(1); + + ATF_REQUIRE(kill(pid, SIGKILL) == 0); + + (void)wait(&sta); + + if (WIFSIGNALED(sta) == 0 || WTERMSIG(sta) != SIGKILL) + atf_tc_fail("FIFO did not block"); + + (void)close(fd); + (void)unlink(path); +} + +ATF_TC_CLEANUP(mkfifo_block, tc) +{ + (void)unlink(path); +} + +ATF_TC_WITH_CLEANUP(mkfifo_err); +ATF_TC_HEAD(mkfifo_err, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test erros from mkfifo(2)"); +} + +ATF_TC_BODY(mkfifo_err, tc) +{ + char buf[PATH_MAX + 1]; + + support(); + + (void)memset(buf, 'x', sizeof(buf)); + ATF_REQUIRE(mkfifo(path, 0600) == 0); + + errno = 0; + ATF_REQUIRE_ERRNO(EFAULT, mkfifo((char *)-1, 0600) == -1); + + errno = 0; + ATF_REQUIRE_ERRNO(EEXIST, mkfifo("/etc/passwd", 0600) == -1); + + errno = 0; + ATF_REQUIRE_ERRNO(EEXIST, mkfifo(path, 0600) == -1); + + errno = 0; + ATF_REQUIRE_ERRNO(ENAMETOOLONG, mkfifo(buf, 0600) == -1); + + errno = 0; + ATF_REQUIRE_ERRNO(ENOENT, mkfifo("/a/b/c/d/e/f/g", 0600) == -1); + + ATF_REQUIRE(unlink(path) == 0); +} + +ATF_TC_CLEANUP(mkfifo_err, tc) +{ + (void)unlink(path); +} + +ATF_TC_WITH_CLEANUP(mkfifo_nonblock); +ATF_TC_HEAD(mkfifo_nonblock, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test O_NONBLOCK with FIFOs"); +} + +ATF_TC_BODY(mkfifo_nonblock, tc) +{ + int fd, sta; + pid_t pid; + + support(); + + fd = -1; + ATF_REQUIRE(mkfifo(path, 0600) == 0); + + pid = fork(); + ATF_REQUIRE(pid >= 0); + + if (pid == 0) { + + /* + * If we open the FIFO as O_NONBLOCK, the O_RDONLY + * call should return immediately, whereas the call + * for write-only should fail with ENXIO. + */ + fd = open(path, O_RDONLY | O_NONBLOCK); + + if (fd >= 0) + _exit(EXIT_SUCCESS); + + (void)pause(); /* NOTREACHED */ + } + + (void)sleep(1); + + errno = 0; + ATF_REQUIRE_ERRNO(ENXIO, open(path, O_WRONLY | O_NONBLOCK) == -1); + + (void)kill(pid, SIGKILL); + (void)wait(&sta); + + if (WIFSIGNALED(sta) != 0 || WTERMSIG(sta) == SIGKILL) + atf_tc_fail("FIFO blocked for O_NONBLOCK open(2)"); + + (void)close(fd); + (void)unlink(path); +} + +ATF_TC_CLEANUP(mkfifo_nonblock, tc) +{ + (void)unlink(path); +} + +ATF_TC_WITH_CLEANUP(mkfifo_perm); +ATF_TC_HEAD(mkfifo_perm, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test permissions with mkfifo(2)"); + atf_tc_set_md_var(tc, "require.user", "unprivileged"); +} + +ATF_TC_BODY(mkfifo_perm, tc) +{ + + support(); + + errno = 0; + ATF_REQUIRE_ERRNO(EACCES, mkfifo("/root/fifo", 0600) == -1); + + ATF_REQUIRE(mkfifo(path, 0600) == 0); + + /* + * For some reason this fails with EFTYPE... + */ + errno = 0; + ATF_REQUIRE_ERRNO(EFTYPE, chmod(path, 1777) == -1); + + ATF_REQUIRE(unlink(path) == 0); +} + +ATF_TC_CLEANUP(mkfifo_perm, tc) +{ + (void)unlink(path); +} + +ATF_TC_WITH_CLEANUP(mkfifo_stat); +ATF_TC_HEAD(mkfifo_stat, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test mkfifo(2) with stat"); +} + +ATF_TC_BODY(mkfifo_stat, tc) +{ + struct stat st; + + support(); + + (void)memset(&st, 0, sizeof(struct stat)); + + ATF_REQUIRE(mkfifo(path, 0600) == 0); + ATF_REQUIRE(stat(path, &st) == 0); + + if (S_ISFIFO(st.st_mode) == 0) + atf_tc_fail("invalid mode from mkfifo(2)"); + + ATF_REQUIRE(unlink(path) == 0); +} + +ATF_TC_CLEANUP(mkfifo_stat, tc) +{ + (void)unlink(path); +} + +ATF_TP_ADD_TCS(tp) +{ + + ATF_TP_ADD_TC(tp, mkfifo_block); + ATF_TP_ADD_TC(tp, mkfifo_err); + ATF_TP_ADD_TC(tp, mkfifo_nonblock); + ATF_TP_ADD_TC(tp, mkfifo_perm); + ATF_TP_ADD_TC(tp, mkfifo_stat); + + return atf_no_error(); +} diff --git a/contrib/netbsd-tests/lib/libc/sys/t_mknod.c b/contrib/netbsd-tests/lib/libc/sys/t_mknod.c new file mode 100644 index 0000000..b394b31 --- /dev/null +++ b/contrib/netbsd-tests/lib/libc/sys/t_mknod.c @@ -0,0 +1,192 @@ +/* $NetBSD: t_mknod.c,v 1.2 2012/03/18 07:00:52 jruoho Exp $ */ + +/*- + * Copyright (c) 2011 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jukka Ruohonen. + * + * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ +#include <sys/cdefs.h> +__RCSID("$NetBSD: t_mknod.c,v 1.2 2012/03/18 07:00:52 jruoho Exp $"); + +#include <sys/stat.h> + +#include <atf-c.h> +#include <errno.h> +#include <fcntl.h> +#include <limits.h> +#include <paths.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> + +static char path[] = "node"; + +ATF_TC_WITH_CLEANUP(mknod_err); +ATF_TC_HEAD(mknod_err, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Test error conditions of mknod(2) (PR kern/45111)"); + atf_tc_set_md_var(tc, "require.user", "root"); +} + +ATF_TC_BODY(mknod_err, tc) +{ + char buf[PATH_MAX + 1]; + + (void)memset(buf, 'x', sizeof(buf)); + + errno = 0; + ATF_REQUIRE_ERRNO(EINVAL, mknod(path, S_IFCHR, -1) == -1); + + errno = 0; + ATF_REQUIRE_ERRNO(ENAMETOOLONG, mknod(buf, S_IFCHR, 0) == -1); + + errno = 0; + ATF_REQUIRE_ERRNO(EFAULT, mknod((char *)-1, S_IFCHR, 0) == -1); + + errno = 0; + ATF_REQUIRE_ERRNO(ENOENT, mknod("/a/b/c/d/e/f/g", S_IFCHR, 0) == -1); +} + +ATF_TC_CLEANUP(mknod_err, tc) +{ + (void)unlink(path); +} + +ATF_TC_WITH_CLEANUP(mknod_exist); +ATF_TC_HEAD(mknod_exist, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test EEXIST from mknod(2)"); + atf_tc_set_md_var(tc, "require.user", "root"); +} + +ATF_TC_BODY(mknod_exist, tc) +{ + int fd; + + fd = open("/etc/passwd", O_RDONLY); + + if (fd >= 0) { + + (void)close(fd); + + errno = 0; + ATF_REQUIRE_ERRNO(EEXIST, + mknod("/etc/passwd", S_IFCHR, 0) == -1); + } + + ATF_REQUIRE(mknod(path, S_IFCHR, 0) == 0); + + errno = 0; + ATF_REQUIRE_ERRNO(EEXIST, mknod(path, S_IFCHR, 0) == -1); + + ATF_REQUIRE(unlink(path) == 0); +} + +ATF_TC_CLEANUP(mknod_exist, tc) +{ + (void)unlink(path); +} + +ATF_TC_WITH_CLEANUP(mknod_perm); +ATF_TC_HEAD(mknod_perm, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test permissions of mknod(2)"); + atf_tc_set_md_var(tc, "require.user", "unprivileged"); +} + +ATF_TC_BODY(mknod_perm, tc) +{ + + errno = 0; + ATF_REQUIRE_ERRNO(EPERM, mknod(path, S_IFCHR, 0) == -1); + + errno = 0; + ATF_REQUIRE_ERRNO(EPERM, mknod(path, S_IFBLK, 0) == -1); +} + +ATF_TC_CLEANUP(mknod_perm, tc) +{ + (void)unlink(path); +} + +ATF_TC_WITH_CLEANUP(mknod_stat); +ATF_TC_HEAD(mknod_stat, tc) +{ + atf_tc_set_md_var(tc, "descr", "A basic test of mknod(2)"); + atf_tc_set_md_var(tc, "require.user", "root"); +} + +ATF_TC_BODY(mknod_stat, tc) +{ + struct stat st; + + (void)memset(&st, 0, sizeof(struct stat)); + + ATF_REQUIRE(mknod(path, S_IFCHR, 0) == 0); + ATF_REQUIRE(stat(path, &st) == 0); + + if (S_ISCHR(st.st_mode) == 0) + atf_tc_fail_nonfatal("invalid mode from mknod(2) (S_IFCHR)"); + + ATF_REQUIRE(unlink(path) == 0); + + (void)memset(&st, 0, sizeof(struct stat)); + + ATF_REQUIRE(mknod(path, S_IFBLK, 0) == 0); + ATF_REQUIRE(stat(path, &st) == 0); + + if (S_ISBLK(st.st_mode) == 0) + atf_tc_fail_nonfatal("invalid mode from mknod(2) (S_IFBLK)"); + + ATF_REQUIRE(unlink(path) == 0); + + (void)memset(&st, 0, sizeof(struct stat)); + + ATF_REQUIRE(mknod(path, S_IFREG, 0) == 0); + ATF_REQUIRE(stat(path, &st) == 0); + + if (S_ISREG(st.st_mode) == 0) + atf_tc_fail_nonfatal("invalid mode from mknod(2) (S_IFREG)"); + + ATF_REQUIRE(unlink(path) == 0); +} + +ATF_TC_CLEANUP(mknod_stat, tc) +{ + (void)unlink(path); +} + +ATF_TP_ADD_TCS(tp) +{ + + ATF_TP_ADD_TC(tp, mknod_err); + ATF_TP_ADD_TC(tp, mknod_exist); + ATF_TP_ADD_TC(tp, mknod_perm); + ATF_TP_ADD_TC(tp, mknod_stat); + + return atf_no_error(); +} diff --git a/contrib/netbsd-tests/lib/libc/sys/t_mlock.c b/contrib/netbsd-tests/lib/libc/sys/t_mlock.c new file mode 100644 index 0000000..52576f7 --- /dev/null +++ b/contrib/netbsd-tests/lib/libc/sys/t_mlock.c @@ -0,0 +1,244 @@ +/* $NetBSD: t_mlock.c,v 1.5 2014/02/26 20:49:26 martin Exp $ */ + +/*- + * Copyright (c) 2012 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jukka Ruohonen. + * + * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ +#include <sys/cdefs.h> +__RCSID("$NetBSD: t_mlock.c,v 1.5 2014/02/26 20:49:26 martin Exp $"); + +#include <sys/mman.h> +#include <sys/resource.h> +#include <sys/sysctl.h> +#include <sys/wait.h> + +#include <errno.h> +#include <atf-c.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +static long page = 0; + +ATF_TC(mlock_clip); +ATF_TC_HEAD(mlock_clip, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test with mlock(2) that UVM only " + "clips if the clip address is within the entry (PR kern/44788)"); +} + +ATF_TC_BODY(mlock_clip, tc) +{ + void *buf; + + buf = malloc(page); + ATF_REQUIRE(buf != NULL); + + if (page < 1024) + atf_tc_skip("page size too small"); + + for (size_t i = page; i >= 1; i = i - 1024) { + (void)mlock(buf, page - i); + (void)munlock(buf, page - i); + } + + free(buf); +} + +ATF_TC(mlock_err); +ATF_TC_HEAD(mlock_err, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Test error conditions in mlock(2) and munlock(2)"); +} + +ATF_TC_BODY(mlock_err, tc) +{ + unsigned long vmin = 0; + size_t len = sizeof(vmin); + void *invalid_ptr; + int null_errno = ENOMEM; /* error expected for NULL */ + + if (sysctlbyname("vm.minaddress", &vmin, &len, NULL, 0) != 0) + atf_tc_fail("failed to read vm.minaddress"); + + if (vmin > 0) + null_errno = EINVAL; /* NULL is not inside user VM */ + + errno = 0; + ATF_REQUIRE_ERRNO(null_errno, mlock(NULL, page) == -1); + + errno = 0; + ATF_REQUIRE_ERRNO(null_errno, mlock((char *)0, page) == -1); + + errno = 0; + ATF_REQUIRE_ERRNO(EINVAL, mlock((char *)-1, page) == -1); + + errno = 0; + ATF_REQUIRE_ERRNO(null_errno, munlock(NULL, page) == -1); + + errno = 0; + ATF_REQUIRE_ERRNO(null_errno, munlock((char *)0, page) == -1); + + errno = 0; + ATF_REQUIRE_ERRNO(EINVAL, munlock((char *)-1, page) == -1); + + /* + * Try to create a pointer to an unmapped page - first after current + * brk will likely do. + */ + invalid_ptr = (void*)(((uintptr_t)sbrk(0)+page) & ~(page-1)); + printf("testing with (hopefully) invalid pointer %p\n", invalid_ptr); + + errno = 0; + ATF_REQUIRE_ERRNO(ENOMEM, mlock(invalid_ptr, page) == -1); + + errno = 0; + ATF_REQUIRE_ERRNO(ENOMEM, munlock(invalid_ptr, page) == -1); +} + +ATF_TC(mlock_limits); +ATF_TC_HEAD(mlock_limits, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test system limits with mlock(2)"); +} + +ATF_TC_BODY(mlock_limits, tc) +{ + struct rlimit res; + void *buf; + pid_t pid; + int sta; + + buf = malloc(page); + ATF_REQUIRE(buf != NULL); + + pid = fork(); + ATF_REQUIRE(pid >= 0); + + if (pid == 0) { + + for (ssize_t i = page; i >= 2; i -= 100) { + + res.rlim_cur = i - 1; + res.rlim_max = i - 1; + + (void)fprintf(stderr, "trying to lock %zd bytes " + "with %zu byte limit\n", i, (size_t)res.rlim_cur); + + if (setrlimit(RLIMIT_MEMLOCK, &res) != 0) + _exit(EXIT_FAILURE); + + errno = 0; + + if (mlock(buf, i) != -1 || errno != EAGAIN) { + (void)munlock(buf, i); + _exit(EXIT_FAILURE); + } + } + + _exit(EXIT_SUCCESS); + } + + (void)wait(&sta); + + if (WIFEXITED(sta) == 0 || WEXITSTATUS(sta) != EXIT_SUCCESS) + atf_tc_fail("mlock(2) locked beyond system limits"); + + free(buf); +} + +ATF_TC(mlock_mmap); +ATF_TC_HEAD(mlock_mmap, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test mlock(2)-mmap(2) interaction"); +} + +ATF_TC_BODY(mlock_mmap, tc) +{ + static const int flags = MAP_ANON | MAP_PRIVATE | MAP_WIRED; + void *buf; + + /* + * Make a wired RW mapping and check that mlock(2) + * does not fail for the (already locked) mapping. + */ + buf = mmap(NULL, page, PROT_READ | PROT_WRITE, flags, -1, 0); + + ATF_REQUIRE(buf != MAP_FAILED); + ATF_REQUIRE(mlock(buf, page) == 0); + ATF_REQUIRE(munlock(buf, page) == 0); + ATF_REQUIRE(munmap(buf, page) == 0); + ATF_REQUIRE(munlock(buf, page) != 0); + + /* + * But it should be impossible to mlock(2) a PROT_NONE mapping. + */ + buf = mmap(NULL, page, PROT_NONE, flags, -1, 0); + + ATF_REQUIRE(buf != MAP_FAILED); + ATF_REQUIRE(mlock(buf, page) != 0); + ATF_REQUIRE(munmap(buf, page) == 0); +} + +ATF_TC(mlock_nested); +ATF_TC_HEAD(mlock_nested, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Test that consecutive mlock(2) calls succeed"); +} + +ATF_TC_BODY(mlock_nested, tc) +{ + const size_t maxiter = 100; + void *buf; + + buf = malloc(page); + ATF_REQUIRE(buf != NULL); + + for (size_t i = 0; i < maxiter; i++) + ATF_REQUIRE(mlock(buf, page) == 0); + + ATF_REQUIRE(munlock(buf, page) == 0); + free(buf); +} + +ATF_TP_ADD_TCS(tp) +{ + + page = sysconf(_SC_PAGESIZE); + ATF_REQUIRE(page >= 0); + + ATF_TP_ADD_TC(tp, mlock_clip); + ATF_TP_ADD_TC(tp, mlock_err); + ATF_TP_ADD_TC(tp, mlock_limits); + ATF_TP_ADD_TC(tp, mlock_mmap); + ATF_TP_ADD_TC(tp, mlock_nested); + + return atf_no_error(); +} diff --git a/contrib/netbsd-tests/lib/libc/sys/t_mmap.c b/contrib/netbsd-tests/lib/libc/sys/t_mmap.c new file mode 100644 index 0000000..c6b97b1 --- /dev/null +++ b/contrib/netbsd-tests/lib/libc/sys/t_mmap.c @@ -0,0 +1,505 @@ +/* $NetBSD: t_mmap.c,v 1.7 2012/06/14 17:47:58 bouyer Exp $ */ + +/*- + * Copyright (c) 2011 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jukka Ruohonen. + * + * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ + +/*- + * Copyright (c)2004 YAMAMOTO Takashi, + * 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. + */ +#include <sys/cdefs.h> +__RCSID("$NetBSD: t_mmap.c,v 1.7 2012/06/14 17:47:58 bouyer Exp $"); + +#include <sys/param.h> +#include <sys/mman.h> +#include <sys/socket.h> +#include <sys/sysctl.h> +#include <sys/wait.h> + +#include <atf-c.h> +#include <errno.h> +#include <fcntl.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <paths.h> +#include <machine/disklabel.h> + +static long page = 0; +static char path[] = "mmap"; +static void map_check(void *, int); +static void map_sighandler(int); +static void testloan(void *, void *, char, int); + +#define BUFSIZE (32 * 1024) /* enough size to trigger sosend_loan */ + +static void +map_check(void *map, int flag) +{ + + if (flag != 0) { + ATF_REQUIRE(map == MAP_FAILED); + return; + } + + ATF_REQUIRE(map != MAP_FAILED); + ATF_REQUIRE(munmap(map, page) == 0); +} + +void +testloan(void *vp, void *vp2, char pat, int docheck) +{ + char buf[BUFSIZE]; + char backup[BUFSIZE]; + ssize_t nwritten; + ssize_t nread; + int fds[2]; + int val; + + val = BUFSIZE; + + if (docheck != 0) + (void)memcpy(backup, vp, BUFSIZE); + + if (socketpair(AF_LOCAL, SOCK_STREAM, PF_UNSPEC, fds) != 0) + atf_tc_fail("socketpair() failed"); + + val = BUFSIZE; + + if (setsockopt(fds[1], SOL_SOCKET, SO_RCVBUF, &val, sizeof(val)) != 0) + atf_tc_fail("setsockopt() failed, SO_RCVBUF"); + + val = BUFSIZE; + + if (setsockopt(fds[0], SOL_SOCKET, SO_SNDBUF, &val, sizeof(val)) != 0) + atf_tc_fail("setsockopt() failed, SO_SNDBUF"); + + if (fcntl(fds[0], F_SETFL, O_NONBLOCK) != 0) + atf_tc_fail("fcntl() failed"); + + nwritten = write(fds[0], (char *)vp + page, BUFSIZE - page); + + if (nwritten == -1) + atf_tc_fail("write() failed"); + + /* Break loan. */ + (void)memset(vp2, pat, BUFSIZE); + + nread = read(fds[1], buf + page, BUFSIZE - page); + + if (nread == -1) + atf_tc_fail("read() failed"); + + if (nread != nwritten) + atf_tc_fail("too short read"); + + if (docheck != 0 && memcmp(backup, buf + page, nread) != 0) + atf_tc_fail("data mismatch"); + + ATF_REQUIRE(close(fds[0]) == 0); + ATF_REQUIRE(close(fds[1]) == 0); +} + +static void +map_sighandler(int signo) +{ + _exit(signo); +} + +ATF_TC(mmap_block); +ATF_TC_HEAD(mmap_block, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test mmap(2) with a block device"); + atf_tc_set_md_var(tc, "require.user", "root"); +} + +ATF_TC_BODY(mmap_block, tc) +{ + static const int mib[] = { CTL_HW, HW_DISKNAMES }; + static const unsigned int miblen = __arraycount(mib); + char *map, *dk, *drives, dev[PATH_MAX]; + size_t len; + int fd = -1; + + atf_tc_skip("The test case causes a panic (PR kern/38889, kern/46592)"); + + ATF_REQUIRE(sysctl(mib, miblen, NULL, &len, NULL, 0) == 0); + drives = malloc(len); + ATF_REQUIRE(drives != NULL); + ATF_REQUIRE(sysctl(mib, miblen, drives, &len, NULL, 0) == 0); + for (dk = strtok(drives, " "); dk != NULL; dk = strtok(NULL, " ")) { + sprintf(dev, _PATH_DEV "%s%c", dk, 'a'+RAW_PART); + fprintf(stderr, "trying: %s\n", dev); + + if ((fd = open(dev, O_RDONLY)) >= 0) { + (void)fprintf(stderr, "using %s\n", dev); + break; + } + } + free(drives); + + if (fd < 0) + atf_tc_skip("failed to find suitable block device"); + + map = mmap(NULL, 4096, PROT_READ, MAP_FILE, fd, 0); + ATF_REQUIRE(map != MAP_FAILED); + + (void)fprintf(stderr, "first byte %x\n", *map); + ATF_REQUIRE(close(fd) == 0); + (void)fprintf(stderr, "first byte %x\n", *map); + + ATF_REQUIRE(munmap(map, 4096) == 0); +} + +ATF_TC(mmap_err); +ATF_TC_HEAD(mmap_err, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test error conditions of mmap(2)"); +} + +ATF_TC_BODY(mmap_err, tc) +{ + size_t addr = SIZE_MAX; + void *map; + + errno = 0; + map = mmap(NULL, 3, PROT_READ, MAP_FILE|MAP_PRIVATE, -1, 0); + + ATF_REQUIRE(map == MAP_FAILED); + ATF_REQUIRE(errno == EBADF); + + errno = 0; + map = mmap(&addr, page, PROT_READ, MAP_FIXED|MAP_PRIVATE, -1, 0); + + ATF_REQUIRE(map == MAP_FAILED); + ATF_REQUIRE(errno == EINVAL); + + errno = 0; + map = mmap(NULL, page, PROT_READ, MAP_ANON|MAP_PRIVATE, INT_MAX, 0); + + ATF_REQUIRE(map == MAP_FAILED); + ATF_REQUIRE(errno == EINVAL); +} + +ATF_TC_WITH_CLEANUP(mmap_loan); +ATF_TC_HEAD(mmap_loan, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test uvm page loanout with mmap(2)"); +} + +ATF_TC_BODY(mmap_loan, tc) +{ + char buf[BUFSIZE]; + char *vp, *vp2; + int fd; + + fd = open(path, O_RDWR | O_CREAT, 0600); + ATF_REQUIRE(fd >= 0); + + (void)memset(buf, 'x', sizeof(buf)); + (void)write(fd, buf, sizeof(buf)); + + vp = mmap(NULL, BUFSIZE, PROT_READ | PROT_WRITE, + MAP_FILE | MAP_PRIVATE, fd, 0); + + ATF_REQUIRE(vp != MAP_FAILED); + + vp2 = vp; + + testloan(vp, vp2, 'A', 0); + testloan(vp, vp2, 'B', 1); + + ATF_REQUIRE(munmap(vp, BUFSIZE) == 0); + + vp = mmap(NULL, BUFSIZE, PROT_READ | PROT_WRITE, + MAP_FILE | MAP_SHARED, fd, 0); + + vp2 = mmap(NULL, BUFSIZE, PROT_READ | PROT_WRITE, + MAP_FILE | MAP_SHARED, fd, 0); + + ATF_REQUIRE(vp != MAP_FAILED); + ATF_REQUIRE(vp2 != MAP_FAILED); + + testloan(vp, vp2, 'E', 1); + + ATF_REQUIRE(munmap(vp, BUFSIZE) == 0); + ATF_REQUIRE(munmap(vp2, BUFSIZE) == 0); +} + +ATF_TC_CLEANUP(mmap_loan, tc) +{ + (void)unlink(path); +} + +ATF_TC_WITH_CLEANUP(mmap_prot_1); +ATF_TC_HEAD(mmap_prot_1, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test mmap(2) protections, #1"); +} + +ATF_TC_BODY(mmap_prot_1, tc) +{ + void *map; + int fd; + + /* + * Open a file write-only and try to + * map it read-only. This should fail. + */ + fd = open(path, O_WRONLY | O_CREAT, 0700); + + if (fd < 0) + return; + + ATF_REQUIRE(write(fd, "XXX", 3) == 3); + + map = mmap(NULL, 3, PROT_READ, MAP_FILE|MAP_PRIVATE, fd, 0); + map_check(map, 1); + + map = mmap(NULL, 3, PROT_WRITE, MAP_FILE|MAP_PRIVATE, fd, 0); + map_check(map, 0); + + ATF_REQUIRE(close(fd) == 0); +} + +ATF_TC_CLEANUP(mmap_prot_1, tc) +{ + (void)unlink(path); +} + +ATF_TC(mmap_prot_2); +ATF_TC_HEAD(mmap_prot_2, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test mmap(2) protections, #2"); +} + +ATF_TC_BODY(mmap_prot_2, tc) +{ + char buf[2]; + void *map; + pid_t pid; + int sta; + + /* + * Make a PROT_NONE mapping and try to access it. + * If we catch a SIGSEGV, all works as expected. + */ + map = mmap(NULL, page, PROT_NONE, MAP_ANON|MAP_PRIVATE, -1, 0); + ATF_REQUIRE(map != MAP_FAILED); + + pid = fork(); + ATF_REQUIRE(pid >= 0); + + if (pid == 0) { + ATF_REQUIRE(signal(SIGSEGV, map_sighandler) != SIG_ERR); + ATF_REQUIRE(strlcpy(buf, map, sizeof(buf)) != 0); + } + + (void)wait(&sta); + + ATF_REQUIRE(WIFEXITED(sta) != 0); + ATF_REQUIRE(WEXITSTATUS(sta) == SIGSEGV); + ATF_REQUIRE(munmap(map, page) == 0); +} + +ATF_TC_WITH_CLEANUP(mmap_prot_3); +ATF_TC_HEAD(mmap_prot_3, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test mmap(2) protections, #3"); +} + +ATF_TC_BODY(mmap_prot_3, tc) +{ + char buf[2]; + int fd, sta; + void *map; + pid_t pid; + + /* + * Open a file, change the permissions + * to read-only, and try to map it as + * PROT_NONE. This should succeed, but + * the access should generate SIGSEGV. + */ + fd = open(path, O_RDWR | O_CREAT, 0700); + + if (fd < 0) + return; + + ATF_REQUIRE(write(fd, "XXX", 3) == 3); + ATF_REQUIRE(close(fd) == 0); + ATF_REQUIRE(chmod(path, 0444) == 0); + + fd = open(path, O_RDONLY); + ATF_REQUIRE(fd != -1); + + map = mmap(NULL, 3, PROT_NONE, MAP_FILE | MAP_SHARED, fd, 0); + ATF_REQUIRE(map != MAP_FAILED); + + pid = fork(); + + ATF_REQUIRE(pid >= 0); + + if (pid == 0) { + ATF_REQUIRE(signal(SIGSEGV, map_sighandler) != SIG_ERR); + ATF_REQUIRE(strlcpy(buf, map, sizeof(buf)) != 0); + } + + (void)wait(&sta); + + ATF_REQUIRE(WIFEXITED(sta) != 0); + ATF_REQUIRE(WEXITSTATUS(sta) == SIGSEGV); + ATF_REQUIRE(munmap(map, 3) == 0); +} + +ATF_TC_CLEANUP(mmap_prot_3, tc) +{ + (void)unlink(path); +} + +ATF_TC_WITH_CLEANUP(mmap_truncate); +ATF_TC_HEAD(mmap_truncate, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test mmap(2) and ftruncate(2)"); +} + +ATF_TC_BODY(mmap_truncate, tc) +{ + char *map; + long i; + int fd; + + fd = open(path, O_RDWR | O_CREAT, 0700); + + if (fd < 0) + return; + + /* + * See that ftruncate(2) works + * while the file is mapped. + */ + ATF_REQUIRE(ftruncate(fd, page) == 0); + + map = mmap(NULL, page, PROT_READ | PROT_WRITE, MAP_FILE|MAP_PRIVATE, + fd, 0); + ATF_REQUIRE(map != MAP_FAILED); + + for (i = 0; i < page; i++) + map[i] = 'x'; + + ATF_REQUIRE(ftruncate(fd, 0) == 0); + ATF_REQUIRE(ftruncate(fd, page / 8) == 0); + ATF_REQUIRE(ftruncate(fd, page / 4) == 0); + ATF_REQUIRE(ftruncate(fd, page / 2) == 0); + ATF_REQUIRE(ftruncate(fd, page / 12) == 0); + ATF_REQUIRE(ftruncate(fd, page / 64) == 0); + + ATF_REQUIRE(close(fd) == 0); +} + +ATF_TC_CLEANUP(mmap_truncate, tc) +{ + (void)unlink(path); +} + +ATF_TC(mmap_va0); +ATF_TC_HEAD(mmap_va0, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test mmap(2) and vm.user_va0_disable"); +} + +ATF_TC_BODY(mmap_va0, tc) +{ + int flags = MAP_ANON | MAP_FIXED | MAP_PRIVATE; + size_t len = sizeof(int); + void *map; + int val; + + /* + * Make an anonymous fixed mapping at zero address. If the address + * is restricted as noted in security(7), the syscall should fail. + */ + if (sysctlbyname("vm.user_va0_disable", &val, &len, NULL, 0) != 0) + atf_tc_fail("failed to read vm.user_va0_disable"); + + map = mmap(NULL, page, PROT_EXEC, flags, -1, 0); + map_check(map, val); + + map = mmap(NULL, page, PROT_READ, flags, -1, 0); + map_check(map, val); + + map = mmap(NULL, page, PROT_WRITE, flags, -1, 0); + map_check(map, val); + + map = mmap(NULL, page, PROT_READ|PROT_WRITE, flags, -1, 0); + map_check(map, val); + + map = mmap(NULL, page, PROT_EXEC|PROT_READ|PROT_WRITE, flags, -1, 0); + map_check(map, val); +} + +ATF_TP_ADD_TCS(tp) +{ + page = sysconf(_SC_PAGESIZE); + ATF_REQUIRE(page >= 0); + + ATF_TP_ADD_TC(tp, mmap_block); + ATF_TP_ADD_TC(tp, mmap_err); + ATF_TP_ADD_TC(tp, mmap_loan); + ATF_TP_ADD_TC(tp, mmap_prot_1); + ATF_TP_ADD_TC(tp, mmap_prot_2); + ATF_TP_ADD_TC(tp, mmap_prot_3); + ATF_TP_ADD_TC(tp, mmap_truncate); + ATF_TP_ADD_TC(tp, mmap_va0); + + return atf_no_error(); +} diff --git a/contrib/netbsd-tests/lib/libc/sys/t_mprotect.c b/contrib/netbsd-tests/lib/libc/sys/t_mprotect.c new file mode 100644 index 0000000..c534e11 --- /dev/null +++ b/contrib/netbsd-tests/lib/libc/sys/t_mprotect.c @@ -0,0 +1,359 @@ +/* $NetBSD: t_mprotect.c,v 1.3 2011/07/20 22:53:44 jym Exp $ */ + +/*- + * Copyright (c) 2011 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jukka Ruohonen. + * + * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ +#include <sys/cdefs.h> +__RCSID("$NetBSD: t_mprotect.c,v 1.3 2011/07/20 22:53:44 jym Exp $"); + +#include <sys/param.h> +#include <sys/mman.h> +#include <sys/sysctl.h> +#include <sys/wait.h> + +#include <errno.h> +#include <fcntl.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include <atf-c.h> + +#include "../common/exec_prot.h" + +static long page = 0; +static int pax_global = -1; +static int pax_enabled = -1; +static char path[] = "mmap"; + +static void sighandler(int); +static bool paxinit(void); +static bool paxset(int, int); + +static void +sighandler(int signo) +{ + _exit(signo); +} + +static bool +paxinit(void) +{ + size_t len = sizeof(int); + int rv; + + rv = sysctlbyname("security.pax.mprotect.global", + &pax_global, &len, NULL, 0); + + if (rv != 0) + return false; + + rv = sysctlbyname("security.pax.mprotect.enabled", + &pax_enabled, &len, NULL, 0); + + if (rv != 0) + return false; + + return paxset(1, 1); +} + +static bool +paxset(int global, int enabled) +{ + size_t len = sizeof(int); + int rv; + + rv = sysctlbyname("security.pax.mprotect.global", + NULL, NULL, &global, len); + + if (rv != 0) + return false; + + rv = sysctlbyname("security.pax.mprotect.enabled", + NULL, NULL, &enabled, len); + + if (rv != 0) + return false; + + return true; +} + + +ATF_TC_WITH_CLEANUP(mprotect_access); +ATF_TC_HEAD(mprotect_access, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test for EACCES from mprotect(2)"); +} + +ATF_TC_BODY(mprotect_access, tc) +{ + int prot[2] = { PROT_NONE, PROT_READ }; + void *map; + size_t i; + int fd; + + fd = open(path, O_RDONLY | O_CREAT); + ATF_REQUIRE(fd >= 0); + + /* + * The call should fail with EACCES if we try to mark + * a PROT_NONE or PROT_READ file/section as PROT_WRITE. + */ + for (i = 0; i < __arraycount(prot); i++) { + + map = mmap(NULL, page, prot[i], MAP_SHARED, fd, 0); + + if (map == MAP_FAILED) + continue; + + errno = 0; + + ATF_REQUIRE(mprotect(map, page, PROT_WRITE) != 0); + ATF_REQUIRE(errno == EACCES); + ATF_REQUIRE(munmap(map, page) == 0); + } + + ATF_REQUIRE(close(fd) == 0); +} + +ATF_TC_CLEANUP(mprotect_access, tc) +{ + (void)unlink(path); +} + +ATF_TC(mprotect_err); +ATF_TC_HEAD(mprotect_err, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test error conditions of mprotect(2)"); +} + +ATF_TC_BODY(mprotect_err, tc) +{ + errno = 0; + + ATF_REQUIRE(mprotect((char *)-1, 1, PROT_READ) != 0); + ATF_REQUIRE(errno == EINVAL); +} + +ATF_TC(mprotect_exec); +ATF_TC_HEAD(mprotect_exec, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Test mprotect(2) executable space protections"); +} + +/* + * Trivial function -- should fit into a page + */ +ATF_TC_BODY(mprotect_exec, tc) +{ + pid_t pid; + void *map; + int sta, xp_support; + + xp_support = exec_prot_support(); + + switch (xp_support) { + case NOTIMPL: + atf_tc_skip( + "Execute protection callback check not implemented"); + break; + case NO_XP: + atf_tc_skip( + "Host does not support executable space protection"); + break; + case PARTIAL_XP: case PERPAGE_XP: default: + break; + } + + /* + * Map a page read/write and copy a trivial assembly function inside. + * We will then change the mapping rights: + * - first by setting the execution right, and check that we can + * call the code found in the allocated page. + * - second by removing the execution right. This should generate + * a SIGSEGV on architectures that can enforce --x permissions. + */ + + map = mmap(NULL, page, PROT_WRITE|PROT_READ, MAP_ANON, -1, 0); + ATF_REQUIRE(map != MAP_FAILED); + + memcpy(map, (void *)return_one, + (uintptr_t)return_one_end - (uintptr_t)return_one); + + /* give r-x rights then call code in page */ + ATF_REQUIRE(mprotect(map, page, PROT_EXEC|PROT_READ) == 0); + ATF_REQUIRE(((int (*)(void))map)() == 1); + + /* remove --x right */ + ATF_REQUIRE(mprotect(map, page, PROT_READ) == 0); + + pid = fork(); + ATF_REQUIRE(pid >= 0); + + if (pid == 0) { + ATF_REQUIRE(signal(SIGSEGV, sighandler) != SIG_ERR); + ATF_CHECK(((int (*)(void))map)() == 1); + _exit(0); + } + + (void)wait(&sta); + + ATF_REQUIRE(munmap(map, page) == 0); + + ATF_REQUIRE(WIFEXITED(sta) != 0); + + switch (xp_support) { + case PARTIAL_XP: + /* Partial protection might fail; skip the test when it does */ + if (WEXITSTATUS(sta) != SIGSEGV) { + atf_tc_skip("Host only supports " + "partial executable space protection"); + } + break; + case PERPAGE_XP: default: + /* Per-page --x protection should not fail */ + ATF_REQUIRE(WEXITSTATUS(sta) == SIGSEGV); + break; + } +} + +ATF_TC(mprotect_pax); +ATF_TC_HEAD(mprotect_pax, tc) +{ + atf_tc_set_md_var(tc, "descr", "PaX restrictions and mprotect(2)"); + atf_tc_set_md_var(tc, "require.user", "root"); +} + +ATF_TC_BODY(mprotect_pax, tc) +{ + const int prot[4] = { PROT_NONE, PROT_READ, PROT_WRITE }; + const char *str = NULL; + void *map; + size_t i; + int rv; + + if (paxinit() != true) + return; + + /* + * As noted in the original PaX documentation [1], + * the following restrictions should apply: + * + * (1) creating executable anonymous mappings + * + * (2) creating executable/writable file mappings + * + * (3) making a non-executable mapping executable + * + * (4) making an executable/read-only file mapping + * writable except for performing relocations + * on an ET_DYN ELF file (non-PIC shared library) + * + * The following will test only the case (3). + * + * [1] http://pax.grsecurity.net/docs/mprotect.txt + * + * (Sun Apr 3 11:06:53 EEST 2011.) + */ + for (i = 0; i < __arraycount(prot); i++) { + + map = mmap(NULL, page, prot[i], MAP_ANON, -1, 0); + + if (map == MAP_FAILED) + continue; + + rv = mprotect(map, 1, prot[i] | PROT_EXEC); + + (void)munmap(map, page); + + if (rv == 0) { + str = "non-executable mapping made executable"; + goto out; + } + } + +out: + if (pax_global != -1 && pax_enabled != -1) + (void)paxset(pax_global, pax_enabled); + + if (str != NULL) + atf_tc_fail("%s", str); +} + +ATF_TC(mprotect_write); +ATF_TC_HEAD(mprotect_write, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test mprotect(2) write protections"); +} + +ATF_TC_BODY(mprotect_write, tc) +{ + pid_t pid; + void *map; + int sta; + + /* + * Map a page read/write, change the protection + * to read-only with mprotect(2), and try to write + * to the page. This should generate a SIGSEGV. + */ + map = mmap(NULL, page, PROT_WRITE|PROT_READ, MAP_ANON, -1, 0); + ATF_REQUIRE(map != MAP_FAILED); + + ATF_REQUIRE(strlcpy(map, "XXX", 3) == 3); + ATF_REQUIRE(mprotect(map, page, PROT_READ) == 0); + + pid = fork(); + ATF_REQUIRE(pid >= 0); + + if (pid == 0) { + ATF_REQUIRE(signal(SIGSEGV, sighandler) != SIG_ERR); + ATF_REQUIRE(strlcpy(map, "XXX", 3) == 0); + } + + (void)wait(&sta); + + ATF_REQUIRE(WIFEXITED(sta) != 0); + ATF_REQUIRE(WEXITSTATUS(sta) == SIGSEGV); + ATF_REQUIRE(munmap(map, page) == 0); +} + +ATF_TP_ADD_TCS(tp) +{ + page = sysconf(_SC_PAGESIZE); + ATF_REQUIRE(page >= 0); + + ATF_TP_ADD_TC(tp, mprotect_access); + ATF_TP_ADD_TC(tp, mprotect_err); + ATF_TP_ADD_TC(tp, mprotect_exec); + ATF_TP_ADD_TC(tp, mprotect_pax); + ATF_TP_ADD_TC(tp, mprotect_write); + + return atf_no_error(); +} diff --git a/contrib/netbsd-tests/lib/libc/sys/t_msgctl.c b/contrib/netbsd-tests/lib/libc/sys/t_msgctl.c new file mode 100644 index 0000000..1e74d60 --- /dev/null +++ b/contrib/netbsd-tests/lib/libc/sys/t_msgctl.c @@ -0,0 +1,358 @@ +/* $NetBSD: t_msgctl.c,v 1.4 2014/02/27 00:59:50 joerg Exp $ */ + +/*- + * Copyright (c) 2011 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jukka Ruohonen. + * + * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ +#include <sys/cdefs.h> +__RCSID("$NetBSD: t_msgctl.c,v 1.4 2014/02/27 00:59:50 joerg Exp $"); + +#include <sys/msg.h> +#include <sys/stat.h> +#include <sys/sysctl.h> +#include <sys/wait.h> + +#include <atf-c.h> +#include <errno.h> +#include <pwd.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sysexits.h> +#include <time.h> +#include <unistd.h> + +#define MSG_KEY 12345689 +#define MSG_MTYPE_1 0x41 + +struct msg { + long mtype; + char buf[3]; +}; + +static void clean(void); + +static void +clean(void) +{ + int id; + + if ((id = msgget(MSG_KEY, 0)) != -1) + (void)msgctl(id, IPC_RMID, 0); +} + +ATF_TC_WITH_CLEANUP(msgctl_err); +ATF_TC_HEAD(msgctl_err, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test errors from msgctl(2)"); +} + +ATF_TC_BODY(msgctl_err, tc) +{ + const int cmd[] = { IPC_STAT, IPC_SET, IPC_RMID }; + struct msqid_ds msgds; + size_t i; + int id; + + (void)memset(&msgds, 0, sizeof(struct msqid_ds)); + + id = msgget(MSG_KEY, IPC_CREAT | 0600); + ATF_REQUIRE(id != -1); + + errno = 0; + ATF_REQUIRE_ERRNO(EINVAL, msgctl(id, INT_MAX, &msgds) == -1); + + errno = 0; + ATF_REQUIRE_ERRNO(EFAULT, msgctl(id, IPC_STAT, (void *)-1) == -1); + + for (i = 0; i < __arraycount(cmd); i++) { + errno = 0; + ATF_REQUIRE_ERRNO(EINVAL, msgctl(-1, cmd[i], &msgds) == -1); + } + + ATF_REQUIRE(msgctl(id, IPC_RMID, 0) == 0); +} + +ATF_TC_CLEANUP(msgctl_err, tc) +{ + clean(); +} + +ATF_TC_WITH_CLEANUP(msgctl_perm); +ATF_TC_HEAD(msgctl_perm, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test permissions with msgctl(2)"); + atf_tc_set_md_var(tc, "require.user", "root"); +} + +ATF_TC_BODY(msgctl_perm, tc) +{ + struct msqid_ds msgds; + struct passwd *pw; + pid_t pid; + int sta; + int id; + + (void)memset(&msgds, 0, sizeof(struct msqid_ds)); + + pw = getpwnam("nobody"); + id = msgget(MSG_KEY, IPC_CREAT | 0600); + + ATF_REQUIRE(id != -1); + ATF_REQUIRE(pw != NULL); + ATF_REQUIRE(msgctl(id, IPC_STAT, &msgds) == 0); + + pid = fork(); + ATF_REQUIRE(pid >= 0); + + if (pid == 0) { + + if (setuid(pw->pw_uid) != 0) + _exit(EX_OSERR); + + msgds.msg_perm.uid = getuid(); + msgds.msg_perm.gid = getgid(); + + errno = 0; + + if (msgctl(id, IPC_SET, &msgds) == 0) + _exit(EXIT_FAILURE); + + if (errno != EPERM) + _exit(EXIT_FAILURE); + + (void)memset(&msgds, 0, sizeof(struct msqid_ds)); + + if (msgctl(id, IPC_STAT, &msgds) != 0) + _exit(EX_OSERR); + + msgds.msg_qbytes = 1; + + if (msgctl(id, IPC_SET, &msgds) == 0) + _exit(EXIT_FAILURE); + + if (errno != EPERM) + _exit(EXIT_FAILURE); + + _exit(EXIT_SUCCESS); + } + + (void)wait(&sta); + + if (WIFEXITED(sta) == 0) { + + if (WEXITSTATUS(sta) == EX_OSERR) + atf_tc_fail("system call failed"); + + if (WEXITSTATUS(sta) == EXIT_FAILURE) + atf_tc_fail("UID %u manipulated root's " + "message queue", pw->pw_uid); + } + + ATF_REQUIRE(msgctl(id, IPC_RMID, 0) == 0); +} + +ATF_TC_CLEANUP(msgctl_perm, tc) +{ + clean(); +} + +ATF_TC_WITH_CLEANUP(msgctl_pid); +ATF_TC_HEAD(msgctl_pid, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test that PIDs are updated"); +} + +ATF_TC_BODY(msgctl_pid, tc) +{ + struct msg msg = { MSG_MTYPE_1, { 'a', 'b', 'c' } }; + struct msqid_ds msgds; + int id, sta; + pid_t pid; + + id = msgget(MSG_KEY, IPC_CREAT | 0600); + ATF_REQUIRE(id != -1); + + pid = fork(); + ATF_REQUIRE(pid >= 0); + + if (pid == 0) { + + (void)msgsnd(id, &msg, sizeof(struct msg), IPC_NOWAIT); + + _exit(EXIT_SUCCESS); + } + + (void)sleep(1); + (void)wait(&sta); + (void)memset(&msgds, 0, sizeof(struct msqid_ds)); + + ATF_REQUIRE(msgctl(id, IPC_STAT, &msgds) == 0); + + if (pid != msgds.msg_lspid) + atf_tc_fail("the PID of last msgsnd(2) was not updated"); + + pid = fork(); + ATF_REQUIRE(pid >= 0); + + if (pid == 0) { + + (void)msgrcv(id, &msg, + sizeof(struct msg), MSG_MTYPE_1, IPC_NOWAIT); + + _exit(EXIT_SUCCESS); + } + + (void)sleep(1); + (void)wait(&sta); + (void)memset(&msgds, 0, sizeof(struct msqid_ds)); + + ATF_REQUIRE(msgctl(id, IPC_STAT, &msgds) == 0); + + if (pid != msgds.msg_lrpid) + atf_tc_fail("the PID of last msgrcv(2) was not updated"); + + ATF_REQUIRE(msgctl(id, IPC_RMID, 0) == 0); +} + +ATF_TC_CLEANUP(msgctl_pid, tc) +{ + clean(); +} + +ATF_TC_WITH_CLEANUP(msgctl_set); +ATF_TC_HEAD(msgctl_set, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test msgctl(2) with IPC_SET"); + atf_tc_set_md_var(tc, "require.user", "root"); +} + +ATF_TC_BODY(msgctl_set, tc) +{ + struct msqid_ds msgds; + struct passwd *pw; + int id; + + (void)memset(&msgds, 0, sizeof(struct msqid_ds)); + + pw = getpwnam("nobody"); + id = msgget(MSG_KEY, IPC_CREAT | 0600); + + ATF_REQUIRE(id != -1); + ATF_REQUIRE(pw != NULL); + ATF_REQUIRE(msgctl(id, IPC_STAT, &msgds) == 0); + + msgds.msg_perm.uid = pw->pw_uid; + + if (msgctl(id, IPC_SET, &msgds) != 0) + atf_tc_fail("root failed to change the UID of message queue"); + + msgds.msg_perm.uid = getuid(); + msgds.msg_perm.gid = pw->pw_gid; + + if (msgctl(id, IPC_SET, &msgds) != 0) + atf_tc_fail("root failed to change the GID of message queue"); + + /* + * Note: setting the qbytes to zero fails even as root. + */ + msgds.msg_qbytes = 1; + msgds.msg_perm.gid = getgid(); + + if (msgctl(id, IPC_SET, &msgds) != 0) + atf_tc_fail("root failed to change qbytes of message queue"); + + ATF_REQUIRE(msgctl(id, IPC_RMID, 0) == 0); +} + +ATF_TC_CLEANUP(msgctl_set, tc) +{ + clean(); +} + +ATF_TC_WITH_CLEANUP(msgctl_time); +ATF_TC_HEAD(msgctl_time, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test that access times are updated"); +} + +ATF_TC_BODY(msgctl_time, tc) +{ + struct msg msg = { MSG_MTYPE_1, { 'a', 'b', 'c' } }; + struct msqid_ds msgds; + time_t t; + int id; + + id = msgget(MSG_KEY, IPC_CREAT | 0600); + ATF_REQUIRE(id != -1); + + t = time(NULL); + + (void)memset(&msgds, 0, sizeof(struct msqid_ds)); + (void)msgsnd(id, &msg, sizeof(struct msg), IPC_NOWAIT); + (void)msgctl(id, IPC_STAT, &msgds); + + if (llabs(t - msgds.msg_stime) > 1) + atf_tc_fail("time of last msgsnd(2) was not updated"); + + if (msgds.msg_rtime != 0) + atf_tc_fail("time of last msgrcv(2) was updated incorrectly"); + + t = time(NULL); + + (void)memset(&msgds, 0, sizeof(struct msqid_ds)); + (void)msgrcv(id, &msg, sizeof(struct msg), MSG_MTYPE_1, IPC_NOWAIT); + (void)msgctl(id, IPC_STAT, &msgds); + + if (llabs(t - msgds.msg_rtime) > 1) + atf_tc_fail("time of last msgrcv(2) was not updated"); + + /* + * Note: this is non-zero even after the memset(3). + */ + if (msgds.msg_stime == 0) + atf_tc_fail("time of last msgsnd(2) was updated incorrectly"); + + ATF_REQUIRE(msgctl(id, IPC_RMID, 0) == 0); +} + +ATF_TC_CLEANUP(msgctl_time, tc) +{ + clean(); +} + +ATF_TP_ADD_TCS(tp) +{ + + ATF_TP_ADD_TC(tp, msgctl_err); + ATF_TP_ADD_TC(tp, msgctl_perm); + ATF_TP_ADD_TC(tp, msgctl_pid); + ATF_TP_ADD_TC(tp, msgctl_set); + ATF_TP_ADD_TC(tp, msgctl_time); + + return atf_no_error(); +} diff --git a/contrib/netbsd-tests/lib/libc/sys/t_msgget.c b/contrib/netbsd-tests/lib/libc/sys/t_msgget.c new file mode 100644 index 0000000..e26cde2 --- /dev/null +++ b/contrib/netbsd-tests/lib/libc/sys/t_msgget.c @@ -0,0 +1,292 @@ +/* $NetBSD: t_msgget.c,v 1.2 2014/02/27 00:59:50 joerg Exp $ */ + +/*- + * Copyright (c) 2011 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jukka Ruohonen. + * + * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ +#include <sys/cdefs.h> +__RCSID("$NetBSD: t_msgget.c,v 1.2 2014/02/27 00:59:50 joerg Exp $"); + +#include <sys/msg.h> +#include <sys/stat.h> +#include <sys/sysctl.h> +#include <sys/wait.h> + +#include <atf-c.h> +#include <errno.h> +#include <pwd.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sysexits.h> +#include <time.h> +#include <unistd.h> + +#define MSG_KEY 12345689 + +static void clean(void); + +static void +clean(void) +{ + int id; + + if ((id = msgget(MSG_KEY, 0)) != -1) + (void)msgctl(id, IPC_RMID, 0); +} + +ATF_TC_WITH_CLEANUP(msgget_excl); +ATF_TC_HEAD(msgget_excl, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test msgget(2) with IPC_EXCL"); +} + +ATF_TC_BODY(msgget_excl, tc) +{ + int id; + + /* + * Create a message queue and re-open it with + * O_CREAT and IPC_EXCL set. This should fail. + */ + id = msgget(MSG_KEY, IPC_CREAT | 0600); + + if (id < 0) + atf_tc_fail("failed to create message queue"); + + errno = 0; + + if (msgget(MSG_KEY, IPC_CREAT | IPC_EXCL | 0600) != -1) + atf_tc_fail("msgget(2) failed for IPC_EXCL"); + + ATF_REQUIRE(errno == EEXIST); + + /* + * However, the same call should succeed + * when IPC_EXCL is not set in the flags. + */ + id = msgget(MSG_KEY, IPC_CREAT | 0600); + + if (id < 0) + atf_tc_fail("msgget(2) failed to re-open"); + + ATF_REQUIRE(msgctl(id, IPC_RMID, 0) == 0); +} + +ATF_TC_CLEANUP(msgget_excl, tc) +{ + clean(); +} + +ATF_TC_WITH_CLEANUP(msgget_exit); +ATF_TC_HEAD(msgget_exit, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Test that XSI message queues are " + "not removed when the process exits"); +} + +ATF_TC_BODY(msgget_exit, tc) +{ + int id, sta; + pid_t pid; + + pid = fork(); + ATF_REQUIRE(pid >= 0); + + if (pid == 0) { + + if (msgget(MSG_KEY, IPC_CREAT | IPC_EXCL | 0600) == -1) + _exit(EXIT_FAILURE); + + _exit(EXIT_SUCCESS); + } + + (void)wait(&sta); + + if (WIFEXITED(sta) == 0 || WEXITSTATUS(sta) != EXIT_SUCCESS) + atf_tc_fail("failed to create message queue"); + + id = msgget(MSG_KEY, 0); + + if (id == -1) + atf_tc_fail("message queue was removed on process exit"); + + ATF_REQUIRE(msgctl(id, IPC_RMID, 0) == 0); +} + +ATF_TC_CLEANUP(msgget_exit, tc) +{ + clean(); +} + +ATF_TC_WITH_CLEANUP(msgget_init); +ATF_TC_HEAD(msgget_init, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Test that msgget(2) initializes data structures properly"); +} + +ATF_TC_BODY(msgget_init, tc) +{ + const uid_t uid = geteuid(); + const gid_t gid = getegid(); + struct msqid_ds msgds; + time_t t; + int id; + + (void)memset(&msgds, 0x9, sizeof(struct msqid_ds)); + + t = time(NULL); + id = msgget(MSG_KEY, IPC_CREAT | 0600); + + ATF_REQUIRE(id !=-1); + ATF_REQUIRE(msgctl(id, IPC_STAT, &msgds) == 0); + + ATF_CHECK(msgds.msg_qnum == 0); + ATF_CHECK(msgds.msg_lspid == 0); + ATF_CHECK(msgds.msg_lrpid == 0); + ATF_CHECK(msgds.msg_rtime == 0); + ATF_CHECK(msgds.msg_stime == 0); + ATF_CHECK(msgds.msg_perm.uid == uid); + ATF_CHECK(msgds.msg_perm.gid == gid); + ATF_CHECK(msgds.msg_perm.cuid == uid); + ATF_CHECK(msgds.msg_perm.cgid == gid); + ATF_CHECK(msgds.msg_perm.mode == 0600); + + if (llabs(t - msgds.msg_ctime) > 5) + atf_tc_fail("msgget(2) initialized current time incorrectly"); + + ATF_REQUIRE(msgctl(id, IPC_RMID, 0) == 0); +} + +ATF_TC_CLEANUP(msgget_init, tc) +{ + clean(); +} + +ATF_TC(msgget_limit); +ATF_TC_HEAD(msgget_limit, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test msgget(2) against system limits"); +} + +ATF_TC_BODY(msgget_limit, tc) +{ + size_t len = sizeof(int); + bool fail = false; + int i, lim = 0; + int *buf; + + if (sysctlbyname("kern.ipc.msgmni", &lim, &len, NULL, 0) != 0) + atf_tc_skip("failed to read kern.ipc.msgmni sysctl"); + + buf = calloc(lim + 1, sizeof(*buf)); + ATF_REQUIRE(buf != NULL); + + for (i = 0; i < lim; i++) { + + buf[i] = msgget(MSG_KEY + i, IPC_CREAT | IPC_EXCL | 0600); + + (void)fprintf(stderr, "key[%d] = %d\n", i, buf[i]); + + /* + * This test only works when there are zero existing + * message queues. Thus, bypass the unit test when + * this precondition is not met, for reason or another. + */ + if (buf[i] == -1) + goto out; + } + + i++; + errno = 0; + + buf[i] = msgget(MSG_KEY + i, IPC_CREAT | IPC_EXCL | 0600); + + if (buf[i] != -1 || errno != ENOSPC) + fail = true; + +out: /* Remember to clean-up. */ + for (i = 0; i < lim; i++) + (void)msgctl(buf[i], IPC_RMID, 0); + + free(buf); + + if (fail != false) + atf_tc_fail("msgget(2) opened more than %d queues", lim); +} + +ATF_TC_WITH_CLEANUP(msgget_mode); +ATF_TC_HEAD(msgget_mode, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test different modes with msgget(2)"); + atf_tc_set_md_var(tc, "require.user", "root"); +} + +ATF_TC_BODY(msgget_mode, tc) +{ + static const mode_t mode[] = { + S_IRWXU, S_IRUSR, S_IWUSR, S_IXUSR, S_IRWXG, S_IRGRP, + S_IWGRP, S_IXGRP, S_IRWXO, S_IROTH, S_IWOTH, S_IXOTH + }; + + struct msqid_ds msgds; + size_t i; + int id; + + for (i = 0; i < __arraycount(mode); i++) { + + (void)fprintf(stderr, "testing mode %d\n", mode[i]); + (void)memset(&msgds, 0, sizeof(struct msqid_ds)); + + id = msgget(MSG_KEY, IPC_CREAT | IPC_EXCL | (int)mode[i]); + + ATF_REQUIRE(id != -1); + ATF_REQUIRE(msgctl(id, IPC_STAT, &msgds) == 0); + ATF_REQUIRE(msgds.msg_perm.mode == mode[i]); + ATF_REQUIRE(msgctl(id, IPC_RMID, 0) == 0); + } +} + +ATF_TC_CLEANUP(msgget_mode, tc) +{ + clean(); +} + + +ATF_TP_ADD_TCS(tp) +{ + + ATF_TP_ADD_TC(tp, msgget_excl); + ATF_TP_ADD_TC(tp, msgget_exit); + ATF_TP_ADD_TC(tp, msgget_init); + ATF_TP_ADD_TC(tp, msgget_limit); + ATF_TP_ADD_TC(tp, msgget_mode); + + return atf_no_error(); +} diff --git a/contrib/netbsd-tests/lib/libc/sys/t_msgrcv.c b/contrib/netbsd-tests/lib/libc/sys/t_msgrcv.c new file mode 100644 index 0000000..e32be26 --- /dev/null +++ b/contrib/netbsd-tests/lib/libc/sys/t_msgrcv.c @@ -0,0 +1,342 @@ +/* $NetBSD: t_msgrcv.c,v 1.3 2013/07/24 11:44:10 skrll Exp $ */ + +/*- + * Copyright (c) 2011 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jukka Ruohonen. + * + * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ +#include <sys/cdefs.h> +__RCSID("$NetBSD: t_msgrcv.c,v 1.3 2013/07/24 11:44:10 skrll Exp $"); + +#include <sys/msg.h> +#include <sys/stat.h> +#include <sys/sysctl.h> +#include <sys/wait.h> + +#include <atf-c.h> +#include <errno.h> +#include <pwd.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sysexits.h> +#include <time.h> +#include <unistd.h> + +#define MSG_KEY 1234 +#define MSG_MTYPE_1 0x41 +#define MSG_MTYPE_2 0x42 +#define MSG_MTYPE_3 0x43 +#define MSG_LEN 3 + +struct msg { + long mtype; + char buf[MSG_LEN]; +}; + +static void clean(void); + +static void +clean(void) +{ + int id; + + if ((id = msgget(MSG_KEY, 0)) != -1) + (void)msgctl(id, IPC_RMID, 0); +} + +ATF_TC_WITH_CLEANUP(msgrcv_basic); +ATF_TC_HEAD(msgrcv_basic, tc) +{ + atf_tc_set_md_var(tc, "descr", "A basic test of msgrcv(2)"); +} + +ATF_TC_BODY(msgrcv_basic, tc) +{ + struct msg msg1 = { MSG_MTYPE_1, { 'a', 'b', 'c' } }; + struct msg msg2 = { MSG_MTYPE_1, { 'x', 'y', 'z' } }; + int id; + + id = msgget(MSG_KEY, IPC_CREAT | 0600); + ATF_REQUIRE(id != -1); + + (void)msgsnd(id, &msg1, MSG_LEN, IPC_NOWAIT); + (void)msgrcv(id, &msg2, MSG_LEN, MSG_MTYPE_1, IPC_NOWAIT); + + ATF_CHECK(msg1.buf[0] == msg2.buf[0]); + ATF_CHECK(msg1.buf[1] == msg2.buf[1]); + ATF_CHECK(msg1.buf[2] == msg2.buf[2]); + + ATF_REQUIRE(msgctl(id, IPC_RMID, 0) == 0); +} + +ATF_TC_CLEANUP(msgrcv_basic, tc) +{ + clean(); +} + +ATF_TC_WITH_CLEANUP(msgrcv_block); +ATF_TC_HEAD(msgrcv_block, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test that msgrcv(2) blocks"); +} + +ATF_TC_BODY(msgrcv_block, tc) +{ + struct msg msg = { MSG_MTYPE_1, { 'a', 'b', 'c' } }; + int id, sta; + pid_t pid; + + id = msgget(MSG_KEY, IPC_CREAT | 0600); + ATF_REQUIRE(id != -1); + + pid = fork(); + ATF_REQUIRE(pid >= 0); + + if (pid == 0) { + + if (msgrcv(id, &msg, MSG_LEN, MSG_MTYPE_1, 0) < 0) + _exit(EXIT_FAILURE); + + _exit(EXIT_SUCCESS); + } + + /* + * Below msgsnd(2) should unblock the child, + * and hence kill(2) should fail with ESRCH. + */ + (void)sleep(1); + (void)msgsnd(id, &msg, MSG_LEN, IPC_NOWAIT); + (void)sleep(1); + (void)kill(pid, SIGKILL); + (void)wait(&sta); + + if (WIFEXITED(sta) == 0 || WIFSIGNALED(sta) != 0) + atf_tc_fail("msgrcv(2) did not block"); + + ATF_REQUIRE(msgctl(id, IPC_RMID, 0) == 0); +} + +ATF_TC_CLEANUP(msgrcv_block, tc) +{ + clean(); +} + +ATF_TC_WITH_CLEANUP(msgrcv_err); +ATF_TC_HEAD(msgrcv_err, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test errors from msgrcv(2)"); +} + +ATF_TC_BODY(msgrcv_err, tc) +{ + struct msg msg = { MSG_MTYPE_1, { 'a', 'b', 'c' } }; + int id, r = 0; + + id = msgget(MSG_KEY, IPC_CREAT | 0600); + ATF_REQUIRE(id != -1); + + errno = 0; + + ATF_REQUIRE_ERRNO(ENOMSG, msgrcv(id, &msg, + MSG_LEN, MSG_MTYPE_1, IPC_NOWAIT) == -1); + + ATF_REQUIRE(msgsnd(id, &msg, MSG_LEN, IPC_NOWAIT) == 0); + + errno = 0; + + ATF_REQUIRE_ERRNO(EFAULT, msgrcv(id, (void *)-1, + MSG_LEN, MSG_MTYPE_1, IPC_NOWAIT) == -1); + + errno = 0; + + ATF_REQUIRE_ERRNO(EINVAL, msgrcv(-1, &msg, + MSG_LEN, MSG_MTYPE_1, IPC_NOWAIT) == -1); + + errno = 0; + + ATF_REQUIRE_ERRNO(EINVAL, msgrcv(-1, &msg, + SSIZE_MAX, MSG_MTYPE_1, IPC_NOWAIT) == -1); + + ATF_REQUIRE(msgsnd(id, &msg, MSG_LEN, IPC_NOWAIT) == 0); + + errno = 0; + + ATF_REQUIRE_ERRNO(E2BIG, msgrcv(id, &r, + MSG_LEN - 1, MSG_MTYPE_1, IPC_NOWAIT) == -1); + + ATF_REQUIRE(msgctl(id, IPC_RMID, 0) == 0); +} + +ATF_TC_CLEANUP(msgrcv_err, tc) +{ + clean(); +} + + +ATF_TC_WITH_CLEANUP(msgrcv_mtype); +ATF_TC_HEAD(msgrcv_mtype, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test message types with msgrcv(2)"); +} + +ATF_TC_BODY(msgrcv_mtype, tc) +{ + struct msg msg1 = { MSG_MTYPE_1, { 'a', 'b', 'c' } }; + struct msg msg2 = { MSG_MTYPE_3, { 'x', 'y', 'z' } }; + int id; + + id = msgget(MSG_KEY, IPC_CREAT | 0600); + ATF_REQUIRE(id != -1); + + (void)msgsnd(id, &msg1, MSG_LEN, IPC_NOWAIT); + (void)msgrcv(id, &msg2, MSG_LEN, MSG_MTYPE_2, IPC_NOWAIT); + + ATF_CHECK(msg1.buf[0] != msg2.buf[0]); /* Different mtype. */ + ATF_CHECK(msg1.buf[1] != msg2.buf[1]); + ATF_CHECK(msg1.buf[2] != msg2.buf[2]); + + (void)msgrcv(id, &msg2, MSG_LEN, MSG_MTYPE_1, IPC_NOWAIT); + + ATF_CHECK(msg1.buf[0] == msg2.buf[0]); /* Same mtype. */ + ATF_CHECK(msg1.buf[1] == msg2.buf[1]); + ATF_CHECK(msg1.buf[2] == msg2.buf[2]); + + ATF_REQUIRE(msgctl(id, IPC_RMID, 0) == 0); +} + +ATF_TC_CLEANUP(msgrcv_mtype, tc) +{ + clean(); +} + +ATF_TC_WITH_CLEANUP(msgrcv_nonblock); +ATF_TC_HEAD(msgrcv_nonblock, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test msgrcv(2) with IPC_NOWAIT"); + atf_tc_set_md_var(tc, "timeout", "10"); +} + +ATF_TC_BODY(msgrcv_nonblock, tc) +{ + struct msg msg = { MSG_MTYPE_1, { 'a', 'b', 'c' } }; + const ssize_t n = 10; + int id, sta; + ssize_t i; + pid_t pid; + + id = msgget(MSG_KEY, IPC_CREAT | 0600); + ATF_REQUIRE(id != -1); + + for (i = 0; i < n; i++) { + + ATF_REQUIRE(msgsnd(id, &msg, MSG_LEN, IPC_NOWAIT) == 0); + } + + pid = fork(); + ATF_REQUIRE(pid >= 0); + + if (pid == 0) { + + while (i != 0) { + + if (msgrcv(id, &msg, MSG_LEN, MSG_MTYPE_1, + IPC_NOWAIT) == -1) + _exit(EXIT_FAILURE); + + i--; + } + + _exit(EXIT_SUCCESS); + } + + (void)sleep(2); + (void)kill(pid, SIGKILL); + (void)wait(&sta); + + if (WIFSIGNALED(sta) != 0 || WTERMSIG(sta) == SIGKILL) + atf_tc_fail("msgrcv(2) blocked with IPC_NOWAIT"); + + if (WIFEXITED(sta) == 0 && WEXITSTATUS(sta) != EXIT_SUCCESS) + atf_tc_fail("msgrcv(2) failed"); + + ATF_REQUIRE(msgctl(id, IPC_RMID, 0) == 0); +} + +ATF_TC_CLEANUP(msgrcv_nonblock, tc) +{ + clean(); +} + +ATF_TC_WITH_CLEANUP(msgrcv_truncate); +ATF_TC_HEAD(msgrcv_truncate, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test msgrcv(2) with MSG_NOERROR"); +} + +ATF_TC_BODY(msgrcv_truncate, tc) +{ +#define MSG_SMALLLEN 2 + struct msgsmall { + long mtype; + char buf[MSG_SMALLLEN]; + }; + + struct msg msg1 = { MSG_MTYPE_1, { 'a', 'b', 'c' } }; + struct msgsmall msg2 = { MSG_MTYPE_1, { 'x', 'y' } }; + int id; + + id = msgget(MSG_KEY, IPC_CREAT | 0600); + ATF_REQUIRE(id != -1); + + (void)msgsnd(id, &msg1, MSG_LEN, IPC_NOWAIT); + (void)msgrcv(id, &msg2, MSG_SMALLLEN, + MSG_MTYPE_1, IPC_NOWAIT | MSG_NOERROR); + + ATF_CHECK(msg1.buf[0] == msg2.buf[0]); + ATF_CHECK(msg1.buf[1] == msg2.buf[1]); + + ATF_REQUIRE(msgctl(id, IPC_RMID, 0) == 0); +} + +ATF_TC_CLEANUP(msgrcv_truncate, tc) +{ + clean(); +} + +ATF_TP_ADD_TCS(tp) +{ + + ATF_TP_ADD_TC(tp, msgrcv_basic); + ATF_TP_ADD_TC(tp, msgrcv_block); + ATF_TP_ADD_TC(tp, msgrcv_err); + ATF_TP_ADD_TC(tp, msgrcv_mtype); + ATF_TP_ADD_TC(tp, msgrcv_nonblock); + ATF_TP_ADD_TC(tp, msgrcv_truncate); + + return atf_no_error(); +} diff --git a/contrib/netbsd-tests/lib/libc/sys/t_msgsnd.c b/contrib/netbsd-tests/lib/libc/sys/t_msgsnd.c new file mode 100644 index 0000000..5493789 --- /dev/null +++ b/contrib/netbsd-tests/lib/libc/sys/t_msgsnd.c @@ -0,0 +1,338 @@ +/* $NetBSD: t_msgsnd.c,v 1.2 2011/11/05 08:47:54 jruoho Exp $ */ + +/*- + * Copyright (c) 2011 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jukka Ruohonen. + * + * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ +#include <sys/cdefs.h> +__RCSID("$NetBSD: t_msgsnd.c,v 1.2 2011/11/05 08:47:54 jruoho Exp $"); + +#include <sys/msg.h> +#include <sys/stat.h> +#include <sys/sysctl.h> +#include <sys/wait.h> + +#include <atf-c.h> +#include <errno.h> +#include <pwd.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sysexits.h> +#include <time.h> +#include <unistd.h> + +#define MSG_KEY 1234 +#define MSG_MTYPE_1 0x41 +#define MSG_MTYPE_2 0x42 +#define MSG_MTYPE_3 0x43 + +struct msg { + long mtype; + char buf[3]; +}; + +static void clean(void); + +static void +clean(void) +{ + int id; + + if ((id = msgget(MSG_KEY, 0)) != -1) + (void)msgctl(id, IPC_RMID, 0); +} + +ATF_TC_WITH_CLEANUP(msgsnd_block); +ATF_TC_HEAD(msgsnd_block, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test that msgsnd(2) blocks"); + atf_tc_set_md_var(tc, "timeout", "10"); +} + +ATF_TC_BODY(msgsnd_block, tc) +{ + struct msg msg = { MSG_MTYPE_1, { 'a', 'b', 'c' } }; + int id, sta; + pid_t pid; + + id = msgget(MSG_KEY, IPC_CREAT | 0600); + ATF_REQUIRE(id != -1); + + pid = fork(); + ATF_REQUIRE(pid >= 0); + + if (pid == 0) { + + /* + * Enqueue messages until some limit (e.g. the maximum + * number of messages in the queue or the maximum number + * of bytes in the queue) is reached. After this the call + * should block when the IPC_NOWAIT is not set. + */ + for (;;) { + + if (msgsnd(id, &msg, sizeof(struct msg), 0) < 0) + _exit(EXIT_FAILURE); + } + } + + (void)sleep(2); + (void)kill(pid, SIGKILL); + (void)wait(&sta); + + if (WIFEXITED(sta) != 0 || WIFSIGNALED(sta) == 0) + atf_tc_fail("msgsnd(2) did not block"); + + ATF_REQUIRE(msgctl(id, IPC_RMID, 0) == 0); +} + +ATF_TC_CLEANUP(msgsnd_block, tc) +{ + clean(); +} + +ATF_TC_WITH_CLEANUP(msgsnd_count); +ATF_TC_HEAD(msgsnd_count, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Test that msgsnd(2) increments the amount of " + "message in the queue, as given by msgctl(2)"); + atf_tc_set_md_var(tc, "timeout", "10"); +} + +ATF_TC_BODY(msgsnd_count, tc) +{ + struct msg msg = { MSG_MTYPE_1, { 'a', 'b', 'c' } }; + struct msqid_ds ds; + size_t i = 0; + int id, rv; + + id = msgget(MSG_KEY, IPC_CREAT | 0600); + ATF_REQUIRE(id != -1); + + for (;;) { + + errno = 0; + rv = msgsnd(id, &msg, sizeof(struct msg), IPC_NOWAIT); + + if (rv == 0) { + i++; + continue; + } + + if (rv == -1 && errno == EAGAIN) + break; + + atf_tc_fail("failed to enqueue a message"); + } + + (void)memset(&ds, 0, sizeof(struct msqid_ds)); + (void)msgctl(id, IPC_STAT, &ds); + + if (ds.msg_qnum != i) + atf_tc_fail("incorrect message count"); + + ATF_REQUIRE(msgctl(id, IPC_RMID, 0) == 0); +} + +ATF_TC_CLEANUP(msgsnd_count, tc) +{ + clean(); +} + +ATF_TC_WITH_CLEANUP(msgsnd_err); +ATF_TC_HEAD(msgsnd_err, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test errors from msgsnd(2)"); +} + +ATF_TC_BODY(msgsnd_err, tc) +{ + struct msg msg = { MSG_MTYPE_1, { 'a', 'b', 'c' } }; + int id; + + id = msgget(MSG_KEY, IPC_CREAT | 0600); + ATF_REQUIRE(id != -1); + + errno = 0; + + ATF_REQUIRE_ERRNO(EFAULT, msgsnd(id, (void *)-1, + sizeof(struct msg), IPC_NOWAIT) == -1); + + errno = 0; + + ATF_REQUIRE_ERRNO(EINVAL, msgsnd(-1, &msg, + sizeof(struct msg), IPC_NOWAIT) == -1); + + errno = 0; + + ATF_REQUIRE_ERRNO(EINVAL, msgsnd(-1, &msg, + SSIZE_MAX, IPC_NOWAIT) == -1); + + errno = 0; + msg.mtype = 0; + + ATF_REQUIRE_ERRNO(EINVAL, msgsnd(id, &msg, + sizeof(struct msg), IPC_NOWAIT) == -1); + + ATF_REQUIRE(msgctl(id, IPC_RMID, 0) == 0); +} + +ATF_TC_CLEANUP(msgsnd_err, tc) +{ + clean(); +} + +ATF_TC_WITH_CLEANUP(msgsnd_nonblock); +ATF_TC_HEAD(msgsnd_nonblock, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test msgsnd(2) with IPC_NOWAIT"); + atf_tc_set_md_var(tc, "timeout", "10"); +} + +ATF_TC_BODY(msgsnd_nonblock, tc) +{ + struct msg msg = { MSG_MTYPE_1, { 'a', 'b', 'c' } }; + int id, rv, sta; + pid_t pid; + + id = msgget(MSG_KEY, IPC_CREAT | 0600); + ATF_REQUIRE(id != -1); + + pid = fork(); + ATF_REQUIRE(pid >= 0); + + if (pid == 0) { + + for (;;) { + + errno = 0; + rv = msgsnd(id, &msg, sizeof(struct msg), IPC_NOWAIT); + + if (rv == -1 && errno == EAGAIN) + _exit(EXIT_SUCCESS); + } + } + + (void)sleep(2); + (void)kill(pid, SIGKILL); + (void)wait(&sta); + + if (WIFEXITED(sta) == 0 || WIFSIGNALED(sta) != 0) + atf_tc_fail("msgsnd(2) blocked with IPC_NOWAIT"); + + ATF_REQUIRE(msgctl(id, IPC_RMID, 0) == 0); +} + +ATF_TC_CLEANUP(msgsnd_nonblock, tc) +{ + clean(); +} + +ATF_TC_WITH_CLEANUP(msgsnd_perm); +ATF_TC_HEAD(msgsnd_perm, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test permissions with msgsnd(2)"); + atf_tc_set_md_var(tc, "require.user", "root"); +} + +ATF_TC_BODY(msgsnd_perm, tc) +{ + struct msg msg = { MSG_MTYPE_1, { 'a', 'b', 'c' } }; + struct passwd *pw; + int id, sta; + pid_t pid; + uid_t uid; + + pw = getpwnam("nobody"); + id = msgget(MSG_KEY, IPC_CREAT | 0600); + + ATF_REQUIRE(id != -1); + ATF_REQUIRE(pw != NULL); + + uid = pw->pw_uid; + ATF_REQUIRE(uid != 0); + + pid = fork(); + ATF_REQUIRE(pid >= 0); + + if (pid == 0) { + + /* + * Try to enqueue a message to the queue + * created by root as RW for owner only. + */ + if (setuid(uid) != 0) + _exit(EX_OSERR); + + id = msgget(MSG_KEY, 0); + + if (id == -1) + _exit(EX_OSERR); + + errno = 0; + + if (msgsnd(id, &msg, sizeof(struct msg), IPC_NOWAIT) == 0) + _exit(EXIT_FAILURE); + + if (errno != EACCES) + _exit(EXIT_FAILURE); + + _exit(EXIT_SUCCESS); + } + + (void)wait(&sta); + + if (WIFEXITED(sta) == 0 || WEXITSTATUS(sta) != EXIT_SUCCESS) { + + if (errno == EX_OSERR) + atf_tc_fail("system call failed"); + + atf_tc_fail("UID %u enqueued message to root's queue", uid); + } + + ATF_REQUIRE(msgctl(id, IPC_RMID, 0) == 0); +} + +ATF_TC_CLEANUP(msgsnd_perm, tc) +{ + clean(); +} + +ATF_TP_ADD_TCS(tp) +{ + + ATF_TP_ADD_TC(tp, msgsnd_block); + ATF_TP_ADD_TC(tp, msgsnd_count); + ATF_TP_ADD_TC(tp, msgsnd_err); + ATF_TP_ADD_TC(tp, msgsnd_nonblock); + ATF_TP_ADD_TC(tp, msgsnd_perm); + + return atf_no_error(); +} diff --git a/contrib/netbsd-tests/lib/libc/sys/t_msync.c b/contrib/netbsd-tests/lib/libc/sys/t_msync.c new file mode 100644 index 0000000..9743300 --- /dev/null +++ b/contrib/netbsd-tests/lib/libc/sys/t_msync.c @@ -0,0 +1,237 @@ +/* $NetBSD: t_msync.c,v 1.2 2012/03/16 06:15:17 matt Exp $ */ + +/*- + * Copyright (c) 2011 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jukka Ruohonen. + * + * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ +#include <sys/cdefs.h> +__RCSID("$NetBSD: t_msync.c,v 1.2 2012/03/16 06:15:17 matt Exp $"); + +#include <sys/mman.h> + +#include <atf-c.h> +#include <errno.h> +#include <fcntl.h> +#include <limits.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +static long page = 0; +static const off_t off = 512; +static const char path[] = "msync"; + +static const char *msync_sync(const char *, int); + +static const char * +msync_sync(const char *garbage, int flags) +{ + char *buf, *map = MAP_FAILED; + const char *str = NULL; + size_t i, len; + ssize_t tot; + int fd, rv; + + /* + * Create a temporary file, write + * one page to it, and map the file. + */ + buf = malloc(page); + + if (buf == NULL) + return NULL; + + for (i = 0; i < (size_t)page; i++) + buf[i] = 'x'; + + fd = open(path, O_RDWR | O_CREAT, 0700); + + if (fd < 0) { + str = "failed to open"; + goto out; + } + + tot = 0; + + while (tot < page) { + + rv = write(fd, buf, sizeof(buf)); + + if (rv < 0) { + str = "failed to write"; + goto out; + } + + tot += rv; + } + + map = mmap(NULL, page, PROT_READ | PROT_WRITE, MAP_FILE|MAP_PRIVATE, + fd, 0); + + if (map == MAP_FAILED) { + str = "failed to map"; + goto out; + } + + /* + * Seek to an arbitrary offset and + * write garbage to this position. + */ + if (lseek(fd, off, SEEK_SET) != off) { + str = "failed to seek"; + goto out; + } + + len = strlen(garbage); + rv = write(fd, garbage, len); + + if (rv != (ssize_t)len) { + str = "failed to write garbage"; + goto out; + } + + /* + * Synchronize the mapping and verify + * that garbage is at the given offset. + */ + if (msync(map, page, flags) != 0) { + str = "failed to msync"; + goto out; + } + + if (memcmp(map + off, garbage, len) != 0) { + str = "msync did not synchronize"; + goto out; + } + +out: + free(buf); + + (void)close(fd); + (void)unlink(path); + + if (map != MAP_FAILED) + (void)munmap(map, page); + + return str; +} + +ATF_TC(msync_async); +ATF_TC_HEAD(msync_async, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test of msync(2), MS_ASYNC"); +} + +ATF_TC_BODY(msync_async, tc) +{ + const char *str; + + str = msync_sync("garbage", MS_ASYNC); + + if (str != NULL) + atf_tc_fail("%s", str); +} + +ATF_TC(msync_err); +ATF_TC_HEAD(msync_err, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test error conditions in msync(2)"); +} + +ATF_TC_BODY(msync_err, tc) +{ + + char *map = MAP_FAILED; + + /* + * Test that invalid flags error out. + */ + ATF_REQUIRE(msync_sync("error", -1) != NULL); + ATF_REQUIRE(msync_sync("error", INT_MAX) != NULL); + + errno = 0; + + /* + * Map a page and then unmap to get an unmapped address. + */ + map = mmap(NULL, page, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, + -1, 0); + ATF_REQUIRE(map != MAP_FAILED); + + (void)munmap(map, page); + + ATF_REQUIRE(msync(map, page, MS_SYNC) != 0); + ATF_REQUIRE(errno == EFAULT); +} + +ATF_TC(msync_invalidate); +ATF_TC_HEAD(msync_invalidate, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test of msync(2), MS_INVALIDATE"); +} + +ATF_TC_BODY(msync_invalidate, tc) +{ + const char *str; + + str = msync_sync("garbage", MS_INVALIDATE); + + if (str != NULL) + atf_tc_fail("%s", str); +} + +ATF_TC(msync_sync); +ATF_TC_HEAD(msync_sync, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test of msync(2), MS_SYNC"); +} + +ATF_TC_BODY(msync_sync, tc) +{ + const char *str; + + str = msync_sync("garbage", MS_SYNC); + + if (str != NULL) + atf_tc_fail("%s", str); +} + +ATF_TP_ADD_TCS(tp) +{ + + page = sysconf(_SC_PAGESIZE); + + ATF_REQUIRE(page >= 0); + ATF_REQUIRE(page > off); + + ATF_TP_ADD_TC(tp, msync_async); + ATF_TP_ADD_TC(tp, msync_err); + ATF_TP_ADD_TC(tp, msync_invalidate); + ATF_TP_ADD_TC(tp, msync_sync); + + return atf_no_error(); +} diff --git a/contrib/netbsd-tests/lib/libc/sys/t_nanosleep.c b/contrib/netbsd-tests/lib/libc/sys/t_nanosleep.c new file mode 100644 index 0000000..317d667 --- /dev/null +++ b/contrib/netbsd-tests/lib/libc/sys/t_nanosleep.c @@ -0,0 +1,187 @@ +/* $NetBSD: t_nanosleep.c,v 1.3 2013/03/31 16:47:16 christos Exp $ */ + +/*- + * Copyright (c) 2011 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jukka Ruohonen. + * + * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ +#include <sys/cdefs.h> +__RCSID("$NetBSD: t_nanosleep.c,v 1.3 2013/03/31 16:47:16 christos Exp $"); + +#include <sys/time.h> +#include <sys/wait.h> + +#include <atf-c.h> +#include <errno.h> +#include <time.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sysexits.h> +#include <unistd.h> + +static void +handler(int signo) +{ + /* Nothing. */ +} + +ATF_TC(nanosleep_basic); +ATF_TC_HEAD(nanosleep_basic, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test that nanosleep(2) works"); +} + +ATF_TC_BODY(nanosleep_basic, tc) +{ + static const size_t maxiter = 10; + struct timespec ts1, ts2, tsn; + size_t i; + + for (i = 1; i < maxiter; i++) { + + tsn.tv_sec = 0; + tsn.tv_nsec = i; + + (void)memset(&ts1, 0, sizeof(struct timespec)); + (void)memset(&ts2, 0, sizeof(struct timespec)); + + ATF_REQUIRE(clock_gettime(CLOCK_MONOTONIC, &ts1) == 0); + ATF_REQUIRE(nanosleep(&tsn, NULL) == 0); + ATF_REQUIRE(clock_gettime(CLOCK_MONOTONIC, &ts2) == 0); + + /* + * Verify that we slept at least one nanosecond. + */ + if (timespeccmp(&ts2, &ts1, <=) != 0) { + + (void)fprintf(stderr, + "sleep time:: sec %llu, nsec %lu\n\t\t" + "ts1: sec %llu, nsec %lu\n\t\t" + "ts2: sec %llu, nsec %lu\n", + (unsigned long long)tsn.tv_sec, tsn.tv_nsec, + (unsigned long long)ts1.tv_sec, ts1.tv_nsec, + (unsigned long long)ts2.tv_sec, ts2.tv_nsec); + + atf_tc_fail_nonfatal("inaccuracies in sleep time " + "(resolution = %lu nsec)", tsn.tv_nsec); + } + } +} + +ATF_TC(nanosleep_err); +ATF_TC_HEAD(nanosleep_err, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Test errors from nanosleep(2) (PR bin/14558)"); +} + +ATF_TC_BODY(nanosleep_err, tc) +{ + struct timespec ts; + + ts.tv_sec = 1; + ts.tv_nsec = -1; + errno = 0; + ATF_REQUIRE_ERRNO(EINVAL, nanosleep(&ts, NULL) == -1); + + ts.tv_sec = 1; + ts.tv_nsec = 1000000000; + errno = 0; + ATF_REQUIRE_ERRNO(EINVAL, nanosleep(&ts, NULL) == -1); + + ts.tv_sec = -1; + ts.tv_nsec = 0; + errno = 0; + ATF_REQUIRE_ERRNO(0, nanosleep(&ts, NULL) == 0); + + errno = 0; + ATF_REQUIRE_ERRNO(EFAULT, nanosleep((void *)-1, NULL) == -1); +} + +ATF_TC(nanosleep_sig); +ATF_TC_HEAD(nanosleep_sig, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test signal for nanosleep(2)"); +} + +ATF_TC_BODY(nanosleep_sig, tc) +{ + struct timespec tsn, tsr; + pid_t pid; + int sta; + + /* + * Test that a signal interrupts nanosleep(2). + * + * (In which case the return value should be -1 and the + * second parameter should contain the unslept time.) + */ + pid = fork(); + + ATF_REQUIRE(pid >= 0); + ATF_REQUIRE(signal(SIGINT, handler) == 0); + + if (pid == 0) { + + tsn.tv_sec = 10; + tsn.tv_nsec = 0; + + tsr.tv_sec = 0; + tsr.tv_nsec = 0; + + errno = 0; + + if (nanosleep(&tsn, &tsr) != -1) + _exit(EXIT_FAILURE); + + if (errno != EINTR) + _exit(EXIT_FAILURE); + + if (tsr.tv_sec == 0 && tsr.tv_nsec == 0) + _exit(EXIT_FAILURE); + + _exit(EXIT_SUCCESS); + } + + (void)sleep(1); + (void)kill(pid, SIGINT); + (void)wait(&sta); + + if (WIFEXITED(sta) == 0 || WEXITSTATUS(sta) != EXIT_SUCCESS) + atf_tc_fail("signal did not interrupt nanosleep(2)"); +} + +ATF_TP_ADD_TCS(tp) +{ + + ATF_TP_ADD_TC(tp, nanosleep_basic); + ATF_TP_ADD_TC(tp, nanosleep_err); + ATF_TP_ADD_TC(tp, nanosleep_sig); + + return atf_no_error(); +} diff --git a/contrib/netbsd-tests/lib/libc/sys/t_pipe.c b/contrib/netbsd-tests/lib/libc/sys/t_pipe.c new file mode 100644 index 0000000..b30b94d --- /dev/null +++ b/contrib/netbsd-tests/lib/libc/sys/t_pipe.c @@ -0,0 +1,163 @@ +/* $NetBSD: t_pipe.c,v 1.3 2011/10/31 15:41:31 christos Exp $ */ + +/*- + * Copyright (c) 2001, 2008 The NetBSD Foundation, 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ + +#include <sys/cdefs.h> +__COPYRIGHT("@(#) Copyright (c) 2008\ + The NetBSD Foundation, inc. All rights reserved."); +__RCSID("$NetBSD: t_pipe.c,v 1.3 2011/10/31 15:41:31 christos Exp $"); + +#include <sys/types.h> +#include <sys/wait.h> + +#include <errno.h> +#include <fcntl.h> +#include <poll.h> +#include <sched.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +#include <atf-c.h> + +#include "../../../h_macros.h" + +static pid_t pid; +static int nsiginfo = 0; + +/* + * This is used for both parent and child. Handle parent's SIGALRM, + * the childs SIGINFO doesn't need anything. + */ +static void +sighand(int sig) +{ + if (sig == SIGALRM) { + kill(pid, SIGINFO); + } + if (sig == SIGINFO) { + nsiginfo++; + } +} + +ATF_TC(pipe_restart); +ATF_TC_HEAD(pipe_restart, tc) +{ + atf_tc_set_md_var(tc, "descr", "Checks that writing to pipe " + "works correctly after being interrupted and restarted " + "(kern/14087)"); +} + +ATF_TC_BODY(pipe_restart, tc) +{ + int pp[2], st; + ssize_t sz, todo, done; + char *f; + sigset_t asigset, osigset, emptysigset; + + /* Initialise signal masks */ + RL(sigemptyset(&emptysigset)); + RL(sigemptyset(&asigset)); + RL(sigaddset(&asigset, SIGINFO)); + + /* Register signal handlers for both read and writer */ + REQUIRE_LIBC(signal(SIGINFO, sighand), SIG_ERR); + REQUIRE_LIBC(signal(SIGALRM, sighand), SIG_ERR); + + todo = 2 * 1024 * 1024; + REQUIRE_LIBC(f = malloc(todo), NULL); + + RL(pipe(pp)); + + RL(pid = fork()); + if (pid == 0) { + /* child */ + RL(close(pp[1])); + + /* Do inital write. This should succeed, make + * the other side do partial write and wait for us to pick + * rest up. + */ + RL(done = read(pp[0], f, 128 * 1024)); + + /* Wait until parent is alarmed and awakens us */ + RL(sigprocmask(SIG_BLOCK, &asigset, &osigset)); + while (nsiginfo == 0) { + if (sigsuspend(&emptysigset) != -1 || errno != EINTR) + atf_tc_fail("sigsuspend(&emptysigset): %s", + strerror(errno)); + } + RL(sigprocmask(SIG_SETMASK, &osigset, NULL)); + + /* Read all what parent wants to give us */ + while((sz = read(pp[0], f, 1024 * 1024)) > 0) + done += sz; + + /* + * Exit with 1 if number of bytes read doesn't match + * number of expected bytes + */ + printf("Read: %#zx\n", (size_t)done); + printf("Expected: %#zx\n", (size_t)todo); + + exit(done != todo); + + /* NOTREACHED */ + } else { + RL(close(pp[0])); + + /* + * Arrange for alarm after two seconds. Since we have + * handler setup for SIGARLM, the write(2) call should + * be restarted internally by kernel. + */ + (void)alarm(2); + + /* We write exactly 'todo' bytes. The very first write(2) + * should partially succeed, block and eventually + * be restarted by kernel + */ + while(todo > 0 && ((sz = write(pp[1], f, todo)) > 0)) + todo -= sz; + + /* Close the pipe, so that child would stop reading */ + RL(close(pp[1])); + + /* And pickup child's exit status */ + RL(waitpid(pid, &st, 0)); + + ATF_REQUIRE_EQ(WEXITSTATUS(st), 0); + } +} + +ATF_TP_ADD_TCS(tp) +{ + ATF_TP_ADD_TC(tp, pipe_restart); + + return atf_no_error(); +} diff --git a/contrib/netbsd-tests/lib/libc/sys/t_pipe2.c b/contrib/netbsd-tests/lib/libc/sys/t_pipe2.c new file mode 100644 index 0000000..51f2240 --- /dev/null +++ b/contrib/netbsd-tests/lib/libc/sys/t_pipe2.c @@ -0,0 +1,188 @@ +/* $NetBSD: t_pipe2.c,v 1.8 2012/05/16 13:54:28 jruoho Exp $ */ + +/*- + * Copyright (c) 2011 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Christos Zoulas. + * + * 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ +#include <sys/cdefs.h> +__RCSID("$NetBSD: t_pipe2.c,v 1.8 2012/05/16 13:54:28 jruoho Exp $"); + +#include <atf-c.h> +#include <fcntl.h> +#include <unistd.h> +#include <stdlib.h> +#include <errno.h> +#include <sys/resource.h> + +static void +run(int flags) +{ + int fd[2], i; + + while ((i = open("/", O_RDONLY)) < 3) + ATF_REQUIRE(i != -1); + + ATF_REQUIRE(fcntl(3, F_CLOSEM) != -1); + + ATF_REQUIRE(pipe2(fd, flags) == 0); + + ATF_REQUIRE(fd[0] == 3); + ATF_REQUIRE(fd[1] == 4); + + if (flags & O_CLOEXEC) { + ATF_REQUIRE((fcntl(fd[0], F_GETFD) & FD_CLOEXEC) != 0); + ATF_REQUIRE((fcntl(fd[1], F_GETFD) & FD_CLOEXEC) != 0); + } else { + ATF_REQUIRE((fcntl(fd[0], F_GETFD) & FD_CLOEXEC) == 0); + ATF_REQUIRE((fcntl(fd[1], F_GETFD) & FD_CLOEXEC) == 0); + } + + if (flags & O_NONBLOCK) { + ATF_REQUIRE((fcntl(fd[0], F_GETFL) & O_NONBLOCK) != 0); + ATF_REQUIRE((fcntl(fd[1], F_GETFL) & O_NONBLOCK) != 0); + } else { + ATF_REQUIRE((fcntl(fd[0], F_GETFL) & O_NONBLOCK) == 0); + ATF_REQUIRE((fcntl(fd[1], F_GETFL) & O_NONBLOCK) == 0); + } + + if (flags & O_NOSIGPIPE) { + ATF_REQUIRE(fcntl(fd[0], F_GETNOSIGPIPE) != 0); + ATF_REQUIRE(fcntl(fd[1], F_GETNOSIGPIPE) != 0); + } else { + ATF_REQUIRE(fcntl(fd[0], F_GETNOSIGPIPE) == 0); + ATF_REQUIRE(fcntl(fd[1], F_GETNOSIGPIPE) == 0); + } + + ATF_REQUIRE(close(fd[0]) != -1); + ATF_REQUIRE(close(fd[1]) != -1); +} + +ATF_TC(pipe2_basic); +ATF_TC_HEAD(pipe2_basic, tc) +{ + atf_tc_set_md_var(tc, "descr", "A basic test of pipe2(2)"); +} + +ATF_TC_BODY(pipe2_basic, tc) +{ + run(0); +} + +ATF_TC(pipe2_consume); +ATF_TC_HEAD(pipe2_consume, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test that consuming file descriptors " + "with pipe2(2) does not crash the system (PR kern/46457)"); +} + +ATF_TC_BODY(pipe2_consume, tc) +{ + struct rlimit rl; + int err, filedes[2]; + + err = fcntl(4, F_CLOSEM); + ATF_REQUIRE(err == 0); + + err = getrlimit(RLIMIT_NOFILE, &rl); + ATF_REQUIRE(err == 0); + /* + * The heart of this test is to run against the number of open + * file descriptor limit in the middle of a pipe2() call - i.e. + * before the call only a single descriptor may be openend. + */ + rl.rlim_cur = 4; + err = setrlimit(RLIMIT_NOFILE, &rl); + ATF_REQUIRE(err == 0); + + err = pipe2(filedes, O_CLOEXEC); + ATF_REQUIRE(err == -1); +} + +ATF_TC(pipe2_nonblock); +ATF_TC_HEAD(pipe2_nonblock, tc) +{ + atf_tc_set_md_var(tc, "descr", "A non-blocking test of pipe2(2)"); +} + +ATF_TC_BODY(pipe2_nonblock, tc) +{ + run(O_NONBLOCK); +} + +ATF_TC(pipe2_cloexec); +ATF_TC_HEAD(pipe2_cloexec, tc) +{ + atf_tc_set_md_var(tc, "descr", "A close-on-exec test of pipe2(2)"); +} + +ATF_TC_BODY(pipe2_cloexec, tc) +{ + run(O_CLOEXEC); +} + +ATF_TC(pipe2_nosigpipe); +ATF_TC_HEAD(pipe2_nosigpipe, tc) +{ + atf_tc_set_md_var(tc, "descr", "A no sigpipe test of pipe2(2)"); +} + +ATF_TC_BODY(pipe2_nosigpipe, tc) +{ + run(O_NOSIGPIPE); +} + +ATF_TC(pipe2_einval); +ATF_TC_HEAD(pipe2_einval, tc) +{ + atf_tc_set_md_var(tc, "descr", "A error check of pipe2(2)"); +} + +ATF_TC_BODY(pipe2_einval, tc) +{ + int fd[2]; + ATF_REQUIRE_ERRNO(EINVAL, pipe2(fd, O_ASYNC) == -1); +} + +ATF_TP_ADD_TCS(tp) +{ + + ATF_TP_ADD_TC(tp, pipe2_basic); + ATF_TP_ADD_TC(tp, pipe2_consume); + ATF_TP_ADD_TC(tp, pipe2_nonblock); + ATF_TP_ADD_TC(tp, pipe2_cloexec); + ATF_TP_ADD_TC(tp, pipe2_nosigpipe); + ATF_TP_ADD_TC(tp, pipe2_einval); + + return atf_no_error(); +} diff --git a/contrib/netbsd-tests/lib/libc/sys/t_poll.c b/contrib/netbsd-tests/lib/libc/sys/t_poll.c new file mode 100644 index 0000000..7a786d2 --- /dev/null +++ b/contrib/netbsd-tests/lib/libc/sys/t_poll.c @@ -0,0 +1,392 @@ +/* $NetBSD: t_poll.c,v 1.3 2012/03/18 07:00:52 jruoho Exp $ */ + +/*- + * Copyright (c) 2011 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Matthias Scheler. + * + * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ + +#include <sys/time.h> +#include <sys/wait.h> + +#include <atf-c.h> +#include <errno.h> +#include <fcntl.h> +#include <paths.h> +#include <poll.h> +#include <stdio.h> +#include <signal.h> +#include <unistd.h> + +static int desc; + +static void +child1(void) +{ + struct pollfd pfd; + + pfd.fd = desc; + pfd.events = POLLIN | POLLHUP | POLLOUT; + + (void)poll(&pfd, 1, 2000); + (void)printf("child1 exit\n"); +} + +static void +child2(void) +{ + struct pollfd pfd; + + pfd.fd = desc; + pfd.events = POLLIN | POLLHUP | POLLOUT; + + (void)sleep(1); + (void)poll(&pfd, 1, INFTIM); + (void)printf("child2 exit\n"); +} + +static void +child3(void) +{ + struct pollfd pfd; + + (void)sleep(5); + + pfd.fd = desc; + pfd.events = POLLIN | POLLHUP | POLLOUT; + + (void)poll(&pfd, 1, INFTIM); + (void)printf("child3 exit\n"); +} + +ATF_TC(poll_3way); +ATF_TC_HEAD(poll_3way, tc) +{ + atf_tc_set_md_var(tc, "timeout", "15"); + atf_tc_set_md_var(tc, "descr", + "Check for 3-way collision for descriptor. First child comes " + "and polls on descriptor, second child comes and polls, first " + "child times out and exits, third child comes and polls. When " + "the wakeup event happens, the two remaining children should " + "both be awaken. (kern/17517)"); +} + +ATF_TC_BODY(poll_3way, tc) +{ + int pf[2]; + int status, i; + pid_t pid; + + pipe(pf); + desc = pf[0]; + + pid = fork(); + ATF_REQUIRE(pid >= 0); + + if (pid == 0) { + (void)close(pf[1]); + child1(); + _exit(0); + /* NOTREACHED */ + } + + pid = fork(); + ATF_REQUIRE(pid >= 0); + + if (pid == 0) { + (void)close(pf[1]); + child2(); + _exit(0); + /* NOTREACHED */ + } + + pid = fork(); + ATF_REQUIRE( pid >= 0); + + if (pid == 0) { + (void)close(pf[1]); + child3(); + _exit(0); + /* NOTREACHED */ + } + + (void)sleep(10); + + (void)printf("parent write\n"); + + ATF_REQUIRE(write(pf[1], "konec\n", 6) == 6); + + for(i = 0; i < 3; ++i) + (void)wait(&status); + + (void)printf("parent terminated\n"); +} + +ATF_TC(poll_basic); +ATF_TC_HEAD(poll_basic, tc) +{ + atf_tc_set_md_var(tc, "timeout", "10"); + atf_tc_set_md_var(tc, "descr", + "Basis functionality test for poll(2)"); +} + +ATF_TC_BODY(poll_basic, tc) +{ + int fds[2]; + struct pollfd pfds[2]; + int ret; + + ATF_REQUIRE_EQ(pipe(fds), 0); + + pfds[0].fd = fds[0]; + pfds[0].events = POLLIN; + pfds[1].fd = fds[1]; + pfds[1].events = POLLOUT; + + /* + * Check that we get a timeout waiting for data on the read end + * of our pipe. + */ + pfds[0].revents = -1; + pfds[1].revents = -1; + ATF_REQUIRE_EQ_MSG(ret = poll(&pfds[0], 1, 1), 0, + "got: %d", ret); + ATF_REQUIRE_EQ_MSG(pfds[0].revents, 0, "got: %d", pfds[0].revents); + ATF_REQUIRE_EQ_MSG(pfds[1].revents, -1, "got: %d", pfds[1].revents); + + /* Check that the write end of the pipe as reported as ready. */ + pfds[0].revents = -1; + pfds[1].revents = -1; + ATF_REQUIRE_EQ_MSG(ret = poll(&pfds[1], 1, 1), 1, + "got: %d", ret); + ATF_REQUIRE_EQ_MSG(pfds[0].revents, -1, "got: %d", pfds[0].revents); + ATF_REQUIRE_EQ_MSG(pfds[1].revents, POLLOUT, "got: %d",\ + pfds[1].revents); + + /* Check that only the write end of the pipe as reported as ready. */ + pfds[0].revents = -1; + pfds[1].revents = -1; + ATF_REQUIRE_EQ_MSG(ret = poll(pfds, 2, 1), 1, + "got: %d", ret); + ATF_REQUIRE_EQ_MSG(pfds[0].revents, 0, "got: %d", pfds[0].revents); + ATF_REQUIRE_EQ_MSG(pfds[1].revents, POLLOUT, "got: %d", + pfds[1].revents); + + /* Write data to our pipe. */ + ATF_REQUIRE_EQ(write(fds[1], "", 1), 1); + + /* Check that both ends of our pipe are reported as ready. */ + pfds[0].revents = -1; + pfds[1].revents = -1; + ATF_REQUIRE_EQ_MSG(ret = poll(pfds, 2, 1), 2, + "got: %d", ret); + ATF_REQUIRE_EQ_MSG(pfds[0].revents, POLLIN, "got: %d", + pfds[0].revents); + ATF_REQUIRE_EQ_MSG(pfds[1].revents, POLLOUT, "got: %d", + pfds[1].revents); + + ATF_REQUIRE_EQ(close(fds[0]), 0); + ATF_REQUIRE_EQ(close(fds[1]), 0); +} + +ATF_TC(poll_err); +ATF_TC_HEAD(poll_err, tc) +{ + atf_tc_set_md_var(tc, "descr", "Check errors from poll(2)"); +} + +ATF_TC_BODY(poll_err, tc) +{ + struct pollfd pfd; + int fd = 0; + + pfd.fd = fd; + pfd.events = POLLIN; + + errno = 0; + ATF_REQUIRE_ERRNO(EFAULT, poll((struct pollfd *)-1, 1, -1) == -1); + + errno = 0; + ATF_REQUIRE_ERRNO(EINVAL, poll(&pfd, 1, -2) == -1); +} + +ATF_TC(pollts_basic); +ATF_TC_HEAD(pollts_basic, tc) +{ + atf_tc_set_md_var(tc, "timeout", "10"); + atf_tc_set_md_var(tc, "descr", + "Basis functionality test for pollts(2)"); +} + +ATF_TC_BODY(pollts_basic, tc) +{ + int fds[2]; + struct pollfd pfds[2]; + struct timespec timeout; + int ret; + + ATF_REQUIRE_EQ(pipe(fds), 0); + + pfds[0].fd = fds[0]; + pfds[0].events = POLLIN; + pfds[1].fd = fds[1]; + pfds[1].events = POLLOUT; + + /* Use a timeout of 1 second. */ + timeout.tv_sec = 1; + timeout.tv_nsec = 0; + + /* + * Check that we get a timeout waiting for data on the read end + * of our pipe. + */ + pfds[0].revents = -1; + pfds[1].revents = -1; + ATF_REQUIRE_EQ_MSG(ret = pollts(&pfds[0], 1, &timeout, NULL), 0, + "got: %d", ret); + ATF_REQUIRE_EQ_MSG(pfds[0].revents, 0, "got: %d", pfds[0].revents); + ATF_REQUIRE_EQ_MSG(pfds[1].revents, -1, "got: %d", pfds[1].revents); + + /* Check that the write end of the pipe as reported as ready. */ + pfds[0].revents = -1; + pfds[1].revents = -1; + ATF_REQUIRE_EQ_MSG(ret = pollts(&pfds[1], 1, &timeout, NULL), 1, + "got: %d", ret); + ATF_REQUIRE_EQ_MSG(pfds[0].revents, -1, "got: %d", pfds[0].revents); + ATF_REQUIRE_EQ_MSG(pfds[1].revents, POLLOUT, "got: %d",\ + pfds[1].revents); + + /* Check that only the write end of the pipe as reported as ready. */ + pfds[0].revents = -1; + pfds[1].revents = -1; + ATF_REQUIRE_EQ_MSG(ret = pollts(pfds, 2, &timeout, NULL), 1, + "got: %d", ret); + ATF_REQUIRE_EQ_MSG(pfds[0].revents, 0, "got: %d", pfds[0].revents); + ATF_REQUIRE_EQ_MSG(pfds[1].revents, POLLOUT, "got: %d", + pfds[1].revents); + + /* Write data to our pipe. */ + ATF_REQUIRE_EQ(write(fds[1], "", 1), 1); + + /* Check that both ends of our pipe are reported as ready. */ + pfds[0].revents = -1; + pfds[1].revents = -1; + ATF_REQUIRE_EQ_MSG(ret = pollts(pfds, 2, &timeout, NULL), 2, + "got: %d", ret); + ATF_REQUIRE_EQ_MSG(pfds[0].revents, POLLIN, "got: %d", + pfds[0].revents); + ATF_REQUIRE_EQ_MSG(pfds[1].revents, POLLOUT, "got: %d", + pfds[1].revents); + + ATF_REQUIRE_EQ(close(fds[0]), 0); + ATF_REQUIRE_EQ(close(fds[1]), 0); +} + +ATF_TC(pollts_err); +ATF_TC_HEAD(pollts_err, tc) +{ + atf_tc_set_md_var(tc, "descr", "Check errors from pollts(2)"); +} + +ATF_TC_BODY(pollts_err, tc) +{ + struct timespec timeout; + struct pollfd pfd; + int fd = 0; + + pfd.fd = fd; + pfd.events = POLLIN; + + timeout.tv_sec = 1; + timeout.tv_nsec = 0; + + errno = 0; + ATF_REQUIRE_ERRNO(EFAULT, pollts((void *)-1, 1, &timeout, NULL) == -1); + + timeout.tv_sec = -1; + timeout.tv_nsec = -1; + + errno = 0; + ATF_REQUIRE_ERRNO(EINVAL, pollts(&pfd, 1, &timeout, NULL) == -1); +} + +ATF_TC(pollts_sigmask); +ATF_TC_HEAD(pollts_sigmask, tc) +{ + atf_tc_set_md_var(tc, "timeout", "10"); + atf_tc_set_md_var(tc, "descr", + "Check that pollts(2) restores the signal mask (PR kern/44986)"); +} + +ATF_TC_BODY(pollts_sigmask, tc) +{ + int fd; + struct pollfd pfd; + struct timespec timeout; + sigset_t mask; + int ret; + + fd = open(_PATH_DEVNULL, O_RDONLY); + ATF_REQUIRE(fd >= 0); + + pfd.fd = fd; + pfd.events = POLLIN; + + /* Use a timeout of 1 second. */ + timeout.tv_sec = 1; + timeout.tv_nsec = 0; + + /* Unblock all signals. */ + ATF_REQUIRE_EQ(sigfillset(&mask), 0); + ATF_REQUIRE_EQ(sigprocmask(SIG_UNBLOCK, &mask, NULL), 0); + + /* + * Check that pollts(2) immediately returns. We block *all* + * signals during pollts(2). + */ + ATF_REQUIRE_EQ_MSG(ret = pollts(&pfd, 1, &timeout, &mask), 1, + "got: %d", ret); + + /* Check that signals are now longer blocked. */ + ATF_REQUIRE_EQ(sigprocmask(SIG_SETMASK, NULL, &mask), 0); + ATF_REQUIRE_EQ_MSG(sigismember(&mask, SIGUSR1), 0, + "signal mask was changed."); + + ATF_REQUIRE_EQ(close(fd), 0); +} + +ATF_TP_ADD_TCS(tp) +{ + + ATF_TP_ADD_TC(tp, poll_3way); + ATF_TP_ADD_TC(tp, poll_basic); + ATF_TP_ADD_TC(tp, poll_err); + ATF_TP_ADD_TC(tp, pollts_basic); + ATF_TP_ADD_TC(tp, pollts_err); + ATF_TP_ADD_TC(tp, pollts_sigmask); + + return atf_no_error(); +} diff --git a/contrib/netbsd-tests/lib/libc/sys/t_posix_fadvise.c b/contrib/netbsd-tests/lib/libc/sys/t_posix_fadvise.c new file mode 100644 index 0000000..da4e746 --- /dev/null +++ b/contrib/netbsd-tests/lib/libc/sys/t_posix_fadvise.c @@ -0,0 +1,165 @@ +/* $NetBSD: t_posix_fadvise.c,v 1.1 2011/10/15 06:10:26 jruoho Exp $ */ + +/*- + * Copyright (c) 2008 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by YAMAMOTO Takashi. + * + * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ + +/*- + * Copyright (c)2005 YAMAMOTO Takashi, + * 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. + */ + +#include <sys/cdefs.h> +__COPYRIGHT("@(#) Copyright (c) 2008\ + The NetBSD Foundation, inc. All rights reserved."); +__RCSID("$NetBSD: t_posix_fadvise.c,v 1.1 2011/10/15 06:10:26 jruoho Exp $"); + +#include <sys/fcntl.h> + +#include <errno.h> +#include <string.h> +#include <unistd.h> + +#include <atf-c.h> + +#include "../../../h_macros.h" + +#include <rump/rump.h> +#include <rump/rump_syscalls.h> + +ATF_TC(posix_fadvise); +ATF_TC_HEAD(posix_fadvise, tc) +{ + atf_tc_set_md_var(tc, "descr", "Checks posix_fadvise(2)"); +} + +ATF_TC(posix_fadvise_reg); +ATF_TC_HEAD(posix_fadvise_reg, tc) +{ + atf_tc_set_md_var(tc, "descr", "Checks posix_fadvise(2) " + "for regular files"); +} + +ATF_TC_BODY(posix_fadvise, tc) +{ + int fd; + int pipe_fds[2]; + int badfd = 10; + int ret; + + RL(fd = open("/dev/null", O_RDWR)); + + (void)close(badfd); + RL(pipe(pipe_fds)); + + /* + * it's hard to check if posix_fadvise is working properly. + * only check return values here. + */ + + /* posix_fadvise shouldn't affect errno. */ + +#define CE(x, exp) \ + do { \ + int save = errno; \ + errno = 999; \ + ATF_CHECK_EQ_MSG(ret = (x), exp, "got: %d", ret); \ + ATF_CHECK_EQ_MSG(errno, 999, "got: %s", strerror(errno)); \ + errno = save; \ + } while (0); + + CE(posix_fadvise(fd, 0, 0, -1), EINVAL); + CE(posix_fadvise(pipe_fds[0], 0, 0, POSIX_FADV_NORMAL), ESPIPE); + CE(posix_fadvise(badfd, 0, 0, POSIX_FADV_NORMAL), EBADF); + CE(posix_fadvise(fd, 0, 0, POSIX_FADV_NORMAL), 0); + CE(posix_fadvise(fd, 0, 0, POSIX_FADV_SEQUENTIAL), 0); + CE(posix_fadvise(fd, 0, 0, POSIX_FADV_RANDOM), 0); + CE(posix_fadvise(fd, 0, 0, POSIX_FADV_WILLNEED), 0); + CE(posix_fadvise(fd, 0, 0, POSIX_FADV_DONTNEED), 0); + CE(posix_fadvise(fd, 0, 0, POSIX_FADV_NOREUSE), 0); +} + +ATF_TC_BODY(posix_fadvise_reg, tc) +{ + int rfd, ret; + + rump_init(); + RL(rfd = rump_sys_open("/a_file", O_CREAT, 0666)); + + CE(rump_sys_posix_fadvise(rfd, 0, 0, POSIX_FADV_NORMAL), 0); + CE(rump_sys_posix_fadvise(rfd, 0, 0, POSIX_FADV_SEQUENTIAL), 0); + CE(rump_sys_posix_fadvise(rfd, 0, 0, POSIX_FADV_RANDOM), 0); + CE(rump_sys_posix_fadvise(rfd, 0, 0, POSIX_FADV_WILLNEED), 0); + CE(rump_sys_posix_fadvise(rfd, 0, 0, POSIX_FADV_NOREUSE), 0); + + CE(rump_sys_posix_fadvise(rfd, + INT64_MAX-getpagesize(), getpagesize(), POSIX_FADV_NORMAL), 0); + CE(rump_sys_posix_fadvise(rfd, + INT64_MAX-getpagesize(), getpagesize(), POSIX_FADV_SEQUENTIAL), 0); + CE(rump_sys_posix_fadvise(rfd, + INT64_MAX-getpagesize(), getpagesize(), POSIX_FADV_RANDOM), 0); + CE(rump_sys_posix_fadvise(rfd, + INT64_MAX-getpagesize(), getpagesize(), POSIX_FADV_WILLNEED), 0); + CE(rump_sys_posix_fadvise(rfd, + INT64_MAX-getpagesize(), getpagesize(), POSIX_FADV_NOREUSE), 0); + + //atf_tc_expect_signal(-1, "http://mail-index.netbsd.org/source-changes-d/2010/11/11/msg002508.html"); + CE(rump_sys_posix_fadvise(rfd, + INT64_MAX-getpagesize(), getpagesize(), POSIX_FADV_DONTNEED), 0); + CE(rump_sys_posix_fadvise(rfd, 0, 0, POSIX_FADV_DONTNEED), 0); +#undef CE +} + +ATF_TP_ADD_TCS(tp) +{ + ATF_TP_ADD_TC(tp, posix_fadvise); + ATF_TP_ADD_TC(tp, posix_fadvise_reg); + + return atf_no_error(); +} diff --git a/contrib/netbsd-tests/lib/libc/sys/t_recvmmsg.c b/contrib/netbsd-tests/lib/libc/sys/t_recvmmsg.c new file mode 100644 index 0000000..76bc7dd --- /dev/null +++ b/contrib/netbsd-tests/lib/libc/sys/t_recvmmsg.c @@ -0,0 +1,161 @@ +/* $NetBSD: t_recvmmsg.c,v 1.1 2012/06/22 18:45:23 christos Exp $ */ + +/*- + * Copyright (c) 2012 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jared McNeill and Christos Zoulas. + * + * 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ +#include <sys/cdefs.h> +__RCSID("$NetBSD: t_recvmmsg.c,v 1.1 2012/06/22 18:45:23 christos Exp $"); + +#include <atf-c.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/wait.h> + +#include <string.h> +#include <time.h> +#include <stdint.h> +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <sched.h> + +#define BUFSIZE 65536 +#define NPKTS 50 + +#define min(a, b) ((a) < (b) ? (a) : (b)) +static int debug; + + +ATF_TC(recvmmsg_basic); +ATF_TC_HEAD(recvmmsg_basic, tc) +{ + atf_tc_set_md_var(tc, "descr", "A basic test of recvmmsg(2)"); +} + +ATF_TC_BODY(recvmmsg_basic, tc) +{ + int fd[2], error, i, cnt; + uint8_t *buf; + struct mmsghdr *mmsghdr; + struct iovec *iov; + unsigned int mmsgcnt, n; + int status; + off_t off; + uint8_t DGRAM[1316] = { 0, 2, 3, 4, 5, 6, 7, 8, 9, }; + + error = socketpair(AF_UNIX, SOCK_DGRAM, 0, fd); + ATF_REQUIRE_MSG(error != -1, "socketpair failed (%s)", strerror(errno)); + + buf = malloc(BUFSIZE); + ATF_REQUIRE_MSG(buf != NULL, "malloc failed (%s)", strerror(errno)); + + mmsgcnt = BUFSIZE / sizeof(DGRAM); + mmsghdr = malloc(sizeof(*mmsghdr) * mmsgcnt); + ATF_REQUIRE_MSG(mmsghdr != NULL, "malloc failed (%s)", strerror(errno)); + iov = malloc(sizeof(*iov) * mmsgcnt); + ATF_REQUIRE_MSG(iov != NULL, "malloc failed (%s)", strerror(errno)); + + for (off = 0, n = 0; n < mmsgcnt; n++) { + iov[n].iov_base = buf + off; + iov[n].iov_len = sizeof(DGRAM); + off += iov[n].iov_len; + mmsghdr[n].msg_hdr.msg_iov = &iov[n]; + mmsghdr[n].msg_hdr.msg_iovlen = 1; + mmsghdr[n].msg_hdr.msg_name = NULL; + mmsghdr[n].msg_hdr.msg_namelen = 0; + } + + switch (fork()) { + case -1: + ATF_REQUIRE_MSG(0, "fork failed (%s)", strerror(errno)); + break; + + case 0: + n = NPKTS; + if (debug) + printf("waiting for %u messages (max %u per syscall)\n", n, + mmsgcnt); + while (n > 0) { + struct timespec ts = { 1, 0 }; + cnt = recvmmsg(fd[1], mmsghdr, min(mmsgcnt, n), + MSG_WAITALL, &ts); + ATF_REQUIRE_MSG(cnt != -1, "recvmmsg failed (%s)", + strerror(errno)); + ATF_REQUIRE_MSG(cnt != 0, "recvmmsg timeout"); + if (debug) + printf("recvmmsg: got %u messages\n", cnt); + for (i = 0; i < cnt; i++) { + ATF_CHECK_EQ_MSG(mmsghdr[i].msg_len, + sizeof(DGRAM), "packet length"); + ATF_CHECK_EQ_MSG( + ((uint8_t *)iov[i].iov_base)[0], + NPKTS - n + i, "packet contents"); + } + n -= cnt; + } + if (debug) + printf("done!\n"); + exit(0); + /*NOTREACHED*/ + default: + sched_yield(); + + for (n = 0; n < NPKTS; n++) { + if (debug) + printf("sending packet %u/%u...\n", (n+1), + NPKTS); + do { + DGRAM[0] = n; + error = send(fd[0], DGRAM, sizeof(DGRAM), 0); + } while (error == -1 && errno == ENOBUFS); + if (error == -1) + ATF_REQUIRE_MSG(error != -1, "send failed (%s)", + strerror(errno)); + } + error = wait(&status); + ATF_REQUIRE_MSG(error != -1, "wait failed (%s)", + strerror(errno)); + break; + } +} + +ATF_TP_ADD_TCS(tp) +{ + + ATF_TP_ADD_TC(tp, recvmmsg_basic); + + return atf_no_error(); +} diff --git a/contrib/netbsd-tests/lib/libc/sys/t_revoke.c b/contrib/netbsd-tests/lib/libc/sys/t_revoke.c new file mode 100644 index 0000000..10fd6d6 --- /dev/null +++ b/contrib/netbsd-tests/lib/libc/sys/t_revoke.c @@ -0,0 +1,186 @@ +/* $NetBSD: t_revoke.c,v 1.1 2011/07/07 06:57:54 jruoho Exp $ */ + +/*- + * Copyright (c) 2011 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jukka Ruohonen. + * + * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ +#include <sys/cdefs.h> +__RCSID("$NetBSD: t_revoke.c,v 1.1 2011/07/07 06:57:54 jruoho Exp $"); + +#include <sys/resource.h> +#include <sys/wait.h> + +#include <atf-c.h> +#include <fcntl.h> +#include <errno.h> +#include <pwd.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +static const char path[] = "revoke"; + +ATF_TC_WITH_CLEANUP(revoke_basic); +ATF_TC_HEAD(revoke_basic, tc) +{ + atf_tc_set_md_var(tc, "descr", "A basic test of revoke(2)"); +} + +ATF_TC_BODY(revoke_basic, tc) +{ + struct rlimit res; + char tmp[10]; + size_t i, n; + int *buf; + + (void)memset(&res, 0, sizeof(struct rlimit)); + (void)getrlimit(RLIMIT_NOFILE, &res); + + if ((n = res.rlim_cur / 10) == 0) + n = 10; + + buf = calloc(n, sizeof(int)); + ATF_REQUIRE(buf != NULL); + + buf[0] = open(path, O_RDWR | O_CREAT, 0600); + ATF_REQUIRE(buf[0] >= 0); + + for (i = 1; i < n; i++) { + buf[i] = open(path, O_RDWR); + ATF_REQUIRE(buf[i] >= 0); + } + + ATF_REQUIRE(revoke(path) == 0); + + for (i = 0; i < n; i++) { + + ATF_REQUIRE(read(buf[i], tmp, sizeof(tmp)) == -1); + + (void)close(buf[i]); + } + + free(buf); + + (void)unlink(path); +} + +ATF_TC_CLEANUP(revoke_basic, tc) +{ + (void)unlink(path); +} + +ATF_TC(revoke_err); +ATF_TC_HEAD(revoke_err, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test errors from revoke(2)"); + atf_tc_set_md_var(tc, "require.user", "unprivileged"); +} + +ATF_TC_BODY(revoke_err, tc) +{ + char buf[1024 + 1]; /* XXX: From the manual page... */ + + (void)memset(buf, 'x', sizeof(buf)); + + errno = 0; + ATF_REQUIRE_ERRNO(EFAULT, revoke((char *)-1) == -1); + + errno = 0; + ATF_REQUIRE_ERRNO(ENAMETOOLONG, revoke(buf) == -1); + + errno = 0; + ATF_REQUIRE_ERRNO(EPERM, revoke("/etc/passwd") == -1); + + errno = 0; + ATF_REQUIRE_ERRNO(ENOENT, revoke("/etc/xxx/yyy") == -1); +} + +ATF_TC_WITH_CLEANUP(revoke_perm); +ATF_TC_HEAD(revoke_perm, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test permissions revoke(2)"); + atf_tc_set_md_var(tc, "require.user", "root"); +} + +ATF_TC_BODY(revoke_perm, tc) +{ + struct passwd *pw; + int fd, sta; + pid_t pid; + + pw = getpwnam("nobody"); + fd = open(path, O_RDWR | O_CREAT, 0600); + + ATF_REQUIRE(fd >= 0); + ATF_REQUIRE(pw != NULL); + ATF_REQUIRE(revoke(path) == 0); + + pid = fork(); + ATF_REQUIRE(pid >= 0); + + if (pid == 0) { + + if (setuid(pw->pw_uid) != 0) + _exit(EXIT_FAILURE); + + errno = 0; + + if (revoke(path) == 0) + _exit(EXIT_FAILURE); + + if (errno != EACCES) + _exit(EXIT_FAILURE); + + if (close(fd) != 0) + _exit(EXIT_FAILURE); + + _exit(EXIT_SUCCESS); + } + + (void)wait(&sta); + + if (WIFEXITED(sta) == 0 || WEXITSTATUS(sta) != EXIT_SUCCESS) + atf_tc_fail("revoke(2) did not obey permissions"); + + ATF_REQUIRE(unlink(path) == 0); +} + +ATF_TC_CLEANUP(revoke_perm, tc) +{ + (void)unlink(path); +} + +ATF_TP_ADD_TCS(tp) +{ + + ATF_TP_ADD_TC(tp, revoke_basic); + ATF_TP_ADD_TC(tp, revoke_err); + ATF_TP_ADD_TC(tp, revoke_perm); + + return atf_no_error(); +} diff --git a/contrib/netbsd-tests/lib/libc/sys/t_select.c b/contrib/netbsd-tests/lib/libc/sys/t_select.c new file mode 100644 index 0000000..4316acf --- /dev/null +++ b/contrib/netbsd-tests/lib/libc/sys/t_select.c @@ -0,0 +1,215 @@ +/* $NetBSD: t_select.c,v 1.3 2012/03/18 07:00:52 jruoho Exp $ */ + +/*- + * Copyright (c) 2011 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundatiom + * by Christos Zoulas. + * + * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ + +#include <assert.h> +#include <sys/types.h> +#include <sys/select.h> +#include <sys/wait.h> +#include <err.h> +#include <stdio.h> +#include <string.h> +#include <signal.h> +#include <stdlib.h> +#include <unistd.h> +#include <errno.h> +#include <fcntl.h> + +#include <atf-c.h> + +static sig_atomic_t keep_going = 1; + +static void +sig_handler(int signum) +{ + keep_going = 0; +} + +static void +sigchld(int signum) +{ +} + +static char +xtoa(uint8_t n) +{ + static const char xarray[] = "0123456789abcdef"; + assert(n < sizeof(xarray)); + return xarray[n]; +} + +static const char * +prmask(const sigset_t *m, char *buf, size_t len) +{ + size_t j = 2; + assert(len >= 3 + sizeof(*m)); + buf[0] = '0'; + buf[1] = 'x'; +#define N(p, a) (((p) >> ((a) * 4)) & 0xf) + for (size_t i = __arraycount(m->__bits); i > 0; i--) { + uint32_t p = m->__bits[i - 1]; + for (size_t k = sizeof(p); k > 0; k--) + buf[j++] = xtoa(N(p, k - 1)); + } + buf[j] = '\0'; + return buf; +} + +static void +child(const struct timespec *ts) +{ + struct sigaction sa; + sigset_t set, oset, nset; + char obuf[sizeof(oset) + 3], nbuf[sizeof(nset) + 3]; + int fd; + + memset(&sa, 0, sizeof(sa)); + sa.sa_handler = sig_handler; + if ((fd = open("/dev/null", O_RDONLY)) == -1) + err(1, "open"); + + if (sigaction(SIGTERM, &sa, NULL) == -1) + err(1, "sigaction"); + + sigfillset(&set); + if (sigprocmask(SIG_BLOCK, &set, NULL) == -1) + err(1, "sigprocmask"); + + if (sigprocmask(SIG_BLOCK, NULL, &oset) == -1) + err(1, "sigprocmask"); + + sigemptyset(&set); + + for (;;) { + fd_set rset; + FD_ZERO(&rset); + FD_SET(fd, &rset); + if (pselect(1, &rset, NULL, NULL, ts, &set) == -1) { + if(errno == EINTR) { + if (!keep_going) + break; + } + } + if (ts) + break; + } + if (sigprocmask(SIG_BLOCK, NULL, &nset) == -1) + err(1, "sigprocmask"); + if (memcmp(&oset, &nset, sizeof(oset)) != 0) + atf_tc_fail("pselect() masks don't match " + "after timeout %s != %s", + prmask(&nset, nbuf, sizeof(nbuf)), + prmask(&oset, obuf, sizeof(obuf))); +} + +ATF_TC(pselect_sigmask); +ATF_TC_HEAD(pselect_sigmask, tc) +{ + atf_tc_set_md_var(tc, "descr", "Checks pselect's temporary mask " + "setting when a signal is received (PR lib/43625)"); +} + +ATF_TC_BODY(pselect_sigmask, tc) +{ + pid_t pid; + int status; + + signal(SIGCHLD, sigchld); + + switch (pid = fork()) { + case 0: + child(NULL); + case -1: + err(1, "fork"); + default: + sleep(1); + if (kill(pid, SIGTERM) == -1) + err(1, "kill"); + sleep(1); + switch (waitpid(pid, &status, WNOHANG)) { + case -1: + err(1, "wait"); + case 0: + if (kill(pid, SIGKILL) == -1) + err(1, "kill"); + atf_tc_fail("pselect() did not receive signal"); + break; + default: + break; + } + } +} + +ATF_TC(pselect_timeout); +ATF_TC_HEAD(pselect_timeout, tc) +{ + + atf_tc_set_md_var(tc, "descr", "Checks pselect's temporary mask " + "setting when a timeout occurs"); +} + +ATF_TC_BODY(pselect_timeout, tc) +{ + pid_t pid; + int status; + static const struct timespec zero = { 0, 0 }; + + signal(SIGCHLD, sigchld); + + switch (pid = fork()) { + case 0: + child(&zero); + break; + case -1: + err(1, "fork"); + default: + sleep(1); + switch (waitpid(pid, &status, WNOHANG)) { + case -1: + err(1, "wait"); + case 0: + if (kill(pid, SIGKILL) == -1) + err(1, "kill"); + atf_tc_fail("pselect() did not receive signal"); + break; + default: + break; + } + } +} + +ATF_TP_ADD_TCS(tp) +{ + + ATF_TP_ADD_TC(tp, pselect_sigmask); + ATF_TP_ADD_TC(tp, pselect_timeout); + + return atf_no_error(); +} diff --git a/contrib/netbsd-tests/lib/libc/sys/t_setrlimit.c b/contrib/netbsd-tests/lib/libc/sys/t_setrlimit.c new file mode 100644 index 0000000..c760cfb --- /dev/null +++ b/contrib/netbsd-tests/lib/libc/sys/t_setrlimit.c @@ -0,0 +1,522 @@ +/* $NetBSD: t_setrlimit.c,v 1.4 2012/06/12 23:56:19 christos Exp $ */ + +/*- + * Copyright (c) 2011 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jukka Ruohonen. + * + * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ +#include <sys/cdefs.h> +__RCSID("$NetBSD: t_setrlimit.c,v 1.4 2012/06/12 23:56:19 christos Exp $"); + +#include <sys/resource.h> +#include <sys/mman.h> +#include <sys/wait.h> + +#include <atf-c.h> +#include <errno.h> +#include <fcntl.h> +#include <limits.h> +#include <lwp.h> +#include <signal.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <ucontext.h> +#include <unistd.h> + +static void sighandler(int); +static const char path[] = "setrlimit"; + +static const int rlimit[] = { + RLIMIT_AS, + RLIMIT_CORE, + RLIMIT_CPU, + RLIMIT_DATA, + RLIMIT_FSIZE, + RLIMIT_MEMLOCK, + RLIMIT_NOFILE, + RLIMIT_NPROC, + RLIMIT_RSS, + RLIMIT_SBSIZE, + RLIMIT_STACK +}; + +ATF_TC(setrlimit_basic); +ATF_TC_HEAD(setrlimit_basic, tc) +{ + atf_tc_set_md_var(tc, "descr", "A basic soft limit test"); +} + +ATF_TC_BODY(setrlimit_basic, tc) +{ + struct rlimit res; + int *buf, lim; + size_t i; + + buf = calloc(__arraycount(rlimit), sizeof(int)); + + if (buf == NULL) + atf_tc_fail("initialization failed"); + + for (i = lim = 0; i < __arraycount(rlimit); i++) { + + (void)memset(&res, 0, sizeof(struct rlimit)); + + if (getrlimit(rlimit[i], &res) != 0) + continue; + + if (res.rlim_cur == RLIM_INFINITY || res.rlim_cur == 0) + continue; + + if (res.rlim_cur == res.rlim_max) /* An unprivileged run. */ + continue; + + buf[i] = res.rlim_cur; + res.rlim_cur = res.rlim_cur - 1; + + if (setrlimit(rlimit[i], &res) != 0) { + lim = rlimit[i]; + goto out; + } + } + +out: + for (i = 0; i < __arraycount(rlimit); i++) { + + (void)memset(&res, 0, sizeof(struct rlimit)); + + if (buf[i] == 0) + continue; + + if (getrlimit(rlimit[i], &res) != 0) + continue; + + res.rlim_cur = buf[i]; + + (void)setrlimit(rlimit[i], &res); + } + + if (lim != 0) + atf_tc_fail("failed to set limit (%d)", lim); +} + +ATF_TC(setrlimit_current); +ATF_TC_HEAD(setrlimit_current, tc) +{ + atf_tc_set_md_var(tc, "descr", "setrlimit(3) with current limits"); +} + +ATF_TC_BODY(setrlimit_current, tc) +{ + struct rlimit res; + size_t i; + + for (i = 0; i < __arraycount(rlimit); i++) { + + (void)memset(&res, 0, sizeof(struct rlimit)); + + ATF_REQUIRE(getrlimit(rlimit[i], &res) == 0); + ATF_REQUIRE(setrlimit(rlimit[i], &res) == 0); + } +} + +ATF_TC(setrlimit_err); +ATF_TC_HEAD(setrlimit_err, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test error conditions"); +} + +ATF_TC_BODY(setrlimit_err, tc) +{ + struct rlimit res; + size_t i; + + for (i = 0; i < __arraycount(rlimit); i++) { + + errno = 0; + + ATF_REQUIRE(getrlimit(rlimit[i], (void *)0) != 0); + ATF_REQUIRE(errno == EFAULT); + } + + errno = 0; + + ATF_REQUIRE(getrlimit(INT_MAX, &res) != 0); + ATF_REQUIRE(errno == EINVAL); +} + +ATF_TC_WITH_CLEANUP(setrlimit_fsize); +ATF_TC_HEAD(setrlimit_fsize, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test setrlimit(2), RLIMIT_FSIZE"); +} + +ATF_TC_BODY(setrlimit_fsize, tc) +{ + struct rlimit res; + int fd, sta; + pid_t pid; + + fd = open(path, O_RDWR | O_CREAT, 0700); + + if (fd < 0) + atf_tc_fail("initialization failed"); + + pid = fork(); + ATF_REQUIRE(pid >= 0); + + if (pid == 0) { + + res.rlim_cur = 2; + res.rlim_max = 2; + + if (setrlimit(RLIMIT_FSIZE, &res) != 0) + _exit(EXIT_FAILURE); + + if (signal(SIGXFSZ, sighandler) == SIG_ERR) + _exit(EXIT_FAILURE); + + /* + * The third call should generate a SIGXFSZ. + */ + (void)write(fd, "X", 1); + (void)write(fd, "X", 1); + (void)write(fd, "X", 1); + + _exit(EXIT_FAILURE); + } + + (void)close(fd); + (void)wait(&sta); + (void)unlink(path); + + if (WIFEXITED(sta) == 0 || WEXITSTATUS(sta) != EXIT_SUCCESS) + atf_tc_fail("RLIMIT_FSIZE not enforced"); +} + +ATF_TC_CLEANUP(setrlimit_fsize, tc) +{ + (void)unlink(path); +} + +static void +sighandler(int signo) +{ + + if (signo != SIGXFSZ) + _exit(EXIT_FAILURE); + + _exit(EXIT_SUCCESS); +} + +ATF_TC(setrlimit_memlock); +ATF_TC_HEAD(setrlimit_memlock, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test setrlimit(2), RLIMIT_MEMLOCK"); +} + +ATF_TC_BODY(setrlimit_memlock, tc) +{ + struct rlimit res; + void *buf; + long page; + pid_t pid; + int sta; + + page = sysconf(_SC_PAGESIZE); + ATF_REQUIRE(page >= 0); + + buf = malloc(page); + pid = fork(); + + if (buf == NULL || pid < 0) + atf_tc_fail("initialization failed"); + + if (pid == 0) { + + /* + * Try to lock a page while + * RLIMIT_MEMLOCK is zero. + */ + if (mlock(buf, page) != 0) + _exit(EXIT_FAILURE); + + if (munlock(buf, page) != 0) + _exit(EXIT_FAILURE); + + res.rlim_cur = 0; + res.rlim_max = 0; + + if (setrlimit(RLIMIT_MEMLOCK, &res) != 0) + _exit(EXIT_FAILURE); + + if (mlock(buf, page) != 0) + _exit(EXIT_SUCCESS); + + (void)munlock(buf, page); + + _exit(EXIT_FAILURE); + } + + free(buf); + + (void)wait(&sta); + + if (WIFEXITED(sta) == 0 || WEXITSTATUS(sta) != EXIT_SUCCESS) + atf_tc_fail("RLIMIT_MEMLOCK not enforced"); +} + +ATF_TC(setrlimit_nofile_1); +ATF_TC_HEAD(setrlimit_nofile_1, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test setrlimit(2), RLIMIT_NOFILE, #1"); +} + +ATF_TC_BODY(setrlimit_nofile_1, tc) +{ + struct rlimit res; + int fd, i, rv, sta; + pid_t pid; + + res.rlim_cur = 0; + res.rlim_max = 0; + + pid = fork(); + ATF_REQUIRE(pid >= 0); + + if (pid == 0) { + + /* + * Close all descriptors, set RLIMIT_NOFILE + * to zero, and try to open a random file. + * This should fail with EMFILE. + */ + for (i = 0; i < 1024; i++) + (void)close(i); + + rv = setrlimit(RLIMIT_NOFILE, &res); + + if (rv != 0) + _exit(EXIT_FAILURE); + + errno = 0; + fd = open("/etc/passwd", O_RDONLY); + + if (fd >= 0 || errno != EMFILE) + _exit(EXIT_FAILURE); + + _exit(EXIT_SUCCESS); + } + + (void)wait(&sta); + + if (WIFEXITED(sta) == 0 || WEXITSTATUS(sta) != EXIT_SUCCESS) + atf_tc_fail("RLIMIT_NOFILE not enforced"); +} + +ATF_TC(setrlimit_nofile_2); +ATF_TC_HEAD(setrlimit_nofile_2, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test setrlimit(2), RLIMIT_NOFILE, #2"); +} + +ATF_TC_BODY(setrlimit_nofile_2, tc) +{ + static const rlim_t lim = 12; + struct rlimit res; + int fd, i, rv, sta; + pid_t pid; + + /* + * See that an arbitrary limit on + * open files is being enforced. + */ + res.rlim_cur = lim; + res.rlim_max = lim; + + pid = fork(); + ATF_REQUIRE(pid >= 0); + + if (pid == 0) { + + for (i = 0; i < 1024; i++) + (void)close(i); + + rv = setrlimit(RLIMIT_NOFILE, &res); + + if (rv != 0) + _exit(EXIT_FAILURE); + + for (i = 0; i < (int)lim; i++) { + + fd = open("/etc/passwd", O_RDONLY); + + if (fd < 0) + _exit(EXIT_FAILURE); + } + + /* + * After the limit has been reached, + * EMFILE should again follow. + */ + fd = open("/etc/passwd", O_RDONLY); + + if (fd >= 0 || errno != EMFILE) + _exit(EXIT_FAILURE); + + _exit(EXIT_SUCCESS); + } + + (void)wait(&sta); + + if (WIFEXITED(sta) == 0 || WEXITSTATUS(sta) != EXIT_SUCCESS) + atf_tc_fail("RLIMIT_NOFILE not enforced"); +} + +ATF_TC(setrlimit_nproc); +ATF_TC_HEAD(setrlimit_nproc, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test setrlimit(2), RLIMIT_NPROC"); + atf_tc_set_md_var(tc, "require.user", "unprivileged"); +} + +ATF_TC_BODY(setrlimit_nproc, tc) +{ + struct rlimit res; + pid_t pid, cpid; + int sta; + + pid = fork(); + ATF_REQUIRE(pid >= 0); + + if (pid == 0) { + + /* + * Set RLIMIT_NPROC to zero and try to fork. + */ + res.rlim_cur = 0; + res.rlim_max = 0; + + if (setrlimit(RLIMIT_NPROC, &res) != 0) + _exit(EXIT_FAILURE); + + cpid = fork(); + + if (cpid < 0) + _exit(EXIT_SUCCESS); + + _exit(EXIT_FAILURE); + } + + (void)waitpid(pid, &sta, 0); + + if (WIFEXITED(sta) == 0 || WEXITSTATUS(sta) != EXIT_SUCCESS) + atf_tc_fail("RLIMIT_NPROC not enforced"); +} + +ATF_TC(setrlimit_nthr); +ATF_TC_HEAD(setrlimit_nthr, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test setrlimit(2), RLIMIT_NTHR"); + atf_tc_set_md_var(tc, "require.user", "unprivileged"); +} + +static void +func(lwpid_t *id) +{ + printf("thread %d\n", *id); + fflush(stdout); + _lwp_exit(); +} + +ATF_TC_BODY(setrlimit_nthr, tc) +{ + struct rlimit res; + lwpid_t lwpid; + ucontext_t c; + + /* + * Set RLIMIT_NTHR to zero and try to create a thread. + */ + res.rlim_cur = 0; + res.rlim_max = 0; + ATF_REQUIRE(setrlimit(RLIMIT_NTHR, &res) == 0); + ATF_REQUIRE(getcontext(&c) == 0); + c.uc_link = NULL; + sigemptyset(&c.uc_sigmask); + c.uc_stack.ss_flags = 0; + c.uc_stack.ss_size = 4096; + ATF_REQUIRE((c.uc_stack.ss_sp = malloc(c.uc_stack.ss_size)) != NULL); + makecontext(&c, func, 1, &lwpid); + ATF_CHECK_ERRNO(EAGAIN, _lwp_create(&c, 0, &lwpid) == -1); +} + +ATF_TC(setrlimit_perm); +ATF_TC_HEAD(setrlimit_perm, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test setrlimit(2) for EPERM"); + atf_tc_set_md_var(tc, "require.user", "unprivileged"); +} + +ATF_TC_BODY(setrlimit_perm, tc) +{ + struct rlimit res; + size_t i; + + /* + * Try to raise the maximum limits as an user. + */ + for (i = 0; i < __arraycount(rlimit); i++) { + + ATF_REQUIRE(getrlimit(rlimit[i], &res) == 0); + + if (res.rlim_max == UINT64_MAX) /* Overflow. */ + continue; + + errno = 0; + res.rlim_max = res.rlim_max + 1; + + ATF_CHECK_ERRNO(EPERM, setrlimit(rlimit[i], &res) != 0); + } +} + +ATF_TP_ADD_TCS(tp) +{ + + ATF_TP_ADD_TC(tp, setrlimit_basic); + ATF_TP_ADD_TC(tp, setrlimit_current); + ATF_TP_ADD_TC(tp, setrlimit_err); + ATF_TP_ADD_TC(tp, setrlimit_fsize); + ATF_TP_ADD_TC(tp, setrlimit_memlock); + ATF_TP_ADD_TC(tp, setrlimit_nofile_1); + ATF_TP_ADD_TC(tp, setrlimit_nofile_2); + ATF_TP_ADD_TC(tp, setrlimit_nproc); + ATF_TP_ADD_TC(tp, setrlimit_perm); + ATF_TP_ADD_TC(tp, setrlimit_nthr); + + return atf_no_error(); +} diff --git a/contrib/netbsd-tests/lib/libc/sys/t_setuid.c b/contrib/netbsd-tests/lib/libc/sys/t_setuid.c new file mode 100644 index 0000000..d2bf523 --- /dev/null +++ b/contrib/netbsd-tests/lib/libc/sys/t_setuid.c @@ -0,0 +1,122 @@ +/* $NetBSD: t_setuid.c,v 1.1 2011/07/07 06:57:54 jruoho Exp $ */ + +/*- + * Copyright (c) 2011 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jukka Ruohonen. + * + * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ +#include <sys/cdefs.h> +__RCSID("$NetBSD: t_setuid.c,v 1.1 2011/07/07 06:57:54 jruoho Exp $"); + +#include <sys/wait.h> + +#include <atf-c.h> +#include <errno.h> +#include <pwd.h> +#include <stdlib.h> +#include <unistd.h> + +ATF_TC(setuid_perm); +ATF_TC_HEAD(setuid_perm, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test setuid(0) as normal user"); + atf_tc_set_md_var(tc, "require.user", "unprivileged"); +} + +ATF_TC_BODY(setuid_perm, tc) +{ + errno = 0; + + ATF_REQUIRE(setuid(0) == -1); + ATF_REQUIRE(errno == EPERM); +} + +ATF_TC(setuid_real); +ATF_TC_HEAD(setuid_real, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test setuid(2) with real UID"); +} + +ATF_TC_BODY(setuid_real, tc) +{ + uid_t uid = getuid(); + + ATF_REQUIRE(setuid(uid) == 0); + + ATF_REQUIRE(getuid() == uid); + ATF_REQUIRE(geteuid() == uid); +} + +ATF_TC(setuid_root); +ATF_TC_HEAD(setuid_root, tc) +{ + atf_tc_set_md_var(tc, "descr", "A basic test of setuid(2)"); + atf_tc_set_md_var(tc, "require.user", "root"); +} + +ATF_TC_BODY(setuid_root, tc) +{ + struct passwd *pw; + int rv, sta; + pid_t pid; + uid_t uid; + + while ((pw = getpwent()) != NULL) { + + pid = fork(); + ATF_REQUIRE(pid >= 0); + + if (pid == 0) { + + rv = setuid(pw->pw_uid); + + if (rv != 0) + _exit(EXIT_FAILURE); + + uid = getuid(); + + if (uid != pw->pw_uid) + _exit(EXIT_FAILURE); + + _exit(EXIT_SUCCESS); + } + + (void)wait(&sta); + + if (WIFEXITED(sta) == 0 || WEXITSTATUS(sta) != EXIT_SUCCESS) + atf_tc_fail("failed to change UID to %u", pw->pw_uid); + } +} + +ATF_TP_ADD_TCS(tp) +{ + + ATF_TP_ADD_TC(tp, setuid_perm); + ATF_TP_ADD_TC(tp, setuid_real); + ATF_TP_ADD_TC(tp, setuid_root); + + return atf_no_error(); +} diff --git a/contrib/netbsd-tests/lib/libc/sys/t_sigaction.c b/contrib/netbsd-tests/lib/libc/sys/t_sigaction.c new file mode 100644 index 0000000..8022353 --- /dev/null +++ b/contrib/netbsd-tests/lib/libc/sys/t_sigaction.c @@ -0,0 +1,154 @@ +/* $NetBSD: t_sigaction.c,v 1.2 2012/11/07 16:51:16 pgoyette Exp $ */ + +/*- + * Copyright (c) 2010 The NetBSD Foundation, 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ + +#include <sys/cdefs.h> +__COPYRIGHT("@(#) Copyright (c) 2010\ + The NetBSD Foundation, inc. All rights reserved."); +__RCSID("$NetBSD: t_sigaction.c,v 1.2 2012/11/07 16:51:16 pgoyette Exp $"); + +#include <sys/wait.h> + +#include <signal.h> +#include <stdbool.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include <atf-c.h> +#include <atf-c/config.h> + +#include "../../../h_macros.h" + +static bool handler_called = false; + +static void +handler(int signo) +{ + handler_called = true; +} + +static void +sa_resethand_child(const int flags) +{ + struct sigaction sa; + + sa.sa_flags = flags; + sa.sa_handler = &handler; + sigemptyset(&sa.sa_mask); + + sigaction(SIGUSR1, &sa, NULL); + kill(getpid(), SIGUSR1); + exit(handler_called ? EXIT_SUCCESS : EXIT_FAILURE); +} + +static void +wait_and_check_child(const pid_t pid, const char *fail_message) +{ + int status; + + (void)waitpid(pid, &status, 0); + + if (WIFEXITED(status)) + ATF_CHECK_EQ(EXIT_SUCCESS, WEXITSTATUS(status)); + else + atf_tc_fail("%s; raw exit status was %d", fail_message, status); +} + +static void +catch(int sig) +{ + return; +} + +ATF_TC(sigaction_basic); +ATF_TC_HEAD(sigaction_basic, tc) +{ + + atf_tc_set_md_var(tc, "descr", "Checks for correct I&D cache" + "synchronization after copying out the trampoline code."); +} + +ATF_TC_BODY(sigaction_basic, tc) +{ + static struct sigaction sa; + + sa.sa_handler = catch; + + sigaction(SIGUSR1, &sa, 0); + kill(getpid(), SIGUSR1); + atf_tc_pass(); +} + +ATF_TC(sigaction_noflags); +ATF_TC_HEAD(sigaction_noflags, tc) +{ + atf_tc_set_md_var(tc, "descr", "Checks programming a signal with " + "sigaction(2) but without any flags"); +} + +ATF_TC_BODY(sigaction_noflags, tc) +{ + const pid_t pid = fork(); + if (pid == -1) + atf_tc_fail_errno("fork(2) failed"); + else if (pid == 0) + sa_resethand_child(0); + else + wait_and_check_child(pid, "Child process did not exit cleanly;" + " it failed to process the signal"); +} + +ATF_TC(sigaction_resethand); +ATF_TC_HEAD(sigaction_resethand, tc) +{ + atf_tc_set_md_var(tc, "descr", "Checks that SA_RESETHAND works"); +} + +ATF_TC_BODY(sigaction_resethand, tc) +{ + const pid_t pid = fork(); + if (pid == -1) + atf_tc_fail_errno("fork(2) failed"); + else if (pid == 0) + sa_resethand_child(SA_RESETHAND); + else { + wait_and_check_child(pid, "Child process did not exit cleanly;" + " it either failed to process the signal or SA_RESETHAND" + " is broken"); + } +} + +ATF_TP_ADD_TCS(tp) +{ + + ATF_TP_ADD_TC(tp, sigaction_basic); + ATF_TP_ADD_TC(tp, sigaction_noflags); + ATF_TP_ADD_TC(tp, sigaction_resethand); + + return atf_no_error(); +} diff --git a/contrib/netbsd-tests/lib/libc/sys/t_sigqueue.c b/contrib/netbsd-tests/lib/libc/sys/t_sigqueue.c new file mode 100644 index 0000000..f9e0c63 --- /dev/null +++ b/contrib/netbsd-tests/lib/libc/sys/t_sigqueue.c @@ -0,0 +1,103 @@ +/* $NetBSD: t_sigqueue.c,v 1.4 2011/07/07 16:31:11 jruoho Exp $ */ + +/*- + * Copyright (c) 2011 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Christos Zoulas. + * + * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ + +#include <sys/cdefs.h> +__RCSID("$NetBSD: t_sigqueue.c,v 1.4 2011/07/07 16:31:11 jruoho Exp $"); + + +#include <atf-c.h> +#include <errno.h> +#include <signal.h> +#include <stdlib.h> +#include <sched.h> +#include <unistd.h> + +static void handler(int, siginfo_t *, void *); + +#define VALUE (int)0xc001dad1 +static int value; + +static void +handler(int signo, siginfo_t *info, void *data) +{ + value = info->si_value.sival_int; + kill(0, SIGINFO); +} + +ATF_TC(sigqueue_basic); +ATF_TC_HEAD(sigqueue_basic, tc) +{ + atf_tc_set_md_var(tc, "descr", "Checks sigqueue(3) sigval delivery"); +} + +ATF_TC_BODY(sigqueue_basic, tc) +{ + struct sigaction sa; + union sigval sv; + + sa.sa_sigaction = handler; + sigemptyset(&sa.sa_mask); + sa.sa_flags = SA_SIGINFO; + + if (sigaction(SIGUSR1, &sa, NULL) != 0) + atf_tc_fail("sigaction failed"); + + sv.sival_int = VALUE; + + if (sigqueue(0, SIGUSR1, sv) != 0) + atf_tc_fail("sigqueue failed"); + + sched_yield(); + ATF_REQUIRE_EQ(sv.sival_int, value); +} + +ATF_TC(sigqueue_err); +ATF_TC_HEAD(sigqueue_err, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test errors from sigqueue(3)"); +} + +ATF_TC_BODY(sigqueue_err, tc) +{ + union sigval sv; + + errno = 0; + ATF_REQUIRE_ERRNO(EINVAL, sigqueue(getpid(), -1, sv) == -1); +} + +ATF_TP_ADD_TCS(tp) +{ + + ATF_TP_ADD_TC(tp, sigqueue_basic); + ATF_TP_ADD_TC(tp, sigqueue_err); + + return atf_no_error(); +} diff --git a/contrib/netbsd-tests/lib/libc/sys/t_sigtimedwait.c b/contrib/netbsd-tests/lib/libc/sys/t_sigtimedwait.c new file mode 100644 index 0000000..64b68d9 --- /dev/null +++ b/contrib/netbsd-tests/lib/libc/sys/t_sigtimedwait.c @@ -0,0 +1,126 @@ +/* $NetBSD: t_sigtimedwait.c,v 1.2 2013/03/08 23:18:00 martin Exp $ */ + +/*- + * Copyright (c) 2011 The NetBSD Foundation, 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ + +#include <sys/cdefs.h> +__RCSID("$NetBSD: t_sigtimedwait.c,v 1.2 2013/03/08 23:18:00 martin Exp $"); + +#include <sys/time.h> +#include <errno.h> +#include <signal.h> +#include <stdio.h> +#include <string.h> +#include <atf-c.h> + + +ATF_TC(sigtimedwait_all0timeout); + +ATF_TC_HEAD(sigtimedwait_all0timeout, tc) +{ + atf_tc_set_md_var(tc, "timeout", "10"); + atf_tc_set_md_var(tc, "descr", "Test for PR kern/47625: sigtimedwait" + " with a timeout value of all zero should return imediately"); +} + +ATF_TC_BODY(sigtimedwait_all0timeout, tc) +{ + sigset_t block; + struct timespec ts, before, after, len; + siginfo_t info; + int r; + + sigemptyset(&block); + ts.tv_sec = 0; + ts.tv_nsec = 0; + clock_gettime(CLOCK_MONOTONIC, &before); + r = sigtimedwait(&block, &info, &ts); + clock_gettime(CLOCK_MONOTONIC, &after); + ATF_REQUIRE(r == -1); + ATF_REQUIRE_ERRNO(EAGAIN, errno); + timespecsub(&after, &before, &len); + ATF_REQUIRE(len.tv_sec < 1); +} + +ATF_TC(sigtimedwait_NULL_timeout); + +ATF_TC_HEAD(sigtimedwait_NULL_timeout, tc) +{ + atf_tc_set_md_var(tc, "timeout", "10"); + atf_tc_set_md_var(tc, "descr", "Test sigtimedwait() without timeout"); +} + +ATF_TC_BODY(sigtimedwait_NULL_timeout, tc) +{ + sigset_t sig; + siginfo_t info; + struct itimerval it; + int r; + + /* arrange for a SIGALRM signal in a few seconds */ + memset(&it, 0, sizeof it); + it.it_value.tv_sec = 5; + ATF_REQUIRE(setitimer(ITIMER_REAL, &it, NULL) == 0); + + /* wait without timeout */ + sigemptyset(&sig); + sigaddset(&sig, SIGALRM); + r = sigtimedwait(&sig, &info, NULL); + ATF_REQUIRE(r == SIGALRM); +} + +ATF_TC(sigtimedwait_small_timeout); + +ATF_TC_HEAD(sigtimedwait_small_timeout, tc) +{ + atf_tc_set_md_var(tc, "timeout", "15"); + atf_tc_set_md_var(tc, "descr", "Test sigtimedwait with a small " + "timeout"); +} + +ATF_TC_BODY(sigtimedwait_small_timeout, tc) +{ + sigset_t block; + struct timespec ts; + siginfo_t info; + int r; + + sigemptyset(&block); + ts.tv_sec = 5; + ts.tv_nsec = 0; + r = sigtimedwait(&block, &info, &ts); + ATF_REQUIRE(r == -1); + ATF_REQUIRE_ERRNO(EAGAIN, errno); +} + +ATF_TP_ADD_TCS(tp) +{ + ATF_TP_ADD_TC(tp, sigtimedwait_all0timeout); + ATF_TP_ADD_TC(tp, sigtimedwait_NULL_timeout); + ATF_TP_ADD_TC(tp, sigtimedwait_small_timeout); + + return atf_no_error(); +} diff --git a/contrib/netbsd-tests/lib/libc/sys/t_socketpair.c b/contrib/netbsd-tests/lib/libc/sys/t_socketpair.c new file mode 100644 index 0000000..532629c3 --- /dev/null +++ b/contrib/netbsd-tests/lib/libc/sys/t_socketpair.c @@ -0,0 +1,137 @@ +/* $NetBSD: t_socketpair.c,v 1.1 2011/11/05 18:19:02 jruoho Exp $ */ + +/*- + * Copyright (c) 2011 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Christos Zoulas. + * + * 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ +#include <sys/cdefs.h> +__RCSID("$NetBSD: t_socketpair.c,v 1.1 2011/11/05 18:19:02 jruoho Exp $"); + +#include <atf-c.h> +#include <fcntl.h> +#include <unistd.h> +#include <stdlib.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <errno.h> + +static void +connected(int fd) +{ + struct sockaddr_un addr; + socklen_t len = (socklen_t)sizeof(addr); + ATF_REQUIRE(getpeername(fd, (struct sockaddr*)(void *)&addr, + &len) == 0); +} + +static void +run(int flags) +{ + int fd[2], i; + + while ((i = open("/", O_RDONLY)) < 3) + ATF_REQUIRE(i != -1); + + ATF_REQUIRE(fcntl(3, F_CLOSEM) != -1); + + ATF_REQUIRE(socketpair(AF_UNIX, SOCK_DGRAM | flags, 0, fd) == 0); + + ATF_REQUIRE(fd[0] == 3); + ATF_REQUIRE(fd[1] == 4); + + connected(fd[0]); + connected(fd[1]); + + if (flags & SOCK_CLOEXEC) { + ATF_REQUIRE((fcntl(fd[0], F_GETFD) & FD_CLOEXEC) != 0); + ATF_REQUIRE((fcntl(fd[1], F_GETFD) & FD_CLOEXEC) != 0); + } else { + ATF_REQUIRE((fcntl(fd[0], F_GETFD) & FD_CLOEXEC) == 0); + ATF_REQUIRE((fcntl(fd[1], F_GETFD) & FD_CLOEXEC) == 0); + } + + if (flags & SOCK_NONBLOCK) { + ATF_REQUIRE((fcntl(fd[0], F_GETFL) & O_NONBLOCK) != 0); + ATF_REQUIRE((fcntl(fd[1], F_GETFL) & O_NONBLOCK) != 0); + } else { + ATF_REQUIRE((fcntl(fd[0], F_GETFL) & O_NONBLOCK) == 0); + ATF_REQUIRE((fcntl(fd[1], F_GETFL) & O_NONBLOCK) == 0); + } + + ATF_REQUIRE(close(fd[0]) != -1); + ATF_REQUIRE(close(fd[1]) != -1); +} + +ATF_TC(socketpair_basic); +ATF_TC_HEAD(socketpair_basic, tc) +{ + atf_tc_set_md_var(tc, "descr", "A basic test of socketpair(2)"); +} + +ATF_TC_BODY(socketpair_basic, tc) +{ + run(0); +} + +ATF_TC(socketpair_nonblock); +ATF_TC_HEAD(socketpair_nonblock, tc) +{ + atf_tc_set_md_var(tc, "descr", "A non-blocking test of socketpair(2)"); +} + +ATF_TC_BODY(socketpair_nonblock, tc) +{ + run(SOCK_NONBLOCK); +} + +ATF_TC(socketpair_cloexec); +ATF_TC_HEAD(socketpair_cloexec, tc) +{ + atf_tc_set_md_var(tc, "descr", "A close-on-exec of socketpair(2)"); +} + +ATF_TC_BODY(socketpair_cloexec, tc) +{ + run(SOCK_CLOEXEC); +} + +ATF_TP_ADD_TCS(tp) +{ + + ATF_TP_ADD_TC(tp, socketpair_basic); + ATF_TP_ADD_TC(tp, socketpair_nonblock); + ATF_TP_ADD_TC(tp, socketpair_cloexec); + + return atf_no_error(); +} diff --git a/contrib/netbsd-tests/lib/libc/sys/t_stat.c b/contrib/netbsd-tests/lib/libc/sys/t_stat.c new file mode 100644 index 0000000..0312e2f --- /dev/null +++ b/contrib/netbsd-tests/lib/libc/sys/t_stat.c @@ -0,0 +1,417 @@ +/* $NetBSD: t_stat.c,v 1.4 2012/03/17 08:37:08 jruoho Exp $ */ + +/*- + * Copyright (c) 2011 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jukka Ruohonen. + * + * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ +#include <sys/cdefs.h> +__RCSID("$NetBSD: t_stat.c,v 1.4 2012/03/17 08:37:08 jruoho Exp $"); + +#include <sys/stat.h> +#include <sys/socket.h> +#include <sys/types.h> + +#include <arpa/inet.h> + +#include <atf-c.h> +#include <errno.h> +#include <fcntl.h> +#include <fts.h> +#include <limits.h> +#include <string.h> +#include <unistd.h> + +#include <stdio.h> + +static const char *path = "stat"; + +ATF_TC_WITH_CLEANUP(stat_chflags); +ATF_TC_HEAD(stat_chflags, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test chflags(2) with stat(2)"); +} + +ATF_TC_BODY(stat_chflags, tc) +{ + struct stat sa, sb; + int fd; + + (void)memset(&sa, 0, sizeof(struct stat)); + (void)memset(&sb, 0, sizeof(struct stat)); + + fd = open(path, O_RDONLY | O_CREAT); + + ATF_REQUIRE(fd != -1); + ATF_REQUIRE(stat(path, &sa) == 0); + ATF_REQUIRE(chflags(path, UF_NODUMP) == 0); + ATF_REQUIRE(stat(path, &sb) == 0); + + if (sa.st_flags == sb.st_flags) + atf_tc_fail("stat(2) did not detect chflags(2)"); + + ATF_REQUIRE(close(fd) == 0); + ATF_REQUIRE(unlink(path) == 0); +} + +ATF_TC_CLEANUP(stat_chflags, tc) +{ + (void)unlink(path); +} + +ATF_TC(stat_dir); +ATF_TC_HEAD(stat_dir, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test stat(2) with directories"); +} + +ATF_TC_BODY(stat_dir, tc) +{ + const short depth = 2; + struct stat sa, sb; + char *argv[2]; + FTSENT *ftse; + FTS *fts; + int ops; + + argv[1] = NULL; + argv[0] = __UNCONST("/"); + + ops = FTS_NOCHDIR; + ops |= FTS_PHYSICAL; + + fts = fts_open(argv, ops, NULL); + ATF_REQUIRE(fts != NULL); + + while ((ftse = fts_read(fts)) != NULL) { + + if (ftse->fts_level < 1) + continue; + + if (ftse->fts_level > depth) { + (void)fts_set(fts, ftse, FTS_SKIP); + continue; + } + + switch(ftse->fts_info) { + + case FTS_DP: + + (void)memset(&sa, 0, sizeof(struct stat)); + (void)memset(&sb, 0, sizeof(struct stat)); + + ATF_REQUIRE(stat(ftse->fts_parent->fts_path,&sa) == 0); + ATF_REQUIRE(chdir(ftse->fts_path) == 0); + ATF_REQUIRE(stat(".", &sb) == 0); + + /* + * The previous two stat(2) calls + * should be for the same directory. + */ + if (sa.st_dev != sb.st_dev || sa.st_ino != sb.st_ino) + atf_tc_fail("inconsistent stat(2)"); + + /* + * Check that fts(3)'s stat(2) + * call equals the manual one. + */ + if (sb.st_ino != ftse->fts_statp->st_ino) + atf_tc_fail("stat(2) and fts(3) differ"); + + break; + + default: + break; + } + } + + (void)fts_close(fts); +} + +ATF_TC(stat_err); +ATF_TC_HEAD(stat_err, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test errors from the stat(2) family"); +} + +ATF_TC_BODY(stat_err, tc) +{ + char buf[NAME_MAX + 1]; + struct stat st; + + (void)memset(buf, 'x', sizeof(buf)); + + errno = 0; + ATF_REQUIRE_ERRNO(EBADF, fstat(-1, &st) == -1); + + errno = 0; + ATF_REQUIRE_ERRNO(ENAMETOOLONG, stat(buf, &st) == -1); + + errno = 0; + ATF_REQUIRE_ERRNO(ENAMETOOLONG, lstat(buf, &st) == -1); + + errno = 0; + ATF_REQUIRE_ERRNO(EFAULT, stat((void *)-1, &st) == -1); + + errno = 0; + ATF_REQUIRE_ERRNO(EFAULT, lstat((void *)-1, &st) == -1); + + errno = 0; + ATF_REQUIRE_ERRNO(EFAULT, stat("/etc/passwd", (void *)-1) == -1); + + errno = 0; + ATF_REQUIRE_ERRNO(EFAULT, lstat("/etc/passwd", (void *)-1) == -1); + + errno = 0; + ATF_REQUIRE_ERRNO(ENOENT, stat("/a/b/c/d/e/f/g/h/i/j/k", &st) == -1); + + errno = 0; + ATF_REQUIRE_ERRNO(ENOENT, lstat("/a/b/c/d/e/f/g/h/i/j/k", &st) == -1); +} + +ATF_TC_WITH_CLEANUP(stat_mtime); +ATF_TC_HEAD(stat_mtime, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test modification times with stat(2)"); +} + +ATF_TC_BODY(stat_mtime, tc) +{ + struct stat sa, sb; + int fd[3]; + size_t i; + + for (i = 0; i < __arraycount(fd); i++) { + + (void)memset(&sa, 0, sizeof(struct stat)); + (void)memset(&sb, 0, sizeof(struct stat)); + + fd[i] = open(path, O_WRONLY | O_CREAT); + + ATF_REQUIRE(fd[i] != -1); + ATF_REQUIRE(write(fd[i], "X", 1) == 1); + ATF_REQUIRE(stat(path, &sa) == 0); + + (void)sleep(1); + + ATF_REQUIRE(write(fd[i], "X", 1) == 1); + ATF_REQUIRE(stat(path, &sb) == 0); + + ATF_REQUIRE(close(fd[i]) == 0); + ATF_REQUIRE(unlink(path) == 0); + + if (sa.st_mtime == sb.st_mtime) + atf_tc_fail("mtimes did not change"); + } +} + +ATF_TC_CLEANUP(stat_mtime, tc) +{ + (void)unlink(path); +} + +ATF_TC_WITH_CLEANUP(stat_perm); +ATF_TC_HEAD(stat_perm, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test permissions with stat(2)"); + atf_tc_set_md_var(tc, "require.user", "root"); +} + +ATF_TC_BODY(stat_perm, tc) +{ + struct stat sa, sb; + gid_t gid; + uid_t uid; + int fd; + + (void)memset(&sa, 0, sizeof(struct stat)); + (void)memset(&sb, 0, sizeof(struct stat)); + + uid = getuid(); + gid = getgid(); + + fd = open(path, O_RDONLY | O_CREAT); + + ATF_REQUIRE(fd != -1); + ATF_REQUIRE(fstat(fd, &sa) == 0); + ATF_REQUIRE(stat(path, &sb) == 0); + + if (gid != sa.st_gid || sa.st_gid != sb.st_gid) + atf_tc_fail("invalid GID"); + + if (uid != sa.st_uid || sa.st_uid != sb.st_uid) + atf_tc_fail("invalid UID"); + + ATF_REQUIRE(close(fd) == 0); + ATF_REQUIRE(unlink(path) == 0); +} + +ATF_TC_CLEANUP(stat_perm, tc) +{ + (void)unlink(path); +} + +ATF_TC_WITH_CLEANUP(stat_size); +ATF_TC_HEAD(stat_size, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test file sizes with stat(2)"); +} + +ATF_TC_BODY(stat_size, tc) +{ + struct stat sa, sb, sc; + const size_t n = 10; + size_t i; + int fd; + + fd = open(path, O_WRONLY | O_CREAT); + ATF_REQUIRE(fd >= 0); + + for (i = 0; i < n; i++) { + + (void)memset(&sa, 0, sizeof(struct stat)); + (void)memset(&sb, 0, sizeof(struct stat)); + (void)memset(&sc, 0, sizeof(struct stat)); + + ATF_REQUIRE(fstat(fd, &sa) == 0); + ATF_REQUIRE(write(fd, "X", 1) == 1); + ATF_REQUIRE(fstat(fd, &sb) == 0); + ATF_REQUIRE(stat(path, &sc) == 0); + + if (sa.st_size + 1 != sb.st_size) + atf_tc_fail("invalid file size"); + + if (sb.st_size != sc.st_size) + atf_tc_fail("stat(2) and fstat(2) mismatch"); + } + + ATF_REQUIRE(close(fd) == 0); + ATF_REQUIRE(unlink(path) == 0); +} + +ATF_TC_CLEANUP(stat_size, tc) +{ + (void)unlink(path); +} + +ATF_TC(stat_socket); +ATF_TC_HEAD(stat_socket, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test fstat(2) with " + "a socket (PR kern/46077)"); +} + +ATF_TC_BODY(stat_socket, tc) +{ + struct sockaddr_in addr; + struct stat st; + uint32_t iaddr; + int fd, flags; + + (void)memset(&st, 0, sizeof(struct stat)); + (void)memset(&addr, 0, sizeof(struct sockaddr_in)); + + fd = socket(AF_INET, SOCK_STREAM, 0); + ATF_REQUIRE(fd >= 0); + + flags = fcntl(fd, F_GETFL); + + ATF_REQUIRE(flags != -1); + ATF_REQUIRE(fcntl(fd, F_SETFL, flags | O_NONBLOCK) != -1); + ATF_REQUIRE(inet_pton(AF_INET, "127.0.0.1", &iaddr) == 1); + + addr.sin_port = htons(42); + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = iaddr; + + errno = 0; + + ATF_REQUIRE_ERRNO(EINPROGRESS, + connect(fd, (struct sockaddr *)&addr, + sizeof(struct sockaddr_in)) == -1); + + errno = 0; + + if (fstat(fd, &st) != 0 || errno != 0) + atf_tc_fail("fstat(2) failed for a EINPROGRESS socket"); + + (void)close(fd); +} + +ATF_TC_WITH_CLEANUP(stat_symlink); +ATF_TC_HEAD(stat_symlink, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test symbolic links with stat(2)"); +} + +ATF_TC_BODY(stat_symlink, tc) +{ + const char *pathlink = "pathlink"; + struct stat sa, sb; + int fd; + + (void)memset(&sa, 0, sizeof(struct stat)); + (void)memset(&sb, 0, sizeof(struct stat)); + + fd = open(path, O_WRONLY | O_CREAT); + + ATF_REQUIRE(fd >= 0); + ATF_REQUIRE(symlink(path, pathlink) == 0); + ATF_REQUIRE(stat(pathlink, &sa) == 0); + ATF_REQUIRE(lstat(pathlink, &sb) == 0); + + if (S_ISLNK(sa.st_mode) != 0) + atf_tc_fail("stat(2) detected symbolic link"); + + if (S_ISLNK(sb.st_mode) == 0) + atf_tc_fail("lstat(2) did not detect symbolic link"); + + if (sa.st_mode == sb.st_mode) + atf_tc_fail("inconsistencies between stat(2) and lstat(2)"); + + ATF_REQUIRE(unlink(path) == 0); + ATF_REQUIRE(unlink(pathlink) == 0); +} + +ATF_TC_CLEANUP(stat_symlink, tc) +{ + (void)unlink(path); +} + +ATF_TP_ADD_TCS(tp) +{ + + ATF_TP_ADD_TC(tp, stat_chflags); + ATF_TP_ADD_TC(tp, stat_dir); + ATF_TP_ADD_TC(tp, stat_err); + ATF_TP_ADD_TC(tp, stat_mtime); + ATF_TP_ADD_TC(tp, stat_perm); + ATF_TP_ADD_TC(tp, stat_size); + ATF_TP_ADD_TC(tp, stat_socket); + ATF_TP_ADD_TC(tp, stat_symlink); + + return atf_no_error(); +} diff --git a/contrib/netbsd-tests/lib/libc/sys/t_swapcontext.c b/contrib/netbsd-tests/lib/libc/sys/t_swapcontext.c new file mode 100644 index 0000000..de36c88 --- /dev/null +++ b/contrib/netbsd-tests/lib/libc/sys/t_swapcontext.c @@ -0,0 +1,133 @@ +/* $NetBSD: t_swapcontext.c,v 1.3 2013/05/05 10:28:11 skrll Exp $ */ + +/* + * Copyright (c) 2012 Emmanuel Dreyfus. 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ + +#include <sys/cdefs.h> +__RCSID("$NetBSD"); + +#include <ucontext.h> +#include <stdio.h> +#include <stdlib.h> +#include <lwp.h> + +#include <atf-c.h> + +#define STACKSIZE 65536 + +char stack[STACKSIZE]; +ucontext_t nctx; +ucontext_t octx; +void *otls; +void *ntls; +int val1, val2; +int alter_tlsbase; + +/* ARGSUSED0 */ +static void +swapfunc(void *arg) +{ + ntls = _lwp_getprivate(); + printf("after swapcontext TLS pointer = %p\n", ntls); + + if (alter_tlsbase) { + ATF_REQUIRE_EQ(ntls, &val1); + printf("TLS pointer modified by swapcontext()\n"); + } else { + ATF_REQUIRE_EQ(ntls, &val2); + printf("TLS pointer left untouched by swapcontext()\n"); + } + + /* Go back in main */ + ATF_REQUIRE(swapcontext(&nctx, &octx)); + + /* NOTREACHED */ + return; +} + +static void +mainfunc(void) +{ + printf("Testing if swapcontext() alters TLS pointer if _UC_TLSBASE " + "is %s\n", (alter_tlsbase) ? "left set" : "cleared"); + + _lwp_setprivate(&val1); + printf("before swapcontext TLS pointer = %p\n", &val1); + + ATF_REQUIRE(getcontext(&nctx) == 0); + + nctx.uc_stack.ss_sp = stack; + nctx.uc_stack.ss_size = sizeof(stack); + +#ifndef _UC_TLSBASE + ATF_REQUIRE_MSG(0, "_UC_TLSBASE is not defined"); +#else /* _UC_TLSBASE */ + ATF_REQUIRE(nctx.uc_flags & _UC_TLSBASE); + if (!alter_tlsbase) + nctx.uc_flags &= ~_UC_TLSBASE; +#endif /* _UC_TLSBASE */ + + makecontext(&nctx, swapfunc, 0); + + _lwp_setprivate(&val2); + otls = _lwp_getprivate(); + printf("before swapcontext TLS pointer = %p\n", otls); + ATF_REQUIRE(swapcontext(&octx, &nctx) == 0); + + printf("Test completed\n"); +} + + +ATF_TC(swapcontext1); +ATF_TC_HEAD(swapcontext1, tc) +{ + atf_tc_set_md_var(tc, "descr", "Testing if swapcontext() can let " + "TLS pointer untouched"); +} +ATF_TC_BODY(swapcontext1, tc) +{ + alter_tlsbase = 0; + mainfunc(); +} + +ATF_TC(swapcontext2); +ATF_TC_HEAD(swapcontext2, tc) +{ + atf_tc_set_md_var(tc, "descr", "Testing if swapcontext() can " + "modify TLS pointer"); +} +ATF_TC_BODY(swapcontext2, tc) +{ + alter_tlsbase = 1; + mainfunc(); +} + +ATF_TP_ADD_TCS(tp) +{ + ATF_TP_ADD_TC(tp, swapcontext1); + ATF_TP_ADD_TC(tp, swapcontext2); + + return atf_no_error(); +} diff --git a/contrib/netbsd-tests/lib/libc/sys/t_timer_create.c b/contrib/netbsd-tests/lib/libc/sys/t_timer_create.c new file mode 100644 index 0000000..ce1fb99 --- /dev/null +++ b/contrib/netbsd-tests/lib/libc/sys/t_timer_create.c @@ -0,0 +1,207 @@ +/* $NetBSD: t_timer_create.c,v 1.4 2012/03/18 07:00:52 jruoho Exp $ */ + +/*- + * Copyright (c) 2010 The NetBSD Foundation, 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ + +#include <atf-c.h> +#include <errno.h> +#include <stdio.h> +#include <signal.h> +#include <string.h> +#include <time.h> +#include <unistd.h> + +static timer_t t; +static bool fail = true; + +static void +timer_signal_handler(int signo, siginfo_t *si, void *osi) +{ + timer_t *tp; + + tp = si->si_value.sival_ptr; + + if (*tp == t && signo == SIGALRM) + fail = false; + + (void)fprintf(stderr, "%s: %s\n", __func__, strsignal(signo)); +} + +static void +timer_signal_create(clockid_t cid, bool expire) +{ + struct itimerspec tim; + struct sigaction act; + struct sigevent evt; + sigset_t set; + + t = 0; + fail = true; + + (void)memset(&evt, 0, sizeof(struct sigevent)); + (void)memset(&act, 0, sizeof(struct sigaction)); + (void)memset(&tim, 0, sizeof(struct itimerspec)); + + /* + * Set handler. + */ + act.sa_flags = SA_SIGINFO; + act.sa_sigaction = timer_signal_handler; + + ATF_REQUIRE(sigemptyset(&set) == 0); + ATF_REQUIRE(sigemptyset(&act.sa_mask) == 0); + + /* + * Block SIGALRM while configuring the timer. + */ + ATF_REQUIRE(sigaction(SIGALRM, &act, NULL) == 0); + ATF_REQUIRE(sigaddset(&set, SIGALRM) == 0); + ATF_REQUIRE(sigprocmask(SIG_SETMASK, &set, NULL) == 0); + + /* + * Create the timer (SIGEV_SIGNAL). + */ + evt.sigev_signo = SIGALRM; + evt.sigev_value.sival_ptr = &t; + evt.sigev_notify = SIGEV_SIGNAL; + + ATF_REQUIRE(timer_create(cid, &evt, &t) == 0); + + /* + * Start the timer. After this, unblock the signal. + */ + tim.it_value.tv_sec = expire ? 5 : 1; + tim.it_value.tv_nsec = 0; + + ATF_REQUIRE(timer_settime(t, 0, &tim, NULL) == 0); + + (void)sigprocmask(SIG_UNBLOCK, &set, NULL); + (void)sleep(2); + + if (expire) { + if (!fail) + atf_tc_fail("timer fired too soon"); + } else { + if (fail) + atf_tc_fail("timer failed to fire"); + } + + ATF_REQUIRE(timer_delete(t) == 0); +} + +ATF_TC(timer_create_err); +ATF_TC_HEAD(timer_create_err, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Check errors from timer_create(2) (PR lib/42434"); +} + +ATF_TC_BODY(timer_create_err, tc) +{ + struct sigevent ev; + + (void)memset(&ev, 0, sizeof(struct sigevent)); + + errno = 0; + ev.sigev_signo = -1; + ev.sigev_notify = SIGEV_SIGNAL; + + ATF_REQUIRE_ERRNO(EINVAL, timer_create(CLOCK_REALTIME, &ev, &t) == -1); + + errno = 0; + ev.sigev_signo = SIGUSR1; + ev.sigev_notify = SIGEV_THREAD + 100; + + ATF_REQUIRE_ERRNO(EINVAL, timer_create(CLOCK_REALTIME, &ev, &t) == -1); +} + +ATF_TC(timer_create_real); +ATF_TC_HEAD(timer_create_real, tc) +{ + + atf_tc_set_md_var(tc, "descr", + "Checks timer_create(2) with CLOCK_REALTIME and sigevent(3), " + "SIGEV_SIGNAL"); +} + +ATF_TC_BODY(timer_create_real, tc) +{ + timer_signal_create(CLOCK_REALTIME, false); +} + +ATF_TC(timer_create_mono); +ATF_TC_HEAD(timer_create_mono, tc) +{ + + atf_tc_set_md_var(tc, "descr", + "Checks timer_create(2) with CLOCK_MONOTONIC and sigevent(3), " + "SIGEV_SIGNAL"); +} + +ATF_TC_BODY(timer_create_mono, tc) +{ + timer_signal_create(CLOCK_MONOTONIC, false); +} + +ATF_TC(timer_create_real_expire); +ATF_TC_HEAD(timer_create_real_expire, tc) +{ + + atf_tc_set_md_var(tc, "descr", + "Checks timer_create(2) with CLOCK_REALTIME and sigevent(3), " + "SIGEV_SIGNAL, with expiration"); +} + +ATF_TC_BODY(timer_create_real_expire, tc) +{ + timer_signal_create(CLOCK_REALTIME, true); +} + +ATF_TC(timer_create_mono_expire); +ATF_TC_HEAD(timer_create_mono_expire, tc) +{ + + atf_tc_set_md_var(tc, "descr", + "Checks timer_create(2) with CLOCK_MONOTONIC and sigevent(3), " + "SIGEV_SIGNAL, with expiration"); +} + +ATF_TC_BODY(timer_create_mono_expire, tc) +{ + timer_signal_create(CLOCK_MONOTONIC, true); +} + +ATF_TP_ADD_TCS(tp) +{ + + ATF_TP_ADD_TC(tp, timer_create_err); + ATF_TP_ADD_TC(tp, timer_create_real); + ATF_TP_ADD_TC(tp, timer_create_mono); + ATF_TP_ADD_TC(tp, timer_create_real_expire); + ATF_TP_ADD_TC(tp, timer_create_mono_expire); + + return atf_no_error(); +} diff --git a/contrib/netbsd-tests/lib/libc/sys/t_truncate.c b/contrib/netbsd-tests/lib/libc/sys/t_truncate.c new file mode 100644 index 0000000..50a9cba --- /dev/null +++ b/contrib/netbsd-tests/lib/libc/sys/t_truncate.c @@ -0,0 +1,175 @@ +/* $NetBSD: t_truncate.c,v 1.2 2011/08/18 19:48:03 dholland Exp $ */ + +/*- + * Copyright (c) 2011 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jukka Ruohonen. + * + * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ +#include <sys/cdefs.h> +__RCSID("$NetBSD: t_truncate.c,v 1.2 2011/08/18 19:48:03 dholland Exp $"); + +#include <sys/stat.h> + +#include <atf-c.h> +#include <errno.h> +#include <fcntl.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> + +static const char path[] = "truncate"; +static const size_t sizes[] = { 8, 16, 512, 1024, 2048, 4094, 3000, 30 }; + +ATF_TC_WITH_CLEANUP(ftruncate_basic); +ATF_TC_HEAD(ftruncate_basic, tc) +{ + atf_tc_set_md_var(tc, "descr", "A basic test of ftruncate(2)"); +} + +ATF_TC_BODY(ftruncate_basic, tc) +{ + struct stat st; + size_t i; + int fd; + + fd = open(path, O_RDWR | O_CREAT, 0600); + ATF_REQUIRE(fd >= 0); + + for (i = 0; i < __arraycount(sizes); i++) { + + (void)memset(&st, 0, sizeof(struct stat)); + + ATF_REQUIRE(ftruncate(fd, sizes[i]) == 0); + ATF_REQUIRE(fstat(fd, &st) == 0); + + (void)fprintf(stderr, "truncating to %zu bytes\n", sizes[i]); + + if (sizes[i] != (size_t)st.st_size) + atf_tc_fail("ftruncate(2) did not truncate"); + } + + (void)close(fd); + (void)unlink(path); +} + +ATF_TC_CLEANUP(ftruncate_basic, tc) +{ + (void)unlink(path); +} + +ATF_TC(ftruncate_err); +ATF_TC_HEAD(ftruncate_err, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test errors from ftruncate(2)"); + atf_tc_set_md_var(tc, "require.user", "unprivileged"); +} + +ATF_TC_BODY(ftruncate_err, tc) +{ + int fd; + + fd = open("/etc/passwd", O_RDONLY, 0400); + ATF_REQUIRE(fd >= 0); + + errno = 0; + ATF_REQUIRE_ERRNO(EBADF, ftruncate(-1, 999) == -1); + + errno = 0; + ATF_REQUIRE_ERRNO(EINVAL, ftruncate(fd, 999) == -1); + + (void)close(fd); +} + +ATF_TC_WITH_CLEANUP(truncate_basic); +ATF_TC_HEAD(truncate_basic, tc) +{ + atf_tc_set_md_var(tc, "descr", "A basic test of truncate(2)"); +} + +ATF_TC_BODY(truncate_basic, tc) +{ + struct stat st; + size_t i; + int fd; + + fd = open(path, O_RDWR | O_CREAT, 0600); + ATF_REQUIRE(fd >= 0); + + for (i = 0; i < __arraycount(sizes); i++) { + + (void)memset(&st, 0, sizeof(struct stat)); + + ATF_REQUIRE(truncate(path, sizes[i]) == 0); + ATF_REQUIRE(fstat(fd, &st) == 0); + + (void)fprintf(stderr, "truncating to %zu bytes\n", sizes[i]); + + if (sizes[i] != (size_t)st.st_size) + atf_tc_fail("truncate(2) did not truncate"); + } + + (void)close(fd); + (void)unlink(path); +} + +ATF_TC_CLEANUP(truncate_basic, tc) +{ + (void)unlink(path); +} + +ATF_TC(truncate_err); +ATF_TC_HEAD(truncate_err, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test errors from truncate(2)"); + atf_tc_set_md_var(tc, "require.user", "unprivileged"); +} + +ATF_TC_BODY(truncate_err, tc) +{ + + errno = 0; + ATF_REQUIRE_ERRNO(EFAULT, truncate((void *)-1, 999) == -1); + + errno = 0; + ATF_REQUIRE_ERRNO(EISDIR, truncate("/etc", 999) == -1); + + errno = 0; + ATF_REQUIRE_ERRNO(ENOENT, truncate("/a/b/c/d/e/f/g", 999) == -1); + + errno = 0; + ATF_REQUIRE_ERRNO(EACCES, truncate("/usr/bin/fpr", 999) == -1); +} + +ATF_TP_ADD_TCS(tp) +{ + + ATF_TP_ADD_TC(tp, ftruncate_basic); + ATF_TP_ADD_TC(tp, ftruncate_err); + ATF_TP_ADD_TC(tp, truncate_basic); + ATF_TP_ADD_TC(tp, truncate_err); + + return atf_no_error(); +} diff --git a/contrib/netbsd-tests/lib/libc/sys/t_ucontext.c b/contrib/netbsd-tests/lib/libc/sys/t_ucontext.c new file mode 100644 index 0000000..27d6740 --- /dev/null +++ b/contrib/netbsd-tests/lib/libc/sys/t_ucontext.c @@ -0,0 +1,76 @@ +/* $NetBSD: t_ucontext.c,v 1.1 2011/10/15 06:54:52 jruoho Exp $ */ + +/* + * Copyright (c) 2008 The NetBSD Foundation, 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ + +#include <sys/cdefs.h> +__COPYRIGHT("@(#) Copyright (c) 2008\ + The NetBSD Foundation, inc. All rights reserved."); +__RCSID("$NetBSD: t_ucontext.c,v 1.1 2011/10/15 06:54:52 jruoho Exp $"); + +#include <atf-c.h> +#include <stdio.h> +#include <ucontext.h> + +ATF_TC(ucontext_basic); +ATF_TC_HEAD(ucontext_basic, tc) +{ + atf_tc_set_md_var(tc, "descr", "Checks {get,set}context(2)"); +} + +ATF_TC_BODY(ucontext_basic, tc) +{ + ucontext_t u, v, w; + volatile int x, y; + + x = 0; + y = 0; + + printf("Start\n"); + + getcontext(&u); + y++; + + printf("x == %d\n", x); + + getcontext(&v); + + if ( x < 20 ) { + x++; + getcontext(&w); + setcontext(&u); + } + + printf("End, y = %d\n", y); + ATF_REQUIRE_EQ(y, 21); +} + +ATF_TP_ADD_TCS(tp) +{ + ATF_TP_ADD_TC(tp, ucontext_basic); + + return atf_no_error(); +} diff --git a/contrib/netbsd-tests/lib/libc/sys/t_umask.c b/contrib/netbsd-tests/lib/libc/sys/t_umask.c new file mode 100644 index 0000000..748cbdc --- /dev/null +++ b/contrib/netbsd-tests/lib/libc/sys/t_umask.c @@ -0,0 +1,205 @@ +/* $NetBSD: t_umask.c,v 1.1 2011/07/07 06:57:54 jruoho Exp $ */ + +/*- + * Copyright (c) 2011 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jukka Ruohonen. + * + * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ +#include <sys/cdefs.h> +__RCSID("$NetBSD: t_umask.c,v 1.1 2011/07/07 06:57:54 jruoho Exp $"); + +#include <sys/stat.h> +#include <sys/wait.h> + +#include <atf-c.h> +#include <fcntl.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +static const char path[] = "umask"; +static const mode_t mask[] = { + S_IRWXU, + S_IRUSR, + S_IWUSR, + S_IXUSR, + S_IRWXG, + S_IRGRP, + S_IWGRP, + S_IXGRP, + S_IRWXO, + S_IROTH, + S_IWOTH, + S_IXOTH +}; + +ATF_TC_WITH_CLEANUP(umask_fork); +ATF_TC_HEAD(umask_fork, tc) +{ + atf_tc_set_md_var(tc, "descr", "Check that umask(2) is inherited"); +} + +ATF_TC_BODY(umask_fork, tc) +{ + mode_t mode; + pid_t pid; + size_t i; + int sta; + + for (i = 0; i < __arraycount(mask) - 1; i++) { + + (void)umask(mask[i] | mask[i + 1]); + + pid = fork(); + + if (pid < 0) + continue; + + if (pid == 0) { + + mode = umask(mask[i]); + + if (mode != (mask[i] | mask[i + 1])) + _exit(EXIT_FAILURE); + + _exit(EXIT_SUCCESS); + } + + (void)wait(&sta); + + if (WIFEXITED(sta) == 0 || WEXITSTATUS(sta) != EXIT_SUCCESS) + goto fail; + } + + return; + +fail: + (void)umask(S_IWGRP | S_IWOTH); + + atf_tc_fail("umask(2) was not inherited"); +} + +ATF_TC_CLEANUP(umask_fork, tc) +{ + (void)umask(S_IWGRP | S_IWOTH); +} + +ATF_TC_WITH_CLEANUP(umask_open); +ATF_TC_HEAD(umask_open, tc) +{ + atf_tc_set_md_var(tc, "descr", "A basic test of open(2) and umask(2)"); +} + +ATF_TC_BODY(umask_open, tc) +{ + const char *str = NULL; + struct stat st; + size_t i; + int fd; + + for (i = 0; i < __arraycount(mask); i++) { + + (void)umask(mask[i]); + + fd = open(path, O_RDWR | O_CREAT, 0777); + + if (fd < 0) + continue; + + (void)memset(&st, 0, sizeof(struct stat)); + + if (stat(path, &st) != 0) { + str = "failed to stat(2)"; + goto out; + } + + if ((st.st_mode & mask[i]) != 0) { + str = "invalid umask(2)"; + goto out; + } + + if (unlink(path) != 0) { + str = "failed to unlink(2)"; + goto out; + } + + } + +out: + (void)umask(S_IWGRP | S_IWOTH); + + if (str != NULL) + atf_tc_fail("%s", str); +} + +ATF_TC_CLEANUP(umask_open, tc) +{ + (void)umask(S_IWGRP | S_IWOTH); + (void)unlink(path); +} + +ATF_TC_WITH_CLEANUP(umask_previous); +ATF_TC_HEAD(umask_previous, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test the return value from umask(2)"); +} + +ATF_TC_BODY(umask_previous, tc) +{ + mode_t mode; + size_t i; + + for (i = 0; i < __arraycount(mask); i++) { + + mode = umask(mask[i]); + mode = umask(mask[i]); + + if (mode != mask[i]) + goto fail; + } + + return; + +fail: + (void)umask(S_IWGRP | S_IWOTH); + + atf_tc_fail("umask(2) did not return the previous mask"); +} + +ATF_TC_CLEANUP(umask_previous, tc) +{ + (void)umask(S_IWGRP | S_IWOTH); +} + +ATF_TP_ADD_TCS(tp) +{ + + ATF_TP_ADD_TC(tp, umask_fork); + ATF_TP_ADD_TC(tp, umask_open); + ATF_TP_ADD_TC(tp, umask_previous); + + return atf_no_error(); +} diff --git a/contrib/netbsd-tests/lib/libc/sys/t_unlink.c b/contrib/netbsd-tests/lib/libc/sys/t_unlink.c new file mode 100644 index 0000000..38bff4c --- /dev/null +++ b/contrib/netbsd-tests/lib/libc/sys/t_unlink.c @@ -0,0 +1,158 @@ +/* $NetBSD: t_unlink.c,v 1.2 2014/04/21 18:05:17 martin Exp $ */ + +/*- + * Copyright (c) 2011 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jukka Ruohonen. + * + * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ +#include <sys/cdefs.h> +__RCSID("$NetBSD: t_unlink.c,v 1.2 2014/04/21 18:05:17 martin Exp $"); + +#include <sys/stat.h> + +#include <atf-c.h> +#include <errno.h> +#include <fcntl.h> +#include <limits.h> +#include <string.h> +#include <unistd.h> + +static char path[] = "unlink"; + +ATF_TC_WITH_CLEANUP(unlink_basic); +ATF_TC_HEAD(unlink_basic, tc) +{ + atf_tc_set_md_var(tc, "descr", "A basic test of unlink(2)"); +} + +ATF_TC_BODY(unlink_basic, tc) +{ + const size_t n = 512; + size_t i; + int fd; + + for (i = 0; i < n; i++) { + + fd = open(path, O_RDWR | O_CREAT, 0666); + + ATF_REQUIRE(fd != -1); + ATF_REQUIRE(close(fd) == 0); + ATF_REQUIRE(unlink(path) == 0); + + errno = 0; + ATF_REQUIRE_ERRNO(ENOENT, open(path, O_RDONLY) == -1); + } +} + +ATF_TC_CLEANUP(unlink_basic, tc) +{ + (void)unlink(path); +} + +ATF_TC_WITH_CLEANUP(unlink_err); +ATF_TC_HEAD(unlink_err, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test error conditions of unlink(2)"); +} + +ATF_TC_BODY(unlink_err, tc) +{ + char buf[PATH_MAX + 1]; + + (void)memset(buf, 'x', sizeof(buf)); + + errno = 0; + ATF_REQUIRE_ERRNO(EBUSY, unlink("/") == -1); + + errno = 0; + ATF_REQUIRE_ERRNO(ENAMETOOLONG, unlink(buf) == -1); + + errno = 0; + ATF_REQUIRE_ERRNO(ENOENT, unlink("/a/b/c/d/e/f/g/h/i/j/k/l/m") == -1); +} + +ATF_TC_CLEANUP(unlink_err, tc) +{ + (void)unlink(path); +} + +ATF_TC_WITH_CLEANUP(unlink_fifo); +ATF_TC_HEAD(unlink_fifo, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test unlink(2) for a FIFO"); +} + +ATF_TC_BODY(unlink_fifo, tc) +{ + + ATF_REQUIRE(mkfifo(path, 0666) == 0); + ATF_REQUIRE(unlink(path) == 0); + + errno = 0; + ATF_REQUIRE_ERRNO(ENOENT, open(path, O_RDONLY) == -1); +} + +ATF_TC_CLEANUP(unlink_fifo, tc) +{ + (void)unlink(path); +} + +ATF_TC_WITH_CLEANUP(unlink_perm); +ATF_TC_HEAD(unlink_perm, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test permissions with unlink(2)"); + atf_tc_set_md_var(tc, "require.user", "unprivileged"); +} + +ATF_TC_BODY(unlink_perm, tc) +{ + int rv; + + errno = 0; + rv = unlink("/etc"); + ATF_REQUIRE_MSG(rv == -1 && (errno == EACCES || errno == EPERM), + "unlinking a directory did not fail with EPERM or EACCESS; " + "unlink() returned %d, errno %d", rv, errno); + + errno = 0; + ATF_REQUIRE_ERRNO(EACCES, unlink("/root/.profile") == -1); +} + +ATF_TC_CLEANUP(unlink_perm, tc) +{ + (void)unlink(path); +} + +ATF_TP_ADD_TCS(tp) +{ + + ATF_TP_ADD_TC(tp, unlink_basic); + ATF_TP_ADD_TC(tp, unlink_err); + ATF_TP_ADD_TC(tp, unlink_fifo); + ATF_TP_ADD_TC(tp, unlink_perm); + + return atf_no_error(); +} diff --git a/contrib/netbsd-tests/lib/libc/sys/t_write.c b/contrib/netbsd-tests/lib/libc/sys/t_write.c new file mode 100644 index 0000000..2b1324a --- /dev/null +++ b/contrib/netbsd-tests/lib/libc/sys/t_write.c @@ -0,0 +1,226 @@ +/* $NetBSD: t_write.c,v 1.2 2011/10/19 16:19:30 jruoho Exp $ */ + +/*- + * Copyright (c) 2001, 2008 The NetBSD Foundation, 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + */ + +#include <sys/cdefs.h> +__COPYRIGHT("@(#) Copyright (c) 2008\ + The NetBSD Foundation, inc. All rights reserved."); +__RCSID("$NetBSD: t_write.c,v 1.2 2011/10/19 16:19:30 jruoho Exp $"); + +#include <sys/uio.h> +#include <sys/syslimits.h> + +#include <atf-c.h> +#include <errno.h> +#include <fcntl.h> +#include <signal.h> +#include <stdio.h> +#include <stdint.h> +#include <string.h> +#include <unistd.h> + +static void sighandler(int); + +static bool fail = false; +static const char *path = "write"; + +static void +sighandler(int signo) +{ + fail = false; +} + +ATF_TC_WITH_CLEANUP(write_err); +ATF_TC_HEAD(write_err, tc) +{ + atf_tc_set_md_var(tc, "descr", "Checks errors from write(2)"); +} + +ATF_TC_BODY(write_err, tc) +{ + char rbuf[3] = { 'a', 'b', 'c' }; + char wbuf[3] = { 'x', 'y', 'z' }; + int fd; + + errno = 0; + ATF_REQUIRE_ERRNO(EBADF, write(-1, wbuf, sizeof(wbuf)) == -1); + + fd = open(path, O_RDWR | O_CREAT); + + if (fd >= 0) { + + errno = 0; + ATF_REQUIRE_ERRNO(0, write(fd, wbuf, 3) == 3); + + errno = 0; + ATF_REQUIRE_ERRNO(EINVAL, write(fd, wbuf, SIZE_MAX) == -1); + + errno = 0; + ATF_REQUIRE_ERRNO(EFAULT, write(fd, (void *)-1, 1) == -1); + + /* + * Check that the above bogus write(2) + * calls did not corrupt the file. + */ + ATF_REQUIRE(lseek(fd, 0, SEEK_SET) == 0); + ATF_REQUIRE(read(fd, rbuf, 3) == 3); + ATF_REQUIRE(memcmp(rbuf, wbuf, 3) == 0); + + (void)close(fd); + (void)unlink(path); + } +} + +ATF_TC_CLEANUP(write_err, tc) +{ + (void)unlink(path); +} + +ATF_TC(write_pipe); +ATF_TC_HEAD(write_pipe, tc) +{ + atf_tc_set_md_var(tc, "descr", "Checks for EPIPE from write(2)"); +} + +ATF_TC_BODY(write_pipe, tc) +{ + int fds[2]; + + ATF_REQUIRE(pipe(fds) == 0); + ATF_REQUIRE(signal(SIGPIPE, sighandler) == 0); + + ATF_REQUIRE(write(fds[1], "x", 1) != -1); + ATF_REQUIRE(close(fds[0]) == 0); + + errno = 0; + fail = true; + + if (write(fds[1], "x", 1) != -1 || errno != EPIPE) + atf_tc_fail_nonfatal("expected EPIPE but write(2) succeeded"); + + ATF_REQUIRE(close(fds[1]) == 0); + + if (fail != false) + atf_tc_fail_nonfatal("SIGPIPE was not raised"); +} + +ATF_TC_WITH_CLEANUP(write_pos); +ATF_TC_HEAD(write_pos, tc) +{ + atf_tc_set_md_var(tc, "descr", "Checks that write(2) " + "updates the file position"); +} + +ATF_TC_BODY(write_pos, tc) +{ + const size_t n = 123; + size_t i; + int fd; + + fd = open(path, O_RDWR | O_CREAT); + ATF_REQUIRE(fd >= 0); + + for (i = 0; i < n; i++) { + ATF_REQUIRE(write(fd, "x", 1) == 1); + ATF_REQUIRE(lseek(fd, 0, SEEK_CUR) == (off_t)(i + 1)); + } + + ATF_REQUIRE(close(fd) == 0); + ATF_REQUIRE(unlink(path) == 0); +} + +ATF_TC_CLEANUP(write_pos, tc) +{ + (void)unlink(path); +} + +ATF_TC_WITH_CLEANUP(write_ret); +ATF_TC_HEAD(write_ret, tc) +{ + atf_tc_set_md_var(tc, "descr", "Checks return values from write(2)"); +} + +ATF_TC_BODY(write_ret, tc) +{ + const size_t n = 99; + char buf[123]; + size_t i, j; + int fd; + + fd = open(path, O_WRONLY | O_CREAT); + ATF_REQUIRE(fd >= 0); + + (void)memset(buf, 'x', sizeof(buf)); + + for (i = j = 0; i < n; i++) + j += write(fd, buf, sizeof(buf)); + + if (j != n * 123) + atf_tc_fail("inconsistent return values from write(2)"); + + (void)close(fd); + (void)unlink(path); +} + +ATF_TC_CLEANUP(write_ret, tc) +{ + (void)unlink(path); +} + +ATF_TC(writev_iovmax); +ATF_TC_HEAD(writev_iovmax, tc) +{ + atf_tc_set_md_var(tc, "timeout", "10"); + atf_tc_set_md_var(tc, "descr", + "Checks that file descriptor is properly FILE_UNUSE()d " + "when iovcnt is greater than IOV_MAX"); +} + +ATF_TC_BODY(writev_iovmax, tc) +{ + ssize_t retval; + + (void)printf("Calling writev(2, NULL, IOV_MAX + 1)...\n"); + + errno = 0; + retval = writev(2, NULL, IOV_MAX + 1); + + ATF_REQUIRE_EQ_MSG(retval, -1, "got: %zd", retval); + ATF_REQUIRE_EQ_MSG(errno, EINVAL, "got: %s", strerror(errno)); +} + +ATF_TP_ADD_TCS(tp) +{ + + ATF_TP_ADD_TC(tp, write_err); + ATF_TP_ADD_TC(tp, write_pipe); + ATF_TP_ADD_TC(tp, write_pos); + ATF_TP_ADD_TC(tp, write_ret); + ATF_TP_ADD_TC(tp, writev_iovmax); + + return atf_no_error(); +} |