1 /*- 2 * Copyright (c) 2018 Aniket Pandey 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 19 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * SUCH DAMAGE. 24 * 25 * $FreeBSD$ 26 */ 27 28 #include <sys/types.h> 29 #include <sys/socket.h> 30 #include <sys/un.h> 31 32 #include <atf-c.h> 33 #include <fcntl.h> 34 #include <stdarg.h> 35 #include <unistd.h> 36 37 #include "utils.h" 38 39 #define SERVER_PATH "server" 40 41 static int sockfd; 42 static socklen_t len; 43 static struct pollfd fds[1]; 44 static char extregex[80]; 45 static const char *auclass = "nt"; 46 static const char *nosupregex = "return,failure : Address family " 47 "not supported by protocol family"; 48 static const char *invalregex = "return,failur.*Socket operation on non-socket"; 49 50 /* 51 * Variadic function to close socket descriptors 52 */ 53 static void 54 close_sockets(int count, ...) 55 { 56 int sockd; 57 va_list socklist; 58 va_start(socklist, count); 59 for (sockd = 0; sockd < count; sockd++) { 60 close(va_arg(socklist, int)); 61 } 62 va_end(socklist); 63 } 64 65 /* 66 * Assign local filesystem address to a Unix domain socket 67 */ 68 static void 69 assign_address(struct sockaddr_un *server) 70 { 71 memset(server, 0, sizeof(*server)); 72 server->sun_family = AF_UNIX; 73 strcpy(server->sun_path, SERVER_PATH); 74 } 75 76 77 ATF_TC_WITH_CLEANUP(socket_success); 78 ATF_TC_HEAD(socket_success, tc) 79 { 80 atf_tc_set_md_var(tc, "descr", "Tests the audit of a successful " 81 "socket(2) call"); 82 } 83 84 ATF_TC_BODY(socket_success, tc) 85 { 86 FILE *pipefd = setup(fds, auclass); 87 ATF_REQUIRE((sockfd = socket(PF_UNIX, SOCK_STREAM, 0)) != -1); 88 /* Check the presence of sockfd in audit record */ 89 snprintf(extregex, sizeof(extregex), "socket.*ret.*success,%d", sockfd); 90 check_audit(fds, extregex, pipefd); 91 close(sockfd); 92 } 93 94 ATF_TC_CLEANUP(socket_success, tc) 95 { 96 cleanup(); 97 } 98 99 100 ATF_TC_WITH_CLEANUP(socket_failure); 101 ATF_TC_HEAD(socket_failure, tc) 102 { 103 atf_tc_set_md_var(tc, "descr", "Tests the audit of an unsuccessful " 104 "socket(2) call"); 105 } 106 107 ATF_TC_BODY(socket_failure, tc) 108 { 109 snprintf(extregex, sizeof(extregex), "socket.*%s", nosupregex); 110 FILE *pipefd = setup(fds, auclass); 111 /* Failure reason: Unsupported value of 'domain' argument: 0 */ 112 ATF_REQUIRE_EQ(-1, socket(0, SOCK_STREAM, 0)); 113 check_audit(fds, extregex, pipefd); 114 } 115 116 ATF_TC_CLEANUP(socket_failure, tc) 117 { 118 cleanup(); 119 } 120 121 122 ATF_TC_WITH_CLEANUP(socketpair_success); 123 ATF_TC_HEAD(socketpair_success, tc) 124 { 125 atf_tc_set_md_var(tc, "descr", "Tests the audit of a successful " 126 "socketpair(2) call"); 127 } 128 129 ATF_TC_BODY(socketpair_success, tc) 130 { 131 int sv[2]; 132 FILE *pipefd = setup(fds, auclass); 133 ATF_REQUIRE_EQ(0, socketpair(PF_UNIX, SOCK_STREAM, 0, sv)); 134 135 /* Check for 0x0 (argument 3: default protocol) in the audit record */ 136 snprintf(extregex, sizeof(extregex), "socketpair.*0x0.*return,success"); 137 check_audit(fds, extregex, pipefd); 138 close_sockets(2, sv[0], sv[1]); 139 } 140 141 ATF_TC_CLEANUP(socketpair_success, tc) 142 { 143 cleanup(); 144 } 145 146 147 ATF_TC_WITH_CLEANUP(socketpair_failure); 148 ATF_TC_HEAD(socketpair_failure, tc) 149 { 150 atf_tc_set_md_var(tc, "descr", "Tests the audit of an unsuccessful " 151 "socketpair(2) call"); 152 } 153 154 ATF_TC_BODY(socketpair_failure, tc) 155 { 156 snprintf(extregex, sizeof(extregex), "socketpair.*%s", nosupregex); 157 FILE *pipefd = setup(fds, auclass); 158 /* Failure reason: Unsupported value of 'domain' argument: 0 */ 159 ATF_REQUIRE_EQ(-1, socketpair(0, SOCK_STREAM, 0, NULL)); 160 check_audit(fds, extregex, pipefd); 161 } 162 163 ATF_TC_CLEANUP(socketpair_failure, tc) 164 { 165 cleanup(); 166 } 167 168 169 ATF_TC_WITH_CLEANUP(setsockopt_success); 170 ATF_TC_HEAD(setsockopt_success, tc) 171 { 172 atf_tc_set_md_var(tc, "descr", "Tests the audit of a successful " 173 "setsockopt(2) call"); 174 } 175 176 ATF_TC_BODY(setsockopt_success, tc) 177 { 178 int tr = 1; 179 ATF_REQUIRE((sockfd = socket(PF_UNIX, SOCK_STREAM, 0)) != -1); 180 /* Check the presence of sockfd in audit record */ 181 snprintf(extregex, sizeof(extregex), 182 "setsockopt.*0x%x.*return,success", sockfd); 183 184 FILE *pipefd = setup(fds, auclass); 185 ATF_REQUIRE_EQ(0, setsockopt(sockfd, SOL_SOCKET, 186 SO_REUSEADDR, &tr, sizeof(int))); 187 check_audit(fds, extregex, pipefd); 188 close(sockfd); 189 } 190 191 ATF_TC_CLEANUP(setsockopt_success, tc) 192 { 193 cleanup(); 194 } 195 196 197 ATF_TC_WITH_CLEANUP(setsockopt_failure); 198 ATF_TC_HEAD(setsockopt_failure, tc) 199 { 200 atf_tc_set_md_var(tc, "descr", "Tests the audit of an unsuccessful " 201 "setsockopt(2) call"); 202 } 203 204 ATF_TC_BODY(setsockopt_failure, tc) 205 { 206 int tr = 1; 207 snprintf(extregex, sizeof(extregex), "setsockopt.*%s", invalregex); 208 FILE *pipefd = setup(fds, auclass); 209 /* Failure reason: Invalid socket descriptor */ 210 ATF_REQUIRE_EQ(-1, setsockopt(0, SOL_SOCKET, 211 SO_REUSEADDR, &tr, sizeof(int))); 212 check_audit(fds, extregex, pipefd); 213 } 214 215 ATF_TC_CLEANUP(setsockopt_failure, tc) 216 { 217 cleanup(); 218 } 219 220 221 ATF_TC_WITH_CLEANUP(bind_success); 222 ATF_TC_HEAD(bind_success, tc) 223 { 224 atf_tc_set_md_var(tc, "descr", "Tests the audit of a successful " 225 "bind(2) call"); 226 } 227 228 ATF_TC_BODY(bind_success, tc) 229 { 230 struct sockaddr_un server; 231 assign_address(&server); 232 len = sizeof(struct sockaddr_un); 233 234 /* Preliminary socket setup */ 235 ATF_REQUIRE((sockfd = socket(PF_UNIX, SOCK_STREAM, 0)) != -1); 236 /* Check the presence of AF_UNIX address path in audit record */ 237 snprintf(extregex, sizeof(extregex), 238 "bind.*unix.*%s.*return,success", SERVER_PATH); 239 240 FILE *pipefd = setup(fds, auclass); 241 ATF_REQUIRE_EQ(0, bind(sockfd, (struct sockaddr *)&server, len)); 242 check_audit(fds, extregex, pipefd); 243 close(sockfd); 244 } 245 246 ATF_TC_CLEANUP(bind_success, tc) 247 { 248 cleanup(); 249 } 250 251 252 ATF_TC_WITH_CLEANUP(bind_failure); 253 ATF_TC_HEAD(bind_failure, tc) 254 { 255 atf_tc_set_md_var(tc, "descr", "Tests the audit of an unsuccessful " 256 "bind(2) call"); 257 } 258 259 ATF_TC_BODY(bind_failure, tc) 260 { 261 /* Preliminary socket setup */ 262 struct sockaddr_un server; 263 assign_address(&server); 264 len = sizeof(struct sockaddr_un); 265 /* Check the presence of AF_UNIX path in audit record */ 266 snprintf(extregex, sizeof(extregex), 267 "bind.*%s.*return,failure", SERVER_PATH); 268 269 FILE *pipefd = setup(fds, auclass); 270 /* Failure reason: Invalid socket descriptor */ 271 ATF_REQUIRE_EQ(-1, bind(0, (struct sockaddr *)&server, len)); 272 check_audit(fds, extregex, pipefd); 273 } 274 275 ATF_TC_CLEANUP(bind_failure, tc) 276 { 277 cleanup(); 278 } 279 280 281 ATF_TC_WITH_CLEANUP(bindat_success); 282 ATF_TC_HEAD(bindat_success, tc) 283 { 284 atf_tc_set_md_var(tc, "descr", "Tests the audit of a successful " 285 "bindat(2) call"); 286 } 287 288 ATF_TC_BODY(bindat_success, tc) 289 { 290 struct sockaddr_un server; 291 assign_address(&server); 292 len = sizeof(struct sockaddr_un); 293 294 /* Preliminary socket setup */ 295 ATF_REQUIRE((sockfd = socket(PF_UNIX, SOCK_STREAM, 0)) != -1); 296 /* Check the presence of socket descriptor in audit record */ 297 snprintf(extregex, sizeof(extregex), 298 "bindat.*0x%x.*return,success", sockfd); 299 300 FILE *pipefd = setup(fds, auclass); 301 ATF_REQUIRE_EQ(0, bindat(AT_FDCWD, sockfd, 302 (struct sockaddr *)&server, len)); 303 check_audit(fds, extregex, pipefd); 304 close(sockfd); 305 } 306 307 ATF_TC_CLEANUP(bindat_success, tc) 308 { 309 cleanup(); 310 } 311 312 313 ATF_TC_WITH_CLEANUP(bindat_failure); 314 ATF_TC_HEAD(bindat_failure, tc) 315 { 316 atf_tc_set_md_var(tc, "descr", "Tests the audit of an unsuccessful " 317 "bindat(2) call"); 318 } 319 320 ATF_TC_BODY(bindat_failure, tc) 321 { 322 /* Preliminary socket setup */ 323 struct sockaddr_un server; 324 assign_address(&server); 325 len = sizeof(struct sockaddr_un); 326 snprintf(extregex, sizeof(extregex), "bindat.*%s", invalregex); 327 328 FILE *pipefd = setup(fds, auclass); 329 /* Failure reason: Invalid socket descriptor */ 330 ATF_REQUIRE_EQ(-1, bindat(AT_FDCWD, 0, 331 (struct sockaddr *)&server, len)); 332 check_audit(fds, extregex, pipefd); 333 } 334 335 ATF_TC_CLEANUP(bindat_failure, tc) 336 { 337 cleanup(); 338 } 339 340 341 ATF_TC_WITH_CLEANUP(listen_success); 342 ATF_TC_HEAD(listen_success, tc) 343 { 344 atf_tc_set_md_var(tc, "descr", "Tests the audit of a successful " 345 "listen(2) call"); 346 } 347 348 ATF_TC_BODY(listen_success, tc) 349 { 350 struct sockaddr_un server; 351 assign_address(&server); 352 len = sizeof(struct sockaddr_un); 353 354 /* Preliminary socket setup */ 355 ATF_REQUIRE((sockfd = socket(PF_UNIX, SOCK_STREAM, 0)) != -1); 356 ATF_REQUIRE_EQ(0, bind(sockfd, (struct sockaddr *)&server, len)); 357 /* Check the presence of socket descriptor in the audit record */ 358 snprintf(extregex, sizeof(extregex), 359 "listen.*0x%x.*return,success", sockfd); 360 361 FILE *pipefd = setup(fds, auclass); 362 ATF_REQUIRE_EQ(0, listen(sockfd, 1)); 363 check_audit(fds, extregex, pipefd); 364 close(sockfd); 365 } 366 367 ATF_TC_CLEANUP(listen_success, tc) 368 { 369 cleanup(); 370 } 371 372 373 ATF_TC_WITH_CLEANUP(listen_failure); 374 ATF_TC_HEAD(listen_failure, tc) 375 { 376 atf_tc_set_md_var(tc, "descr", "Tests the audit of an unsuccessful " 377 "listen(2) call"); 378 } 379 380 ATF_TC_BODY(listen_failure, tc) 381 { 382 snprintf(extregex, sizeof(extregex), "listen.*%s", invalregex); 383 FILE *pipefd = setup(fds, auclass); 384 /* Failure reason: Invalid socket descriptor */ 385 ATF_REQUIRE_EQ(-1, listen(0, 1)); 386 check_audit(fds, extregex, pipefd); 387 } 388 389 ATF_TC_CLEANUP(listen_failure, tc) 390 { 391 cleanup(); 392 } 393 394 395 ATF_TP_ADD_TCS(tp) 396 { 397 ATF_TP_ADD_TC(tp, socket_success); 398 ATF_TP_ADD_TC(tp, socket_failure); 399 ATF_TP_ADD_TC(tp, socketpair_success); 400 ATF_TP_ADD_TC(tp, socketpair_failure); 401 ATF_TP_ADD_TC(tp, setsockopt_success); 402 ATF_TP_ADD_TC(tp, setsockopt_failure); 403 404 ATF_TP_ADD_TC(tp, bind_success); 405 ATF_TP_ADD_TC(tp, bind_failure); 406 ATF_TP_ADD_TC(tp, bindat_success); 407 ATF_TP_ADD_TC(tp, bindat_failure); 408 ATF_TP_ADD_TC(tp, listen_success); 409 ATF_TP_ADD_TC(tp, listen_failure); 410 411 return (atf_no_error()); 412 } 413