1 /* $OpenBSD: sigio_common.c,v 1.1 2020/09/16 14:02:23 mpi Exp $ */ 2 3 /* 4 * Copyright (c) 2018 Visa Hankala 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <sys/ioctl.h> 20 #include <sys/limits.h> 21 #include <assert.h> 22 #include <errno.h> 23 #include <fcntl.h> 24 #include <pwd.h> 25 #include <signal.h> 26 #include <unistd.h> 27 28 #include "common.h" 29 30 static char buf[1024]; 31 32 int 33 test_common_badpgid(int fd) 34 { 35 int pgid; 36 37 /* ID of non-existent process */ 38 pgid = 1000000; 39 errno = 0; 40 assert(fcntl(fd, F_SETOWN, pgid) == -1); 41 assert(errno == ESRCH); 42 errno = 0; 43 assert(ioctl(fd, FIOSETOWN, &pgid) == -1); 44 assert(errno == ESRCH); 45 46 /* ID of non-existent process group */ 47 pgid = -1000000; 48 errno = 0; 49 assert(fcntl(fd, F_SETOWN, pgid) == -1); 50 assert(errno == ESRCH); 51 errno = 0; 52 assert(ioctl(fd, FIOSETOWN, &pgid) == -1); 53 assert(errno == ESRCH); 54 55 return 0; 56 } 57 58 int 59 test_common_badsession(int fd) 60 { 61 int arg, sfd; 62 pid_t pid, ppid; 63 64 /* Ensure this process has its own process group. */ 65 assert(setpgid(0, 0) == 0); 66 67 ppid = getpid(); 68 if (test_fork(&pid, &sfd) == PARENT) { 69 test_barrier(sfd); 70 } else { 71 assert(setsid() != -1); 72 errno = 0; 73 assert(fcntl(fd, F_SETOWN, ppid) == -1); 74 assert(errno == EPERM); 75 errno = 0; 76 assert(fcntl(fd, F_SETOWN, -ppid) == -1); 77 assert(errno == EPERM); 78 arg = ppid; 79 errno = 0; 80 assert(ioctl(fd, FIOSETOWN, &arg) == -1); 81 assert(errno == EPERM); 82 arg = -ppid; 83 errno = 0; 84 assert(ioctl(fd, FIOSETOWN, &arg) == -1); 85 assert(errno == EPERM); 86 test_barrier(sfd); 87 } 88 return test_wait(pid, sfd); 89 } 90 91 /* 92 * Test that signal is not delivered if there is a privilege mismatch. 93 */ 94 int 95 test_common_cansigio(int *fds) 96 { 97 struct passwd *pw; 98 int flags, sfd; 99 pid_t pid, ppid; 100 101 assert((pw = getpwnam(SIGIO_REGRESS_USER)) != NULL); 102 assert(pw->pw_uid != getuid()); 103 104 flags = fcntl(fds[0], F_GETFL); 105 assert(fcntl(fds[0], F_SETFL, flags | O_ASYNC) == 0); 106 107 ppid = getpid(); 108 if (test_fork(&pid, &sfd) == PARENT) { 109 /* Privilege mismatch prevents signal sending. */ 110 reject_signal(SIGIO); 111 test_barrier(sfd); 112 test_barrier(sfd); 113 reject_signal(SIGIO); 114 assert(read(fds[0], buf, 1) == 1); 115 116 test_barrier(sfd); 117 assert(setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid) == 0); 118 119 /* Privileges allow signal sending. */ 120 reject_signal(SIGIO); 121 test_barrier(sfd); 122 test_barrier(sfd); 123 expect_signal(SIGIO); 124 assert(read(fds[0], buf, 1) == 1); 125 } else { 126 assert(setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid) == 0); 127 assert(fcntl(fds[0], F_SETOWN, ppid) == 0); 128 129 test_barrier(sfd); 130 assert(write(fds[1], buf, 1) == 1); 131 test_barrier(sfd); 132 133 test_barrier(sfd); 134 135 test_barrier(sfd); 136 assert(write(fds[1], buf, 1) == 1); 137 test_barrier(sfd); 138 } 139 return test_wait(pid, sfd); 140 } 141 142 /* 143 * Test that fcntl(fd, F_GETOWN) and ioctl(fd, FIOGETOWN, &arg) reflect 144 * successful fcntl(fd, F_SETOWN, arg) and ioctl(fd, FIOSETOWN, &arg). 145 */ 146 int 147 test_common_getown(int fd) 148 { 149 int pgid; 150 151 assert(fcntl(fd, F_GETOWN) == 0); 152 153 pgid = getpid(); 154 assert(fcntl(fd, F_SETOWN, pgid) == 0); 155 assert(fcntl(fd, F_GETOWN) == pgid); 156 157 pgid = -getpgrp(); 158 assert(fcntl(fd, F_SETOWN, pgid) == 0); 159 assert(fcntl(fd, F_GETOWN) == pgid); 160 161 assert(fcntl(fd, F_SETOWN, 0) == 0); 162 assert(fcntl(fd, F_GETOWN) == 0); 163 164 pgid = INT_MIN; 165 assert(ioctl(fd, FIOGETOWN, &pgid) == 0); 166 assert(pgid == 0); 167 168 pgid = getpid(); 169 assert(ioctl(fd, FIOSETOWN, &pgid) == 0); 170 pgid = INT_MIN; 171 assert(ioctl(fd, FIOGETOWN, &pgid) == 0); 172 assert(pgid == getpid()); 173 174 pgid = -getpgrp(); 175 assert(ioctl(fd, FIOSETOWN, &pgid) == 0); 176 pgid = INT_MIN; 177 assert(ioctl(fd, FIOGETOWN, &pgid) == 0); 178 assert(pgid == -getpgrp()); 179 180 pgid = 0; 181 assert(ioctl(fd, FIOSETOWN, &pgid) == 0); 182 pgid = INT_MIN; 183 assert(ioctl(fd, FIOGETOWN, &pgid) == 0); 184 assert(pgid == 0); 185 186 return 0; 187 } 188 189 /* 190 * Test that SIGIO gets triggered when data becomes available for reading. 191 */ 192 int 193 test_common_read(int *fds) 194 { 195 int flags, sfd; 196 pid_t pid; 197 198 flags = fcntl(fds[0], F_GETFL); 199 assert(fcntl(fds[0], F_SETFL, flags | O_ASYNC) == 0); 200 201 assert(fcntl(fds[0], F_SETOWN, getpid()) == 0); 202 203 if (test_fork(&pid, &sfd) == PARENT) { 204 reject_signal(SIGIO); 205 test_barrier(sfd); 206 test_barrier(sfd); 207 expect_signal(SIGIO); 208 assert(read(fds[0], buf, 1) == 1); 209 } else { 210 test_barrier(sfd); 211 assert(write(fds[1], buf, 1) == 1); 212 test_barrier(sfd); 213 } 214 return test_wait(pid, sfd); 215 } 216 217 /* 218 * Test that SIGIO gets triggered when buffer space becomes available 219 * for writing. 220 */ 221 int 222 test_common_write(int *fds) 223 { 224 ssize_t n; 225 int flags, sfd; 226 pid_t pid; 227 228 flags = fcntl(fds[0], F_GETFL); 229 assert(fcntl(fds[0], F_SETFL, flags | O_ASYNC | O_NONBLOCK) == 0); 230 flags = fcntl(fds[1], F_GETFL); 231 assert(fcntl(fds[1], F_SETFL, flags | O_NONBLOCK) == 0); 232 233 assert(fcntl(fds[0], F_SETOWN, getpid()) == 0); 234 235 if (test_fork(&pid, &sfd) == PARENT) { 236 while ((n = write(fds[0], buf, sizeof(buf))) > 0) 237 continue; 238 assert(n == -1); 239 assert(errno == EWOULDBLOCK); 240 reject_signal(SIGIO); 241 242 test_barrier(sfd); 243 test_barrier(sfd); 244 expect_signal(SIGIO); 245 assert(write(fds[0], buf, 1) == 1); 246 } else { 247 test_barrier(sfd); 248 while ((n = read(fds[1], buf, sizeof(buf))) > 0) 249 continue; 250 assert(n == -1); 251 assert(errno == EWOULDBLOCK); 252 test_barrier(sfd); 253 } 254 return test_wait(pid, sfd); 255 } 256