jv@mhres.mh.nl (Johan Vromans) (08/20/87)
Some UN*X implementations allow a process to change its argv, which subsequently shows up when doing a "ps". This can be used to reveal a process' continuation status and such. I have found out, that the process should execute something like strcpy (argv[0], "Hi there, I'm doing fine."); changing argv with argv[0] = "Hello, world!"; does not work. My questions: - How does this work? Does it work only on BSD type systems, any others? - Whose memory is the process writing into? What happens if the process writes more bytes than the caller specified in the command line? - How can the remainder of the command line be blanked. Filling with a few null-characters seems not to be sufficient. Thanks in advance. -- Johan Vromans | jv@mh.nl via European backbone Multihouse N.V., Gouda, the Netherlands | uucp: ..{seismo!}mcvax!mh.nl!jv "It is better to light a candle than to curse the darkness"
gwyn@brl-smoke.ARPA (Doug Gwyn ) (08/20/87)
In article <1217@mhres.mh.nl> jv@mhres.mh.nl (Johan Vromans) writes: >I have found out, that the process should execute something like > strcpy (argv[0], "Hi there, I'm doing fine."); Great if you really want to clobber other arguments and/or environment variables. argv[0] is a pointer to a string that was set up for you by the exec() system call, or at least by the C run-time startup module. There will not in general be enough room to hold a long string like that, so the strcpy() would overwrite other useful stuff as well. Why bother? Are you trying to run games on a system where you're not supposed to, or what?
jv@mhres.mh.nl (Johan Vromans) (08/21/87)
In article <6303@brl-smoke.ARPA> gwyn@brl.arpa (Doug Gwyn (VLD/VMB) <gwyn>) writes: >Great if you really want to clobber other arguments and/or >environment variables. [ ...] > >Why bother? Are you trying to run games on a system where >you're not supposed to, or what? What I have is the following situation (definitely not a game): We are running a kind of interpreter for a programming language in which lots of applications have been written. One of the features of the language is that a program can chain to a successor program. Chains are handled internally by the interpreter, no new process is started. When a user starts an application with "RUN menu", and menu chains to different application programs which all chain back to menu for the next choice, the "ps" will always show the "RUN menu" command. What I want to achieve is a method - more or less defined on some systems - to show what the user is really doing. The interpreter runs on lots of systems (System V, BSD, MS-DOS), and I am aware that there is no generic solution for this problem. That's why I am looking for alternatives. Changing argv is tricky, but it seems to work on some systems ... -- Johan Vromans | jv@mh.nl via European backbone Multihouse N.V., Gouda, the Netherlands | uucp: ..{seismo!}mcvax!mh.nl!jv "It is better to light a candle than to curse the darkness"
ron@topaz.rutgers.edu (Ron Natalie) (08/21/87)
On MOST UNIXs the arguments to a program are not stored anywhere other than being placed (usually at the top of the stack) in the memory image of the invoked program. PS tries to be clever by looking around in memory (and on the paging disk if necessary) for the arguments. On most UNIXs the stack is easy to find, so PS just scans the stack reassembling the arguments, hence it can be fooled by overwriting those arguments with something else. It used to be fun to make PS core dump by poking the 0 at the end of the arglist with something else. PS is a little more robust now. -Ron
guy%gorodish@Sun.COM (Guy Harris) (08/21/87)
> - How does this work? "ps", on some versions of UNIX, figures out where the last page or so of the process' stack is, and grabs characters from there. It does NOT look at the "argv" vector, just at the pool of characters it points into, so changing the "argv" vector has no effect. On some other versions of UNIX, the kernel copies the argument list into a location in the U page, and "ps" looks there instead; on those versions, there is nothing whatsoever a non-privileged can do to affect what "ps" sees other than doing something bizarre such as re-"exec"ing itself. > Does it work only on BSD type systems, any others? It works on some BSD systems, and some non-BSD systems. It does not work on systems with the argument list copy in the U page mentioned above; AT&T's paging releases of System V (at least the 3B2 S5R3, and the VAX S5R2 Version 2, releases) work that way. In short, this trick is NOT portable; it may be a nice hack, but don't depend on it working. > - Whose memory is the process writing into? Its own, of course. > What happens if the process writes more bytes than the caller specified > in the command line? It could, conceivably, write off the end of its stack, and quite likely get a signal of some sort. Guy Harris {ihnp4, decvax, seismo, decwrl, ...}!sun!guy guy@sun.com
guy%gorodish@Sun.COM (Guy Harris) (08/21/87)
> In short, this trick is NOT portable; it may be a nice hack, but don't depend > on it working. In addition, as Doug Gwyn points out, if the string you're writing is longer than the original argument, you will start scribbling on top of other strings, such as other arguments or environment variables. You *might*, conceivably, be able to save the arguments away before you smash them; however, it's not so easy to save the environment variables, because some routine you don't even know about may want to query one of them! You might be able to save them all, zero out your environment, and reconstruct it with "putenv" on a system that has "putenv"; however, it sounds like too much trouble. If you want to do this sort of thing, make VERY SURE you always overwrite the zeroth argument with exactly as many characters as it originally had, truncating or padding with NUL characters as needed. If the truncation is a problem, too bad. Remember, this trick depends on a *quirk of the implementation*; vendors are under no obligation whatsoever to provide implementations with this quirk. Guy Harris {ihnp4, decvax, seismo, decwrl, ...}!sun!guy guy@sun.com
mikep@ism780c.UUCP (Michael A. Petonic) (08/22/87)
In article <1224@mhres.mh.nl> jv@mh.nl (Johan Vromans) writes: }We are running a kind of interpreter for a programming language in which }lots of applications have been written. One of the features of the }language is that a program can chain to a successor program. Chains are }handled internally by the interpreter, no new process is started. } }When a user starts an application with "RUN menu", and menu chains to different }application programs which all chain back to menu for the next choice, }the "ps" will always show the "RUN menu" command. Well, how about making links to small C programs that would "RUN Menu" (or a shell script) and then arv[0] would be the name of the link.
jv@mhres.mh.nl (Johan Vromans) (08/22/87)
In article <7164@ism780c.UUCP> mikep@ism780c.UUCP (Michael A. Petonic) writes: >In article <1224@mhres.mh.nl> jv@mh.nl (Johan Vromans) writes: >}We are running a kind of interpreter for a programming language in which >}lots of applications have been written. One of the features of the >}language is that a program can chain to a successor program. Chains are >}handled internally by the interpreter, no new process is started. >} >}When a user starts an application with "RUN menu", and menu chains to different >}application programs which all chain back to menu for the next choice, >}the "ps" will always show the "RUN menu" command. > > >Well, how about making links to small C programs that would "RUN Menu" >(or a shell script) and then arv[0] would be the name of the link. Apparently you missed the point. There is a "real" program (the interpreter) and lots of "pseudo" programs (programs written for the interpreter). The user invokes the interpreter and specifies which pseudo program to execute. This pseudo program chains to other (pseudo) programs. During this process, the interpreter stays resident. For the user, the pseudo program is what he is running; for ps it's the interpreter. By clobbing argv, it is possible to reveal in a ps display which pseudo program the interpreter is currently executing. This can be important in situations where the system manager has to decide whether a user task can be killed safely. Currently there is no way for the system administrator to find out who is doing what. Clobbing argv supplies a method which works on at least some systems (the BSD type systems). For other systems, other methods must be used. -- Johan Vromans | jv@mh.nl via European backbone Multihouse N.V., Gouda, the Netherlands | uucp: ..{seismo!}mcvax!mh.nl!jv "It is better to light a candle than to curse the darkness"
gwyn@brl-smoke.ARPA (Doug Gwyn ) (08/22/87)
In article <26253@sun.uucp> guy%gorodish@Sun.COM (Guy Harris) writes: >Remember, this trick depends on a *quirk of the implementation*; vendors are >under no obligation whatsoever to provide implementations with this quirk. However, X3J11 did decide that one could modify the argv[] strings. What is not guaranteed is their visibility outside the process.
mikep@ism780c.UUCP (Michael A. Petonic) (08/24/87)
In article <1229@mhres.mh.nl> jv@mhres.mh.nl (Johan Vromans) writes: >By clobbing argv, it is possible to reveal in a ps display which pseudo >program the interpreter is currently executing. This can be important in >situations where the system manager has to decide whether a user task can >be killed safely. > >Currently there is no way for the system administrator to find out who is >doing what. Clobbing argv supplies a method which works on at least >some systems (the BSD type systems). For other systems, other methods >must be used. Ok, enough "illegial" things that are crossing the net. How about the simple approach of modifying the interpreter to write pertinent info to a file (say in /usr/adm) which shows what program is running? This could be done in much the same way that utmp is implemented. That way, you don't stand a chance of clobbering core that doesn't belong to you and it is probably the way it "should" be done. Then, you could have a program that reads the file (or if you stuck really close to the utmp format, you could use the "who" program) and output's what they are doing. Does this make more sense?
hubcap@hubcap.UUCP (Mike S Marshall) (08/24/87)
Here's a program that drops a shell, & lets you see anything you want
to see when you do a ps...
main(argc,argv,envp)
int argc;
char **argv;
char **envp;
{
char *malloc();
strcpy((argv[0]=malloc(20)),"bloop -q gunk");
execve("/bin/sh",argv,envp);
}
This doesn't screw up any of your environment variables... maybe it
screws up something else I don't know about...
-Mike Marshall hubcap@hubcap.clemson.edu ...!hubcap!hubcap
rjd@tiger.UUCP (08/25/87)
> I have found out, that the process should execute something like > strcpy (argv[0], "Hi there, I'm doing fine."); > changing argv with > argv[0] = "Hello, world!"; > does not work. > My questions: > - How does this work? Does it work only on BSD type systems, any others? > - Whose memory is the process writing into? What happens if the process > writes more bytes than the caller specified in the command line? > - How can the remainder of the command line be blanked. Filling with a few > null-characters seems not to be sufficient. I'll put in my two cents worth. I did a simple experiment; source: main(argc,argv) int argc; char *argv[]; { strcpy(argv[0],"Q"); system("ps -ef"); } Notice that the new argv[0] is only one character. I had called this program "g", also one character, just so there would be no problem with length mismatch in the character array. Here's the output (greping for just this line, like "./g | grep Q | grep -v grep"): root 19030 6545 5 12:37:29 console 0:00 Q ...so it works... (I always wondered why UUCICO would show up in my process table...this might be the way) This also explains the man page on crypt(1) mentioning that any key entered into the command line would be blanked before execution, but that it was inadvisable to enter the key on the command line (a lucky ps -ef would see the key before it was blanked). Answer #1: This is on AT&T Unix System 5, release 2.0.4 (3B2), don't know about any others. Answer #2: Whose memory? The memory allocated to the process, i.e. yours. What happens if more characters are written than strlen(argv[0])? You overwrite argv[1] or more and screw it all up, i.e. argv[1] will give you last portion of your new argv[0]. If you overwrote more than was originally given (past the end of the argument array), probably more bad things happen, or it just does not work like a "memory error: core dumped", or somesuch. Answer #3: Beats me. Anybody else? Randy (ihnp4!)3b2fst!randy
allbery@ncoast.UUCP (Brandon Allbery) (08/26/87)
As quoted from <7164@ism780c.UUCP> by mikep@ism780c.UUCP (Michael A. Petonic): +--------------- | In article <1224@mhres.mh.nl> jv@mh.nl (Johan Vromans) writes: | }When a user starts an application with "RUN menu", and menu chains to different | }application programs which all chain back to menu for the next choice, | }the "ps" will always show the "RUN menu" command. | | Well, how about making links to small C programs that would "RUN Menu" | (or a shell script) and then arv[0] would be the name of the link. +--------------- Won't work, as I understand his problem. An example of what he's saying: Many RM/COBOL programs have a menu module which chains to programs; those chain back to the menu. There is a single "chain manager" module which is entered and immediately CALL USING's the menu module with a linkage area to contain the name of the next program to run. It then enters a loop wherein every time a CALLed program returns, the program indicated in the linkage area is immediately CALL USING'ed with the same linkage area. The final module does a STOP RUN, which halts all CALL USING'ed programs and the chain manager. (MCS-3 does this; probably others do as well, since only two modules need ever be loaded at one time, and many of these programs are designed to work under CP/M-80 on a 32K machine.) The problem in this case is to make the linkage area's next-program-name field visible to "ps". (One way to do this is to use an RM/COBOL C hook and CALL USING it in the chain manager before "chaining" to the next module. But if this is what the poster is doing, s/he was wrong in at least one place: I can't find a BSD system which supports RM/COBOL. Whether this is a feature or a misfeature is debateable in a business environment.) As for a way to do it: about all I can think of is to run RM/COS. ;-) -- Brandon S. Allbery, moderator of comp.sources.misc {{harvard,mit-eddie}!necntc,well!hoptoad,sun!mandrill!hal}!ncoast!allbery ARPA: necntc!ncoast!allbery@harvard.harvard.edu Fido: 157/502 MCI: BALLBERY <<ncoast Public Access UNIX: +1 216 781 6201 24hrs. 300/1200/2400 baud>> ** Site "cwruecmp" has changed its name to "mandrill". Please re-address ** *** all mail to ncoast to pass through "mandrill" instead of "cwruecmp". ***
jack@mcvax.UUCP (08/26/87)
In article <26252@sun.uucp> guy%gorodish@Sun.COM (Guy Harris) writes: >On some other versions of UNIX, the kernel copies the argument list into a >location in the U page, and "ps" looks there instead;... Huh? What is the use of this? Is this only so that ps can find out this information, or is there some other reason? -- Jack Jansen, jack@cwi.nl (or jack@mcvax.uucp) The shell is my oyster.
mikep@ism780c.UUCP (Michael A. Petonic) (08/27/87)
Another way of doing it (informing the SysAdmin about the status of a program) instead of what I earlier proposed (writing information to a file much like the utmp file) is to: (break for lack of anything else) Modify the interpreter so that instead of calling loading "menu" and running it, just execl("/usr/lbin/interp","menu",0) and at the beginning of interp, have a switch statement based on argv[0] which will do the rest. This way you get fast results with a ps (but I still like the other way). MikeP
stew@hanauma.UUCP (Stewart Levin) (08/27/87)
Instead of having the interpreter try to rewrite argv, have it initially popen() a tiny program which has the name RUN, say. Then when the interpreter wants to show it is now performing MULT, say, it fprintf's the name MULT to the pipe and the tiny program links the name MULT to its own executable and execl's itself under that new name. Standard input remains open and the new copy waits for the next process name to come down the pipe so it can repeat the link/exec. And unlink the name MULT also, unless there are only a fixed set of possibilities. The logic of doing it with a child is that a fork and load of a tiny program is minor, asynchronous overhead, forking the interpreter is major, synchronous overhead.