1 /*- 2 * SPDX-License-Identifier: BSD-4-Clause 3 * 4 * Copyright (c) 1993 Paul Kranenburg 5 * 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. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by Paul Kranenburg. 18 * 4. The name of the author may not be used to endorse or promote products 19 * derived from this software without specific prior written permission 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 #include <sys/cdefs.h> 34 __FBSDID("$FreeBSD$"); 35 36 #include <sys/wait.h> 37 38 #include <machine/elf.h> 39 40 #include <arpa/inet.h> 41 42 #include <dlfcn.h> 43 #include <err.h> 44 #include <errno.h> 45 #include <fcntl.h> 46 #include <stdio.h> 47 #include <stdlib.h> 48 #include <string.h> 49 #include <unistd.h> 50 51 #include "extern.h" 52 53 /* We don't support a.out executables on arm64 and riscv */ 54 #if !defined(__aarch64__) && !defined(__riscv) 55 #include <a.out.h> 56 #define AOUT_SUPPORTED 57 #endif 58 59 /* 60 * 32-bit ELF data structures can only be used if the system header[s] declare 61 * them. There is no official macro for determining whether they are declared, 62 * so check for the existence of one of the 32-macros defined in elf(5). 63 */ 64 #ifdef ELF32_R_TYPE 65 #define ELF32_SUPPORTED 66 #endif 67 68 #define LDD_SETENV(name, value, overwrite) do { \ 69 setenv("LD_" name, value, overwrite); \ 70 setenv("LD_32_" name, value, overwrite); \ 71 } while (0) 72 73 #define LDD_UNSETENV(name) do { \ 74 unsetenv("LD_" name); \ 75 unsetenv("LD_32_" name); \ 76 } while (0) 77 78 static int is_executable(const char *fname, int fd, int *is_shlib, 79 int *type); 80 static void usage(void); 81 82 #define TYPE_UNKNOWN 0 83 #define TYPE_AOUT 1 84 #define TYPE_ELF 2 /* Architecture default */ 85 #if __ELF_WORD_SIZE > 32 && defined(ELF32_SUPPORTED) 86 #define TYPE_ELF32 3 /* Explicit 32 bits on architectures >32 bits */ 87 88 #define _PATH_LDD32 "/usr/bin/ldd32" 89 90 static int 91 execldd32(char *file, char *fmt1, char *fmt2, int aflag, int vflag) 92 { 93 char *argv[9]; 94 int i, rval, status; 95 96 LDD_UNSETENV("TRACE_LOADED_OBJECTS"); 97 rval = 0; 98 i = 0; 99 argv[i++] = strdup(_PATH_LDD32); 100 if (aflag) 101 argv[i++] = strdup("-a"); 102 if (vflag) 103 argv[i++] = strdup("-v"); 104 if (fmt1 != NULL) { 105 argv[i++] = strdup("-f"); 106 argv[i++] = strdup(fmt1); 107 } 108 if (fmt2 != NULL) { 109 argv[i++] = strdup("-f"); 110 argv[i++] = strdup(fmt2); 111 } 112 argv[i++] = strdup(file); 113 argv[i++] = NULL; 114 115 switch (fork()) { 116 case -1: 117 err(1, "fork"); 118 break; 119 case 0: 120 execv(_PATH_LDD32, argv); 121 warn("%s", _PATH_LDD32); 122 _exit(127); 123 break; 124 default: 125 if (wait(&status) < 0) 126 rval = 1; 127 else if (WIFSIGNALED(status)) 128 rval = 1; 129 else if (WIFEXITED(status) && WEXITSTATUS(status) != 0) 130 rval = 1; 131 break; 132 } 133 while (i--) 134 free(argv[i]); 135 LDD_SETENV("TRACE_LOADED_OBJECTS", "yes", 1); 136 return (rval); 137 } 138 #endif 139 140 int 141 main(int argc, char *argv[]) 142 { 143 char *fmt1, *fmt2; 144 int rval, c, aflag, vflag; 145 146 aflag = vflag = 0; 147 fmt1 = fmt2 = NULL; 148 149 while ((c = getopt(argc, argv, "af:v")) != -1) { 150 switch (c) { 151 case 'a': 152 aflag++; 153 break; 154 case 'f': 155 if (fmt1 != NULL) { 156 if (fmt2 != NULL) 157 errx(1, "too many formats"); 158 fmt2 = optarg; 159 } else 160 fmt1 = optarg; 161 break; 162 case 'v': 163 vflag++; 164 break; 165 default: 166 usage(); 167 /* NOTREACHED */ 168 } 169 } 170 argc -= optind; 171 argv += optind; 172 173 if (vflag && fmt1 != NULL) 174 errx(1, "-v may not be used with -f"); 175 176 if (argc <= 0) { 177 usage(); 178 /* NOTREACHED */ 179 } 180 181 #ifdef __i386__ 182 if (vflag) { 183 for (c = 0; c < argc; c++) 184 dump_file(argv[c]); 185 exit(error_count == 0 ? EXIT_SUCCESS : EXIT_FAILURE); 186 } 187 #endif 188 189 rval = 0; 190 for (; argc > 0; argc--, argv++) { 191 int fd, status, is_shlib, rv, type; 192 193 if ((fd = open(*argv, O_RDONLY, 0)) < 0) { 194 warn("%s", *argv); 195 rval |= 1; 196 continue; 197 } 198 rv = is_executable(*argv, fd, &is_shlib, &type); 199 close(fd); 200 if (rv == 0) { 201 rval |= 1; 202 continue; 203 } 204 205 switch (type) { 206 case TYPE_ELF: 207 case TYPE_AOUT: 208 break; 209 #if __ELF_WORD_SIZE > 32 && defined(ELF32_SUPPORTED) 210 case TYPE_ELF32: 211 rval |= execldd32(*argv, fmt1, fmt2, aflag, vflag); 212 continue; 213 #endif 214 case TYPE_UNKNOWN: 215 default: 216 /* 217 * This shouldn't happen unless is_executable() 218 * is broken. 219 */ 220 errx(EDOOFUS, "unknown executable type"); 221 } 222 223 /* ld.so magic */ 224 LDD_SETENV("TRACE_LOADED_OBJECTS", "yes", 1); 225 if (fmt1 != NULL) 226 LDD_SETENV("TRACE_LOADED_OBJECTS_FMT1", fmt1, 1); 227 if (fmt2 != NULL) 228 LDD_SETENV("TRACE_LOADED_OBJECTS_FMT2", fmt2, 1); 229 230 LDD_SETENV("TRACE_LOADED_OBJECTS_PROGNAME", *argv, 1); 231 if (aflag) 232 LDD_SETENV("TRACE_LOADED_OBJECTS_ALL", "1", 1); 233 else if (fmt1 == NULL && fmt2 == NULL) 234 /* Default formats */ 235 printf("%s:\n", *argv); 236 fflush(stdout); 237 238 switch (fork()) { 239 case -1: 240 err(1, "fork"); 241 break; 242 default: 243 if (wait(&status) < 0) { 244 warn("wait"); 245 rval |= 1; 246 } else if (WIFSIGNALED(status)) { 247 fprintf(stderr, "%s: signal %d\n", *argv, 248 WTERMSIG(status)); 249 rval |= 1; 250 } else if (WIFEXITED(status) && 251 WEXITSTATUS(status) != 0) { 252 fprintf(stderr, "%s: exit status %d\n", *argv, 253 WEXITSTATUS(status)); 254 rval |= 1; 255 } 256 break; 257 case 0: 258 if (is_shlib == 0) { 259 execl(*argv, *argv, (char *)NULL); 260 warn("%s", *argv); 261 } else { 262 dlopen(*argv, RTLD_TRACE); 263 warnx("%s: %s", *argv, dlerror()); 264 } 265 _exit(1); 266 } 267 } 268 269 return rval; 270 } 271 272 static void 273 usage(void) 274 { 275 276 fprintf(stderr, "usage: ldd [-a] [-v] [-f format] program ...\n"); 277 exit(1); 278 } 279 280 static int 281 is_executable(const char *fname, int fd, int *is_shlib, int *type) 282 { 283 union { 284 #ifdef AOUT_SUPPORTED 285 struct exec aout; 286 #endif 287 #if __ELF_WORD_SIZE > 32 && defined(ELF32_SUPPORTED) 288 Elf32_Ehdr elf32; 289 #endif 290 Elf_Ehdr elf; 291 } hdr; 292 Elf_Phdr phdr, dynphdr; 293 Elf_Dyn *dynp; 294 void *dyndata; 295 #if __ELF_WORD_SIZE > 32 && defined(ELF32_SUPPORTED) 296 Elf32_Phdr phdr32, dynphdr32; 297 Elf32_Dyn *dynp32; 298 #endif 299 int df1pie, dynamic, i, n; 300 301 *is_shlib = 0; 302 *type = TYPE_UNKNOWN; 303 df1pie = 0; 304 305 if ((n = read(fd, &hdr, sizeof(hdr))) == -1) { 306 warn("%s: can't read program header", fname); 307 return (0); 308 } 309 310 #ifdef AOUT_SUPPORTED 311 if ((size_t)n >= sizeof(hdr.aout) && !N_BADMAG(hdr.aout)) { 312 /* a.out file */ 313 if ((N_GETFLAG(hdr.aout) & EX_DPMASK) != EX_DYNAMIC 314 #if 1 /* Compatibility */ 315 || hdr.aout.a_entry < __LDPGSZ 316 #endif 317 ) { 318 warnx("%s: not a dynamic executable", fname); 319 return (0); 320 } 321 *type = TYPE_AOUT; 322 warnx("%s: aout support is deprecated", fname); 323 return (1); 324 } 325 #endif 326 327 #if __ELF_WORD_SIZE > 32 && defined(ELF32_SUPPORTED) 328 if ((size_t)n >= sizeof(hdr.elf32) && IS_ELF(hdr.elf32) && 329 hdr.elf32.e_ident[EI_CLASS] == ELFCLASS32) { 330 /* Handle 32 bit ELF objects */ 331 332 dynamic = 0; 333 *type = TYPE_ELF32; 334 335 if (lseek(fd, hdr.elf32.e_phoff, SEEK_SET) == -1) { 336 warnx("%s: header too short", fname); 337 return (0); 338 } 339 for (i = 0; i < hdr.elf32.e_phnum; i++) { 340 if (read(fd, &phdr32, hdr.elf32.e_phentsize) != 341 sizeof(phdr32)) { 342 warnx("%s: can't read program header", fname); 343 return (0); 344 } 345 if (phdr32.p_type == PT_DYNAMIC) { 346 dynamic = 1; 347 dynphdr32 = phdr32; 348 break; 349 } 350 } 351 352 if (!dynamic) { 353 warnx("%s: not a dynamic ELF executable", fname); 354 return (0); 355 } 356 357 if (hdr.elf32.e_type == ET_DYN) { 358 if (lseek(fd, dynphdr32.p_offset, SEEK_SET) == -1) { 359 warnx("%s: dynamic segment out of range", 360 fname); 361 return (0); 362 } 363 dyndata = malloc(dynphdr32.p_filesz); 364 if (dyndata == NULL) { 365 warn("malloc"); 366 return (0); 367 } 368 if (read(fd, dyndata, dynphdr32.p_filesz) != 369 (ssize_t)dynphdr32.p_filesz) { 370 free(dyndata); 371 warnx("%s: can't read dynamic segment", fname); 372 return (0); 373 } 374 for (dynp32 = dyndata; dynp32->d_tag != DT_NULL; 375 dynp32++) { 376 if (dynp32->d_tag != DT_FLAGS_1) 377 continue; 378 df1pie = (dynp32->d_un.d_val & DF_1_PIE) != 0; 379 break; 380 } 381 free(dyndata); 382 383 if (hdr.elf32.e_ident[EI_OSABI] == ELFOSABI_FREEBSD) { 384 if (!df1pie) 385 *is_shlib = 1; 386 return (1); 387 } 388 warnx("%s: not a FreeBSD ELF shared object", fname); 389 return (0); 390 } 391 392 return (1); 393 } 394 #endif 395 396 if ((size_t)n >= sizeof(hdr.elf) && IS_ELF(hdr.elf) && 397 hdr.elf.e_ident[EI_CLASS] == ELF_TARG_CLASS) { 398 /* Handle default ELF objects on this architecture */ 399 400 dynamic = 0; 401 *type = TYPE_ELF; 402 403 if (lseek(fd, hdr.elf.e_phoff, SEEK_SET) == -1) { 404 warnx("%s: header too short", fname); 405 return (0); 406 } 407 for (i = 0; i < hdr.elf.e_phnum; i++) { 408 if (read(fd, &phdr, hdr.elf.e_phentsize) 409 != sizeof(phdr)) { 410 warnx("%s: can't read program header", fname); 411 return (0); 412 } 413 if (phdr.p_type == PT_DYNAMIC) { 414 dynamic = 1; 415 dynphdr = phdr; 416 break; 417 } 418 } 419 420 if (!dynamic) { 421 warnx("%s: not a dynamic ELF executable", fname); 422 return (0); 423 } 424 425 if (hdr.elf.e_type == ET_DYN) { 426 if (lseek(fd, dynphdr.p_offset, SEEK_SET) == -1) { 427 warnx("%s: dynamic segment out of range", 428 fname); 429 return (0); 430 } 431 dyndata = malloc(dynphdr.p_filesz); 432 if (dyndata == NULL) { 433 warn("malloc"); 434 return (0); 435 } 436 if (read(fd, dyndata, dynphdr.p_filesz) != 437 (ssize_t)dynphdr.p_filesz) { 438 free(dyndata); 439 warnx("%s: can't read dynamic segment", fname); 440 return (0); 441 } 442 for (dynp = dyndata; dynp->d_tag != DT_NULL; dynp++) { 443 if (dynp->d_tag != DT_FLAGS_1) 444 continue; 445 df1pie = (dynp->d_un.d_val & DF_1_PIE) != 0; 446 break; 447 } 448 free(dyndata); 449 450 switch (hdr.elf.e_ident[EI_OSABI]) { 451 case ELFOSABI_FREEBSD: 452 if (!df1pie) 453 *is_shlib = 1; 454 return (1); 455 #ifdef __ARM_EABI__ 456 case ELFOSABI_NONE: 457 if (hdr.elf.e_machine != EM_ARM) 458 break; 459 if (EF_ARM_EABI_VERSION(hdr.elf.e_flags) < 460 EF_ARM_EABI_FREEBSD_MIN) 461 break; 462 *is_shlib = 1; 463 return (1); 464 #endif 465 } 466 warnx("%s: not a FreeBSD ELF shared object", fname); 467 return (0); 468 } 469 470 return (1); 471 } 472 473 warnx("%s: not a dynamic executable", fname); 474 return (0); 475 } 476