When ldd is used on linux yes it invokes it instead of producing the usual output. # pkg_info -W /compat/linux/usr/bin/yes /compat/linux/usr/bin/yes was installed by package linux_base-f8-8_4 # sysctl compat.linux.osrelease compat.linux.osrelease: 2.6.16 This behaviour breaks pkg_libchk from the sysutils/bsdadminscripts port. How-To-Repeat: # ldd /compat/linux/usr/bin/yes
ldd is not going to work for Linux binaries. The Linux ldd should be used for Linux binaries. -- John Baldwin
I don't need it to work, I just need it not to invoke linux binaries. I'm using ldd in a script and by ldd not returning 0 the script should know that it hasn't encountered a valid binary. Instead ldd opens a linux binary like yes and the script spills out ys (yes) or waits for input from stdin (md5sum). I'm pretty certain ldd is in no way meant to invoke programs.
I chatted briefly with John about this. The way our ldd works is by setting the environment variable TRACE_LOADED_OBJECTS and after some dlopen() magic it exec()'s the binary. FreeBSD rtld detects the environmental variable, prints the list of shared objects and quits. Linux rtld doesn't work this way, so FreeBSD ldd on a Linux binary will just run the Linux binary (Linux rtld will ignore the rest). Also, ldd wil return 1 on static binaries. Your best bet is to use file(1) to detect FreeBSD binaries. Something like `file $binary | grep FreeBSD-style` does the trick. Regards, -- Rui Paulo
As Rui indicated, ldd always execs binaries. It just sets environment variables that the FreeBSD runtime linker checks for. If the runtime linker sees them, it will modify it's behavior. You can achieve the same thing using env: % ldd /bin/ls /bin/ls: libutil.so.7 => /lib/libutil.so.7 (0x2808b000) libncurses.so.7 => /lib/libncurses.so.7 (0x28099000) libc.so.7 => /lib/libc.so.7 (0x280d8000) % env LD_TRACE_LOADED_OBJECTS=yes /bin/ls libutil.so.7 => /lib/libutil.so.7 (0x2808b000) libncurses.so.7 => /lib/libncurses.so.7 (0x28099000) libc.so.7 => /lib/libc.so.7 (0x280d8000) All the "ldd" printfs, etc. are actually from the runtime linker, not ldd itself. The Linux runtime linker doesn't modify it's behavior for LD_TRACE_LOADED_OBJECTS, so Linux apps just run normally when invoked by ldd. -- John Baldwin
Ok, thanks. I have already created a workaround with readelf, but I'd still consider this a bug in ldd. Shouldn't it check the elf brand if it only works for a single one? Regards
----- Forwarded message from John Baldwin <jhb@freebsd.org> ----- FreeBSD binaries from various releases have been branded in different ways. I would consider it more of a user error to run ldd on a Linux binary. :) You could maybe add a "IMPLEMENTATION NOTES" section to the manpage that explains how it works and why it will execute any binary using a different runtime linker. -- John Baldwin ----- End forwarded message -----
State Changed From-To: open->suspended As noted in the feedback trail, the fix is not as obvious as it first might appear. Mark this as 'suspended' for now to note that although we understand the problem, it is going to need more research.
How about documenting this behaviour in the manual page and closing this bug? I'm willing to write a patch if someone thinks this would be an acceptable solution.
----Next_Part(Tue_May_04_12_21_45_2010_795)-- Content-Type: Text/Plain; charset=us-ascii Content-Transfer-Encoding: 7bit Hello, I investigate this problem today and found that Linux's ld.so accepts "LD_TRACE_LOADED_OBJECTS". % env LD_TRACE_LOADED_OBJECTS=yes /compat/linux/bin/ls librt.so.1 => /lib/librt.so.1 (0x28087000) libselinux.so.1 => /lib/libselinux.so.1 (0x28092000) libcap.so.2 => /lib/libcap.so.2 (0x280af000) libacl.so.1 => /lib/libacl.so.1 (0x280b4000) libc.so.6 => /lib/libc.so.6 (0x280bc000) libpthread.so.0 => /lib/libpthread.so.0 (0x28234000) /lib/ld-linux.so.2 (0x28063000) libdl.so.2 => /lib/libdl.so.2 (0x2824e000) libattr.so.1 => /lib/libattr.so.1 (0x28254000) I think environment variable "LD_32_TRACE_LOADED_OBJECTS" is FreeBSD specific, and "LD_TRACE_LOADED_OBJECTS" should be passed to other binaries. Attached patch is reasonable? -- Shuichi KITAGUCHI // kit@ysnb.net / ki@hh.iij4u.or.jp ----Next_Part(Tue_May_04_12_21_45_2010_795)-- Content-Type: Text/X-Patch; charset=us-ascii Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="ldd.c.patch" --- ldd.c.old 2009-09-19 21:45:17.000000000 +0900 +++ ldd.c 2010-05-04 11:48:42.000000000 +0900 @@ -65,7 +65,7 @@ #endif static int is_executable(const char *fname, int fd, int *is_shlib, - int *type); + int *osabi, int *type); static void usage(void); #define TYPE_UNKNOWN 0 @@ -177,14 +177,14 @@ rval = 0; for (; argc > 0; argc--, argv++) { - int fd, status, is_shlib, rv, type; + int fd, status, is_shlib, rv, type, osabi; if ((fd = open(*argv, O_RDONLY, 0)) < 0) { warn("%s", *argv); rval |= 1; continue; } - rv = is_executable(*argv, fd, &is_shlib, &type); + rv = is_executable(*argv, fd, &is_shlib, &osabi, &type); close(fd); if (rv == 0) { rval |= 1; @@ -197,6 +197,8 @@ break; #if __ELF_WORD_SIZE > 32 && defined(ELF32_SUPPORTED) case TYPE_ELF32: + if (osabi != ELFOSABI_FREEBSD) + break; rval |= execldd32(*argv, fmt1, fmt2, aflag, vflag); continue; #endif @@ -267,7 +269,7 @@ } static int -is_executable(const char *fname, int fd, int *is_shlib, int *type) +is_executable(const char *fname, int fd, int *is_shlib, int *osabi, int *type) { union { struct exec aout; @@ -300,6 +302,8 @@ return (1); } + *osabi = hdr.elf.e_ident[EI_OSABI]; + #if __ELF_WORD_SIZE > 32 && defined(ELF32_SUPPORTED) if ((size_t)n >= sizeof(hdr.elf32) && IS_ELF(hdr.elf32) && hdr.elf32.e_ident[EI_CLASS] == ELFCLASS32) { ----Next_Part(Tue_May_04_12_21_45_2010_795)----
State Changed From-To: suspended->open Back to open, because a patch has been submitted.
Responsible Changed From-To: freebsd-amd64->freebsd-bugs This issue doesn't seem to be amd64 specific.
I tested the patch, prior to the test: > ldd /compat/linux/usr/bin/yes y y y y y y ... After I applied the patch: > ldd /compat/linux/usr/bin/yes /compat/linux/usr/bin/yes: libc.so.6 => /lib/libc.so.6 (0x28075000) /lib/ld-linux.so.2 (0x2804f000) Apparently it returns libraries from the /compat/linux perspective. > ldd /compat/linux/lib/ld-linux.so.2 ldd: /compat/linux/lib/ld-linux.so.2: not a FreeBSD ELF shared object The behaviour caused by the patch is comprehensible and a vast improvement over the old behaviour in my opinion, so I'm all for it. At some point the manual page of ldd should be updated to describe the new behaviour. If the patch is committed, I volunteer to make the changes. Because the patch was mangled by Gnats, I resubmit it here. I did not make any changes apart from the header to trigger the usual patch detection magic. Regards diff -u ldd.c.old ldd.c --- ldd.c.old 2009-09-19 21:45:17.000000000 +0900 +++ ldd.c 2010-05-04 11:48:42.000000000 +0900 @@ -65,7 +65,7 @@ #endif static int is_executable(const char *fname, int fd, int *is_shlib, - int *type); + int *osabi, int *type); static void usage(void); #define TYPE_UNKNOWN 0 @@ -177,14 +177,14 @@ rval = 0; for (; argc > 0; argc--, argv++) { - int fd, status, is_shlib, rv, type; + int fd, status, is_shlib, rv, type, osabi; if ((fd = open(*argv, O_RDONLY, 0)) < 0) { warn("%s", *argv); rval |= 1; continue; } - rv = is_executable(*argv, fd, &is_shlib, &type); + rv = is_executable(*argv, fd, &is_shlib, &osabi, &type); close(fd); if (rv == 0) { rval |= 1; @@ -197,6 +197,8 @@ break; #if __ELF_WORD_SIZE > 32 && defined(ELF32_SUPPORTED) case TYPE_ELF32: + if (osabi != ELFOSABI_FREEBSD) + break; rval |= execldd32(*argv, fmt1, fmt2, aflag, vflag); continue; #endif @@ -267,7 +269,7 @@ } static int -is_executable(const char *fname, int fd, int *is_shlib, int *type) +is_executable(const char *fname, int fd, int *is_shlib, int *osabi, int *type) { union { struct exec aout; @@ -300,6 +302,8 @@ return (1); } + *osabi = hdr.elf.e_ident[EI_OSABI]; + #if __ELF_WORD_SIZE > 32 && defined(ELF32_SUPPORTED) if ((size_t)n >= sizeof(hdr.elf32) && IS_ELF(hdr.elf32) && hdr.elf32.e_ident[EI_CLASS] == ELFCLASS32) {
Author: markj Date: Wed Aug 7 00:28:17 2013 New Revision: 254018 URL: http://svnweb.freebsd.org/changeset/base/254018 Log: Pass variables prefixed with both LD_ and LD_32_ to the run-time linker. This prevents unintentional execution of programs when running ldd(1) on 32-bit Linux binaries. PR: 175339, 127276 Suggested by: kib, rstone Reviewed by: kib MFC after: 2 weeks Modified: head/usr.bin/ldd/ldd.c Modified: head/usr.bin/ldd/ldd.c ============================================================================== --- head/usr.bin/ldd/ldd.c Wed Aug 7 00:20:30 2013 (r254017) +++ head/usr.bin/ldd/ldd.c Wed Aug 7 00:28:17 2013 (r254018) @@ -49,12 +49,6 @@ __FBSDID("$FreeBSD$"); #include "extern.h" -#ifdef COMPAT_32BIT -#define LD_ "LD_32_" -#else -#define LD_ "LD_" -#endif - /* * 32-bit ELF data structures can only be used if the system header[s] declare * them. There is no official macro for determining whether they are declared, @@ -64,6 +58,16 @@ __FBSDID("$FreeBSD$"); #define ELF32_SUPPORTED #endif +#define LDD_SETENV(name, value, overwrite) do { \ + setenv("LD_" name, value, overwrite); \ + setenv("LD_32_" name, value, overwrite); \ +} while (0) + +#define LDD_UNSETENV(name) do { \ + unsetenv("LD_" name); \ + unsetenv("LD_32_" name); \ +} while (0) + static int is_executable(const char *fname, int fd, int *is_shlib, int *type); static void usage(void); @@ -82,7 +86,7 @@ execldd32(char *file, char *fmt1, char * char *argv[8]; int i, rval, status; - unsetenv(LD_ "TRACE_LOADED_OBJECTS"); + LDD_UNSETENV("TRACE_LOADED_OBJECTS"); rval = 0; i = 0; argv[i++] = strdup(_PATH_LDD32); @@ -121,7 +125,7 @@ execldd32(char *file, char *fmt1, char * } while (i--) free(argv[i]); - setenv(LD_ "TRACE_LOADED_OBJECTS", "yes", 1); + LDD_SETENV("TRACE_LOADED_OBJECTS", "yes", 1); return (rval); } #endif @@ -210,15 +214,15 @@ main(int argc, char *argv[]) } /* ld.so magic */ - setenv(LD_ "TRACE_LOADED_OBJECTS", "yes", 1); + LDD_SETENV("TRACE_LOADED_OBJECTS", "yes", 1); if (fmt1 != NULL) - setenv(LD_ "TRACE_LOADED_OBJECTS_FMT1", fmt1, 1); + LDD_SETENV("TRACE_LOADED_OBJECTS_FMT1", fmt1, 1); if (fmt2 != NULL) - setenv(LD_ "TRACE_LOADED_OBJECTS_FMT2", fmt2, 1); + LDD_SETENV("TRACE_LOADED_OBJECTS_FMT2", fmt2, 1); - setenv(LD_ "TRACE_LOADED_OBJECTS_PROGNAME", *argv, 1); + LDD_SETENV("TRACE_LOADED_OBJECTS_PROGNAME", *argv, 1); if (aflag) - setenv(LD_ "TRACE_LOADED_OBJECTS_ALL", "1", 1); + LDD_SETENV("TRACE_LOADED_OBJECTS_ALL", "1", 1); else if (fmt1 == NULL && fmt2 == NULL) /* Default formats */ printf("%s:\n", *argv); _______________________________________________ svn-src-all@freebsd.org mailing list http://lists.freebsd.org/mailman/listinfo/svn-src-all To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"
State Changed From-To: open->patched This has been fixed with r254018 by passing both LD_TRACE_LOADED_OBJECTS and LD_32_TRACE_LOADED_OBJECTS to the runtime linker.
Responsible Changed From-To: freebsd-bugs->markj This has been fixed with r254018 by passing both LD_TRACE_LOADED_OBJECTS and LD_32_TRACE_LOADED_OBJECTS to the runtime linker.
State Changed From-To: patched->closed A fix has been merged to stable/8 and stable/9.
A commit in branch main references this bug: URL: https://cgit.FreeBSD.org/src/commit/?id=9cabef3d146e9a844813b6bc8952d6cf2e9d45e5 commit 9cabef3d146e9a844813b6bc8952d6cf2e9d45e5 Author: Konstantin Belousov <kib@FreeBSD.org> AuthorDate: 2022-09-21 13:55:44 +0000 Commit: Konstantin Belousov <kib@FreeBSD.org> CommitDate: 2022-10-06 15:50:26 +0000 ldd: use direct exec mode unconditionally Trying to exec malformed or unusual binary, for instance, a non-FreeBSD ABI, or using a non-standard interpreter, might give unexpected outcome. Reported by: The UK's National Cyber Security Centre (NCSC) Reviewed by: emaste, markj, philip Discussed with: jhb Sponsored by: The FreeBSD Foundation admbug: 991 PR: 127276, 175339, 231926 MFC after: 1 week Differential revision: https://reviews.freebsd.org/D36650 usr.bin/ldd/ldd.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-)
A commit in branch stable/13 references this bug: URL: https://cgit.FreeBSD.org/src/commit/?id=a763331899b4bb5502382ce1d5dfc8a35d857e27 commit a763331899b4bb5502382ce1d5dfc8a35d857e27 Author: Konstantin Belousov <kib@FreeBSD.org> AuthorDate: 2022-09-21 13:55:44 +0000 Commit: Konstantin Belousov <kib@FreeBSD.org> CommitDate: 2022-10-13 04:46:01 +0000 ldd: use direct exec mode unconditionally PR: 127276, 175339, 231926 (cherry picked from commit 9cabef3d146e9a844813b6bc8952d6cf2e9d45e5) usr.bin/ldd/ldd.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-)