diff options
Diffstat (limited to 'regress/lib/libc')
49 files changed, 10692 insertions, 0 deletions
diff --git a/regress/lib/libc/sys/Makefile b/regress/lib/libc/sys/Makefile new file mode 100644 index 00000000000..e8c06d0fb21 --- /dev/null +++ b/regress/lib/libc/sys/Makefile @@ -0,0 +1,104 @@ +# $OpenBSD: Makefile,v 1.1.1.1 2019/11/19 19:57:03 bluhm Exp $ + +# Copyright (c) 2019 Moritz Buhl <openbsd@moritzbuhl.de> +# Copyright (c) 2019 Alexander Bluhm <bluhm@openbsd.org> +# +# Permission to use, copy, modify, and distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +# Each test program in PROGS may define several numbered subtests. +# In a first step compile all programs and extract their parameters. +# For each PROG define new regression subtests based on the test number. + +.if defined(NUMBERS) +REGRESS_TARGETS = ${NUMBERS:S/^/run-${PROG}-/} +.else +REGRESS_TARGETS = ${PROGS:S/^/run-/} +.endif + +PROGS = +PROGS += t_access t_bind t_chroot t_clock_gettime t_dup t_fsync +PROGS += t_getgroups t_getitimer t_getlogin t_getpid t_getrusage +PROGS += t_getsid t_getsockname t_gettimeofday t_kill t_link t_listen +PROGS += t_mkdir t_mknod t_msgctl t_msgget t_msgsnd t_msync t_pipe +PROGS += t_poll t_revoke t_select t_sendrecv t_setuid t_socketpair +PROGS += t_sigaction t_truncate t_umask t_write + +# failing tests +.if 0 +PROGS += t_mkfifo +PROGS += t_mlock +PROGS += t_mmap +PROGS += t_msgrcv +PROGS += t_pipe2 +PROGS += t_ptrace +PROGS += t_stat +PROGS += t_syscall +PROGS += t_unlink +.endif + +. for p in ${PROGS} +SRCS_$p = $p.c atf-c.c +. endfor + +LDADD_t_getpid = -lpthread + +run-t_truncate: setup-t_truncate +setup-t_truncate: + ${SUDO} touch truncate_test.root_owned + ${SUDO} chown root:wheel truncate_test.root_owned + +run-t_chroot: cleanup-t_chroot +cleanup-t_chroot: + ${SUDO} rm -rf dir + +CLEANFILES = access dummy mmap truncate_test.root_owned + +.for p in ${PROGS} +run-$p: $p + @echo "\n======== $@ ========" + ntests="`./$p -n`" && \ + echo "1..$$ntests" && \ + tnumbers="`jot -ns' ' - 1 $$ntests`" && \ + ${.MAKE} -C ${.CURDIR} PROG=$p NUMBERS="$$tnumbers" regress +.endfor + +.if defined(NUMBERS) +CUR_USER != id -g + +. for n in ${NUMBERS} +DESCR_$n != eval `./${PROG} -i $n` && echo $$DESCR +REQ_USER_$n != eval `./${PROG} -i $n` && echo $$REQ_USER + +. if ${REQ_USER_$n} == "root" +REGRESS_ROOT_TARGETS += run-${PROG}-$n +. endif + +run-${PROG}-$n: + @echo "$n ${DESCR_$n}" +. if ${REQ_USER_$n} == "root" + ${SUDO} ./${PROG} -r $n +. elif ${REQ_USER_$n} == "unprivileged" && ${CUR_USER} == 0 + ${SUDO} su ${BUILDUSER} -c exec ./${PROG} -r $n +. elif ${REQ_USER_$n} == "unprivileged" || ${REQ_USER_$n} == "" + ./${PROG} -r $n +. else + # bad REQ_USER: ${REQ_USER_$n} + false +. endif + +. endfor +.endif + +.include <bsd.regress.mk> + +clean: cleanup-t_chroot diff --git a/regress/lib/libc/sys/README b/regress/lib/libc/sys/README new file mode 100644 index 00000000000..979f3bde4a9 --- /dev/null +++ b/regress/lib/libc/sys/README @@ -0,0 +1,68 @@ +Regression tests for system calls ported from NetBSD. + +Reimplement ATF with many hacks to adjust the tests as little as possible. + +Tests passing without source file adjustments: +t_access t_getpid t_kill t_msgsnd t_sigaction +t_bind t_link t_msync t_socketpair t_getgroups +t_getsid t_listen t_pipe t_truncate t_getitimer +t_getsockname t_mkdir t_sendrecv t_umask t_getlogin +t_gettimeofday t_msgctl t_setuid t_write + +Tests passing after adjustments: +t_chroot - fchroot is not implemented +t_clock_gettime - requires sysctlbyname +t_dup - OpenBSD dup3 is similar to Linux dup3 +t_fsync - replace mkstemp +t_getrusage - no expected fail, PR kern/30115 is NetBSD, work more +t_mknod - remove tests for unsupported file types +t_msgget - remove msgget_limit test +t_poll - remove pollts_* tests +t_revoke - remove basic tests, revoke only on ttys supported +t_select - remove sigset_t struct as it is int on OpenBSD + +Failing tests: +t_mkfifo - every test case fails now +t_mlock - wrong errno, succeeds where not expected, POSIX imprecise +t_mmap - ENOTBLK on test NetBSD is skipping, remove mmap_va0 test +t_msgrcv - msgrcv(id, &r, 3 - 1, 0x41, 004000) != -1 +t_pipe2 - closefrom(4) == -1, remove F_GETNOSIGPIPE and nosigpipe test +t_ptrace - ptrace(0, 0, ((void *)0), 0) != -1 +t_stat - invalid GID with doas +t_syscall - SIGSEGV +t_unlink - wrong errno according to POSIX + +Excluded tests: +t_clock_nanosleep - not available +t_clone - not available +t_connect - +t_fork - +t_getcontext - +t_issetugid - +t_kevent - +t_lwp_create - not available +t_lwp_ctl - not available +t_mincore - removed +t_minherit - +t_mprotect - +t_nanosleep - not available +t_posix_fadvise - +t_posix_fallocate - +t_ptrace_wait - +t_ptrace_wait3 - +t_ptrace_wait4 - +t_ptrace_wait6 - not implemented +t_ptrace_waitid - +t_ptrace_waitpid - +t_recvmmsg - +t_sendmmsg - +t_setrlimit - +t_sigqueue - +t_sigtimedwait - +t_swapcontext - +t_timer_create - +t_ucontext - +t_vfork - +t_wait - +t_wait_noproc - +t_wait_noproc_wnohang - diff --git a/regress/lib/libc/sys/atf-c.c b/regress/lib/libc/sys/atf-c.c new file mode 100644 index 00000000000..45181c73538 --- /dev/null +++ b/regress/lib/libc/sys/atf-c.c @@ -0,0 +1,113 @@ +/* $OpenBSD: atf-c.c,v 1.1.1.1 2019/11/19 19:57:03 bluhm Exp $ */ + +#include <sys/wait.h> + +#include <err.h> +#include <errno.h> +#include <limits.h> +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <pwd.h> +#include <unistd.h> + +#include "atf-c.h" + +void usage(void); + +int cleanup; +int count; +int inspect; +int run; +int test; + +int +main(int argc, char *argv[]) +{ + int ch, test; + const char *errstr, *num; + + while ((ch = getopt(argc, argv, "c:i:nr:")) != -1) { + switch(ch) { + case 'c': + cleanup = 1; + num = optarg; + break; + case 'i': + inspect = 1; + num = optarg; + break; + case 'n': + count = 1; + break; + case 'r': + run = 1; + num = optarg; + break; + default: + usage(); + } + } + argc -= optind; + argv += optind; + + if (cleanup + count + inspect + run > 1) + usage(); + + if (cleanup || inspect || run) { + test = strtonum(num, 1, INT_MAX, &errstr); + if (errstr != NULL) + errx(1, "test # is %s: %s", errstr, argv[1]); + } + if (count) + printf("%d\n", atf_test(0, 0)); + else if (cleanup) + ATF_CLEANUP(test); + else if (run) + ATF_RUN(test); + else if (inspect) + ATF_INSPECT(test); + else + usage(); + + return 0; +} + +void +usage(void) +{ + fprintf(stderr, "usage: %s [-n] [-c|i|r test#]\n", getprogname()); + exit(1); +} + +void +atf_require(int exp, int expected_errno, const char *expstr, const char *src, + const int lineno, char *fmt, ...) +{ + va_list args; + if (!(exp)) { + fprintf(stderr, "\n%s:%d: ", src, lineno); + if (fmt != NULL) { + va_start(args, fmt); + vfprintf(stderr, fmt, args); + va_end(args); + } else { + fprintf(stderr, "'%s' evaluated to false\n", expstr); + } + exit(1); + } else if (expected_errno >= 0 && errno != expected_errno) { + fprintf(stderr, "\n%s:%d: ", src, lineno); + fprintf(stderr, "expected errno %d but got %d instead\n", + expected_errno, errno); + exit(1); + } + return; +} + +void +atf_tc_fail(char *fmt, ...) +{ + va_list args; + va_start(args, fmt); + verrx(1, fmt, args); +} diff --git a/regress/lib/libc/sys/atf-c.h b/regress/lib/libc/sys/atf-c.h new file mode 100644 index 00000000000..740881485db --- /dev/null +++ b/regress/lib/libc/sys/atf-c.h @@ -0,0 +1,100 @@ +/* $OpenBSD: atf-c.h,v 1.1.1.1 2019/11/19 19:57:03 bluhm Exp $ */ +/* + * Copyright (c) 2019 Moritz Buhl <openbsd@moritzbuhl.de> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#if !defined(ATF_C_H) +#define ATF_C_H + +#include <pwd.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> + + +int atf_test(int, int); +void atf_require(int, int, const char *, const char *, const int, char *, ...); +void atf_tc_fail(char *, ...) + __attribute__((__noreturn__, __format__ (printf, 1, 2))); + +#define ATF_INSPECT_TEST 1 +#define ATF_RUN_TEST 2 +#define ATF_CLEANUP_TEST 3 + +#define ATF_TC_FUNCTIONS(fn) \ +void atf_head_##fn(void); \ +void atf_body_##fn(void); \ +void atf_cleanup_##fn(void); + +#define ATF_TC(fn) \ +ATF_TC_FUNCTIONS(fn) \ +void atf_cleanup_##fn(void) { return; } + +#define ATF_TC_WITH_CLEANUP(fn) \ +ATF_TC_FUNCTIONS(fn) + +#define ATF_TC_HEAD(fn, tc) void atf_head_##fn(void) +#define ATF_TC_BODY(fn, tc) void atf_body_##fn(void) +#define ATF_TC_CLEANUP(fn, tc) void atf_cleanup_##fn(void) + +#define ATF_TP_ADD_TCS(tp) int atf_test(int tst, int what) +#define ATF_TP_ADD_TC(tp, fn) tst--; \ + if (tst == 0) { \ + if (what == ATF_INSPECT_TEST) \ + atf_head_##fn(); \ + else if (what == ATF_RUN_TEST) \ + atf_body_##fn(); \ + else if (what == ATF_CLEANUP_TEST) \ + atf_cleanup_##fn(); \ + return 0; \ + } + +#define atf_no_error() (-tst) + +#define ATF_INSPECT(i) atf_test(i, ATF_INSPECT_TEST) +#define ATF_RUN(i) atf_test(i, ATF_RUN_TEST) +#define ATF_CLEANUP(i) atf_test(i, ATF_CLEANUP_TEST) + +#define atf_tc_set_md_var(tc, attr, fmt, ...) \ + if (strcmp(attr, "descr") == 0) \ + printf("DESCR=\"" fmt "\"\n", ##__VA_ARGS__); \ + else if (strcmp(attr, "require.user") == 0) \ + printf("REQ_USER=" fmt "\n", ##__VA_ARGS__); + +#define ATF_CHECK ATF_REQUIRE +#define ATF_CHECK_MSG ATF_REQUIRE_MSG +#define ATF_CHECK_EQ ATF_REQUIRE_EQ + +#define atf_req(exp, err, msg, ...) \ + atf_require(exp, err, #exp, __FILE__, __LINE__, NULL) +#define ATF_REQUIRE(exp) atf_req(exp, -1, NULL) +#define ATF_REQUIRE_ERRNO(no, exp) atf_req(exp, no, NULL) +#define ATF_REQUIRE_MSG(exp, fmt, ...) atf_req(exp, -1, fmt, ##__VA_ARGS__) +#define ATF_REQUIRE_EQ(a, b) atf_req((a) == (b), -1, NULL) +#define ATF_REQUIRE_EQ_MSG(a, b, fmt, ...) \ + atf_req((a) == (b), -1, fmt, ##__VA_ARGS__) + +#define atf_tc_fail_nonfatal(fmt, ...) atf_tc_fail(fmt, ##__VA_ARGS__) +#define atf_tc_expect_fail(fmt, ...) \ + atf_tc_fail(fmt "\nEXPECTED_FAIL", ##__VA_ARGS__) +#define atf_tc_skip(fmt, ...) \ + atf_tc_fail(fmt "\nSKIPPING", ##__VA_ARGS__) +#define atf_tc_pass() exit(0) + +#define atf_tc_get_config_var(a, b) "." + +#define atf_utils_fork() fork() + +#endif /* !defined(ATF_C_H) */ diff --git a/regress/lib/libc/sys/h_macros.h b/regress/lib/libc/sys/h_macros.h new file mode 100644 index 00000000000..227db0f31be --- /dev/null +++ b/regress/lib/libc/sys/h_macros.h @@ -0,0 +1,87 @@ +/* $NetBSD: h_macros.h,v 1.13 2016/08/20 15:49:08 christos Exp $ */ + +/*- + * Copyright (c) 2008, 2009 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. + */ + +#ifndef SRC_TESTS_H_MACROS_H_ +#define SRC_TESTS_H_MACROS_H_ + +#include <sys/types.h> +#include <errno.h> +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "atf-c.h" + +#define REQUIRE_LIBC(x, v) \ + ATF_REQUIRE_MSG((x) != (v), "%s: %s", #x, strerror(errno)) + +#define CHECK_LIBC(x, v) \ + ATF_CHECK_MSG((x) != (v), "%s: %s", #x, strerror(errno)) + +#define RL(x) REQUIRE_LIBC(x, -1) +#define RLF(x, fmt, arg) \ + ATF_CHECK_MSG((x) != -1, "%s [" fmt "]: %s", #x, arg, strerror(errno)) +#define RZ(x) \ +do { \ + int RZ_rv = x; \ + ATF_REQUIRE_MSG(RZ_rv == 0, "%s: %s", #x, strerror(RZ_rv)); \ +} while (/*CONSTCOND*/0) + +__dead static __inline __attribute__((__format__(__printf__,1,2))) void +atf_tc_fail_errno(const char *fmt, ...) +{ + va_list ap; + char buf[1024]; + int sverrno = errno; + + va_start(ap, fmt); + vsnprintf(buf, sizeof(buf), fmt, ap); + va_end(ap); + + strlcat(buf, ": ", sizeof(buf)); + strlcat(buf, strerror(sverrno), sizeof(buf)); + + atf_tc_fail("%s", buf); +} + +static __inline void +tests_makegarbage(void *space, size_t len) +{ + uint16_t *sb = space; + uint16_t randval; + + while (len >= sizeof(randval)) { + *sb++ = (uint16_t)random(); + len -= sizeof(*sb); + } + randval = (uint16_t)random(); + memcpy(sb, &randval, len); +} + +#endif diff --git a/regress/lib/libc/sys/macros.h b/regress/lib/libc/sys/macros.h new file mode 100644 index 00000000000..932f230c03a --- /dev/null +++ b/regress/lib/libc/sys/macros.h @@ -0,0 +1,55 @@ +/* $OpenBSD: macros.h,v 1.1.1.1 2019/11/19 19:57:03 bluhm Exp $ */ +/* Public domain - Moritz Buhl */ + +#include <sys/param.h> +#include <sys/socket.h> +#include <sys/stdint.h> +#include <sys/sysctl.h> +#include <sys/types.h> + +#include <stdbool.h> +#include <string.h> + +#define __RCSID(str) +#define __COPYRIGHT(str) + +#define __arraycount(_a) nitems(_a) +#define __unreachable() atf_tc_fail("unreachable") +#define __UNCONST(a) (a) + +/* t_chroot.c */ +#define fchroot(fd) 0 + +/* t_clock_gettime.c */ +int sysctlbyname(char *, void *, size_t *, void *, size_t); + +int +sysctlbyname(char* s, void *oldp, size_t *oldlenp, void *newp, size_t newlen) +{ + int ktc; + if (strcmp(s, "kern.timecounter.hardware") == 0) + ktc = KERN_TIMECOUNTER_HARDWARE; + else if (strcmp(s, "kern.timecounter.choice") == 0) + ktc = KERN_TIMECOUNTER_CHOICE; + + int mib[3]; + mib[0] = CTL_KERN; + mib[1] = KERN_TIMECOUNTER; + mib[2] = ktc; + return sysctl(mib, 3, oldp, oldlenp, newp, newlen); +} + +/* t_mlock.c */ +#define MAP_WIRED __MAP_NOREPLACE + +/* t_pipe2.c */ +#define O_NOSIGPIPE 0 + +/* t_poll.c */ +#define pollts(a, b, c, e) 0 + +/* t_sendrecv.c */ +#define SO_RERROR SO_DEBUG + +/* t_write.c */ +#define _PATH_DEVZERO "/dev/zero" diff --git a/regress/lib/libc/sys/t_access.c b/regress/lib/libc/sys/t_access.c new file mode 100644 index 00000000000..33888c70399 --- /dev/null +++ b/regress/lib/libc/sys/t_access.c @@ -0,0 +1,216 @@ +/* $OpenBSD: t_access.c,v 1.1.1.1 2019/11/19 19:57:03 bluhm Exp $ */ +/* $NetBSD: t_access.c,v 1.2 2017/01/10 22:36:29 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 "macros.h" + +#include <sys/cdefs.h> +__RCSID("$NetBSD: t_access.c,v 1.2 2017/01/10 22:36:29 christos Exp $"); + +#include "atf-c.h" + +#include <sys/stat.h> + +#include <errno.h> +#include <fcntl.h> +#include <limits.h> +#include <stdint.h> +#include <stdlib.h> +#include <unistd.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/regress/lib/libc/sys/t_bind.c b/regress/lib/libc/sys/t_bind.c new file mode 100644 index 00000000000..7989c7c2294 --- /dev/null +++ b/regress/lib/libc/sys/t_bind.c @@ -0,0 +1,81 @@ +/* $OpenBSD: t_bind.c,v 1.1.1.1 2019/11/19 19:57:03 bluhm Exp $ */ +/* $NetBSD: t_bind.c,v 1.3 2015/04/05 23:28:10 rtr Exp $ */ +/* + * Copyright (c) 2015 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 "macros.h" + +#include <errno.h> +#include <stdlib.h> +#include <string.h> + +#include <unistd.h> + +#include <sys/socket.h> +#include <arpa/inet.h> +#include <netinet/in.h> + +#include "atf-c.h" + +ATF_TC(bind_foreign_family); + +ATF_TC_HEAD(bind_foreign_family, tc) +{ + atf_tc_set_md_var(tc, "descr", "Checks that binding a socket " + "with a different address family fails"); +} + +ATF_TC_BODY(bind_foreign_family, tc) +{ + struct sockaddr_in addr; + + /* addr.sin_family = AF_UNSPEC = 0 */ + memset(&addr, 0, sizeof(addr)); + + /* + * it is not necessary to initialize sin_{addr,port} since + * those structure members shall not be accessed if bind + * fails correctly. + */ + + int sock = socket(AF_LOCAL, SOCK_STREAM, 0); + ATF_REQUIRE(sock != -1); + + /* should fail but currently doesn't */ + ATF_REQUIRE(-1 == bind(sock, (struct sockaddr *)&addr, sizeof(addr))); + ATF_REQUIRE(EAFNOSUPPORT == errno); + + close(sock); +} + +ATF_TP_ADD_TCS(tp) +{ + + ATF_TP_ADD_TC(tp, bind_foreign_family); + + return atf_no_error(); +} diff --git a/regress/lib/libc/sys/t_chroot.c b/regress/lib/libc/sys/t_chroot.c new file mode 100644 index 00000000000..1fbe392a883 --- /dev/null +++ b/regress/lib/libc/sys/t_chroot.c @@ -0,0 +1,321 @@ +/* $OpenBSD: t_chroot.c,v 1.1.1.1 2019/11/19 19:57:03 bluhm Exp $ */ +/* $NetBSD: t_chroot.c,v 1.2 2017/01/10 22:36:29 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 "macros.h" + +#include <sys/cdefs.h> +__RCSID("$NetBSD: t_chroot.c,v 1.2 2017/01/10 22:36:29 christos Exp $"); + +#include <sys/wait.h> +#include <sys/stat.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); +/* + * Not available on OpenBSD + * 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/regress/lib/libc/sys/t_clock_gettime.c b/regress/lib/libc/sys/t_clock_gettime.c new file mode 100644 index 00000000000..206710799e3 --- /dev/null +++ b/regress/lib/libc/sys/t_clock_gettime.c @@ -0,0 +1,215 @@ +/* $NetBSD: t_clock_gettime.c,v 1.3 2017/01/13 21:30:41 christos 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 "macros.h" + +#include <sys/cdefs.h> +__COPYRIGHT("@(#) Copyright (c) 2008\ + The NetBSD Foundation, inc. All rights reserved."); +__RCSID("$NetBSD: t_clock_gettime.c,v 1.3 2017/01/13 21:30:41 christos Exp $"); + +#include <sys/param.h> +#include <sys/sysctl.h> + + +#include "atf-c.h" +#include <errno.h> +#include <limits.h> +#include <stdio.h> +#include <stdint.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/regress/lib/libc/sys/t_dup.c b/regress/lib/libc/sys/t_dup.c new file mode 100644 index 00000000000..4021a4f6e4f --- /dev/null +++ b/regress/lib/libc/sys/t_dup.c @@ -0,0 +1,395 @@ +/* $OpenBSD: t_dup.c,v 1.1.1.1 2019/11/19 19:57:03 bluhm Exp $ */ +/* $NetBSD: t_dup.c,v 1.9 2017/01/13 20:31:53 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 "macros.h" + +#include <sys/cdefs.h> +__RCSID("$NetBSD: t_dup.c,v 1.9 2017/01/13 20:31:53 christos 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 <stdbool.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; + /* Adjusted for OpenBSD, initially != -1 */ + ATF_REQUIRE(dup3(fd, fd, O_CLOEXEC) == -1); + + errno = 0; + /* Adjusted for OpenBSD, initially EBADF */ + ATF_REQUIRE_ERRNO(EINVAL, 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. + */ + /* Adjusted for OpenBSD, initially 0 */ + (void)closefrom(STDERR_FILENO + 1); + (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); + + /* Adjusted for OpenBSD, initially mkstemp(path) */ + buf[0] = open(path, O_CREAT|O_EXCL|O_RDWR, S_IRUSR|S_IWUSR); + + if (buf[0] < 0) + _exit(EX_OSERR); + + /* Adjusted for OpenBSD, initially i < n */ + for (i = 1; i < n - (STDERR_FILENO + 1); 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/regress/lib/libc/sys/t_fsync.c b/regress/lib/libc/sys/t_fsync.c new file mode 100644 index 00000000000..c6f24c0e859 --- /dev/null +++ b/regress/lib/libc/sys/t_fsync.c @@ -0,0 +1,125 @@ +/* $OpenBSD: t_fsync.c,v 1.1.1.1 2019/11/19 19:57:03 bluhm Exp $ */ +/* $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 "macros.h" + +#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); + + /* Adjusted for OpenBSD, initially mkstemp(buf) */ + fd = open(buf, O_CREAT|O_EXCL|O_RDWR, 0600); + + 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/regress/lib/libc/sys/t_getgroups.c b/regress/lib/libc/sys/t_getgroups.c new file mode 100644 index 00000000000..dcef3c16f59 --- /dev/null +++ b/regress/lib/libc/sys/t_getgroups.c @@ -0,0 +1,175 @@ +/* $OpenBSD: t_getgroups.c,v 1.1.1.1 2019/11/19 19:57:03 bluhm Exp $ */ +/* $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 "macros.h" + +#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(NGROUPS_MAX, (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/regress/lib/libc/sys/t_getitimer.c b/regress/lib/libc/sys/t_getitimer.c new file mode 100644 index 00000000000..b6cc4102bb8 --- /dev/null +++ b/regress/lib/libc/sys/t_getitimer.c @@ -0,0 +1,215 @@ +/* $OpenBSD: t_getitimer.c,v 1.1.1.1 2019/11/19 19:57:03 bluhm Exp $ */ +/* $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 "macros.h" + +#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/regress/lib/libc/sys/t_getlogin.c b/regress/lib/libc/sys/t_getlogin.c new file mode 100644 index 00000000000..3c98cd7de89 --- /dev/null +++ b/regress/lib/libc/sys/t_getlogin.c @@ -0,0 +1,241 @@ +/* $OpenBSD: t_getlogin.c,v 1.1.1.1 2019/11/19 19:57:03 bluhm Exp $ */ +/* $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 "macros.h" + +#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/regress/lib/libc/sys/t_getpid.c b/regress/lib/libc/sys/t_getpid.c new file mode 100644 index 00000000000..0dbf7f43fee --- /dev/null +++ b/regress/lib/libc/sys/t_getpid.c @@ -0,0 +1,138 @@ +/* $OpenBSD: t_getpid.c,v 1.1.1.1 2019/11/19 19:57:03 bluhm Exp $ */ +/* $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 "macros.h" + +#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/regress/lib/libc/sys/t_getrusage.c b/regress/lib/libc/sys/t_getrusage.c new file mode 100644 index 00000000000..481d73431bb --- /dev/null +++ b/regress/lib/libc/sys/t_getrusage.c @@ -0,0 +1,269 @@ +/* $OpenBSD: t_getrusage.c,v 1.1.1.1 2019/11/19 19:57:03 bluhm Exp $ */ +/* $NetBSD: t_getrusage.c,v 1.8 2018/05/09 08:45:03 mrg 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 "macros.h" + +#include <sys/cdefs.h> +__RCSID("$NetBSD: t_getrusage.c,v 1.8 2018/05/09 08:45:03 mrg Exp $"); + +#include <sys/resource.h> +#include <sys/time.h> + +#include "atf-c.h" +#include <stdio.h> +#include <errno.h> +#include <limits.h> +#include <signal.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> +#include <fcntl.h> +#include <sys/socket.h> +#include <netinet/in.h> + +static void work(void); +static void sighandler(int); + +static const size_t maxiter = 2000; + +static void +sighandler(int signo __unused) +{ + /* Nothing. */ +} + +static void +work(void) +{ + size_t n = UINT16_MAX * 10; + + while (n > 0) { +#ifdef __or1k__ + asm volatile("l.nop"); /* Do something. */ +#elif defined(__ia64__) + asm volatile("nop 0"); /* 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_maxrss); +ATF_TC_HEAD(getrusage_maxrss, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test maxrss growing with getrusage(2)"); +} + +ATF_TC_BODY(getrusage_maxrss, tc) +{ + struct rusage ru; + long maxrss; + int i, fd; + +#define DUMP_FILE "dump" + + fd = open(DUMP_FILE, O_WRONLY|O_CREAT|O_TRUNC, 0222); + ATF_REQUIRE(fd != -1); + + (void)memset(&ru, 0, sizeof(struct rusage)); + ATF_REQUIRE(getrusage(RUSAGE_SELF, &ru) == 0); + maxrss = ru.ru_maxrss; + +#define CHUNK (1024 * 1024) + for (i = 0; i < 40; i++) { + void *p = malloc(CHUNK); + memset(p, 0, CHUNK); + write(fd, p, CHUNK); + } + close(fd); + unlink(DUMP_FILE); + + ATF_REQUIRE(getrusage(RUSAGE_SELF, &ru) == 0); + ATF_REQUIRE_MSG(maxrss < ru.ru_maxrss, + "maxrss: %ld, ru.ru_maxrss: %ld", maxrss, ru.ru_maxrss); +} + +ATF_TC(getrusage_msgsnd); +ATF_TC_HEAD(getrusage_msgsnd, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test send growing with getrusage(2)"); +} + +ATF_TC_BODY(getrusage_msgsnd, tc) +{ + struct rusage ru; + long msgsnd; + int s, i; + struct sockaddr_in sin; + + ATF_REQUIRE(getrusage(RUSAGE_SELF, &ru) == 0); + msgsnd = ru.ru_msgsnd; + + s = socket(AF_INET, SOCK_DGRAM, 0); + ATF_REQUIRE(s >= 0); + memset(&sin, 0, sizeof(sin)); + sin.sin_family = AF_INET; + sin.sin_len = sizeof(sin); + sin.sin_addr.s_addr = ntohl(INADDR_LOOPBACK); + sin.sin_port = htons(3333); + + for (i = 0; i < 10; i++) + ATF_REQUIRE(sendto(s, &sin, sizeof(sin), 0, (void *)&sin, + (socklen_t)sizeof(sin)) != -1); + + ATF_REQUIRE(getrusage(RUSAGE_SELF, &ru) == 0); + ATF_REQUIRE(msgsnd + 10 == ru.ru_msgsnd); + close(s); +} + +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. + */ + + 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(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. + */ + + 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_TP_ADD_TCS(tp) +{ + + ATF_TP_ADD_TC(tp, getrusage_err); + ATF_TP_ADD_TC(tp, getrusage_sig); + ATF_TP_ADD_TC(tp, getrusage_maxrss); + ATF_TP_ADD_TC(tp, getrusage_msgsnd); + ATF_TP_ADD_TC(tp, getrusage_utime_back); + ATF_TP_ADD_TC(tp, getrusage_utime_zero); + + return atf_no_error(); +} diff --git a/regress/lib/libc/sys/t_getsid.c b/regress/lib/libc/sys/t_getsid.c new file mode 100644 index 00000000000..5ccc2ca1a17 --- /dev/null +++ b/regress/lib/libc/sys/t_getsid.c @@ -0,0 +1,123 @@ +/* $OpenBSD: t_getsid.c,v 1.1.1.1 2019/11/19 19:57:03 bluhm Exp $ */ +/* $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 "macros.h" + +#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/regress/lib/libc/sys/t_getsockname.c b/regress/lib/libc/sys/t_getsockname.c new file mode 100644 index 00000000000..8b0accd7a06 --- /dev/null +++ b/regress/lib/libc/sys/t_getsockname.c @@ -0,0 +1,85 @@ +/* $OpenBSD: t_getsockname.c,v 1.1.1.1 2019/11/19 19:57:03 bluhm Exp $ */ +/* $NetBSD: t_getsockname.c,v 1.1 2016/07/30 11:03:54 njoly Exp $ */ +/* + * Copyright (c) 2016 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 "macros.h" + +#include <sys/socket.h> +#include <sys/un.h> + +#include <string.h> +#include <unistd.h> + +#include "atf-c.h" + +ATF_TC(getsockname_unix); + +ATF_TC_HEAD(getsockname_unix, tc) +{ + atf_tc_set_md_var(tc, "descr", "Checks getsockname with UNIX domain"); +} + +ATF_TC_BODY(getsockname_unix, tc) +{ + const char *path = "sock.unix"; + int sd; + socklen_t len; + struct sockaddr_un sun; + + sd = socket(AF_UNIX, SOCK_STREAM, 0); + ATF_REQUIRE(sd != -1); + + len = sizeof(sun); + memset(&sun, 0, sizeof(sun)); + ATF_REQUIRE(getsockname(sd, (struct sockaddr *)&sun, &len) != -1); + ATF_CHECK(sun.sun_family == AF_UNIX); + ATF_CHECK(strcmp(sun.sun_path, "") == 0); + + len = sizeof(sun); + memset(&sun, 0, sizeof(sun)); + sun.sun_family = AF_UNIX; + strcpy(sun.sun_path, path); + ATF_REQUIRE(bind(sd, (struct sockaddr *)&sun, len) != -1); + + len = sizeof(sun); + memset(&sun, 0, sizeof(sun)); + ATF_REQUIRE(getsockname(sd, (struct sockaddr *)&sun, &len) != -1); + ATF_CHECK(sun.sun_family == AF_UNIX); + ATF_CHECK(strcmp(sun.sun_path, path) == 0); + + ATF_REQUIRE(close(sd) != -1); + ATF_REQUIRE(unlink(path) != -1); +} + +ATF_TP_ADD_TCS(tp) +{ + + ATF_TP_ADD_TC(tp, getsockname_unix); + + return atf_no_error(); +} diff --git a/regress/lib/libc/sys/t_gettimeofday.c b/regress/lib/libc/sys/t_gettimeofday.c new file mode 100644 index 00000000000..de768b023ae --- /dev/null +++ b/regress/lib/libc/sys/t_gettimeofday.c @@ -0,0 +1,90 @@ +/* $OpenBSD: t_gettimeofday.c,v 1.1.1.1 2019/11/19 19:57:03 bluhm Exp $ */ +/* $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 "macros.h" + +#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/regress/lib/libc/sys/t_kill.c b/regress/lib/libc/sys/t_kill.c new file mode 100644 index 00000000000..c92bbdd18bb --- /dev/null +++ b/regress/lib/libc/sys/t_kill.c @@ -0,0 +1,316 @@ +/* $OpenBSD: t_kill.c,v 1.1.1.1 2019/11/19 19:57:03 bluhm Exp $ */ +/* $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 "macros.h" + +#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/regress/lib/libc/sys/t_link.c b/regress/lib/libc/sys/t_link.c new file mode 100644 index 00000000000..291fd9cda40 --- /dev/null +++ b/regress/lib/libc/sys/t_link.c @@ -0,0 +1,234 @@ +/* $OpenBSD: t_link.c,v 1.1.1.1 2019/11/19 19:57:03 bluhm Exp $ */ +/* $NetBSD: t_link.c,v 1.3 2017/01/13 20:42:36 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 "macros.h" + +#include <sys/cdefs.h> +__RCSID("$NetBSD: t_link.c,v 1.3 2017/01/13 20:42:36 christos Exp $"); + +#include <sys/param.h> +#include <sys/stat.h> + +#include "atf-c.h" +#include <errno.h> +#include <fcntl.h> +#include <limits.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/regress/lib/libc/sys/t_listen.c b/regress/lib/libc/sys/t_listen.c new file mode 100644 index 00000000000..da5b287cdf1 --- /dev/null +++ b/regress/lib/libc/sys/t_listen.c @@ -0,0 +1,139 @@ +/* $OpenBSD: t_listen.c,v 1.1.1.1 2019/11/19 19:57:03 bluhm Exp $ */ +/* $NetBSD: t_listen.c,v 1.6 2019/07/09 16:24:01 maya 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 "macros.h" + +#include <sys/socket.h> +#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); + ATF_REQUIRE_MSG(sd != -1, "socket failed: %s", strerror(errno)); + + 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 atf_no_error(); +} diff --git a/regress/lib/libc/sys/t_mkdir.c b/regress/lib/libc/sys/t_mkdir.c new file mode 100644 index 00000000000..41df34ace93 --- /dev/null +++ b/regress/lib/libc/sys/t_mkdir.c @@ -0,0 +1,213 @@ +/* $OpenBSD: t_mkdir.c,v 1.1.1.1 2019/11/19 19:57:03 bluhm Exp $ */ +/* $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 "macros.h" + +#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/regress/lib/libc/sys/t_mkfifo.c b/regress/lib/libc/sys/t_mkfifo.c new file mode 100644 index 00000000000..1c2fe60e3a1 --- /dev/null +++ b/regress/lib/libc/sys/t_mkfifo.c @@ -0,0 +1,309 @@ +/* $OpenBSD: t_mkfifo.c,v 1.1.1.1 2019/11/19 19:57:03 bluhm Exp $ */ +/* $NetBSD: t_mkfifo.c,v 1.3 2019/06/20 03:31:54 kamil 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 "macros.h" + +#include <sys/cdefs.h> +__RCSID("$NetBSD: t_mkfifo.c,v 1.3 2019/06/20 03:31:54 kamil 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_TC_WITH_CLEANUP(mknod_s_ififo); +ATF_TC_HEAD(mknod_s_ififo, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test mknod(2) with S_IFIFO"); +} + +ATF_TC_BODY(mknod_s_ififo, tc) +{ + struct stat st; + + support(); + + (void)memset(&st, 0, sizeof(struct stat)); + + ATF_REQUIRE(mknod(path, S_IFIFO | 0600, 0) == 0); + ATF_REQUIRE(stat(path, &st) == 0); + + if (S_ISFIFO(st.st_mode) == 0) + atf_tc_fail("invalid mode from mknod(2) with S_IFIFO"); + + ATF_REQUIRE(unlink(path) == 0); +} + +ATF_TC_CLEANUP(mknod_s_ififo, 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); + ATF_TP_ADD_TC(tp, mknod_s_ififo); + + return atf_no_error(); +} diff --git a/regress/lib/libc/sys/t_mknod.c b/regress/lib/libc/sys/t_mknod.c new file mode 100644 index 00000000000..0a16124859d --- /dev/null +++ b/regress/lib/libc/sys/t_mknod.c @@ -0,0 +1,199 @@ +/* $OpenBSD: t_mknod.c,v 1.1.1.1 2019/11/19 19:57:03 bluhm Exp $ */ +/* $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 "macros.h" + +#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)); + + /* + * Adjusted for OpenBSD, only supports FIFO and device special files + * 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/regress/lib/libc/sys/t_mlock.c b/regress/lib/libc/sys/t_mlock.c new file mode 100644 index 00000000000..1fd986383d5 --- /dev/null +++ b/regress/lib/libc/sys/t_mlock.c @@ -0,0 +1,325 @@ +/* $OpenBSD: t_mlock.c,v 1.1.1.1 2019/11/19 19:57:04 bluhm Exp $ */ +/* $NetBSD: t_mlock.c,v 1.7 2019/03/13 08:50:12 kre 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 "macros.h" + +#include <sys/cdefs.h> +__RCSID("$NetBSD: t_mlock.c,v 1.7 2019/03/13 08:50:12 kre 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 <string.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; + int err1, err2; + + buf = malloc(page); + ATF_REQUIRE(buf != NULL); + fprintf(stderr, "mlock_clip: buf = %p (page=%ld)\n", buf, page); + + if (page < 1024) + atf_tc_skip("page size too small"); + + for (size_t i = page; i >= 1; i = i - 1024) { + err1 = mlock(buf, page - i); + if (err1 != 0) + fprintf(stderr, "mlock_clip: page=%ld i=%zu," + " mlock(%p, %ld): %s\n", page, i, buf, page - i, + strerror(errno)); + err2 = munlock(buf, page - i); + if (err2 != 0) + fprintf(stderr, "mlock_clip: page=%ld i=%zu," + " munlock(%p, %ld): %s (mlock %s)\n", page, i, + buf, page - i, strerror(errno), err1?"failed":"ok"); + } + + 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) +{ + void *invalid_ptr; + void *buf; + int mlock_err, munlock_err; + + /* + * Any bad address must return ENOMEM (for lock & unlock) + */ + errno = 0; + ATF_REQUIRE_ERRNO(ENOMEM, mlock(NULL, page) == -1); + + errno = 0; + ATF_REQUIRE_ERRNO(ENOMEM, mlock((char *)0, page) == -1); + + errno = 0; + /* Adjusted for OpenBSD, initially ENOMEM */ + ATF_REQUIRE_ERRNO(EINVAL, mlock((char *)-1, page) == -1); + + errno = 0; + ATF_REQUIRE_ERRNO(ENOMEM, munlock(NULL, page) == -1); + + errno = 0; + ATF_REQUIRE_ERRNO(ENOMEM, munlock((char *)0, page) == -1); + + errno = 0; + /* Adjusted for OpenBSD, initially ENOMEM */ + ATF_REQUIRE_ERRNO(EINVAL, munlock((char *)-1, page) == -1); + + buf = malloc(page); + ATF_REQUIRE(buf != NULL); + fprintf(stderr, "mlock_err: buf = %p (page=%ld)\n", buf, page); + + /* + * unlocking memory that is not locked is an error... + */ + + /* + * Adjusted for OpenBSD + * errno = 0; + * ATF_REQUIRE_ERRNO(ENOMEM, munlock(buf, page) == -1); + */ + + /* + * These are permitted to fail (EINVAL) but do not on NetBSD + */ + mlock_err = mlock((void *)(((uintptr_t)buf) + page/3), page/5); + if (mlock_err != 0) + fprintf(stderr, "mlock_err: mlock(%p, %ld): %d [%d] %s\n", + (void *)(((uintptr_t)buf) + page/3), page/5, mlock_err, + errno, strerror(errno)); + ATF_REQUIRE(mlock_err == 0); + munlock_err= munlock((void *)(((uintptr_t)buf) + page/3), page/5); + if (munlock_err != 0) + fprintf(stderr, "mlock_err: munlock(%p, %ld): %d [%d] %s\n", + (void *)(((uintptr_t)buf) + page/3), page/5, munlock_err, + errno, strerror(errno)); + ATF_REQUIRE(munlock_err == 0); + + (void)free(buf); + + /* + * 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); + fprintf(stderr, "mlock_limits: buf = %p (page=%ld)\n", buf, page); + + 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 %zu bytes " + "with %zu byte limit\n", i, (size_t)res.rlim_cur); + + if (setrlimit(RLIMIT_MEMLOCK, &res) != 0) + _exit(EXIT_FAILURE); + + errno = 0; + + if ((sta = mlock(buf, i)) != -1 || errno != EAGAIN) { + fprintf(stderr, "mlock(%p, %zu): %d [%d] %s\n", + buf, i, sta, errno, strerror(errno)); + (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) +{ + /* Adjusted for OpenBSD, initially ... | MAP_WIRED */ + static const int flags = MAP_ANON | MAP_PRIVATE; + 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); + + if (buf == MAP_FAILED) + fprintf(stderr, + "mlock_mmap: mmap(NULL, %ld, %#x, %#x, -1, 0): MAP_FAILED" + " [%d] %s\n", page, PROT_READ | PROT_WRITE, flags, errno, + strerror(errno)); + + ATF_REQUIRE(buf != MAP_FAILED); + + fprintf(stderr, "mlock_mmap: buf=%p, page=%ld\n", buf, page); + + ATF_REQUIRE(mlock(buf, page) == 0); + ATF_REQUIRE(munlock(buf, page) == 0); + ATF_REQUIRE(munmap(buf, page) == 0); + ATF_REQUIRE(munlock(buf, page) != 0); + + fprintf(stderr, "mlock_mmap: first test succeeded\n"); + + /* + * But it should be impossible to mlock(2) a PROT_NONE mapping. + */ + buf = mmap(NULL, page, PROT_NONE, flags, -1, 0); + + if (buf == MAP_FAILED) + fprintf(stderr, + "mlock_mmap: mmap(NULL, %ld, %#x, %#x, -1, 0): MAP_FAILED" + " [%d] %s\n", page, PROT_NONE, flags, errno, + strerror(errno)); + + ATF_REQUIRE(buf != MAP_FAILED); + ATF_REQUIRE(mlock(buf, page) != 0); + ATF_REQUIRE(munmap(buf, page) == 0); + + fprintf(stderr, "mlock_mmap: second test succeeded\n"); +} + +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; + int err; + + buf = malloc(page); + ATF_REQUIRE(buf != NULL); + fprintf(stderr, "mlock_nested: buf = %p (page=%ld)\n", buf, page); + + for (size_t i = 0; i < maxiter; i++) { + err = mlock(buf, page); + if (err != 0) + fprintf(stderr, + "mlock_nested: i=%zu (of %zu) mlock(%p, %ld): %d [%d] %s\n", + i, maxiter, buf, page, err, errno, strerror(errno)); + ATF_REQUIRE(err == 0); + } + + err = munlock(buf, page); + if (err != 0) + fprintf(stderr, "mlock_nested: munlock(%p, %ld): %d [%d] %s\n", + buf, page, err, errno, strerror(errno)); + ATF_REQUIRE(err == 0); + free(buf); +} + +ATF_TP_ADD_TCS(tp) +{ + + page = sysconf(_SC_PAGESIZE); + fprintf(stderr, "t_mlock: pagesize %ld\n", page); + 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/regress/lib/libc/sys/t_mmap.c b/regress/lib/libc/sys/t_mmap.c new file mode 100644 index 00000000000..6dbfae5bb1a --- /dev/null +++ b/regress/lib/libc/sys/t_mmap.c @@ -0,0 +1,584 @@ +/* $OpenBSD: t_mmap.c,v 1.1.1.1 2019/11/19 19:57:04 bluhm Exp $ */ +/* $NetBSD: t_mmap.c,v 1.13 2017/05/23 13:04:29 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. + */ + +/*- + * 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 "macros.h" + +#include <sys/cdefs.h> +__RCSID("$NetBSD: t_mmap.c,v 1.13 2017/05/23 13:04:29 christos Exp $"); + +#include <sys/param.h> +#include <sys/disklabel.h> +#include <sys/mman.h> +#include <sys/stat.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> + +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, " ")) { + if (strncmp(dk, "dk", 2) == 0) + snprintf(dev, sizeof(dev), _PATH_DEV "%s", dk); + else + snprintf(dev, sizeof(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; + } else + (void)fprintf(stderr, "%s: %s\n", dev, strerror(errno)); + } + 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_MSG(map != MAP_FAILED, "mmap: %s", strerror(errno)); + + (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); + + (void)munmap(map, page); + ATF_REQUIRE(close(fd) == 0); +} + +ATF_TC_CLEANUP(mmap_truncate, tc) +{ + (void)unlink(path); +} + +ATF_TC_WITH_CLEANUP(mmap_truncate_signal); +ATF_TC_HEAD(mmap_truncate_signal, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Test mmap(2) ftruncate(2) causing signal"); +} + +ATF_TC_BODY(mmap_truncate_signal, tc) +{ + char *map; + long i; + int fd, sta; + pid_t pid; + + fd = open(path, O_RDWR | O_CREAT, 0700); + + if (fd < 0) + return; + + ATF_REQUIRE(write(fd, "foo\n", 5) == 5); + + map = mmap(NULL, page, PROT_READ, MAP_FILE|MAP_PRIVATE, fd, 0); + ATF_REQUIRE(map != MAP_FAILED); + + sta = 0; + for (i = 0; i < 5; i++) + sta += map[i]; + ATF_REQUIRE(sta == 334); + + ATF_REQUIRE(ftruncate(fd, 0) == 0); + pid = fork(); + ATF_REQUIRE(pid >= 0); + + if (pid == 0) { + ATF_REQUIRE(signal(SIGBUS, map_sighandler) != SIG_ERR); + ATF_REQUIRE(signal(SIGSEGV, map_sighandler) != SIG_ERR); + sta = 0; + for (i = 0; i < page; i++) + sta += map[i]; + /* child never will get this far, but the compiler will + not know, so better use the values calculated to + prevent the access to be optimized out */ + ATF_REQUIRE(i == 0); + ATF_REQUIRE(sta == 0); + (void)munmap(map, page); + (void)close(fd); + return; + } + + (void)wait(&sta); + + ATF_REQUIRE(WIFEXITED(sta) != 0); + if (WEXITSTATUS(sta) == SIGSEGV) + atf_tc_fail("child process got SIGSEGV instead of SIGBUS"); + ATF_REQUIRE(WEXITSTATUS(sta) == SIGBUS); + ATF_REQUIRE(munmap(map, page) == 0); + ATF_REQUIRE(close(fd) == 0); +} + +ATF_TC_CLEANUP(mmap_truncate_signal, 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_truncate_signal); + /* + * Adjusted for OpenBSD, not available + * ATF_TP_ADD_TC(tp, mmap_va0); + */ + + return atf_no_error(); +} diff --git a/regress/lib/libc/sys/t_msgctl.c b/regress/lib/libc/sys/t_msgctl.c new file mode 100644 index 00000000000..980f11ee0b8 --- /dev/null +++ b/regress/lib/libc/sys/t_msgctl.c @@ -0,0 +1,405 @@ +/* $OpenBSD: t_msgctl.c,v 1.1.1.1 2019/11/19 19:57:04 bluhm Exp $ */ +/* $NetBSD: t_msgctl.c,v 1.7 2017/10/07 17:15:44 kre 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 "macros.h" + +#include <sys/cdefs.h> +__RCSID("$NetBSD: t_msgctl.c,v 1.7 2017/10/07 17:15:44 kre 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 <limits.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 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(); +} + +static volatile int sig_caught; + +static void +sigsys_handler(int signum) +{ + + sig_caught = signum; +} + +static int +no_kernel_sysvmsg(void) +{ + int id; + void (*osig)(int); + + sig_caught = 0; + osig = signal(SIGSYS, sigsys_handler); + id = msgget(MSG_KEY, IPC_CREAT | 0600); + if (sig_caught || id == -1) + return 1; + + (void)msgctl(id, IPC_RMID, 0); + (void)signal(SIGSYS, osig); + + return 0; +} + +ATF_TC(msgctl_query); +ATF_TC_HEAD(msgctl_query, tc) +{ + atf_tc_set_md_var(tc, "descr", "Skip msgctl_* tests - no SYSVMSG"); +} +ATF_TC_BODY(msgctl_query, tc) +{ + atf_tc_skip("No SYSVMSG in kernel"); +} + +ATF_TP_ADD_TCS(tp) +{ + + if (no_kernel_sysvmsg()) { + ATF_TP_ADD_TC(tp, msgctl_query); + } else { + 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/regress/lib/libc/sys/t_msgget.c b/regress/lib/libc/sys/t_msgget.c new file mode 100644 index 00000000000..2a9bb4cf3b5 --- /dev/null +++ b/regress/lib/libc/sys/t_msgget.c @@ -0,0 +1,339 @@ +/* $OpenBSD: t_msgget.c,v 1.1.1.1 2019/11/19 19:57:04 bluhm Exp $ */ +/* $NetBSD: t_msgget.c,v 1.3 2017/10/08 08:31:05 kre 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 "macros.h" + +#include <sys/cdefs.h> +__RCSID("$NetBSD: t_msgget.c,v 1.3 2017/10/08 08:31:05 kre 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(); +} + +static volatile int sig_caught; + +static void +sigsys_handler(int signum) +{ + + sig_caught = signum; +} + +static int +no_kernel_sysvmsg(void) +{ + int id; + void (*osig)(int); + + sig_caught = 0; + osig = signal(SIGSYS, sigsys_handler); + id = msgget(MSG_KEY, IPC_CREAT | 0600); + if (sig_caught || id == -1) + return 1; + + (void)msgctl(id, IPC_RMID, 0); + (void)signal(SIGSYS, osig); + + return 0; +} + +ATF_TC(msgget_query); +ATF_TC_HEAD(msgget_query, tc) +{ + atf_tc_set_md_var(tc, "descr", "Skip msgget_* tests - no SYSVMSG"); +} +ATF_TC_BODY(msgget_query, tc) +{ + atf_tc_skip("No SYSVMSG in kernel"); +} + +ATF_TP_ADD_TCS(tp) +{ + + if (no_kernel_sysvmsg()) { + ATF_TP_ADD_TC(tp, msgget_query); + } else { + ATF_TP_ADD_TC(tp, msgget_excl); + ATF_TP_ADD_TC(tp, msgget_exit); + ATF_TP_ADD_TC(tp, msgget_init); + /* + * Adjusted for OpenBSD, not available + * ATF_TP_ADD_TC(tp, msgget_limit); + */ + ATF_TP_ADD_TC(tp, msgget_mode); + } + + return atf_no_error(); +} diff --git a/regress/lib/libc/sys/t_msgrcv.c b/regress/lib/libc/sys/t_msgrcv.c new file mode 100644 index 00000000000..1fbcd416951 --- /dev/null +++ b/regress/lib/libc/sys/t_msgrcv.c @@ -0,0 +1,388 @@ +/* $OpenBSD: t_msgrcv.c,v 1.1.1.1 2019/11/19 19:57:04 bluhm Exp $ */ +/* $NetBSD: t_msgrcv.c,v 1.5 2017/10/08 08:31:05 kre 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 "macros.h" + +#include <sys/cdefs.h> +__RCSID("$NetBSD: t_msgrcv.c,v 1.5 2017/10/08 08:31:05 kre 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 <limits.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(); +} + +static volatile int sig_caught; + +static void +sigsys_handler(int signum) +{ + + sig_caught = signum; +} + +static int +no_kernel_sysvmsg(void) +{ + int id; + void (*osig)(int); + + sig_caught = 0; + osig = signal(SIGSYS, sigsys_handler); + id = msgget(MSG_KEY, IPC_CREAT | 0600); + if (sig_caught || id == -1) + return 1; + + (void)msgctl(id, IPC_RMID, 0); + (void)signal(SIGSYS, osig); + + return 0; +} + +ATF_TC(msgrcv_query); +ATF_TC_HEAD(msgrcv_query, tc) +{ + atf_tc_set_md_var(tc, "descr", "Skip msgrcv_* tests - no SYSVMSG"); +} +ATF_TC_BODY(msgrcv_query, tc) +{ + atf_tc_skip("No SYSVMSG in kernel"); +} + +ATF_TP_ADD_TCS(tp) +{ + + if (no_kernel_sysvmsg()) { + ATF_TP_ADD_TC(tp, msgrcv_query); + } else { + 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/regress/lib/libc/sys/t_msgsnd.c b/regress/lib/libc/sys/t_msgsnd.c new file mode 100644 index 00000000000..ab0cc87e6f8 --- /dev/null +++ b/regress/lib/libc/sys/t_msgsnd.c @@ -0,0 +1,384 @@ +/* $OpenBSD: t_msgsnd.c,v 1.1.1.1 2019/11/19 19:57:04 bluhm Exp $ */ +/* $NetBSD: t_msgsnd.c,v 1.4 2017/10/08 08:31:05 kre 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 "macros.h" + +#include <sys/cdefs.h> +__RCSID("$NetBSD: t_msgsnd.c,v 1.4 2017/10/08 08:31:05 kre 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 <limits.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(); +} + +static volatile int sig_caught; + +static void +sigsys_handler(int signum) +{ + + sig_caught = signum; +} + +static int +no_kernel_sysvmsg(void) +{ + int id; + void (*osig)(int); + + sig_caught = 0; + osig = signal(SIGSYS, sigsys_handler); + id = msgget(MSG_KEY, IPC_CREAT | 0600); + if (sig_caught || id == -1) + return 1; + + (void)msgctl(id, IPC_RMID, 0); + (void)signal(SIGSYS, osig); + + return 0; +} + +ATF_TC(msgsnd_query); +ATF_TC_HEAD(msgsnd_query, tc) +{ + atf_tc_set_md_var(tc, "descr", "Skip msgsnd_* tests - no SYSVMSG"); +} +ATF_TC_BODY(msgsnd_query, tc) +{ + atf_tc_skip("No SYSVMSG in kernel"); +} + +ATF_TP_ADD_TCS(tp) +{ + + if (no_kernel_sysvmsg()) { + ATF_TP_ADD_TC(tp, msgsnd_query); + } else { + 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/regress/lib/libc/sys/t_msync.c b/regress/lib/libc/sys/t_msync.c new file mode 100644 index 00000000000..8e06d79d9a3 --- /dev/null +++ b/regress/lib/libc/sys/t_msync.c @@ -0,0 +1,228 @@ +/* $OpenBSD: t_msync.c,v 1.1.1.1 2019/11/19 19:57:04 bluhm Exp $ */ +/* $NetBSD: t_msync.c,v 1.3 2017/01/14 20:52:42 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 "macros.h" + +#include <sys/cdefs.h> +__RCSID("$NetBSD: t_msync.c,v 1.3 2017/01/14 20:52:42 christos 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 len; + int fd, rv; + + /* + * Create a temporary file, write + * one page to it, and map the file. + */ + buf = malloc(page); + + if (buf == NULL) + return NULL; + + memset(buf, 'x', page); + + fd = open(path, O_RDWR | O_CREAT, 0700); + + if (fd < 0) { + free(buf); + return "failed to open"; + } + + ATF_REQUIRE_MSG(write(fd, buf, page) != -1, "write(2) failed: %s", + strerror(errno)); + + 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/regress/lib/libc/sys/t_pipe.c b/regress/lib/libc/sys/t_pipe.c new file mode 100644 index 00000000000..bd9805a4b94 --- /dev/null +++ b/regress/lib/libc/sys/t_pipe.c @@ -0,0 +1,168 @@ +/* $OpenBSD: t_pipe.c,v 1.1.1.1 2019/11/19 19:57:04 bluhm Exp $ */ +/* $NetBSD: t_pipe.c,v 1.5 2017/01/13 21:30:41 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 "macros.h" + +#include <sys/cdefs.h> +#include <sys/cdefs.h> +__COPYRIGHT("@(#) Copyright (c) 2008\ + The NetBSD Foundation, inc. All rights reserved."); +__RCSID("$NetBSD: t_pipe.c,v 1.5 2017/01/13 21:30:41 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); + } + free(f); +} + +ATF_TP_ADD_TCS(tp) +{ + ATF_TP_ADD_TC(tp, pipe_restart); + + return atf_no_error(); +} diff --git a/regress/lib/libc/sys/t_pipe2.c b/regress/lib/libc/sys/t_pipe2.c new file mode 100644 index 00000000000..4964be14ced --- /dev/null +++ b/regress/lib/libc/sys/t_pipe2.c @@ -0,0 +1,203 @@ +/* $OpenBSD: t_pipe2.c,v 1.1.1.1 2019/11/19 19:57:04 bluhm Exp $ */ +/* $NetBSD: t_pipe2.c,v 1.9 2017/01/13 21:19:45 christos 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 "macros.h" + +#include <sys/cdefs.h> +__RCSID("$NetBSD: t_pipe2.c,v 1.9 2017/01/13 21:19:45 christos 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_MSG(closefrom(3) != -1, "closefrom failed: %s", + strerror(errno)); + + 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); + } + + /* + * Adjusted for OpenBSD, not available + * 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]; + int old; + + ATF_REQUIRE_MSG(closefrom(4) != -1, "closefrom failed: %s", + strerror(errno)); + + 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. + */ + old = rl.rlim_cur; + rl.rlim_cur = 4; + err = setrlimit(RLIMIT_NOFILE, &rl); + ATF_REQUIRE(err == 0); + + err = pipe2(filedes, O_CLOEXEC); + ATF_REQUIRE(err == -1); + rl.rlim_cur = old; + err = setrlimit(RLIMIT_NOFILE, &rl); +} + +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); + /* + * Adjusted for OpenBSD, not available + * ATF_TP_ADD_TC(tp, pipe2_nosigpipe); + */ + ATF_TP_ADD_TC(tp, pipe2_einval); + + return atf_no_error(); +} diff --git a/regress/lib/libc/sys/t_poll.c b/regress/lib/libc/sys/t_poll.c new file mode 100644 index 00000000000..bbb8dc2d14b --- /dev/null +++ b/regress/lib/libc/sys/t_poll.c @@ -0,0 +1,398 @@ +/* $OpenBSD: t_poll.c,v 1.1.1.1 2019/11/19 19:57:04 bluhm Exp $ */ +/* $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 "macros.h" + +#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); + /* + * Adjusted for OpenBSD, not supported + * 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/regress/lib/libc/sys/t_ptrace.c b/regress/lib/libc/sys/t_ptrace.c new file mode 100644 index 00000000000..756c9c514e8 --- /dev/null +++ b/regress/lib/libc/sys/t_ptrace.c @@ -0,0 +1,231 @@ +/* $OpenBSD: t_ptrace.c,v 1.1.1.1 2019/11/19 19:57:04 bluhm Exp $ */ +/* $NetBSD: t_ptrace.c,v 1.4 2018/05/14 12:44:40 kamil Exp $ */ + +/*- + * Copyright (c) 2016 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 "macros.h" + +#include <sys/cdefs.h> +__RCSID("$NetBSD: t_ptrace.c,v 1.4 2018/05/14 12:44:40 kamil Exp $"); + +#include <sys/param.h> +#include <sys/types.h> +#include <sys/ptrace.h> +#include <sys/stat.h> +#include <sys/sysctl.h> +#include <err.h> +#include <errno.h> +#include <unistd.h> + +#include "atf-c.h" + +#include "h_macros.h" + +/* + * A child process cannot call atf functions and expect them to magically + * work like in the parent. + * The printf(3) messaging from a child will not work out of the box as well + * without estabilishing a communication protocol with its parent. To not + * overcomplicate the tests - do not log from a child and use err(3)/errx(3) + * wrapped with FORKEE_ASSERT()/FORKEE_ASSERTX() as that is guaranteed to work. + */ +#define FORKEE_ASSERTX(x) \ +do { \ + int ret = (x); \ + if (!ret) \ + errx(EXIT_FAILURE, "%s:%d %s(): Assertion failed for: %s", \ + __FILE__, __LINE__, __func__, #x); \ +} while (0) + +#define FORKEE_ASSERT(x) \ +do { \ + int ret = (x); \ + if (!ret) \ + err(EXIT_FAILURE, "%s:%d %s(): Assertion failed for: %s", \ + __FILE__, __LINE__, __func__, #x); \ +} while (0) + +ATF_TC(attach_pid0); +ATF_TC_HEAD(attach_pid0, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Assert that a debugger cannot attach to PID 0"); +} + +ATF_TC_BODY(attach_pid0, tc) +{ + errno = 0; + ATF_REQUIRE_ERRNO(EPERM, ptrace(PT_ATTACH, 0, NULL, 0) == -1); +} + +ATF_TC(attach_pid1); +ATF_TC_HEAD(attach_pid1, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Assert that a debugger cannot attach to PID 1 (as non-root)"); + + atf_tc_set_md_var(tc, "require.user", "unprivileged"); +} + +ATF_TC_BODY(attach_pid1, tc) +{ + ATF_REQUIRE_ERRNO(EPERM, ptrace(PT_ATTACH, 1, NULL, 0) == -1); +} + +ATF_TC(attach_pid1_securelevel); +ATF_TC_HEAD(attach_pid1_securelevel, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Assert that a debugger cannot attach to PID 1 with " + "securelevel >= 0 (as root)"); + + atf_tc_set_md_var(tc, "require.user", "root"); +} + +ATF_TC_BODY(attach_pid1_securelevel, tc) +{ + int level; + size_t len = sizeof(level); + + ATF_REQUIRE(sysctlbyname("kern.securelevel", &level, &len, NULL, 0) + != -1); + + if (level < 0) { + atf_tc_skip("Test must be run with securelevel >= 0"); + } + + ATF_REQUIRE_ERRNO(EPERM, ptrace(PT_ATTACH, 1, NULL, 0) == -1); +} + +ATF_TC(attach_self); +ATF_TC_HEAD(attach_self, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Assert that a debugger cannot attach to self (as it's nonsense)"); +} + +ATF_TC_BODY(attach_self, tc) +{ + ATF_REQUIRE_ERRNO(EINVAL, ptrace(PT_ATTACH, getpid(), NULL, 0) == -1); +} + +ATF_TC(attach_chroot); +ATF_TC_HEAD(attach_chroot, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Assert that a debugger cannot trace another process unless the " + "process's root directory is at or below the tracing process's " + "root"); + + atf_tc_set_md_var(tc, "require.user", "root"); +} + +ATF_TC_BODY(attach_chroot, tc) +{ + char buf[PATH_MAX]; + pid_t child; + int fds_toparent[2], fds_fromparent[2]; + int rv; + uint8_t msg = 0xde; /* dummy message for IPC based on pipe(2) */ + + (void)memset(buf, '\0', sizeof(buf)); + ATF_REQUIRE(getcwd(buf, sizeof(buf)) != NULL); + (void)strlcat(buf, "/dir", sizeof(buf)); + + ATF_REQUIRE(mkdir(buf, 0500) == 0); + ATF_REQUIRE(chdir(buf) == 0); + + ATF_REQUIRE(pipe(fds_toparent) == 0); + ATF_REQUIRE(pipe(fds_fromparent) == 0); + child = atf_utils_fork(); + if (child == 0) { + FORKEE_ASSERT(close(fds_toparent[0]) == 0); + FORKEE_ASSERT(close(fds_fromparent[1]) == 0); + + FORKEE_ASSERT(chroot(buf) == 0); + + rv = write(fds_toparent[1], &msg, sizeof(msg)); + FORKEE_ASSERTX(rv == sizeof(msg)); + + ATF_REQUIRE_ERRNO(EPERM, + ptrace(PT_ATTACH, getppid(), NULL, 0) == -1); + + rv = read(fds_fromparent[0], &msg, sizeof(msg)); + FORKEE_ASSERTX(rv == sizeof(msg)); + + _exit(0); + } + ATF_REQUIRE(close(fds_toparent[1]) == 0); + ATF_REQUIRE(close(fds_fromparent[0]) == 0); + + printf("Waiting for chrooting of the child PID %d", child); + rv = read(fds_toparent[0], &msg, sizeof(msg)); + ATF_REQUIRE(rv == sizeof(msg)); + + printf("Child is ready, it will try to PT_ATTACH to parent\n"); + rv = write(fds_fromparent[1], &msg, sizeof(msg)); + ATF_REQUIRE(rv == sizeof(msg)); + + printf("fds_fromparent is no longer needed - close it\n"); + ATF_REQUIRE(close(fds_fromparent[1]) == 0); + + printf("fds_toparent is no longer needed - close it\n"); + ATF_REQUIRE(close(fds_toparent[0]) == 0); +} + +ATF_TC(traceme_twice); +ATF_TC_HEAD(traceme_twice, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Assert that a process cannot mark its parent a debugger twice"); +} + +ATF_TC_BODY(traceme_twice, tc) +{ + + printf("Mark the parent process (PID %d) a debugger of PID %d", + getppid(), getpid()); + ATF_REQUIRE(ptrace(PT_TRACE_ME, 0, NULL, 0) == 0); + + printf("Mark the parent process (PID %d) a debugger of PID %d again", + getppid(), getpid()); + ATF_REQUIRE_ERRNO(EBUSY, ptrace(PT_TRACE_ME, 0, NULL, 0) == -1); +} + +ATF_TP_ADD_TCS(tp) +{ + setvbuf(stdout, NULL, _IONBF, 0); + setvbuf(stderr, NULL, _IONBF, 0); + ATF_TP_ADD_TC(tp, attach_pid0); + ATF_TP_ADD_TC(tp, attach_pid1); + ATF_TP_ADD_TC(tp, attach_pid1_securelevel); + ATF_TP_ADD_TC(tp, attach_self); + ATF_TP_ADD_TC(tp, attach_chroot); + ATF_TP_ADD_TC(tp, traceme_twice); + + return atf_no_error(); +} diff --git a/regress/lib/libc/sys/t_revoke.c b/regress/lib/libc/sys/t_revoke.c new file mode 100644 index 00000000000..ad54f814d14 --- /dev/null +++ b/regress/lib/libc/sys/t_revoke.c @@ -0,0 +1,198 @@ +/* $OpenBSD: t_revoke.c,v 1.1.1.1 2019/11/19 19:57:04 bluhm Exp $ */ +/* $NetBSD: t_revoke.c,v 1.2 2017/01/13 21:15:57 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 "macros.h" + +#include <sys/cdefs.h> +__RCSID("$NetBSD: t_revoke.c,v 1.2 2017/01/13 21:15:57 christos 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; + /* Adjusted for OpenBSD, initially EPERM */ + ATF_REQUIRE_ERRNO(ENOTTY, 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"); + + (void)close(fd); + ATF_REQUIRE(unlink(path) == 0); +} + +ATF_TC_CLEANUP(revoke_perm, tc) +{ + (void)unlink(path); +} + +ATF_TP_ADD_TCS(tp) +{ + + /* + * Adjusted for OpenBSD, revoke only on ttys supported + * ATF_TP_ADD_TC(tp, revoke_basic); + */ + ATF_TP_ADD_TC(tp, revoke_err); + /* + * Adjusted for OpenBSD, revoke only on ttys supported + * ATF_TP_ADD_TC(tp, revoke_perm); + */ + + return atf_no_error(); +} diff --git a/regress/lib/libc/sys/t_select.c b/regress/lib/libc/sys/t_select.c new file mode 100644 index 00000000000..94ff3d3410c --- /dev/null +++ b/regress/lib/libc/sys/t_select.c @@ -0,0 +1,219 @@ +/* $OpenBSD: t_select.c,v 1.1.1.1 2019/11/19 19:57:04 bluhm Exp $ */ +/* $NetBSD: t_select.c,v 1.4 2017/01/13 21:18:33 christos 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 "macros.h" + +#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 __unused) +{ + keep_going = 0; +} + +static void +sigchld(int signum __unused) +{ +} + +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) + /* Adjusted for OpenBSD, on NetBSD sigset_t is a struct */ + uint32_t p = (*m); + for (size_t k = sizeof(p); k > 0; k--) + buf[j++] = xtoa(N(p, k - 1)); + buf[j] = '\0'; + return buf; +} + +static __dead 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))); + _exit(0); +} + +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); + /*NOTREACHED*/ + 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/regress/lib/libc/sys/t_sendrecv.c b/regress/lib/libc/sys/t_sendrecv.c new file mode 100644 index 00000000000..cf44af2b3e2 --- /dev/null +++ b/regress/lib/libc/sys/t_sendrecv.c @@ -0,0 +1,186 @@ +/* $OpenBSD: t_sendrecv.c,v 1.1.1.1 2019/11/19 19:57:04 bluhm Exp $ */ +/* $NetBSD: t_sendrecv.c,v 1.6 2019/02/03 03:19:28 mrg Exp $ */ + +/*- + * Copyright (c) 2018 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 "macros.h" + +#include <sys/cdefs.h> +__RCSID("$NetBSD: t_sendrecv.c,v 1.6 2019/02/03 03:19:28 mrg Exp $"); + +#include "atf-c.h" +#include <sys/types.h> +#include <sys/socket.h> + +#include <string.h> +#include <stdint.h> +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <sched.h> +#include <signal.h> + + +#define COUNT 100 + +union packet { + uint8_t buf[1316]; + uintmax_t seq; +}; + +static volatile sig_atomic_t rdied; + +static void +handle_sigchld(__unused int pid) +{ + + rdied = 1; +} + +static void +sender(int fd) +{ + union packet p; + ssize_t n; + p.seq = 0; + for (size_t i = 0; i < COUNT; i++) { + for (; (n = send(fd, &p, sizeof(p), 0)) == sizeof(p); + p.seq++) + continue; + printf(">>%zd %d %ju\n", n, errno, p.seq); + ATF_REQUIRE_MSG(errno == ENOBUFS, "send %s", strerror(errno)); +// sched_yield(); + } + printf("sender done\n"); +} + +static void +receiver(int fd) +{ + union packet p; + ssize_t n; + uintmax_t seq = 0; + + do { + if (rdied) + return; + while ((n = recv(fd, &p, sizeof(p), 0), sizeof(p)) + == sizeof(p)) + { + if (rdied) + return; + if (p.seq != seq) + printf("%ju != %ju\n", p.seq, seq); + seq = p.seq + 1; + } + printf("<<%zd %d %ju\n", n, errno, seq); + if (n == 0) + return; + ATF_REQUIRE_EQ(n, -1); + ATF_REQUIRE_MSG(errno == ENOBUFS, "recv %s", strerror(errno)); + } while (p.seq < COUNT); +} + +static void +sendrecv(int rerror) +{ + int fd[2], error; + struct sigaction sa; + + error = socketpair(AF_UNIX, SOCK_DGRAM, 0, fd); +// error = pipe(fd); + ATF_REQUIRE_MSG(error != -1, "socketpair failed (%s)", strerror(errno)); + + for (size_t i = 0; i < __arraycount(fd); i++) { + error = setsockopt(fd[i], SOL_SOCKET, SO_RERROR, &rerror, + sizeof(rerror)); + ATF_REQUIRE_MSG(error != -1, + "setsockopt(SO_RERROR) failed (%s)", strerror(errno)); + } + + memset(&sa, 0, sizeof(sa)); + sa.sa_flags = 0; + sa.sa_handler = &handle_sigchld; + sigemptyset(&sa.sa_mask); + error = sigaction(SIGCHLD, &sa, 0); + ATF_REQUIRE_MSG(error != -1, "sigaction failed (%s)", + strerror(errno)); + + switch (fork()) { + case -1: + ATF_REQUIRE_MSG(errno == 0, + "socketpair failed (%s)", strerror(errno)); + __unreachable(); + /*NOTREACHED*/ + case 0: + sched_yield(); + sender(fd[0]); + close(fd[0]); + exit(EXIT_SUCCESS); + /*NOTREACHED*/ + default: + receiver(fd[1]); + return; + } +} + +ATF_TC(sendrecv_basic); + +ATF_TC_HEAD(sendrecv_basic, tc) +{ + atf_tc_set_md_var(tc, "descr", "A basic test of send/recv(2)"); +} + +ATF_TC_BODY(sendrecv_basic, tc) +{ + sendrecv(0); +} + +ATF_TC(sendrecv_rerror); + +ATF_TC_HEAD(sendrecv_rerror, tc) +{ + atf_tc_set_md_var(tc, "descr", "Test send/recv(2) with receiver error"); +} + +ATF_TC_BODY(sendrecv_rerror, tc) +{ + sendrecv(1); +} + +ATF_TP_ADD_TCS(tp) +{ + + ATF_TP_ADD_TC(tp, sendrecv_basic); + ATF_TP_ADD_TC(tp, sendrecv_rerror); + + return atf_no_error(); +} diff --git a/regress/lib/libc/sys/t_setuid.c b/regress/lib/libc/sys/t_setuid.c new file mode 100644 index 00000000000..7d3bd1986b0 --- /dev/null +++ b/regress/lib/libc/sys/t_setuid.c @@ -0,0 +1,126 @@ +/* $OpenBSD: t_setuid.c,v 1.1.1.1 2019/11/19 19:57:04 bluhm Exp $ */ +/* $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 "macros.h" + +#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/regress/lib/libc/sys/t_sigaction.c b/regress/lib/libc/sys/t_sigaction.c new file mode 100644 index 00000000000..21c793d74ac --- /dev/null +++ b/regress/lib/libc/sys/t_sigaction.c @@ -0,0 +1,156 @@ +/* $OpenBSD: t_sigaction.c,v 1.1.1.1 2019/11/19 19:57:04 bluhm Exp $ */ +/* $NetBSD: t_sigaction.c,v 1.5 2017/01/13 21:30:41 christos 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 "macros.h" + +#include <sys/cdefs.h> +__COPYRIGHT("@(#) Copyright (c) 2010\ + The NetBSD Foundation, inc. All rights reserved."); +__RCSID("$NetBSD: t_sigaction.c,v 1.5 2017/01/13 21:30:41 christos 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 "h_macros.h" + +static bool handler_called = false; + +static void +handler(int signo __unused) +{ + 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 __unused) +{ + 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/regress/lib/libc/sys/t_socketpair.c b/regress/lib/libc/sys/t_socketpair.c new file mode 100644 index 00000000000..076d2fa057a --- /dev/null +++ b/regress/lib/libc/sys/t_socketpair.c @@ -0,0 +1,141 @@ +/* $OpenBSD: t_socketpair.c,v 1.1.1.1 2019/11/19 19:57:04 bluhm Exp $ */ +/* $NetBSD: t_socketpair.c,v 1.2 2017/01/13 20:04:52 christos 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 "macros.h" + +#include <sys/cdefs.h> +__RCSID("$NetBSD: t_socketpair.c,v 1.2 2017/01/13 20:04:52 christos 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(closefrom(3) != -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/regress/lib/libc/sys/t_stat.c b/regress/lib/libc/sys/t_stat.c new file mode 100644 index 00000000000..ea7f4b24a27 --- /dev/null +++ b/regress/lib/libc/sys/t_stat.c @@ -0,0 +1,423 @@ +/* $OpenBSD: t_stat.c,v 1.1.1.1 2019/11/19 19:57:04 bluhm Exp $ */ +/* $NetBSD: t_stat.c,v 1.5 2017/01/13 20:06:50 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 "macros.h" + +#include <sys/cdefs.h> +__RCSID("$NetBSD: t_stat.c,v 1.5 2017/01/13 20:06:50 christos Exp $"); + +#include <sys/stat.h> +#include <sys/socket.h> +#include <sys/types.h> + +#include <arpa/inet.h> +#include <netinet/in.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)"); + + (void)close(fd); + 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/regress/lib/libc/sys/t_syscall.c b/regress/lib/libc/sys/t_syscall.c new file mode 100644 index 00000000000..e8649702623 --- /dev/null +++ b/regress/lib/libc/sys/t_syscall.c @@ -0,0 +1,122 @@ +/* $OpenBSD: t_syscall.c,v 1.1.1.1 2019/11/19 19:57:04 bluhm Exp $ */ +/* $NetBSD: t_syscall.c,v 1.3 2018/05/28 07:55:56 martin Exp $ */ + +/*- + * Copyright (c) 2018 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Martin Husemann. + * + * 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 "macros.h" + +#include <sys/cdefs.h> +__RCSID("$NetBSD: t_syscall.c,v 1.3 2018/05/28 07:55:56 martin Exp $"); + + +#include "atf-c.h" +#include <stdio.h> +#include <unistd.h> +#include <fcntl.h> +#include <err.h> +#include <string.h> +#include <stdlib.h> +#include <sys/mman.h> +#include <sys/endian.h> +#include <sys/syscall.h> + +#if !defined(_LP64) && BYTE_ORDER == _BIG_ENDIAN +#define __SYSCALL_TO_UINTPTR_T(V) ((uintptr_t)((V)>>32)) +#else +#define __SYSCALL_TO_UINTPTR_T(V) ((uintptr_t)(V)) +#endif + +static const char secrect_data[1024] = { + "my secret key\n" +}; + +#define FILE_NAME "dummy" + +#ifndef _LP64 +ATF_TC(mmap_syscall); + +ATF_TC_HEAD(mmap_syscall, tc) +{ + atf_tc_set_md_var(tc, "descr", "Tests mmap(2) via syscall(2)"); +} + +ATF_TC_BODY(mmap_syscall, tc) +{ + int fd; + const char *p; + + fd = open(FILE_NAME, O_RDWR|O_CREAT|O_TRUNC, 0666); + ATF_REQUIRE(fd != -1); + + write(fd, secrect_data, sizeof(secrect_data)); + + p = (const char *)syscall(SYS_mmap, + 0, sizeof(secrect_data), PROT_READ, MAP_PRIVATE, fd, 0, 0, 0); + ATF_REQUIRE(p != NULL); + + ATF_REQUIRE(strcmp(p, secrect_data) == 0); +} +#endif + +ATF_TC(mmap___syscall); + +ATF_TC_HEAD(mmap___syscall, tc) +{ + atf_tc_set_md_var(tc, "descr", "Tests mmap(2) via __syscall(2)"); +} + +ATF_TC_BODY(mmap___syscall, tc) +{ + int fd; + const char *p; + + fd = open(FILE_NAME, O_RDWR|O_CREAT|O_TRUNC, 0666); + ATF_REQUIRE(fd != -1); + + write(fd, secrect_data, sizeof(secrect_data)); + + p = (const char *)__SYSCALL_TO_UINTPTR_T(__syscall(SYS_mmap, + 0, sizeof(secrect_data), PROT_READ, MAP_PRIVATE, fd, + /* pad*/ 0, (off_t)0)); + ATF_REQUIRE(p != NULL); + + ATF_REQUIRE(strcmp(p, secrect_data) == 0); +} + +ATF_TP_ADD_TCS(tp) +{ + +#ifndef _LP64 + ATF_TP_ADD_TC(tp, mmap_syscall); +#endif + ATF_TP_ADD_TC(tp, mmap___syscall); + + return atf_no_error(); +} diff --git a/regress/lib/libc/sys/t_truncate.c b/regress/lib/libc/sys/t_truncate.c new file mode 100644 index 00000000000..1d059af5f51 --- /dev/null +++ b/regress/lib/libc/sys/t_truncate.c @@ -0,0 +1,183 @@ +/* $OpenBSD: t_truncate.c,v 1.1.1.1 2019/11/19 19:57:04 bluhm Exp $ */ +/* $NetBSD: t_truncate.c,v 1.3 2017/01/13 20:03:51 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 "macros.h" + +#include <sys/cdefs.h> +__RCSID("$NetBSD: t_truncate.c,v 1.3 2017/01/13 20:03:51 christos Exp $"); + +#include <sys/stat.h> + +#include "atf-c.h" +#include <errno.h> +#include <fcntl.h> +#include <limits.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) +{ + char buf[PATH_MAX]; + + 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; + snprintf(buf, sizeof(buf), "%s/truncate_test.root_owned", + atf_tc_get_config_var(tc, "srcdir")); + ATF_REQUIRE_ERRNO(EACCES, truncate(buf, 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/regress/lib/libc/sys/t_umask.c b/regress/lib/libc/sys/t_umask.c new file mode 100644 index 00000000000..b312e8183b8 --- /dev/null +++ b/regress/lib/libc/sys/t_umask.c @@ -0,0 +1,210 @@ +/* $OpenBSD: t_umask.c,v 1.1.1.1 2019/11/19 19:57:04 bluhm Exp $ */ +/* $NetBSD: t_umask.c,v 1.2 2017/01/13 19:34: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 "macros.h" + +#include <sys/cdefs.h> +__RCSID("$NetBSD: t_umask.c,v 1.2 2017/01/13 19:34:19 christos 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)close(fd); + (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/regress/lib/libc/sys/t_unlink.c b/regress/lib/libc/sys/t_unlink.c new file mode 100644 index 00000000000..9736d775931 --- /dev/null +++ b/regress/lib/libc/sys/t_unlink.c @@ -0,0 +1,162 @@ +/* $OpenBSD: t_unlink.c,v 1.1.1.1 2019/11/19 19:57:04 bluhm Exp $ */ +/* $NetBSD: t_unlink.c,v 1.4 2017/01/14 20:55:26 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 "macros.h" + +#include <sys/cdefs.h> +__RCSID("$NetBSD: t_unlink.c,v 1.4 2017/01/14 20:55:26 christos 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/regress/lib/libc/sys/t_write.c b/regress/lib/libc/sys/t_write.c new file mode 100644 index 00000000000..d22f32383a0 --- /dev/null +++ b/regress/lib/libc/sys/t_write.c @@ -0,0 +1,287 @@ +/* $OpenBSD: t_write.c,v 1.1.1.1 2019/11/19 19:57:04 bluhm Exp $ */ +/* $NetBSD: t_write.c,v 1.6 2017/07/09 22:18:43 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 "macros.h" + +#include <sys/cdefs.h> +__COPYRIGHT("@(#) Copyright (c) 2008\ + The NetBSD Foundation, inc. All rights reserved."); +__RCSID("$NetBSD: t_write.c,v 1.6 2017/07/09 22:18:43 christos Exp $"); + +#include <sys/uio.h> +#include <sys/mman.h> + +#include "atf-c.h" +#include <errno.h> +#include <fcntl.h> +#include <signal.h> +#include <limits.h> +#include <stdio.h> +#include <stdint.h> +#include <string.h> +#include <unistd.h> +#include <paths.h> + +static void sighandler(int); + +static bool fail = false; +static const char *path = "write"; + +static void +sighandler(int signo __unused) +{ + 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_TC(write_fault); + +ATF_TC_HEAD(write_fault, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Check that writing to non-permitted space returns EFAULT"); +} + +#define SIZE 8192 + +ATF_TC_BODY(write_fault, tc) +{ + int fd[2]; + ATF_REQUIRE(pipe(fd) != -1); + // Can't use /dev/null cause it doesn't access the buffer. + + void *map = mmap(NULL, SIZE, PROT_NONE, MAP_ANON | MAP_PRIVATE, -1, 0); + ATF_REQUIRE(map != MAP_FAILED); + + ssize_t retval = write(fd[1], map, SIZE); + + ATF_REQUIRE_EQ_MSG(retval, -1, "got: %zd", retval); + ATF_REQUIRE_EQ_MSG(errno, EFAULT, "got: %s", strerror(errno)); + + munmap(map, SIZE); + close(fd[0]); + close(fd[1]); +} + +ATF_TC(read_fault); + +ATF_TC_HEAD(read_fault, tc) +{ + atf_tc_set_md_var(tc, "descr", + "Check that reading from non-permitted space returns EFAULT"); +} + +ATF_TC_BODY(read_fault, tc) +{ + int fd = open(_PATH_DEVZERO, O_RDONLY); + ATF_REQUIRE(fd != -1); + + void *map = mmap(NULL, SIZE, PROT_NONE, MAP_ANON | MAP_PRIVATE, -1, 0); + ATF_REQUIRE(map != MAP_FAILED); + + ssize_t retval = read(fd, map, SIZE); + + ATF_REQUIRE_EQ_MSG(retval, -1, "got: %zd", retval); + ATF_REQUIRE_EQ_MSG(errno, EFAULT, "got: %s", strerror(errno)); + + munmap(map, SIZE); + close(fd); +} + +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); + ATF_TP_ADD_TC(tp, write_fault); + ATF_TP_ADD_TC(tp, read_fault); + + return atf_no_error(); +} |