dlopen not finding library that ldconfig -p finds - c

I'm trying to bind against the CUDA library shared. As a quick verification I wrote the following code:
#include <stdlib.h>
#include <stdio.h>
#include <dlfcn.h>
int main(int argc, char **argv) {
void *handle;
handle = dlopen ("libcuda.so", RTLD_LAZY);
if (!handle) {
fputs (dlerror(), stderr);
exit(1);
}
dlclose(handle);
}
This fails with libcuda.so: cannot open shared object file: No such file or directory.
However, if I check ldconfig I get:
ldconfig -p | grep libcuda
libcuda.so.1 (libc6,x86-64) => /usr/lib/x86_64-linux-gnu/libcuda.so.1
libcuda.so.1 (libc6) => /usr/lib/i386-linux-gnu/libcuda.so.1
libcuda.so (libc6) => /usr/lib/i386-linux-gnu/libcuda.so
So it seems that libcuda.so does exist and is seen by the system. So why is dlopen() failing?
This is on Ubuntu 14.04.

I can see from your ldconfig -p that there is no symlink for libcuda.so.1 x86_64, you just need to create it, try
sudo ln -svf /usr/lib/x86_64-linux-gnu/libcuda.so{.1,}
it might be the case that you don't have the -dev package installed.
Or simply change
handle = dlopen ("libcuda.so", RTLD_LAZY);
to
handle = dlopen ("libcuda.so.1", RTLD_LAZY);
but the first solution is better because when you link dynamically to libcuda.so.1 with -lcuda the symlink migh be mandatory.

Related

Where do Linux shells look for interpreters for ELF binaries? [duplicate]

