Looks like split of execve(2) syscall created bugs
Maxim Sobolev
sobomax at portaone.com
Sat Jan 29 12:47:27 PST 2005
Matthew Dillon wrote:
:Hi DF'ers!
:
:I am working on eliminating stackgap in FreeBSD's linuxlator following
:DF's footsteps and fond that there is potential bug has been introduced
:into execve(). The problem is that DF now first checks if argv[0] is
:NULL, then replaces it with pathname and then proceeds with scanning
:other arguments instead of stopping there. According to the comment in
:the code, such behaviour has been introduced to make shell scripts
:working. However there are two problems with this approach:
:
:1. According to the POSIX, execve() should pass arguments list
:unmodified to the newly created process. This means that if I invoke
:execve with argv[0] being NULL, the new image should see argc == 0 and
:argv[0] = NULL. DF in this case will copy the new image path as argv[0]
:and new image will see see it as argv[0]/argc == 1.
:
:2. In some cases, the new logic will result in bogus arguments passed to
:the new image or EFAULT when first argument is NULL. This will happen
:due to the bug in routine which copies arguments from the user space
:into the kernel space. It assumes that both argv[0] and argv[1] are
:NULL, while only former is required to be to stop processing.
:
:The proper fix is to move special handling of argv[0] == NULL case into
:imgact_shell.c where it belongs.
:
:-Maxim
It's unclear whether passing a NULL argv[0] for any case is legal.
I think to be strictly conforming, argv[0] must always be non-NULL.
Latest POSIX explicitly mentions that NULL argv[0] is permitted,
although discouraged for compatibility reasons:
----
RATIONALE
Early proposals required that the value of argc passed to main() be "one
or greater". This was driven by the same requirement in drafts of the
ISO C standard. In fact, historical implementations have passed a value
of zero when no arguments are supplied to the caller of the exec
functions. This requirement was removed from the ISO C standard and
subsequently removed from this volume of IEEE Std 1003.1-2001 as well.
The wording, in particular the use of the word should, requires a
Strictly Conforming POSIX Application to pass at least one argument to
the exec function, thus guaranteeing that argc be one or greater when
invoked by such an application. In fact, this is good practice, since
many existing applications reference argv[0] without first checking the
value of argc.
----
You'll have to be more specific about case (2). What in the codebase
are you refering to, file and line ?
Trunk as of several hours ago, sys/kern/kern_exec.c function
exec_copyin_args() around line 700. The code there fetches pointer to
argv[0] from userspace, checks if it's NULL and puts first argument
instead of it. Then it increases userspace pointer by one and fetches
the next pointer *unconditionally*, so that in the case when argv[0] is
NULL you may get some invalid (e.g. junk but non-NULL pointer) and get
EFAULT for no reason. The same code ignores argv being NULL - see my
follow-up. FreeBSD code in this case explicitly returns EFAULT.
-Maxim
More information about the Bugs
mailing list