12

I am confused with the syscall of __NR_execve. When I learn linux system call. The correct way that I know to use execve is like this:

char *sc[2]; 
sc[0]="/bin/sh"; 
sc[1]= NULL; 
execve(sc[0],sc,NULL); 

Then the function execve will call syscall() to get into system kernel with putting the arguments on Registers EAX, EBX, ECX and EDX. However, It still succeed if I use

execve("/bin/sh",NULL,NULL);

But if I replace "/bin/sh" with "/bin/ls",it fail with:

A NULL argv[0] was passed through an exec system call.

I wonder why "/bin/sh" can be executed successfully without enough parameters while "/bin/ls" fail?

Ciro Santilli OurBigBook.com
  • 347,512
  • 102
  • 1,199
  • 985
Arvin Hsu
  • 181
  • 1
  • 1
  • 10
  • I'd not rely on `NULL` working at all there; the `execve` man page says that the `argv` is an array of argument strings; a `NULL` pointer is not a valid pointer to an array. (Neither does using `NULL` for `env` look good; rather, use `execv` or `execvp`, or pass a pointer to `char *p = NULL`.) – Antti Haapala -- Слава Україні Apr 17 '16 at 09:16
  • Arrays are pointers to its first element when passed as functions arguments, so NULL is certainly valid here. – fluter Apr 17 '16 at 09:45
  • @AnttiHaapala: [Linux's `execve(2)` does accept a NULL pointer](http://man7.org/linux/man-pages/man2/execve.2.html), and treats it as a pointer to an empty list. This is discouraged and not portable, but is future-proof on Linux specifically. The main use case I've seen is for exploit shellcode that zeros a couple registers before a system call (x86 `int 0x80` or `syscall`), instead of pushing a `0` and getting pointers to that into two registers. i.e. it saves a few bytes of exploit payload size, and doesn't require writing to memory if the `"/bin/sh"` string is already in the payload. – Peter Cordes Apr 13 '18 at 01:59
  • @petercordes good that the hellcodez stay compatible – Antti Haapala -- Слава Україні Apr 13 '18 at 02:53
  • But yeah, the man pages do mention this exception – Antti Haapala -- Слава Україні Apr 13 '18 at 02:55
  • @AnttiHaapala: I know, right. If the only thing it would break is existing exploits for `sys_execve` to return `-EFAULT` there, it's not really a downside. But presumably there's some valid use-case, like maybe passing an empty environment, that some code uses. Or maybe it's easier / cleaner in the kernel implementation to accept that than reject. Although it does check early enough that it could easily return an error, unlike some later errors that result in the process dying with a signal or something, because the caller is already partially destroyed so `execve` can't return. – Peter Cordes Apr 13 '18 at 03:05

1 Answers1

16

This is not a kernel issue. The kernel will run with the filename arg of execve regardless of whether argv and envp are NULL or not. It is just a Unix convention that argv[0] points to the program name.

And what you saw is just normal, i.e. nothing is wrong. Because ls is part of GNU's coreutils, and all programs in the coreutils package call set_program_name to do some setup work. You can see this in the source: it checks whether argv[0] is NULL, and it will call abort when it is.

On the other hand, /bin/sh is apparently a program that does not belong to coreutils, and does not check against argv[0]. That's why it runs without the problem.

Refer to the source code:

General Grievance
  • 4,555
  • 31
  • 31
  • 45
fluter
  • 13,238
  • 8
  • 62
  • 100