1

Can a process read /proc/self/exe using mmap? This program fails to mmap the file:

$ cat e.c
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
int main()
{
  int f=open("/proc/self/exe",O_RDONLY);
  char*p=mmap(NULL,0,PROT_READ,0,f,0);
  return 0;
}

$ cc e.c -o e
$ strace ./e
[snip]
open("/proc/self/exe", O_RDONLY)        = 3
mmap(NULL, 0, PROT_READ, MAP_FILE, 3, 0) = -1 EINVAL (Invalid argument)
exit_group(0)                           = ?
+++ exited with 0 +++
effbiae
  • 1,087
  • 1
  • 7
  • 22
  • 1
    Possible duplicate of [Invalid argument for read-write mmap?](http://stackoverflow.com/questions/18420473/invalid-argument-for-read-write-mmap) – P.P Feb 16 '17 at 11:33
  • you can map the same file if you do it at program start by mapping `main()`'s `argv[0]`, which is the program file name. – Luis Colorado Feb 17 '17 at 06:28
  • @LuisColorado, argv[0] is sometimes the program file name unless it was found in $PATH – effbiae Feb 18 '17 at 07:19
  • @JackAndrews, i'm not completely sure about that, have you tested?. The `$PATH` search is done by the `execlp(2)` or `execvp(2)` calls before doing the actual system call, which actually receives the final path found as I think the kernel does not search for an executable in the calling process' environment. The environment is user data, not system data, and the user process can break its structure enough to make it impossible to be used for a search path inside kernel code. – Luis Colorado Feb 18 '17 at 08:24
  • @JackAndrews, well, I have just tested your assert and it seems that even making the path search in user space, the final exec call is made with the original parameter instead of the found one. But it is true that just after the `exec(2)` call you can use the `$PATH` variable to search for the file yourself, and get a more portable program (it will run in any unix, not in one with access to a `/proc` filesystem) – Luis Colorado Feb 18 '17 at 08:54
  • @JackAndrews, sorry, you are completely right, as you can use an executable file path and pass a completely different value as `argv[0]` to the exec'd program. It was my mistake. – Luis Colorado Feb 18 '17 at 09:29

1 Answers1

1

You are making 2 mistakes here:

  • Mapped size must be > 0. Zero-size mappings are invalid.
  • You have to specify, if you want to create a shared (MAP_SHARED) or a private (MAP_PRIVATE) mapping.

The following should work for example:

char *p = mmap(NULL, 4096, PROT_READ, MAP_SHARED, f, 0);

If you wish to map the full executable, you will have to do a stat() on it first, to retrieve the correct file size and then use that as the second parameter to mmap().

Ctx
  • 18,090
  • 24
  • 36
  • 51
  • that fixed it: char*p=mmap(NULL,1,PROT_READ,MAP_PRIVATE,f,0); – effbiae Feb 16 '17 at 11:38
  • @JackAndrews Yes, but this will map only the very first page (usually 4096 bytes) of the executable. Is that enough for your needs? – Ctx Feb 16 '17 at 11:40
  • enough to get me started reading ELF... will stat the file to get length and pass to mmap – effbiae Feb 16 '17 at 11:55