1 /* $OpenBSD: ktrstruct.c,v 1.21 2016/06/07 06:12:37 deraadt Exp $ */ 2 3 /*- 4 * Copyright (c) 1988, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of the University nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32 #include <sys/types.h> 33 #include <sys/resource.h> 34 #include <sys/socket.h> 35 #include <sys/stat.h> 36 #include <sys/time.h> 37 #include <sys/event.h> 38 #include <sys/un.h> 39 #include <ufs/ufs/quota.h> 40 #include <netinet/in.h> 41 #include <arpa/inet.h> 42 43 #include <ctype.h> 44 #include <err.h> 45 #include <limits.h> 46 #include <netdb.h> 47 #include <poll.h> 48 #include <signal.h> 49 #include <stddef.h> 50 #include <stdio.h> 51 #include <stdlib.h> 52 #include <stdint.h> 53 #include <string.h> 54 #include <grp.h> 55 #include <pwd.h> 56 #include <unistd.h> 57 #include <vis.h> 58 59 #include "kdump.h" 60 #include "kdump_subr.h" 61 62 #define TIME_FORMAT "%b %e %T %Y" 63 64 static void 65 ktrsockaddr(struct sockaddr *sa) 66 { 67 /* 68 * TODO: Support additional address families 69 * #include <netmpls/mpls.h> 70 * struct sockaddr_mpls *mpls; 71 */ 72 73 /* 74 * note: ktrstruct() has already verified that sa points to a 75 * buffer at least sizeof(struct sockaddr) bytes long and exactly 76 * sa->sa_len bytes long. 77 */ 78 printf("struct sockaddr { "); 79 sockfamilyname(sa->sa_family); 80 printf(", "); 81 82 #define check_sockaddr_len(n) \ 83 if (sa_##n->s##n##_len < sizeof(struct sockaddr_##n)) { \ 84 printf("invalid"); \ 85 break; \ 86 } 87 88 switch(sa->sa_family) { 89 case AF_INET: { 90 struct sockaddr_in *sa_in; 91 char addr[64]; 92 93 sa_in = (struct sockaddr_in *)sa; 94 check_sockaddr_len(in); 95 inet_ntop(AF_INET, &sa_in->sin_addr, addr, sizeof addr); 96 printf("%s:%u", addr, ntohs(sa_in->sin_port)); 97 break; 98 } 99 case AF_INET6: { 100 struct sockaddr_in6 *sa_in6; 101 char addr[64]; 102 103 sa_in6 = (struct sockaddr_in6 *)sa; 104 check_sockaddr_len(in6); 105 inet_ntop(AF_INET6, &sa_in6->sin6_addr, addr, sizeof addr); 106 printf("[%s]:%u", addr, htons(sa_in6->sin6_port)); 107 break; 108 } 109 case AF_UNIX: { 110 struct sockaddr_un *sa_un; 111 char path[4 * sizeof(sa_un->sun_path) + 1]; 112 size_t len; 113 114 sa_un = (struct sockaddr_un *)sa; 115 len = sa_un->sun_len; 116 if (len <= offsetof(struct sockaddr_un, sun_path)) { 117 printf("invalid"); 118 break; 119 } 120 len -= offsetof(struct sockaddr_un, sun_path); 121 if (len > sizeof(sa_un->sun_path)) { 122 printf("too long"); 123 break; 124 } 125 /* format, stopping at first NUL */ 126 len = strnlen(sa_un->sun_path, len); 127 strvisx(path, sa_un->sun_path, len, 128 VIS_CSTYLE | VIS_DQ | VIS_TAB | VIS_NL); 129 printf("\"%s\"", path); 130 break; 131 } 132 default: 133 printf("unknown address family"); 134 } 135 printf(" }\n"); 136 } 137 138 static void 139 print_time(time_t t, int relative, int have_subsec) 140 { 141 char timestr[PATH_MAX + 4]; 142 struct tm *tm; 143 144 if (t < 0 && have_subsec) { 145 /* negative times with non-zero subsecs require care */ 146 printf("-%jd", -(intmax_t)(t + 1)); 147 } else 148 printf("%jd", (intmax_t)t); 149 150 /* 1970s times are probably relative */ 151 if (!relative && t > (10 * 365 * 24 * 3600)) { 152 tm = localtime(&t); 153 if (tm != NULL) { 154 (void)strftime(timestr, sizeof(timestr), TIME_FORMAT, 155 tm); 156 printf("<\"%s\">", timestr); 157 } 158 } 159 } 160 161 static void 162 print_timespec(const struct timespec *tsp, int relative) 163 { 164 if (tsp->tv_nsec == UTIME_NOW) 165 printf("UTIME_NOW"); 166 else if (tsp->tv_nsec == UTIME_OMIT) 167 printf("UTIME_OMIT"); 168 else { 169 print_time(tsp->tv_sec, relative, tsp->tv_nsec); 170 if (tsp->tv_nsec != 0) 171 printf(".%09ld", tsp->tv_sec >= 0 ? tsp->tv_nsec : 172 1000000000 - tsp->tv_nsec); 173 } 174 } 175 176 void 177 uidname(int uid) 178 { 179 const char *name; 180 181 if (uid == -1) 182 printf("-1"); 183 else { 184 printf("%u<", (unsigned)uid); 185 if (uid > UID_MAX || (name = user_from_uid(uid, 1)) == NULL) 186 printf("unknown>"); 187 else 188 printf("\"%s\">", name); 189 } 190 } 191 192 void 193 gidname(int gid) 194 { 195 const char *name; 196 197 if (gid == -1) 198 printf("-1"); 199 else { 200 printf("%u<", (unsigned)gid); 201 if (gid > GID_MAX || (name = group_from_gid(gid, 1)) == NULL) 202 printf("unknown>"); 203 else 204 printf("\"%s\">", name); 205 } 206 } 207 208 static void 209 ktrstat(const struct stat *statp) 210 { 211 char mode[12]; 212 213 /* 214 * note: ktrstruct() has already verified that statp points to a 215 * buffer exactly sizeof(struct stat) bytes long. 216 */ 217 printf("struct stat { "); 218 strmode(statp->st_mode, mode); 219 printf("dev=%d, ino=%llu, mode=%s, nlink=%u, uid=", 220 statp->st_dev, (unsigned long long)statp->st_ino, 221 mode, statp->st_nlink); 222 uidname(statp->st_uid); 223 printf(", gid="); 224 gidname(statp->st_gid); 225 printf(", rdev=%d, ", statp->st_rdev); 226 printf("atime="); 227 print_timespec(&statp->st_atim, 0); 228 printf(", mtime="); 229 print_timespec(&statp->st_mtim, 0); 230 printf(", ctime="); 231 print_timespec(&statp->st_ctim, 0); 232 printf(", size=%lld, blocks=%lld, blksize=%d, flags=0x%x, gen=0x%x", 233 statp->st_size, statp->st_blocks, statp->st_blksize, 234 statp->st_flags, statp->st_gen); 235 printf(" }\n"); 236 } 237 238 static void 239 ktrtimespec(const struct timespec *tsp, int relative) 240 { 241 printf("struct timespec { "); 242 print_timespec(tsp, relative); 243 printf(" }\n"); 244 } 245 246 static void 247 print_timeval(const struct timeval *tvp, int relative) 248 { 249 print_time(tvp->tv_sec, relative, tvp->tv_usec); 250 if (tvp->tv_usec != 0) 251 printf(".%06ld", tvp->tv_sec >= 0 ? tvp->tv_usec : 252 1000000 - tvp->tv_usec); 253 } 254 255 static void 256 ktrtimeval(const struct timeval *tvp, int relative) 257 { 258 printf("struct timeval { "); 259 print_timeval(tvp, relative); 260 printf(" }\n"); 261 } 262 263 static void 264 ktrsigaction(const struct sigaction *sa) 265 { 266 /* 267 * note: ktrstruct() has already verified that sa points to a 268 * buffer exactly sizeof(struct sigaction) bytes long. 269 */ 270 /* 271 * Fuck! Comparison of function pointers on hppa assumes you can 272 * dereference them if they're plabels! Cast everything to void * 273 * to suppress that extra logic; sorry folks, the address we report 274 * here might not match what you see in your executable... 275 */ 276 printf("struct sigaction { "); 277 if ((void *)sa->sa_handler == (void *)SIG_DFL) 278 printf("handler=SIG_DFL"); 279 else if ((void *)sa->sa_handler == (void *)SIG_IGN) 280 printf("handler=SIG_IGN"); 281 else if (sa->sa_flags & SA_SIGINFO) 282 printf("sigaction=%p", (void *)sa->sa_sigaction); 283 else 284 printf("handler=%p", (void *)sa->sa_handler); 285 printf(", mask="); 286 sigset(sa->sa_mask); 287 printf(", flags="); 288 sigactionflagname(sa->sa_flags); 289 printf(" }\n"); 290 } 291 292 static void 293 print_rlim(rlim_t lim) 294 { 295 if (lim == RLIM_INFINITY) 296 printf("infinite"); 297 else 298 printf("%llu", (unsigned long long)lim); 299 } 300 301 static void 302 ktrrlimit(const struct rlimit *limp) 303 { 304 printf("struct rlimit { "); 305 printf("cur="); 306 print_rlim(limp->rlim_cur); 307 printf(", max="); 308 print_rlim(limp->rlim_max); 309 printf(" }\n"); 310 } 311 312 static void 313 ktrtfork(const struct __tfork *tf) 314 { 315 printf("struct __tfork { tcb=%p, tid=%p, stack=%p }\n", 316 tf->tf_tcb, (void *)tf->tf_tid, tf->tf_stack); 317 } 318 319 static void 320 ktrfdset(struct fd_set *fds, int len) 321 { 322 int nfds, i, start = -1; 323 char sep = ' '; 324 325 nfds = len * NBBY; 326 printf("struct fd_set {"); 327 for (i = 0; i <= nfds; i++) 328 if (i != nfds && FD_ISSET(i, fds)) { 329 if (start == -1) 330 start = i; 331 } else if (start != -1) { 332 putchar(sep); 333 if (start == i - 1) 334 printf("%d", start); 335 else if (start == i - 2) 336 printf("%d,%d", start, i - 1); 337 else 338 printf("%d-%d", start, i - 1); 339 sep = ','; 340 start = -1; 341 } 342 343 printf(" }\n"); 344 } 345 346 static void 347 ktrrusage(const struct rusage *rup) 348 { 349 printf("struct rusage { utime="); 350 print_timeval(&rup->ru_utime, 1); 351 printf(", stime="); 352 print_timeval(&rup->ru_stime, 1); 353 printf(", maxrss=%ld, ixrss=%ld, idrss=%ld, isrss=%ld," 354 " minflt=%ld, majflt=%ld, nswap=%ld, inblock=%ld," 355 " oublock=%ld, msgsnd=%ld, msgrcv=%ld, nsignals=%ld," 356 " nvcsw=%ld, nivcsw=%ld }\n", 357 rup->ru_maxrss, rup->ru_ixrss, rup->ru_idrss, rup->ru_isrss, 358 rup->ru_minflt, rup->ru_majflt, rup->ru_nswap, rup->ru_inblock, 359 rup->ru_oublock, rup->ru_msgsnd, rup->ru_msgrcv, rup->ru_nsignals, 360 rup->ru_nvcsw, rup->ru_nivcsw); 361 } 362 363 static void 364 ktrquota(const struct dqblk *quota) 365 { 366 printf("struct dqblk { bhardlimit=%u, bsoftlimit=%u, curblocks=%u," 367 " ihardlimit=%u, isoftlimit=%u, curinodes=%u, btime=", 368 quota->dqb_bhardlimit, quota->dqb_bsoftlimit, 369 quota->dqb_curblocks, quota->dqb_ihardlimit, 370 quota->dqb_isoftlimit, quota->dqb_curinodes); 371 print_time(quota->dqb_btime, 0, 0); 372 printf(", itime="); 373 print_time(quota->dqb_itime, 0, 0); 374 printf(" }\n"); 375 } 376 377 static void 378 ktrmsghdr(const struct msghdr *msg) 379 { 380 printf("struct msghdr { name=%p, namelen=%u, iov=%p, iovlen=%u," 381 " control=%p, controllen=%u, flags=", 382 msg->msg_name, msg->msg_namelen, msg->msg_iov, msg->msg_iovlen, 383 msg->msg_control, msg->msg_controllen); 384 sendrecvflagsname(msg->msg_flags); 385 printf(" }\n"); 386 } 387 388 static void 389 ktriovec(const char *data, int count) 390 { 391 struct iovec iov; 392 int i; 393 394 printf("struct iovec"); 395 if (count > 1) 396 printf(" [%d]", count); 397 for (i = 0; i < count; i++) { 398 memcpy(&iov, data, sizeof(iov)); 399 data += sizeof(iov); 400 printf(" { base=%p, len=%lu }", iov.iov_base, iov.iov_len); 401 } 402 printf("\n"); 403 } 404 405 static void 406 ktrevent(const char *data, int count) 407 { 408 struct kevent kev; 409 int i; 410 411 printf("struct kevent"); 412 if (count > 1) 413 printf(" [%d]", count); 414 for (i = 0; i < count; i++) { 415 memcpy(&kev, data, sizeof(kev)); 416 data += sizeof(kev); 417 printf(" { ident=%lu, filter=", kev.ident); 418 evfiltername(kev.filter); 419 printf(", flags="); 420 evflagsname(kev.flags); 421 printf(", fflags="); 422 evfflagsname(kev.filter, kev.fflags); 423 printf(", data=%llu", kev.data); 424 if ((kev.flags & EV_ERROR) && fancy) { 425 printf("<\"%s\">", strerror(kev.data)); 426 } 427 printf(", udata=%p }", kev.udata); 428 } 429 printf("\n"); 430 } 431 432 static void 433 ktrpollfd(const char *data, int count) 434 { 435 struct pollfd pfd; 436 int i; 437 438 printf("struct pollfd"); 439 if (count > 1) 440 printf(" [%d]", count); 441 for (i = 0; i < count; i++) { 442 memcpy(&pfd, data, sizeof(pfd)); 443 data += sizeof(pfd); 444 printf(" { fd=%d, events=", pfd.fd); 445 pollfdeventname(pfd.events); 446 printf(", revents="); 447 pollfdeventname(pfd.revents); 448 printf(" }"); 449 } 450 printf("\n"); 451 } 452 453 static void 454 ktrcmsghdr(char *data, socklen_t len) 455 { 456 struct msghdr msg; 457 struct cmsghdr *cmsg; 458 int i, count, *fds; 459 460 msg.msg_control = data; 461 msg.msg_controllen = len; 462 463 /* count the control messages */ 464 count = 0; 465 for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; 466 cmsg = CMSG_NXTHDR(&msg, cmsg)) { 467 count++; 468 } 469 470 printf("struct cmsghdr"); 471 if (count > 1) 472 printf(" [%d]", count); 473 474 for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; 475 cmsg = CMSG_NXTHDR(&msg, cmsg)) { 476 printf(" { len=%u, level=", cmsg->cmsg_len); 477 if (cmsg->cmsg_level == SOL_SOCKET) { 478 printf("SOL_SOCKET, type="); 479 switch (cmsg->cmsg_type) { 480 case SCM_RIGHTS: 481 printf("SCM_RIGHTS, data="); 482 fds = (int *)CMSG_DATA(cmsg); 483 for (i = 0; 484 cmsg->cmsg_len > CMSG_LEN(sizeof(int) * i); 485 i++) { 486 printf("%s%d", i ? "," : "", fds[i]); 487 } 488 break; 489 case SCM_TIMESTAMP: 490 default: 491 printf("%d", cmsg->cmsg_type); 492 break; 493 } 494 } else { 495 struct protoent *p = getprotobynumber(cmsg->cmsg_level); 496 497 printf("%u<%s>, type=%d", cmsg->cmsg_level, 498 p != NULL ? p->p_name : "unknown", cmsg->cmsg_type); 499 } 500 printf(" }"); 501 } 502 printf("\n"); 503 } 504 505 void 506 ktrstruct(char *buf, size_t buflen) 507 { 508 char *name, *data; 509 size_t namelen, datalen; 510 int i; 511 512 for (name = buf, namelen = 0; namelen < buflen && name[namelen] != '\0'; 513 ++namelen) 514 /* nothing */; 515 if (namelen == buflen) 516 goto invalid; 517 if (name[namelen] != '\0') 518 goto invalid; 519 data = buf + namelen + 1; 520 datalen = buflen - namelen - 1; 521 if (datalen == 0) 522 goto invalid; 523 /* sanity check */ 524 for (i = 0; i < namelen; ++i) 525 if (!isalpha((unsigned char)name[i])) 526 goto invalid; 527 if (strcmp(name, "stat") == 0) { 528 struct stat sb; 529 530 if (datalen != sizeof(struct stat)) 531 goto invalid; 532 memcpy(&sb, data, datalen); 533 ktrstat(&sb); 534 } else if (strcmp(name, "sockaddr") == 0) { 535 struct sockaddr_storage ss; 536 537 if (datalen > sizeof(ss)) 538 goto invalid; 539 memcpy(&ss, data, datalen); 540 if ((ss.ss_family != AF_UNIX && 541 datalen < sizeof(struct sockaddr)) || datalen != ss.ss_len) 542 goto invalid; 543 ktrsockaddr((struct sockaddr *)&ss); 544 } else if (strcmp(name, "abstimespec") == 0 || 545 strcmp(name, "reltimespec") == 0) { 546 struct timespec ts; 547 548 if (datalen != sizeof(ts)) 549 goto invalid; 550 memcpy(&ts, data, datalen); 551 ktrtimespec(&ts, name[0] == 'r'); 552 } else if (strcmp(name, "abstimeval") == 0 || 553 strcmp(name, "reltimeval") == 0) { 554 struct timeval tv; 555 556 if (datalen != sizeof(tv)) 557 goto invalid; 558 memcpy(&tv, data, datalen); 559 ktrtimeval(&tv, name[0] == 'r'); 560 } else if (strcmp(name, "sigaction") == 0) { 561 struct sigaction sa; 562 563 if (datalen != sizeof(sa)) 564 goto invalid; 565 memcpy(&sa, data, datalen); 566 ktrsigaction(&sa); 567 } else if (strcmp(name, "rlimit") == 0) { 568 struct rlimit lim; 569 570 if (datalen != sizeof(lim)) 571 goto invalid; 572 memcpy(&lim, data, datalen); 573 ktrrlimit(&lim); 574 } else if (strcmp(name, "rusage") == 0) { 575 struct rusage ru; 576 577 if (datalen != sizeof(ru)) 578 goto invalid; 579 memcpy(&ru, data, datalen); 580 ktrrusage(&ru); 581 } else if (strcmp(name, "tfork") == 0) { 582 struct __tfork tf; 583 584 if (datalen != sizeof(tf)) 585 goto invalid; 586 memcpy(&tf, data, datalen); 587 ktrtfork(&tf); 588 } else if (strcmp(name, "fdset") == 0) { 589 struct fd_set *fds; 590 591 if ((fds = malloc(datalen)) == NULL) 592 err(1, "malloc"); 593 memcpy(fds, data, datalen); 594 ktrfdset(fds, datalen); 595 free(fds); 596 } else if (strcmp(name, "quota") == 0) { 597 struct dqblk quota; 598 599 if (datalen != sizeof(quota)) 600 goto invalid; 601 memcpy("a, data, datalen); 602 ktrquota("a); 603 } else if (strcmp(name, "msghdr") == 0) { 604 struct msghdr msg; 605 606 if (datalen != sizeof(msg)) 607 goto invalid; 608 memcpy(&msg, data, datalen); 609 ktrmsghdr(&msg); 610 } else if (strcmp(name, "iovec") == 0) { 611 if (datalen % sizeof(struct iovec)) 612 goto invalid; 613 ktriovec(data, datalen / sizeof(struct iovec)); 614 } else if (strcmp(name, "kevent") == 0) { 615 if (datalen % sizeof(struct kevent)) 616 goto invalid; 617 ktrevent(data, datalen / sizeof(struct kevent)); 618 } else if (strcmp(name, "pollfd") == 0) { 619 if (datalen % sizeof(struct pollfd)) 620 goto invalid; 621 ktrpollfd(data, datalen / sizeof(struct pollfd)); 622 } else if (strcmp(name, "cmsghdr") == 0) { 623 char *cmsg; 624 625 if ((cmsg = malloc(datalen)) == NULL) 626 err(1, "malloc"); 627 memcpy(cmsg, data, datalen); 628 ktrcmsghdr(cmsg, datalen); 629 free(cmsg); 630 } else if (strcmp(name, "pledgereq") == 0) { 631 printf("pledge request="); 632 showbufc(basecol + sizeof("pledge request=") - 1, 633 (unsigned char *)data, datalen, VIS_DQ | VIS_TAB | VIS_NL); 634 } else if (strcmp(name, "pledgepath") == 0) { 635 printf("pledge path="); 636 showbufc(basecol + sizeof("pledge path=") - 1, 637 (unsigned char *)data, datalen, VIS_DQ | VIS_TAB | VIS_NL); 638 } else { 639 printf("unknown structure %s\n", name); 640 } 641 return; 642 invalid: 643 printf("invalid record\n"); 644 } 645