So everyone probably knows that glibc's /lib/libc.so.6 can be executed in the shell like a normal executable in which cases it prints its version information and exits. This is done via defining an entry point in the .so. For some cases it could be interesting to use this for other projects too. Unfortunately, the low-level entry point you can set by ld's -e option is a bit too low-level: the dynamic loader is not available so you cannot call any proper library functions. glibc for this reason implements the write() system call via a naked system call in this entry point.
My question now is, can anyone think of a nice way how one could bootstrap a full dynamic linker from that entry point so that one could access functions from other .so's?
Update 2: see Andrew G Morgan's slightly more complicated solution which does work for any GLIBC (that solution is also used in libc.so.6 itself (since forever), which is why you can run it as ./libc.so.6 (it prints version info when invoked that way)).
Update 1: this no longer works with newer GLIBC versions:
./a.out: error while loading shared libraries: ./pie.so: cannot dynamically load position-independent executable
Original answer from 2009:
Building your shared library with -pie option appears to give you everything you want:
/* pie.c */
#include <stdio.h>
int foo()
{
printf("in %s %s:%d\n", __func__, __FILE__, __LINE__);
return 42;
}
int main()
{
printf("in %s %s:%d\n", __func__, __FILE__, __LINE__);
return foo();
}
/* main.c */
#include <stdio.h>
extern int foo(void);
int main()
{
printf("in %s %s:%d\n", __func__, __FILE__, __LINE__);
return foo();
}
$ gcc -fPIC -pie -o pie.so pie.c -Wl,-E
$ gcc main.c ./pie.so
$ ./pie.so
in main pie.c:9
in foo pie.c:4
$ ./a.out
in main main.c:6
in foo pie.c:4
$
P.S. glibc implements write(3) via system call because it doesn't have anywhere else to call (it is the lowest level already). This has nothing to do with being able to execute libc.so.6.
I have been looking to add support for this to pam_cap.so, and found this question. As #EmployedRussian notes in a follow-up to their own post, the accepted answer stopped working at some point. It took a while to figure out how to make this work again, so here is a worked example.
This worked example involves 5 files to show how things work with some corresponding tests.
First, consider this trivial program (call it empty.c):
int main(int argc, char **argv) { return 0; }
Compiling it, we can see how it resolves the dynamic symbols on my system as follows:
$ gcc -o empty empty.c
$ objcopy --dump-section .interp=/dev/stdout empty ; echo
/lib64/ld-linux-x86-64.so.2
$ DL_LOADER=/lib64/ld-linux-x86-64.so.2
That last line sets a shell variable for use later.
Here are the two files that build my example shared library:
/* multi.h */
void multi_main(void);
void multi(const char *caller);
and
/* multi.c */
#include <stdio.h>
#include <stdlib.h>
#include "multi.h"
void multi(const char *caller) {
printf("called from %s\n", caller);
}
__attribute__((force_align_arg_pointer))
void multi_main(void) {
multi(__FILE__);
exit(42);
}
const char dl_loader[] __attribute__((section(".interp"))) =
DL_LOADER ;
(Update 2021-11-13: The forced alignment is to help __i386__ code be SSE compatible - without it we get hard to debug glibc SIGSEGV crashes.)
We can compile and run it as follows:
$ gcc -fPIC -shared -o multi.so -DDL_LOADER="\"${DL_LOADER}\"" multi.c -Wl,-e,multi_main
$ ./multi.so
called from multi.c
$ echo $?
42
So, this is a .so that can be executed as a stand alone binary. Next, we validate that it can be loaded as shared object.
/* opener.c */
#include <dlfcn.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char **argv) {
void *handle = dlopen("./multi.so", RTLD_NOW);
if (handle == NULL) {
perror("no multi.so load");
exit(1);
}
void (*multi)(const char *) = dlsym(handle, "multi");
multi(__FILE__);
}
That is we dynamically load the shared-object and run a function from it:
$ gcc -o opener opener.c -ldl
$ ./opener
called from opener.c
Finally, we link against this shared object:
/* main.c */
#include "multi.h"
int main(int argc, char **argv) {
multi(__FILE__);
}
Where we compile and run it as follows:
$ gcc main.c -o main multi.so
$ LD_LIBRARY_PATH=./ ./main
called from main.c
(Note, because multi.so isn't in a standard system library location, we need to override where the runtime looks for the shared object file with the LD_LIBRARY_PATH environment variable.)
I suppose you'd have your ld -e point to an entry point which would then use the dlopen() family of functions to find and bootstrap the rest of the dynamic linker. Of course you'd have to ensure that dlopen() itself was either statically linked or you might have to implement enough of your own linker stub to get at it (using system call interfaces such as mmap() just as libc itself is doing.
None of that sounds "nice" to me. In fact just the thought of reading the glibc sources (and the ld-linux source code, as one example) enough to assess the size of the job sounds pretty hoary to me. It might also be a portability nightmare. There may be major differences between how Linux implements ld-linux and how the linkages are done under OpenSolaris, FreeBSD, and so on. (I don't know).

syscall(SYS_getuid) returns different result from getuid()

I would like to use syscalls to get the id of the current user. I tried it like this:
#include <unistd.h>
#include <sys/syscall.h>
#include <stdio.h>
int main(int argc, char *argv[])
{
int uid = syscall(SYS_getuid);
printf("%d\n", uid);
return 0;
}
I executed it with root, but it prints -1 instead of 0.
If I replace it with int uid = syscall(SYS_getuid);, then it correctly returns 0. What do I wrong? How to get the current user id using syscall?
I run it on i686/ubuntu docker image, because I have to create 32bit executables.
Minimal reproducible example:
Dockerfile
FROM i686/ubuntu
RUN apt-get update
RUN apt-get install --assume-yes --no-install-recommends --quiet \
gcc libc6-dev
RUN apt-get clean all
main.c
#include <unistd.h>
#include <sys/syscall.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
int main(int argc, char *argv[])
{
int uid = syscall(SYS_getuid);//getuid();//
if(uid == -1)
printf("Error: %s\n", strerror(errno));
printf("%d\n", uid);
return 0;
}
Run ( On x64 Windows10 ):
docker build --platform linux/386 -t my-gcc .
docker run --platform linux/386 --rm -v ${pwd}:/usr/local/src/:rw my-gcc gcc -m32 -xc /usr/local/src/main.c -o /usr/local/src/main
docker run --platform linux/386 --rm -v ${pwd}:/usr/local/src/:rw my-gcc /usr/local/src/main
The result is:
Error: Function not implemented
-1
Per getuid(2):
The original Linux getuid() and geteuid() system calls supported only 16-bit user IDs. Subsequently, Linux 2.4 added getuid32() and geteuid32(), supporting 32-bit IDs. The glibc getuid() and geteuid() wrapper functions transparently deal with the variations across kernel versions.
Apparently you are running your program on a kernel that has the old getuid system call compiled out, and only getuid32 is available on x86-32. If you run fgrep CONFIG_UID16 "/boot/config-$(uname -r)", you will be able to see if your running kernel supports the 16-bit syscall. If this command prints anything other than CONFIG_UID16=y, it means the old system call is unavailable.
If you invoke SYS_getuid32 instead, it should work fine. Note that SYS_getuid32 may fail to be available on other architectures.

C call function type error

I'm trying to compile this code which call func from "libcfmapi.so" to decrypt "cfg" file
#include <stdlib.h>
#include <stdio.h>
int restorebackup(const char *tmp_cfg_name,const char *xml_cfg_name);
int ATP_CFM_ExtCustomImportEncryptedUserCfgFile(const char *tmp_cfg_name);
int main(int argc, char **argv)
{
int ret;
if(argc < 3)
{
printf("specify temp config file name.\n");
exit(1);
}
ret=restorebackup(argv[1],argv[2]);
return ret;
}
int restorebackup(const char *tmp_cfg_name,const char *xml_cfg_name)
{
int ret=0;
//ret = ATP_CFM_ExtDigVerifyFile(tmp_cfg_name,tmp_cfg_name);
if(ret != 0)
{
printf("Verify File failed.\n");
return ret;
}
ret = ATP_CFM_ExtCustomImportEncryptedUserCfgFile(tmp_cfg_name);
return ret;
}
but got error regarding func type declare
root#kali:~/debian-qemu# gcc h.c -o demo
/tmp/ccVbt5NT.o: In function `restorebackup':
h.c:(.text+0x8c): undefined reference to `ATP_CFM_ExtCustomImportEncryptedUserCfgFile'
collect2: error: ld returned 1 exit status
any help appreciated
The reason you're getting this error is because you're not linking against the required library, libcfmapi.so.
This is not a library you would expect to find in your Debian system as it is unique to the BT device you're trying to hack.
In short - get the lib from your device, cross compile to the device architecture against the lib you extracted from the device and you should be fine.
More information based on Ishay Peled answer:
readelf -s <pulled library> | grep ATP_CFM_ExtCustomImportEncryptedUserCfgFile
I suspect the problem isn't that function you call doesn't exist but rather there are no functions being displayed it is most likely empty just like nm result:
nm: libcfmapi.so: no symbols
do the command without piping to grep, my bet is your output is:
readelf -s libcfmapi.so
Dynamic symbol information is not available for displaying symbols.
If someone knows the way of getting the headers from the file, i believe then you can find your function you require then link and run (i too am trying to use libcfmapi.so, but lack the programming/reversing knowledge required).
when using a library, then must:
include that library in the link statement via
-l cfmapi
include the header file for that library in the source code:
#include <cfmapi.h>

problems compiling c code with libusb on linux

I'm trying to use libusb for a project but i'm unable to get the library working properly. Here is some source code i'm trying to compile. It doesn't do anything special. It's just a dummy program that gets the USB driver list then frees it.
#include <stdio.h>
#include <usb.h>
#include <stdlib.h>
int main(int argc, char *argv[]){
struct libusb_device **devs;
struct libusb_context *context = NULL;
size_t list;
size_t i;
int ret;
ret = libusb_init(&context);
if(ret < 0)
{
perror("libusb_init");
exit(1);
}
list = libusb_get_device_list(context, &devs);
if(list < 0)
{
fprintf(stderr, "error in getting device list\n");
libusb_free_device_list(devs, 1);
libusb_exit(context);
exit(1);
}
libusb_free_device_list(devs, 1);
libusb_exit(context);
return 0;
}
I compile with
gcc -o test test.c -lusb
I get the error
/tmp/cc2hwzii.o: in function 'main:
test.c:(.text+0x24): undefined reference to 'libusb_init'
test.c:(.text+0x59): undefined reference to 'libusb_get_device_list'
test.c:(.text+0x8e): undefined reference to 'libusb_free_device_list'
test.c:(.text+0x9f): undefined reference to 'libusb_exit'
collect2: error: ld returned 1 exit status
I'm running ubuntu 14.04.3
I've installed libusb by sudo apt-get install libusb-dev
I've searched for my header file and it is called usb.h
I've looked to make sure I have the correct flag and it's -lusb
any ideas? I'd appreciate the help. If any more information is needed just ask.
those libusb_init are included in libusb-1.0.
you have to install libusb-1.0-0-dev
$ sudo apt-get install libusb-1.0-0-dev
$ gcc -o test test.c -lusb-1.0
/usr/lib/x86_64-linux-gnu/pkgconfig/libusb.pc which is included in libusb-dev says that the version is 0.1.12
and
/usr/lib/x86_64-linux-gnu/pkgconfig/libusb-1.0.pc which is included in libusb-1.0-0-dev says that the version is 1.0.17.
http://www.libusb.org/ says that 0.1 is legacy, and seems that API is different from 1.0.
You forgot to include the file that defines the functions, such as libusb_init. Have you tried including libusb.h?

How install header files for opencv in C in my ubuntu 11.10

Resently I'm installed Opencv in my machine. Its working in python well(I just checked it by some eg programs). But due to the lack of tutorials in python I decided to move to c. I just run an Hello world program from http://www.cs.iit.edu/~agam/cs512/lect-notes/opencv-intro/
My program is
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <cv.h>
#include <highgui.h>
int main(int argc, char *argv[])
{
IplImage* img = 0;
int height,width,step,channels;
uchar *data;
int i,j,k;
if(argc<2){
printf("Usage: main <image-file-name>\n\7");
exit(0);
}
// load an image
img=cvLoadImage(argv[1]);
if(!img){
printf("Could not load image file: %s\n",argv[1]);
exit(0);
}
// get the image data
height = img->height;
width = img->width;
step = img->widthStep;
channels = img->nChannels;
data = (uchar *)img->imageData;
printf("Processing a %dx%d image with %d channels\n",height,width,channels);
// create a window
cvNamedWindow("mainWin", CV_WINDOW_AUTOSIZE);
cvMoveWindow("mainWin", 100, 100);
// invert the image
for(i=0;i<height;i++) for(j=0;j<width;j++) for(k=0;k<channels;k++)
data[i*step+j*channels+k]=255-data[i*step+j*channels+k];
// show the image
cvShowImage("mainWin", img );
// wait for a key
cvWaitKey(0);
// release the image
cvReleaseImage(&img );
return 0;
}
first while compiling I got the following error
hello-world.c:4:16: fatal error: cv.h: No such file or directory
compilation terminated.
and I rectify this error by compiling like this
gcc -I/usr/lib/perl/5.12.4/CORE -o hello-world hello-world.c
But now the error is
In file included from hello-world.c:4:0:
/usr/lib/perl/5.12.4/CORE/cv.h:14:5: error: expected specifier-qualifier-list before ‘_XPV_HEAD’
hello-world.c:5:21: fatal error: highgui.h: No such file or directory
compilation terminated.
Qns :
Is it this header is not installed in my system? While I'm using this command find /usr -name "highgui.h" I'm not find anything
If this header is not in my sysytem hoew I install this?
Please help me . I'm new in opencv
First check if highgui.h exists on your machine:
sudo find /usr/include -name "highgui.h"
If you find it on path lets say "/usr/include/opencv/highgui.h"
then use:
#include <opencv/highgui.h> in your c file.
or
while compiling you could add
-I/usr/include/opencv in gcc line
but then your include line in c file should become:
#include "highgui.h"
if, your first command fails that is you don't "find" highgui.h on your machine. Then clearly you are missing some package. To figure out that package name, use apt-find command:
sudo apt-find search highgui.h
on my machine, it gave me this:
libhighgui-dev: /usr/include/opencv/highgui.h
libhighgui-dev: /usr/include/opencv/highgui.hpp
if you don't have apt-find then install it first, using:
sudo apt-get install apt-find
So, now you know the package name, then issue:
sudo apt-get install libhighgui-dev
once this is done, use the find command to see where exactly, headers been installed and then use then change include path accordingly
I have the following headers in my project:
#include <opencv2/opencv.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/objdetect/objdetect.hpp>
#include <opencv2/features2d/features2d.hpp>
The version of OpenCV 2.4.2

Resources