Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

like image 910
Havli Avatar asked Apr 16 '15 12:04

Havli


2 Answers

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.

like image 122
Edward Avatar answered Sep 30 '22 01:09

Edward


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
like image 41
Breno Leitão Avatar answered Sep 30 '22 02:09

Breno Leitão