[comp.unix.wizards] Using argv to show process status

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.