ldd command libasan not showing - shared-libraries

I have a binary in my dev machine ldd command doesn't show libasan. But when I copy the same binary to another production machine. ldd command shows libasan. I am not sure How this happens. Please help me.
## DEV VM ##
cohesity - main: ldd <path> | grep -i asan
cohesity - main: md5sum <path>
11152b37c616555eed06800ee499323a <path>
### Production machine ##
[support#suresh-test-005056af8cb9-node-1 ~]$ md5sum <path>
11152b37c616555eed06800ee499323a <path>
[support#suresh-test-005056af8cb9-node-1 ~]$ ldd <path> | grep -i asan
libasan.so.4 => <path to libasan> (0x00007f72595e7000)
[support#suresh-test-005056af8cb9-node-1 ~]$

I am not sure How this happens.
The ldd command output depends on a few things:
the binary you give it
all the shared libraries this binary depends on, recursively
local system configuration (for search paths, any preload libraries, etc.)
By copying the main binary to a different machine, you only guaranteed that "step 1" is identical.
Chances are that one of the shared libraries in "step 2" has been built with -fsanitize=address on node-1, but not in "dev VM".
You can find out which library that is by using readelf -d /path/to/foo.so | grep NEEDED.*libasan.so.4 on each of the libraries in ldd output.

Related

How can my bash find binaries if the binary is not in $PATH?

I got a class VM which uses ubuntu 18.04 as a base. The terminal is bash and I confirmed from
echo $0
There is a command called elastalert which auto-complete if I just type "elast" and then hit tab. This is pretty normal for any binaries that locates in $PATH.
However, when i do
which elastalert
It returns no info. I searched the file from root directory
$ sudo find -name elastalert 2>null
./backup/elastalert
./elastic_stack/elastalert
However, both path above are directories. I check the $PATH, it does not contain the above path
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
Q: What kind of linux mechanism allows me to auto-complete elastalert, but the elastalert does not exist in $PATH?
Update:
$type elastalert
elastalert is aliased to `docker run -it --rm --net=bridge --network=labs_esnet --name elastalert --hostname elastalert -v /labs:/labs --link elasticsearch hasecuritysolutions/elastalert:v0.1.31 /usr/local/bin/elastalert'
There are some Qs on why sudo is needed. As you can see below, the files are in directories only accessible to root.
$ sudo find -type f -name elastalert 2>/dev/null
[sudo] password for student:
./var/lib/docker/overlay2/c8b9f4ad647fad4090665c6ee6d63af998265ba008756f6dd24563245043d091/diff/usr/local/bin/elastalert
$ sudo file ./var/lib/docker/overlay2/c8b9f4ad647fad4090665c6ee6d63af998265ba008756f6dd24563245043d091/diff/usr/local/bin/elastalert
./var/lib/docker/overlay2/c8b9f4ad647fad4090665c6ee6d63af998265ba008756f6dd24563245043d091/diff/usr/local/bin/elastalert: Python script, ASCII text executable
I can't give you a specific answer but you may find clues in the bash infotext sections 8.6, 8.7 and 8.8.
In section 8.8 it is ilustrated that scripts that aid completion can be installed separatly from programs which would explain why you get a completion without the said program being in your PATH.

Bash: No such file or directory?

I try to use an executable script (wkhtmltopdf) on a Linux shared webserver (Debian, 64bit). I am pretty sure that I compiled everything correct, but whenever I want to execute the file I get as an response :
> ./wkhtmltopdf -H
-bash: ./wkhtmltopdf: No such file or directory
To be sure that the file is there, here the ls output :
> ls
wkhtmltoimage wkhtmltopdf
Furthermore I tested the file command on it, which outputs the following :
> file wkhtmltopdf
wkhtmltopdf: ELF 64-bit LSB executable, x86-64, version 1 (GNU/Linux), dynamically linked (uses shared libs), for GNU/Linux 2.6.18, stripped
My question is now :
Why does bash tells me that there is no 'file or directory', when there obviously is one?
My first guess would be that the shared server does not allow to execute binary files? But shouldn't it then be a problem of permissions, with a different bash output?
Edit :
> id
uid=2725674(p8907906) gid=600(ftpusers) groups=600(ftpusers)
> ls -l wkhtmltopdf
-rwxrwxrwx 1 p8907906 ftpusers 39745960 Jan 20 09:33 wkhtmltopdf
> ls -ld
drwx---r-x 2 p8907906 ftpusers 44 Jan 28 21:02 .
I bet you miss dynamic linker. Just do a
readelf --all ./wkhtmltopdf | grep interpreter
You should get an output like this:
[Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]
There are high chances that you system lacks the interpreter (/lib64/ld-linux-x86-64.so.2 in the example). In this case bash would yell No such file or directory, just like when the binary itself is missing.
You can try to use a different linker. Sometime you can succeed. Just do a:
/path/to/the/linker /path/to/your/executable
This command:
find /lib* -name ld-linux\*
will help you find the linkers on your system. Or you can do the readelf command on some command that does run. It will show you correct, working linker.
OR, since you are running Debian system, just do a
sudo apt-get install wkhtmltopdf
to install native version of the tool :)
In my case
$ readelf --all ./wkhtmltopdf | grep interpreter # readelf: Displays information about ELF files.
[Requesting program interpreter: /lib/ld-linux.so.2]
On a machine where the executable was working:
$ ls -lah /lib/ld-linux.so.2
lrwxrwxrwx 1 root root 25 Apr 16 2018 /lib/ld-linux.so.2 -> i386-linux-gnu/ld-2.27.so
$ dpkg -S /lib/ld-linux.so.2 # -S, --search filename-search-pattern: Search for a filename from installed packages.
libc6:i386: /lib/ld-linux.so.2
So to fix the problem (reference)
sudo dpkg --add-architecture i386
sudo apt update
sudo apt install libc6:i386 # GNU C Library: Shared libraries (from apt show)
Missing the linker was my case as well. I could fix it with the help of nsilent22 answer like this:
readelf --all /usr/local/myprogram | grep interpreter
[Requesting program interpreter: /lib64/ld-lsb-x86-64.so.3]
But that linker did not exist anymore.
The old situation in /lib64 was:
ld-linux-x86-64.so.2 -> /lib/x86_64-linux-gnu/ld-2.31.so
ld-linux-x86-64.so.3 -> ld-linux-x86-64.so.2
So it turned out this was just a symlink to the systems' linker.
Moving over to /lib64 , which itself is a symlink to usr/lib64 and creating a symlink over there did not work. I assume that there are to many symbolic link levels after Debian moved everything into /usr
However creating a 'direct' symlink
ln -s /usr/lib64/ld-linux-x86-64.so.2 /lib64/ld-lsb-x86-64.so.3
did the job; /usr/lib64 now shows:
ld-linux-x86-64.so.2 -> /lib/x86_64-linux-gnu/ld-2.31.so
ld-lsb-x86-64.so.3 -> /usr/lib64/ld-linux-x86-64.so.2
I ran into this issue on my raspberry pi 4 running aarch64 alpine 3.13. Using the answer provided by #vkersten, I was able to determine that I was missing /lib/ld-linux-aarch64.so.1.
I resolved this by installing gcompat with apk add gcompat.

C program compiling with glibc and not the default libraries: Permission denied on execution

it's my first question on stackoverflow, so I will try to do it well.
Context:
I would like to deliver a program who could run on every Linux distribution (for example, a program who will use C++11, running on a system who don't have the C++11 library).
For that I would like to copy all the libraries who are used by my program and put them in a folder with the executable, so it can use these libraries instead of the system's one.
I got 2 environments to test:
- Opensuse, with (GNU libc) 2.19
- Ubuntu, with (Ubuntu EGLIBC 2.17-Oubuntu5.1) 2.17
I compile my program under Opensuse, and run it under Ubuntu. The program works well when it uses the default library.
Project:
Here is the main.c:
int main(int ac, char **av) {
printf("Hello World !\n");
}
Here is the tree of my folder under Opensuse (same under Ubuntu without main.c et exec.sh):
+ project
|
+--- main.c
+--- a.out
+--- exec.sh
+---+ lib
|
+--- libc.so.6
+--- ld-linux-x86-64.so.2
And finally here is the ldd and the readelf when I launch the program with a simple compilation:
> gcc main.c -o a.out
> ldd ./a.out
linux-vdso.so.1 (0x00007fff85f57000)
libc.so.6 => /lib64/libc.so.6 (0x00007f1fdaaaf000)
/lib64/ld-linux-x86-64.so.2 (0x00007f1dae75000)
> readelf -d a.out | grep "library\|Library"
0x0000000000000001 (NEEDED) Shared library: [libc.so.6]
I have done some research, and finally found this post who explain a bit about the ld-linux.so.
Here is the script that I use to compile:
#!/bin/bash
dir=`pwd`
execName="a.out"
libDir="/lib"
linker="ld-linux-x86-64.so.2"
gcc main.c -o ${execName} -Wl,--rpath=${dir}${libDir} -Wl,--dynamic-linker=${dir}${libDir}/${linker}
When I launch my a.out compiling with the script on my Opensuse i got the following:
> ./a.out
Hello World !
> ldd ./a.out
linux-vdso.so.1 (0x00007f3222e27000)
libc.so.6 => /path/to/project/lib/libc.so.6 (0x00007f3222a7e000)
/path/to/project/lib/ld-linux-x86-64.so.2 => /lib64/ld-linux-x86-64.so.2 (0x000073222e2b000)
> readelf -d a.out | grep "library\|Library"
0x0000000000000001 (NEEDED) Shared library: [libc.so.6]
0x000000000000001d (RUNPATH) Library runpath: [/path/to/project/lib]
Problem:
Now, when I launch this executable a.out (compiled under Opensuse) on my Ubuntu, i got the following output:
> ./a.out
./a.out: Permission denied.
> ldd ./a.out
linux-vdso.so.1 (0x00007fff5b5fe000)
libc.so.6 => /path/to/project/lib/libc.so.6 (0x00007f47df480000)
/path/to/project/lib/ld-linux-x86-64.so.2 => /lib64/ld-linux-x86-64.so.2 (0x00007f47df82a000)
> readelf -d a.out | grep "library\|Library"
0x0000000000000001 (NEEDED) Shared library: [libc.so.6]
0x000000000000001d (RUNPATH) Library runpath: [/path/to/project/lib]
I keep having this permission denied when I launch the executable, and I don't know why.
I transfer my a.out and my lib folder from Opensuse to Ubuntu with Filezilla, and a.out isn't an executable after that transfer, so I need to do:
chmod 755 a.out
I have the same tree under Opensuse and Ubuntu
The 2 libraries in the lib folder are default library from Opensuse
Any help about the permission denied, or another way to do what I want will be welcome.
Thanks in advance for your help!
Note: I can't use LD_PRELOAD, since you need to be root to use it, it will not work for what I want to do.
Also i would like to avoid the static compilation, but if it's the only solution i will think about it
There are many things that could be wrong with this. Here are a few suggestions.
Check file permissions for copied libraries
You've mentioned that whatever you're using to copy your a.out alters permissions for that file. Libraries need specific permissions, too, so check those.
Check for broken symlinks
Many of those libraries are typically actually symlinks to the real binary. If you've only copied the links and not the underlying binary, it won't work.
Check for mismatched libraries
As you know, libc is more than just a single file. For example, on my Linux machine, if I run ldd /lib64/libc.so.6 I get this result:
/lib64/ld-linux-x86-64.so.2 (0x0000003531200000)
linux-vdso.so.1 => (0x00007ffe2c78c000)
Unless you are also copying all of the libraries that are needed, it won't work.
Consider using -R for the linker
The -L flag tells the linker where it can find the libraries, but there's also a -R flag that tells the resulting executable where to find the libraries at runtime. It's not clear to me whether you'll need that or not.
You can follow the easier way that is compiling your application not depending on share object. In this case, your application will be static compiled, and you should use the flag -static.
Take a look at my example:
$ cat main.c
#include <stdio.h>
int main(int ac, char **av) {
printf("Hello World !\n");
}
$ gcc main.c -o main -static
$ ldd main
not a dynamic executable
Reproduce the permission error by running the application under strace utility and analyze the logs to isolate the real runtime issue.
$ strace -fv ./a.out
Any help about the permission denied
That part is simple: not only the a.out must be made executable with chmod, but the /path/to/project/lib/ld-linux-x86-64.so.2 must be executable as well.
Note: I can't use LD_PRELOAD, since you need to be root to use it
You are mistaken: you absolutely do not need to be root to use LD_PRELOAD (unless you are using it on set-uid binary).

How to add my own software to a Buildroot Linux package?

I am trying to add my own program to a small linux, created with Buildroot.
What I've done so far:
I've created a new directory inside my 'buildroot/package/' called 'HelloWorld'.
Inside 'buildroot/package/HelloWorld' I have : a Config.in, HelloWorld.mk and HelloWorld directory.
Config.in holds this:
config BR2_PACKAGE_HELLOWORLD
bool "helloworld"
default y
help
Hello world component.
HelloWorld.mk holds this:
HELLOWORLD_VERSION:= 1.0.0
HELLOWORLD_SITE:= /home/userpc/Downloads/helloworld/
HELLOWORLD_SITE_METHOD:=local
HELLOWORLD_INSTALL_TARGET:=YES
define HELLOWORLD_BUILD_CMDS
$(MAKE) CC="$(TARGET_CC)" LD="$(TARGET_LD)" -C $(#D) all
endef
define HELLOWORLD_INSTALL_TARGET_CMDS
$(INSTALL) -D -m 0755 $(#D)/helloworld $(TARGET_DIR)/bin
endef
define HELLOWORLD_PERMISSIONS
/bin/helloworld f 4755 0 0 - - - - -
endef
$(eval $(generic-package))
(inspiration source)
The HelloWorld directory contains: main.c & Makefile:
main.c :
#include <stdio.h>
int main()
{
printf("\nMain entry.\n");
return 0;
}
Makefile:
CC=gcc
CFLAGS=-I.
all: *.c
$(CC) -Os -Wall *.c -o helloworld
# $(STRIP) helloworld
clean:
rm -f a.out helloworld
rm -f *.o
Edit: And I have also added source "package/HelloWorld/Config.in" to 'package/Config.in'
But when I mount my rootfs.ext2 partition I can't find my HelloWorld executable inside /usr/bin .., I am really new to this and don't have any prior knowledge, so could you please explain to me, what am I missing from this, because I'm sure I'm doing something wrong.
UPDATE: The program builds and install at the desired location but when I try to run it like so: ./helloworld, I get: bash: ./helloworld: No such file or directory It has execution rights. What is the matter with it? (I try to run it after I mount the rootfs.ext2 into a ubuntu directory, the target arch for buildroot is i386, so it should be ok, right?)
After building and installing the HelloWorld program, and eventually running it, I'd like to add to init.d so it starts after booting, and replace the HelloWorld with a Qt Window that doesn't need a X server, like this thing here.
The main source of inspiration here.
Minimal tested example on top of 2016.05
GitHub upstream:
https://github.com/cirosantilli/buildroot/tree/in-tree-package-2016.05
This example adds the package source in-tree, which is simple for educational purposes and the way to go if you want to merge back (kudos!),
If you do not intend on merging back (booooh!), it is more likely that you will want to use Buildroot as a git submodule and either:
an out of tree package with BR2_EXTERNAL as shown at: https://github.com/cirosantilli/buildroot/tree/out-of-tree-2016.05
*_OVERRIDE_SRCDIR + other git submodules as explained at: How to modify the source of Buildroot packages for package development?
Files modified:
package/Config.in
menu "Misc"
source "package/hello/Config.in"
endmenu
package/hello/Config.in
config BR2_PACKAGE_HELLO
bool "hello"
help
Hello world package.
http://example.com
package/hello/hello.mk
################################################################################
#
# hello
#
################################################################################
HELLO_VERSION = 1.0
HELLO_SITE = ./package/hello/src
HELLO_SITE_METHOD = local
define HELLO_BUILD_CMDS
$(MAKE) CC="$(TARGET_CC)" LD="$(TARGET_LD)" -C $(#D)
endef
define HELLO_INSTALL_TARGET_CMDS
$(INSTALL) -D -m 0755 $(#D)/hello $(TARGET_DIR)/usr/bin
endef
$(eval $(generic-package))
package/hello/src/.gitignore
hello
package/hello/src/Makefile
CC = gcc
.PHONY: clean
hello: hello.c
$(CC) -o '$#' '$<'
clean:
rm hello
package/hello/src/hello.c
#include <stdio.h>
int main(void) {
puts("hello");
}
Usage:
make qemu_x86_64_defconfig
echo 'BR2_PACKAGE_HELLO=y' >> .config
make BR2_JLEVEL=2
qemu-system-x86_64 -M pc -kernel output/images/bzImage -drive file=output/images/rootfs.ext2,if=virtio,format=raw -append root=/dev/vda -net nic,model=virtio -net user
From inside qemu:
hello
Expected output:
hello
Tested in Ubuntu 16.04.
In general, the sources for buildroot packages are taken from a (downloaded) tarball. What you are doing right now (placing the sources inside package/HelloWorld) is not the right way to proceed.
Buildroot does have provisions for 'local' package sources, which you could use if you really need to. You'll need the HELLOWORLD_SITE_METHOD variable for that.
Please refer to http://buildroot.uclibc.org/downloads/manual/manual.html#adding-packages for more information.
Also, you don't need to define HELLOWORLD_DIR, HELLOWORLD_BINARY, HELLOWORLD_TARGET_BINARY.
Update: regarding your additional question:
UPDATE: The program builds and install at the desired location but when I try to run it
like so: ./helloworld, I get: bash: ./helloworld: No such file or directory, it has
execution rights.. what is the matter with it? (I try to run it after I mount the
rootfs.ext2 into a ubuntu directory, the target arch for buildroot is i368, so it should
be ok, right?)
No, it does not work like that. You can't just mount rootfs.ext2 and expect to run programs from it. This is, among others, because the programs inside rootfs.ext2 are compiled against the libraries also inside rootfs.ext2, but if you run it like that it will use the libraries in /usr/lib. You either have to boot your system entirely with the rootfs.ext2, use qemu, or use a chroot environment. For chroot, you should use the 'tar' filesystem format, not ext2. See also here:
http://buildroot.uclibc.org/downloads/manual/manual.html#_chroot

Without admin prevlieges, how do I find the directories searched by ld?

How do I find the directories searched in by the GNU linker, without admin privileges?
I can get the listing in the following way:
$ sudo ldconfig -v 2>/dev/null | grep -v ^$'\t'
/lib/i386-linux-gnu:
/usr/lib/i386-linux-gnu:
/usr/local/lib:
/lib/x86_64-linux-gnu:
/usr/lib/x86_64-linux-gnu:
/usr/lib/fglrx:
/usr/lib32/fglrx:
/lib32:
/usr/lib32:
/lib:
/usr/lib:
/usr/lib/i386-linux-gnu/sse2: (hwcap: 0x0000000004000000)
this solution came from: How to print the ld(linker) search path
However, on a machine where I do not have admin privileges, this will not work. I assume that’s because ldconfig is located in /sbin/. I download glibc and installed it locally to create another version of ldconfig. I guess that was silly though because the local version gives me:
/usr/local/lib:
/usr/local/lib64:
Is it still possible to get all the directories as a non-admin?
There doesn't appear to be any helpful ld flags, or environment variables to do the job.
Just because ldconfig is in sbin doesn't mean it can't be run as a normal user. Simply use that command and specify the full path to ldconfig:
/sbin/ldconfig -v 2>/dev/null | grep -v ^$'\t'

Resources