/* * This file and its contents are supplied under the terms of the * Common Development and Distribution License ("CDDL"), version 1.0. * You may only use this file in accordance with the terms of version * 1.0 of the CDDL. * * A full copy of the text of the CDDL should have accompanied this * source. A copy of the CDDL is also available via the Internet at * http://www.illumos.org/license/CDDL. */ /* * Copyright 2024 Oxide Computer Company */ /* * Verify that unsupported flags will properly generate errors across the * functions that we know perform strict error checking. This includes: * * o fcntl(..., F_DUP3FD, ...) * o dup3() * o pipe2() * o socket() * o accept4() */ #include #include #include #include #include #include #include #include #include #include static bool oclo_check(const char *desc, const char *act, int ret, int e) { if (ret >= 0) { warnx("TEST FAILED: %s: fd was %s!", desc, act); return (false); } else if (errno != EINVAL) { int e = errno; warnx("TEST FAILED: %s: failed with %s, expected " "EINVAL", desc, strerrorname_np(e)); return (false); } (void) printf("TEST PASSED: %s: correctly failed with EINVAL\n", desc); return (true); } static bool oclo_dup3(const char *desc, int flags) { int fd = dup3(STDERR_FILENO, 23, flags); return (oclo_check(desc, "duplicated", fd, errno)); } static bool oclo_dup3fd(const char *desc, int flags) { int fd = fcntl(STDERR_FILENO, F_DUP3FD, 23, flags); return (oclo_check(desc, "duplicated", fd, errno)); } static bool oclo_pipe2(const char *desc, int flags) { int fds[2], ret; ret = pipe2(fds, flags); return (oclo_check(desc, "piped", ret, errno)); } static bool oclo_socket(const char *desc, int type) { int fd = socket(PF_UNIX, SOCK_STREAM | type, 0); return (oclo_check(desc, "created", fd, errno)); } static bool oclo_accept(const char *desc, int flags) { int sock, fd, e; struct sockaddr_in in; sock = socket(PF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0); if (sock < 0) { warn("TEST FAILED: %s: failed to create listen socket", desc); return (false); } (void) memset(&in, 0, sizeof (in)); in.sin_family = AF_INET; in.sin_port = 0; in.sin_addr.s_addr = htonl(INADDR_LOOPBACK); if (bind(sock, (struct sockaddr *)&in, sizeof (in)) != 0) { warn("TEST FAILED: %s: failed to bind socket", desc); (void) close(sock); return (false); } if (listen(sock, 5) < 0) { warn("TEST FAILED: %s: failed to listen on socket", desc); (void) close(sock); return (false); } fd = accept4(sock, NULL, NULL, flags); e = errno; (void) close(sock); return (oclo_check(desc, "accepted", fd, e)); } int main(void) { int ret = EXIT_SUCCESS; closefrom(STDERR_FILENO + 1); if (!oclo_dup3("dup3(): O_RDWR", O_RDWR)) { ret = EXIT_FAILURE; } if (!oclo_dup3("dup3(): O_NONBLOCK|O_CLOXEC", O_NONBLOCK | O_CLOEXEC)) { ret = EXIT_FAILURE; } if (!oclo_dup3("dup3(): O_CLOFORK|O_WRONLY", O_CLOFORK | O_WRONLY)) { ret = EXIT_FAILURE; } if (!oclo_dup3fd("fcntl(FDUP3FD): 0x7777", 0x7777)) { ret = EXIT_FAILURE; } if (!oclo_dup3fd("fcntl(FDUP3FD): FD_CLOEXEC|FD_CLOFORK + 1", (FD_CLOEXEC | FD_CLOFORK) + 1)) { ret = EXIT_FAILURE; } if (!oclo_dup3fd("fcntl(FDUP3FD): INT_MAX", INT_MAX)) { ret = EXIT_FAILURE; } if (!oclo_pipe2("pipe2(): O_RDWR", O_RDWR)) { ret = EXIT_FAILURE; } if (!oclo_pipe2("pipe2(): O_SYNC|O_CLOXEC", O_SYNC | O_CLOEXEC)) { ret = EXIT_FAILURE; } if (!oclo_pipe2("pipe2(): O_CLOFORK|O_WRONLY", O_CLOFORK | O_WRONLY)) { ret = EXIT_FAILURE; } if (!oclo_pipe2("pipe2(): INT32_MAX", INT32_MAX)) { ret = EXIT_FAILURE; } if (!oclo_socket("socket(): INT32_MAX", INT32_MAX)) { ret = EXIT_FAILURE; } if (!oclo_socket("socket(): 3 << 25", 3 << 25)) { ret = EXIT_FAILURE; } if (!oclo_accept("accept4(): INT32_MAX", INT32_MAX)) { ret = EXIT_FAILURE; } if (!oclo_accept("accept4(): 3 << 25", 3 << 25)) { ret = EXIT_FAILURE; } if (ret == EXIT_SUCCESS) { (void) printf("All tests completed successfully\n"); } return (ret); }