--On Tuesday, October 28, 2008 05:04:25 PM -0700 Sumanth Naropanth <Sumanth.Naropanth at Sun.COM> wrote:
>>> ease of use as the system(3C), by defining a single (const char *) >>> argument. The implementation will be a wrapper around the >>> posix_spawn(3C)/waitpid(3C) functions. This interface will provide >>> greater security in comparison with the system() function by avoiding >>> shell invocation. Quoted arguments will be supported by using a new >>> macro called 'ES_QUOTE', which will be defined as: >>> >>> # define ES_QUOTE '\377%s\377' >>> >>> The special character '\377' is chosen since it lies outside the >>> printable character set. This quoting mechanism will make it harder for >> >> Is that true for *every* character set and encoding scheme that we >> support or might support? It's true for US-ASCII and for UTF-8, for >> example, but not for ISO8859-1, for example. >> > > I agree that it's not impossible to supply '\377' as an input when some > encoding schemes may allow for it. Using '\377' makes it much harder > (but not completely impossible) to trick the argument parsing than using > single/double quotes. No, you're missing the point. The statement "it lies outside the printable character set" is true for US-ASCII, but it is simply not true for every character set. In ISO8859-1, to use Nico's example, '\377' is '?' (U+00FF, LATIN SMALL LETTER Y WITH DIAERESIS). Proposing that this character be used for quoting arguments suggests that you have not considered the i18n implications. >> So this is likely a terrible choice of quote character. Perhaps the >> only safe quote character would be NUL, and then you'd need to use NUL >> NUL as the terminator (or something). That would preclude using the empty string as an argument. >> Moreover, why even have a quote character? Make this function take a >> variable number of arguments, with the last being NULL, and be done. >> > > Sounds like a good idea, but that pulls it away from a simple (const > char *) interface. I'll give this more thought. Thanks! The single-string interface is too simple to reliably do anything other than run a program with no arguments. Any attempt to encode arguments in the same string will end up being inadequate, too complex, or both. I think Nico is on the right track; give this thing the same interface as execl(), but with the fork-and-wait semantics of system. I'd also consider whether you want an interface like that of execve(), which takes a char ** rather than a variable number of char * arguments, and/or a variant that accepts a single va_list instead of a variable number of arguments, to make it easier to write wrappers. >>> When used inside a setuid program, the exec_system() function will drop >>> privileges to those of the real user while executing the file/command. >> >> Maybe the user ID (real or effective) to use should be an argument, as >> well as whether to drop privs. >> > > This feature mimics the behavior of system(3C) when it's used inside > setuid program. Really? system(3C) changes its UID before running a command? Not according to the man page on my machine. >>> The exec_system() implementation will extend the signal handling model >>> of system(3C) and will set SIGCHLD to be blocked for the calling thread, >> >> Why not use forkx() to avoid SIGCHLD issues altogether? >> > > Using posix_spawn()/waitpid() allows me to pass the return value of the > execve() call back to the parent process when exec fails. I don't > suppose forkx()/exec() will allow for that (apart from just causing the > child to exit(127))? Even with posix_spawn(), you might still end up with a failure in which the child exits with 127. So, callers of your new interface will need to be prepared for that.