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?
NULL
working at all there; theexecve
man page says that theargv
is an array of argument strings; aNULL
pointer is not a valid pointer to an array. (Neither does usingNULL
forenv
look good; rather, useexecv
orexecvp
, or pass a pointer tochar *p = NULL
.) – Sanfredexecve(2)
does accept a NULL pointer, 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 (x86int 0x80
orsyscall
), instead of pushing a0
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. – Amblygonitesys_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 soexecve
can't return. – Amblygonite