Can argv be changed at runtime (not by the app itself)
I'd say there are two main options based on your threat model here:
You do not trust the environment and assume that other privileged processes on your machine are able to alter the contents of memory of your program while it is running. If so, nothing is safe, the program could be altered to do literally anything. In such case, you can't even trust an integer comparison.
You trust the environment in which your program is running. In this case your program is the only owner of its data, and as long as you don't explicitly decide to alter
argv
or any other piece of data, you can rely on it.
In the first case, it doesn't matter if you guard against potential argv
modifications, since you are not trusting the execution environment, so even those guards could be fooled. In the second case, you trust the execution environment, so you don't need to guard against the problem in the first place.
In both the above cases, the answer is: no, you shouldn't protect the app from a possible TOCTTOU attack when handling data in argv
.
TOCTTOU kind of problems usually arise from external untrusted data, that can be modified by somebody else and should not be trusted by definition. A simple example is the existence of a file: you cannot rely on it, as other users or programs on the machine could delete or move it, the only way you can make sure the file can be used is by trying to open it. In the case of argv
, the data is not external and is owned by the process itself, so the problem really does not apply.
In general, the set of strings that are passed to main()
in the argv
array are set inside the program user space, mostly in a fixed place at the top of the program stack.
The reason for such a fixed place, is that some programs modify this area to allow for a privileged program (e.g. the ps
command) to gather and show you different command arguments, as the program evolves at runtime. This is used in programs like sendmail(8)
or in user program's threads, to show you which thread is doing what job in your program.
This is a feature that is not standard, it is used differently by the different operating systems (I have described you the BSD way) As far as I know, linux also exhibits this behaviour and Solaris.
In general, this makes the arguments to main something that, belonging to the user process space, has to be modified with care (using some operating system specific contract), as it is normally subject to rigid conventions. The ps(1)
command digs in the user space of the process it is going to show in order to show the long listing showing the command parameters. The different operating systems document (probably you can get this from the linker standard script used in your system the exact format or how the stack is intialized by the exec(2)
familiy of calls -- the exec(2)
manual page should be of help also)
I don't exactly know if this is what you expect, or if you just want to see if you can modify the arguments.... as something belonging to the user space of the proces, they are modifiable most probably, but I cannot guess any reasons to do that, apart of those described in this answer.
By the way, the FreeBSD manual page for the execlp(2)
system call shows the following excerpt:
The type of the
argv
andenvp
parameters toexecle()
,exect()
,execv()
,execvp()
, andexecvP()
is a historical accident and no sane implementation should modify the provided strings. The bogus parameter types trigger false positives fromconst
correctness analyzers. On FreeBSD, the__DECONST()
macro may be used to work around this limitation.
This states clearly that you cannot modify them (in FreeBSD at least). I assume the ps(8)
command will handle the extra work of verifying those parameters in a proper way in order to never incurr in a security issue bug (well, this can be tested, but I leave it as an exercise for the interested people)
EDIT
If you look at /usr/include/sys/exec.h
(line 43) in FreeBSD, you will find that there's a struct ps_strings
located in the top of the user stack, that is used by ps(1)
command to find and locate the the process environment and argv
strings. While you can edit this to change the information a program gives to ps(1)
, you have a setproctitle(3)
library function (again, all of this is FreeBSDish, you'll have to dig to get the way linux, or other, solves this problem)
I've tried this approach, but it doesn't work. Today there's a library function call to get this approach, but the top of the stack is actually filled with the data mentioned above (I assume for compatibility reasons)