All program start by exec
calls, despite OS implementations, lets see what does POSIX standard says about exec
functions.
int execve(const char *path, char *const argv[], char *const envp[]);
argv
are arguments passed to the program, envp
are environment variables.
The argv and environ arrays are each terminated by a null pointer. The null pointer terminating the argv array is not counted in argc.
The argument argv is an array of character pointers to null-terminated strings.
So, it is very easy to conclude:
- Empty (zero length) string can be passed to
argv
NULL
string can't be passed to argv, it will terminate argv
, and discard all following arguments.
- any string in
argv
can't contain \x0
character, \x0
will terminate the current parameter string.
Explain what happened when run
python -c 'print "\x30\x00\x31"' | xargs --null prog
Try:
python -c 'print "\x30\x00\x31"' | strace -f xargs --null echo
We can find:
...
...
...
read(0, "0\0001\n", 4096) = 4
...
...
...
clone(child_stack=NULL, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7f09f46d9850) = 21232
strace: Process 21232 attached
...
...
...
[pid 21232] execve("/bin/echo", ["echo", "0", "1\n"], 0x7ffe5ccd7638 /* 74 vars */ <unfinished ...>
It shows that xargs
potentially separate argument containing \x0
into two arguments when calling prog
. Not done by shell, not done by OS, libc, but xargs