[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#650234: Use chroot's ld.so to do loading?



unmerge 626482
reassign 650234 fakechroot 2.15-1
severity 650234 important
tags 650234 + upstream
quit

Elliott Mitchell wrote:

> user@host:/$ ls
> Segmentation fault
> user@host:/$ /lib/ld-linux.so.2 ls
> ls: error while loading shared libraries: ls: cannot open shared object file: No such file or directory
> user@host:/$ /lib/ld-linux.so.2 /bin/ls
> bin   debootstrap  etc	 lib  proc  sbin     sys  usr
[...]
> So, something along these lines is possible.

Thanks.  Indeed, ideally fakechroot's execve should look up the
interpreter filename from the ELF .interp section, map it according to
the faked chroot, and set argv[0].  The hard part is the ELF parsing.

Hints for inspiration[1]:

  git://github.com/NixOS/patchelf.git
  https://fedorahosted.org/elfutils/

Doable, though it seems a little too much like work for me to actually
do it. ;-)  Reassigning because I can't imagine glibc changing its
compatibility requirements any time soon.

Hope that helps,
Jonathan

[1] some pseudocode to experiment with for your amusement:

diff --git i/src/execve.c w/src/execve.c
index 60351177..70d0a9ea 100644
--- i/src/execve.c
+++ w/src/execve.c
@@ -71,6 +71,25 @@ static int try_cmd_subst (char * env, const char * filename, char * cmd_subst)
     return 0;
 }
 
+static int get_elf_interp(const char * filename, char * buf, size_t buflen)
+{
+    int num_sections = num_sections();  /* header->e_shnum */
+    int i;
+
+    for (i = 0; i < num_sections; i++) {
+        string section_name = section_names + section_header[i].sh_name;
+        if (section_name == ".interp")  /* found it! */
+            break;
+    }
+    if (i == num_sections)
+        return -1;
+
+    // found .interp section
+    size_t offset = section_hdr.sh_offset;
+    size_t size = section_hdr.sh_size;
+    ...
+}
+
 
 wrapper(execve, int, (const char * filename, char * const argv [], char * const envp []))
 {
@@ -195,8 +214,11 @@ wrapper(execve, int, (const char * filename, char * const argv [], char * const
     }
 
     /* No hashbang in argv */
-    if (hashbang[0] != '#' || hashbang[1] != '!')
-        return nextcall(execve)(filename, argv, newenvp);
+    if (hashbang[0] != '#' || hashbang[1] != '!') {
+        if (get_elf_interp(filename, hashbang + 2, sizeof(hashbang) - 3))
+            return nextcall(execve)(filename, argv, newenvp);
+        i = strlen(hashbang);
+    }
 
     /* For hashbang we must fix argv[0] */
     hashbang[i] = hashbang[i+1] = 0;


Reply to: