guy%gorodish@Sun.COM (Guy Harris) (05/18/87)
This really isn't a C question at all, it's a UNIX question, so I'll redirect it where it should have been sent in the first place. > Newsgroups: comp.lang.c > Distribution: comp.unix.questions In fact, it looks like the orignal poster may have tried directing it there, but goofed. > Alas, this wonderfully simple technique simply does not work with > the 4BSD `ps', which reads the strings themselves, not the pointers > thereto. As do most other versions of "ps". The 3B2 version of "ps" does it differently; the kernel stashes a string away in the U area that contains the original arguments used to invoke the program. (I have no idea whether this was done because somebody thought this was the right way to do things, or because they couldn't figure out how to snarf the arguments up on a machine whose stack grows upward in memory....) On this machine, you *can't* smash your argument list. Period. The answer is "forget it". In general, it can't be done. Some versions of "crypt" write '\0' all over the password it is handed, which means it'll smash the argument if that was where the key appeared, but 1) this won't work on a system that works the way 3B2 UNIX does and 2) still leaves a window in which the argument can be seen. We won't mention that it also leaves the encryption key on your screen when you type the command, or that using "crypt" in this fashion in a *script* is a very bad mistake as it leaves the encryption key in a file. In short, the answer is "always get encryption keys from the user, and turn off echoing when you do so".
jgy@hropus.UUCP (John Young) (05/19/87)
Guy Harris says: > This really isn't a C question at all, it's a UNIX question, so I'll > redirect it where it should have been sent in the first place. > ......... > As do most other versions of "ps". The 3B2 version of "ps" does it > differently; the kernel stashes a string away in the U area that > contains the original arguments used to invoke the program. (I have > no idea whether this was done because somebody thought this was the > right way to do things, or because they couldn't figure out how to > snarf the arguments up on a machine whose stack grows upward in > memory....) On this machine, you *can't* smash your argument list. > Period. > ...... Not true. It depends on which UNIX your running on your 3B2: a) On a SWAPPING system a 'ps -l' will show you the u.u_comm field which will give you JUST the first argument (normally the program name) of the process. This can not be changed by normal methods from inside the process. 'ps -f' will show you what's really pointed to by argv[0] which can be changed. b) On a PAGING system ONLY the first 40 bytes of arguments are copied into the saftey of the user block (ps may not show you much more than this anyway) so if you want arguments passed to you with some secrecy just put them futher down the line.
levy@ttrdc.UUCP (05/20/87)
In article <19131@sun.uucp>, guy%gorodish@Sun.COM (Guy Harris) writes: > The 3B2 version of "ps" does it > differently; the kernel stashes a string away in the U area that > contains the original arguments used to invoke the program. (I have > no idea whether this was done because somebody thought this was the > right way to do things, or because they couldn't figure out how to > snarf the arguments up on a machine whose stack grows upward in > memory....) On this machine, you *can't* smash your argument list. > Period. > The answer is "forget it". In general, it can't be done. This may well be true on some machines and implementations, but don't unjustly blacken the 3B2, please. I tried this code on a 3B2/400 running System V Release 2.0.4 swapping: main(argc,argv) int argc; char *argv[]; { int i; char *c; void perror(); for (i=0; i<argc; i++) for (c=argv[i]; *c; c++) *c = 'X'; /* stomp all over argv */ if (fork() == 0) { (void) execl("/bin/ps", "ps", "-f", (char *) 0); perror("Can't execute /bin/ps"); } else (void) wait((int *)0); /* hang around till ps finishes */ return 0; } The results (call the program stompargv): $ stompargv arg_one arg_two arg_three UID PID PPID C STIME TTY TIME COMMAND levy 1603 1 0 16:30:04 tty11 0:03 -sh levy 1605 1603 7 18:40:18 tty11 0:00 XXXXXXXXX XXXXXXX XXXXXXX XXXXXXXXX levy 1606 1605 44 18:40:18 tty11 0:00 ps -f (Could someone please try this on SVR3 3B2 and tell me if it works the same way?) -- |------------dan levy------------| Path: ..!{akgua,homxb,ihnp4,ltuxa,mvuxa, | an engihacker @ | vax135}!ttrdc!ttrda!levy | at&t data systems division | Disclaimer: try datclaimer. |--------skokie, illinois--------|
guy%gorodish@Sun.COM (Guy Harris) (05/21/87)
> > The 3B2 version of "ps" does it > > differently; the kernel stashes a string away in the U area that > > contains the original arguments used to invoke the program. (I have > > no idea whether this was done because somebody thought this was the > > right way to do things, or because they couldn't figure out how to > > snarf the arguments up on a machine whose stack grows upward in > > memory....) On this machine, you *can't* smash your argument list. > > Period. > > This may well be true on some machines and implementations, but don't > unjustly blacken the 3B2, please. I tried this code on a 3B2/400 > running System V Release 2.0.4 swapping: > > (Could someone please try this on SVR3 3B2 and tell me if it works the > same way?) I just did. It doesn't work the same way. If I do $ ./stomp_argv the "ps" it runs says that a program named "./stomp_argv" is running (and no, it is not picking up "u.u_comm"; if it were, it would have said "[ stomp_argv ]", not "./stomp_argv"). In other words, on a 3B2 running S5R3, you can't hide your argument list from "ps"; my assertions stand. Maybe the swapping release didn't have this hack to stuff the argument list into the U area - there is a comment in the S5R3 "ps" that says /* no u_psargs on 3b5, look in user stack */ and I'm not certain the 3B5 had a paging release, so this may be the case. One is tempted to ask, however, what is so difficult about this? The code to snarf this stuff from the user area has #if vax || u3b || u3b2 around it. It is certainly not impossible to get the argument list from the process' stack on a paging VAX. Guy Harris {ihnp4, decvax, seismo, decwrl, ...}!sun!guy guy@sun.com
kimcm@olamb.UUCP (Kim Chr. Madsen) (05/21/87)
In article <19131@sun.uucp>, guy%gorodish@Sun.COM (Guy Harris) writes: > > As do most other versions of "ps". The 3B2 version of "ps" does it > differently; the kernel stashes a string away in the U area that > contains the original arguments used to invoke the program. (I have > no idea whether this was done because somebody thought this was the > right way to do things, or because they couldn't figure out how to > snarf the arguments up on a machine whose stack grows upward in > memory....) On this machine, you *can't* smash your argument list. > Period. (remove 'period) It can be done on the 3B2 w/ standard ps(1), I've used it! (set 'period) I've used the argv[1] to tell some status information about the program, which ran in the background and just doing a "ps -fp <pid>" returned the info. nicely. For information I ran this under UNIX V 2.0.4 on a 3B2-400. And don't tell me it's non-portable it wasn't meant to be ! Kim Chr. Madsen
guy%gorodish@Sun.COM (Guy Harris) (05/22/87)
> b) On a PAGING system ONLY the first 40 bytes of arguments are copied > into the saftey of the user block (ps may not show you much more > than this anyway) so if you want arguments passed to you with some > secrecy just put them futher down the line. Funny, the source we have says 80 bytes.... And as for "put them further down the line", *who* is doing the putting? If a program wants arguments passed to it with some secrecy, it has to politely request that whoever or whatever *invokes* it should ensure that the argument in question appear more than 80 characters into the argument list. A program (or programmer) that made such a request of me would be likely to get a rude gesture in response. The point is that you can't, in general, ensure that arguments passed to a program can't be seen by somebody doing a "ps"; you definitely can't do so on a 3B2 running any reasonably recent version of UNIX for the 3B2. Even on machines where you can smash the argument list, there is a small chance that "ps" will suck up the argument list before the program gets a chance to smash it. In other words, don't put encryption keys on the command line if you can possibly avoid it. (Another question that comes to mind is "why did they waste 80 bytes of U-area space with this stuff?" It's not as if you can't fetch an argument list on a paged machine, and the ability to get the command line used to run a program does not seem to be of sufficient importance that stuffing it in the U page buys you anything. You *still* aren't guaranteed that you can get it, since the process may get swapped in or out between the point at which "ps" gets the process table entry for the process and the point at which it grabs the U area.) Guy Harris {ihnp4, decvax, seismo, decwrl, ...}!sun!guy guy@sun.com
jgy@hropus.UUCP (John Young) (05/22/87)
>> b) On a PAGING system ONLY the first 40 bytes of arguments are copied >> into the saftey of the user block (ps may not show you much more >> than this anyway) so if you want arguments passed to you with some >> secrecy just put them futher down the line. > >Funny, the source we have says 80 bytes.... > >And as for "put them further down the line", *who* is doing the >putting? If a program wants arguments passed to it with some >secrecy, it has to politely request that whoever or whatever >*invokes* it should ensure that the argument in question appear more >than 80 characters into the argument list. A program (or programmer) >that made such a request of me would be likely to get a rude gesture >in response. > Seems to me that if you wanted to pass an argument "safely" to a process, and knew how to, you would do it the way I suggested. If you do not want secrecy or wanted to spite yourself for the inconvenience (maybe you don't have auto repeat on your keyboard) then you would not. Or maybe you'd just wall the argument around the system. jgy
guy%gorodish@Sun.COM (Guy Harris) (05/23/87)
> Seems to me that if you wanted to pass an argument "safely" to a > process, and knew how to, you would do it the way > I suggested. If I wanted to pass a password safely to a program, I'd have the program ask me for the password and I'd type it in! If the program insisted that I pass it as an argument, I'd simply declare the program unacceptable. I wouldn't do it the way you suggest at all; requiring the user to type 40, or 80, or however many Xes is simply silly. > If you do not want secrecy or wanted to spite yourself for the inconvenience > (maybe you don't have auto repeat on your keyboard) then you would not. Great. Now, in order to use some program safely, you just require 1) that the user know the maximum number of characters the "ps" on the system will print (of course, this assumes that "ps" *imposes* such a maximum; the maximum might very well be NCARGS) and 2) that the user type this many Xes. Sorry, that user interface design gets an F. Guy Harris {ihnp4, decvax, seismo, decwrl, ...}!sun!guy guy@sun.com
ado@elsie.UUCP (Arthur David Olson) (05/23/87)
> ...requiring the user to type 40, or 80, or however many Xes is simply > silly. Seems like you could reduce (but not eliminate) the window of vulnerability by having the program reexecute itself this way: #define XX "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" main(argc, argv) char * argv[]; { if (strcmp(argv[0], XX) != 0) { argv[0] = XX; execv(MYSELF, argv); perror(MYSELF); } } Doing this would not require the user to type in Xes. -- UUCP: ..seismo!elsie!ado ARPA: elsie!ado@seismo.CSS.GOV Elsie and Ado are trademarks of Borden, Inc. and Ampex.x
dhesi@bsu-cs.UUCP (Rahul Dhesi) (05/23/87)
In article <19590@sun.uucp> guy%gorodish@Sun.COM (Guy Harris) writes: >If I wanted to pass a password safely to a program, I'd have the >program ask me for the password and I'd type it in! I once wanted to write a shell script that would invoke crypt. The shell script prompted for the password, then later invoked crypt and supplied the password to it. The problem I ran into was that there seemed to be no way (at that time, on a 4.2BSD system; I haven't tried recently under 4.3BSD) to let crypt read the password from the script. The only way seemed to be either to let crypt read it from the terminal or get it from a parameter. Reading from the terminal was not practical because I was using a script that encrypted a large number of files using the same password, and typing in the password multiple times is a pain. Supplying the password to crypt as a parameter was obviously unacceptable. I eventually gave up trying to do it from a shell script. It would probably have been necessary to write an executable program. -- Rahul Dhesi UUCP: {ihnp4,seismo}!{iuvax,pur-ee}!bsu-cs!dhesi
levy@ttrdc.UUCP (Daniel R. Levy) (05/24/87)
In article <19364@sun.uucp>, guy%gorodish@Sun.COM (Guy Harris) writes: < < < The 3B2 version of "ps" does it < < < differently; the kernel stashes a string away in the U area that < < < contains the original arguments used to invoke the program. < < < On this machine, you *can't* smash your argument list. ^^^^^^^^^^^^ !!!! < < < Period. [My refutation program behaves differently on a 3B2 running SVR2 swapping. Guy tries it on SVR3 3B2 and finds ps still shows the argv at time of invocation.] < In other words, on a 3B2 < running S5R3, you can't hide your argument list from "ps"; my ^^^^^^^^^^^^ !!!! < assertions stand. They fail when applied to the 3B2 as a MACHINE. Sorry, Guy, my example to the contrary disproves your assertion AS YOU STATED IT IN YOUR ORIGINAL COMMENTS. Now if you wish to comment upon SPECIFIC OPERATING SYSTEM VERSION AND MACHINE COMBINATIONS, be my guest. -- |------------dan levy------------| Path: ..!{akgua,homxb,ihnp4,ltuxa,mvuxa, | an engihacker @ | vax135}!ttrdc!ttrda!levy | at&t data systems division | Disclaimer: try datclaimer. |--------skokie, illinois--------|
guy%gorodish@Sun.COM (Guy Harris) (05/24/87)
> The problem I ran into was that there seemed to be no way (at that > time, on a 4.2BSD system; I haven't tried recently under 4.3BSD) to let > crypt read the password from the script. All the versions of "crypt" I know of use "getpass" to read the encryption key. This means that the only ways to get any of them to read the key from something other than the user's terminal would be: 1) detach "crypt" from the terminal, in which case *some* versions would read from the standard input. The System V version doesn't; the V7, 4BSD, and S3 versions do. 2) somehow attach the "crypt" process to a pseudo-terminal so that its "/dev/tty" is that pseudo-terminal, and feed it the key through the pseudo-terminal. The S5R3 version permits you to specify the encryption key with an environment variable, which is more secure than specifying it as an argument iff you have no version of "ps" that can look at environment variables. The one distributed with S5 doesn't, but that doesn't mean you can't make one that does, and the one distributed with 4BSD definitely does. If you pass the key as an argument, the S5R3 version stuffs the key into an environment variable and "exec"s itself with no arguments, in an attempt to hide the key away. (Null and void with a "ps" that dumps the environment, of course.) (BTW, the S5R3 manual lies; the environment variable is named "CrYpTkEy", not "CRYPTKEY".) Then again, I'd be a tad chary of typing such an encryption key to a shell, unless I could make sure nobody was looking over my shoulder. If at a printing terminal, you'd also have to safely discard the printout, and if at a CRT terminal you'd have to make sure nobody could somehow coax your terminal into transmitting the screen's contents and read what it transmitted. For that matter, you'd also have to make sure nobody had a "crypt"-cracker handy. See "File Security and the UNIX System Crypt Command", J. A. Reeds and P. J. Weinberger, AT&T Bell Laboratories Technical Journal, October 1984, Vol. 63, No. 8, Part 2. > Reading from the terminal was not practical because I was > using a script that encrypted a large number of files using the same > password, and typing in the password multiple times is a pain. The number of files would have to be *very* large for "a pain" to imply "impractical". Guy Harris {ihnp4, decvax, seismo, decwrl, ...}!sun!guy guy@sun.com
guy%gorodish@Sun.COM (Guy Harris) (05/24/87)
> Seems like you could reduce (but not eliminate) the window of vulnerability > by having the program reexecute itself this way: Yup - a much better suggestion than the one offered by the guy who suggested using the repeat key to type lots of letters, or perhaps writing your own wrapper around a utility putatively provided in usable form; this one puts the burden on the author of the encryption program, not its user, which is as it should be. However, this still relies on having a "ps" that won't divulge more than N characters of the argument list. There is probably some appropriate value of N for most UNIX implementations, but I don't know that 1) all implementations would have such a limit or 2) for those implementations that do, that this value of N would be smaller than NCARGS by a sufficient amount to include an encryption key. Guy Harris {ihnp4, decvax, seismo, decwrl, ...}!sun!guy guy@sun.com
jjw@celerity.UUCP (Jim ) (05/25/87)
If you really want secure arguments then they shouldn't be on the command line at all. Put them in a file with read permission denied to all but the owner and pass the name of the file to the program. Anyone with a Berkeley based system should check out what happens with "ps axww" (that's two w's) to see how secure the idea of pushing the arguments down the list are. -- J. J. Whelan Celerity Computing
hope@gatech.UUCP (05/26/87)
In article <199@celerity.UUCP> jjw@celerity.UUCP (Jim (JJ) Whelan) writes: >Anyone with a Berkeley based system should check out what happens with > "ps axww" If you _really_ want secure (i.e., unreadable) arguments then fill up your environment with _lots_ of junk. Twenty-five or so environment variables set to about 70 characters each will keep 'w' and 'ps' from displaying them, even with ps axwwwwwww. This works on BSD systems, although different implementations might "require" you to have much more in your environment. I don't think it works on SysV. -- Theodore Hope School of Information & Computer Science, Georgia Tech, Atlanta GA 30332 CSNet: Hope@gatech ARPA: Hope@Gatech.EDU uucp: ...!{akgua,decvax,hplabs,ihnp4,linus,seismo,ulysses}!gatech!hope
pdg@ihdev.ATT.COM (Joe Isuzu) (05/26/87)
In article <15605@gatech.gatech.edu> hope@gatech.UUCP (Theodore Hope @ LEGOLAND) writes: >In article <199@celerity.UUCP> jjw@celerity.UUCP (Jim (JJ) Whelan) writes: >>Anyone with a Berkeley based system should check out what happens with >> "ps axww" >If you _really_ want secure (i.e., unreadable) arguments then fill up your >environment with _lots_ of junk. Twenty-five or so environment variables set >to about 70 characters each will keep 'w' and 'ps' from displaying them, even >with ps axwwwwwww. >This works on BSD systems, although different implementations might "require" >you to have much more in your environment. >I don't think it works on SysV. Actually it does. System V ps does not have an option for displaying the environment, though. It isn't difficult to find, however, and anyone with the slightest kernel hacking experience could do such an addition. I don't recommend the above method (filling the environment). Remember this is overhead on process creation. There are also certain programs (none I know under Berkeley, but a few under system V) that will break (read core dump) if the environment is too large. (I still would maintain that that is a bug which should be fixed - but that'll take a long time). If you want to fix this on a system wide basis, and have a reasonably secure system (ps, w setgid to kmem, and mem, kmem unreadable by all), why not just fix up ps and w to display u.u_comm, instead of looking for all the args? And turn off the environment option while you are there (this is also good for seeing what directory someone is in as csh and ksh add this into the environment). -- Paul Guthrie "Another day, another Jaguar" ihnp4!ihdev!pdg -- Pat Sajak
jjw@celerity.UUCP (05/27/87)
In article <15605@gatech.gatech.edu> hope@gatech.UUCP (Theodore Hope @ LEGOLAND) writes: >If you _really_ want secure (i.e., unreadable) arguments then fill up your >environment with _lots_ of junk. Twenty-five or so environment variables set >to about 70 characters each will keep 'w' and 'ps' from displaying them, even >with ps axwwwwwww. > >This works on BSD systems, although different implementations might "require" >you to have much more in your environment. > >I don't think it works on SysV. Also doesn't work on Celerity BSD systems which can find the command arguments regardless of environment variables.
gwyn@brl-smoke.UUCP (05/27/87)
In article <19590@sun.uucp> guy%gorodish@Sun.COM (Guy Harris) writes: >If I wanted to pass a password safely to a program, I'd have the >program ask me for the password and I'd type it in! There's even a library routine, getpass(), to make this easy to do.
rml@hpfcdc.HP.COM (Bob Lenk) (05/29/87)
> > Seems like you could reduce (but not eliminate) the window of vulnerability > > by having the program reexecute itself this way: > > ... However, this still > relies on having a "ps" that won't divulge more than N characters of > the argument list. > > There is probably some appropriate value of N for most UNIX > implementations, but... If you really want to use this type of an approach, the initial invocation can pipe() and write the password to the pipe, and the second (re-exec'd) invocation can read it back. I suppose this somewhat increases the window when when first invocation runs. Bob Lenk {ihnp4, hplabs}!hpfcla!rml