mchinni@ardec.arpa (Michael J. Chinni, SMCAR-CCS-E) (04/07/88)
In a message from Michael Deutsch <deutsch@jplgodo.uucp> dated 6 Apr 88 03:47:17 GMT he writes: > I have a "C" program that records the program > results into a file, provided that file already > exists. In case the file DOES NOT exist I want > the program to function identically but the results > should be flushed down the tube, i.e. nowhere, i.e. > written to a non-existing file? > > What sort of "file pointer" or trick should I use > to accomplish my goal? I have a couple of suggestions. First, try writing to "/dev/null". Second, a temporary file could be used ("mkstemp" in BSD or "tmpnam"/"tempnam" and "tmpfile" in SysV). Last, a filename of personal choice could be created, written to, and then deleted at the end of the program. Mike Chinni US Army Armament Research, Development, and Engineering Center Picatinny Arsenal, New Jersey 07806-5000 AUTOVON: 880-4140 MILNET: <mchinni@ardec> COMMERCIAL: (201) 724-4140 ------ Standard Disclaimer ------
anamaria@lll-lcc.llnl.gov (Ana Maria De Alvare) (04/08/88)
I will also suggest to write it to stdout or use stderr. They are there to be used on those instances. Ana Maria De Alvare' LLNL
drears@ardec.arpa (Dennis G. Rears (FSAC)) (04/08/88)
Michael Deutsch writes: -> I have a "C" program that records the program -> results into a file, provided that file already -> exists. In case the file DOES NOT exist I want -> the program to function identically but the results -> should be flushed down the tube, i.e. nowhere, i.e. -> written to a non-existing file? -> -> What sort of "file pointer" or trick should I use -> to accomplish my goal? Here is sample code that will allow you to do this. It will exit if it can't open for appending any file. If it can not stat the file it assumes it doesn't exist. You can be fancy and check errno though. ---------------------------------------------------------------------- #include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #define FILENAME "/usr/foobar" /* not a trademark of AT&T *? #define NULL "/dev/null/" main(a,b,c) int a; char *b[],*c[]; { struct stat *buf; FILE *fopen(), *fp, *fr; if(!stat(FILE,buf){ if ( (fp=fopen(NULL,"a")) == NULL ) { /* or use perror() */ (void)fprintf (stderr, "%s: Can not open /dev/null file\n",b[0])); exit(-1); } else if ( (fp=fopen(FILENAME,"a")) == NULL ) { (void)fprintf (stderr, "%s: Can not open %sfile\n",b[0],FILENAME)); exit(-1); } Dennis ------------------------------------------------------------ ARPA: drears@ardec-ac4.arpa UUCP: ...!uunet!ardec-ac4.arpa!drears AT&T: 201-724-6639 Snailmail: Box 210, Wharton, NJ 07885 Govt Nonmail: US Army ARDEC, ATTN SMCAR-FSS-E, Dennis Rears Bldg 94, Picatinny Arsenal, NJ 07806 Flames: /dev/null ------------------------------------------------------------
mlandau@bbn.com (Matt Landau) (04/08/88)
In comp.unix.wizards (<12860@brl-adm.ARPA>), drears@ardec.arpa (Dennis G. Rears (FSAC)) writes: >Here is sample code that will allow you to do this. It will exit >if it can't open for appending any file. If it can not stat the >file it assumes it doesn't exist. You can be fancy and check errno >though. >#define NULL "/dev/null/" Probably want to pick another name for /dev/null, tho... :-) -- Matt Landau The happiest cold and lonely guy mlandau@bbn.com stuck in the Yukon without a dog.
gandalf@csli.STANFORD.EDU (Juergen Wagner) (04/08/88)
Why all these lengthy solutions? As I tried to e-mail (host unreachable),
you could just do
# define do_output_p(file) (!access((file),02))
and assign the result to a variable, say
static int do_output_flag;
main(...)
...
{
char *file;
...
...
do_output_flag = do_output_p(file);
...
}
Then, to access the file use
# define Fopen if (do_output_flag) fopen
# define Printf if (do_output_flag) printf
# define Fclose if (do_output_flag) fclose
Of course, another alternative would be just to open "/dev/null" instead of
the file specified.
Juergen "Gandalf" Wagner, gandalf@csli.stanford.edu
Center for the Study of Language and Information (CSLI), Stanford CA
--
Juergen "Gandalf" Wagner, gandalf@csli.stanford.edu
Center for the Study of Language and Information (CSLI), Stanford CA
henrik@blblbl.UUCP (Larry DeLuca) (04/10/88)
In article <12840@brl-adm.ARPA>, mchinni@ardec.arpa (Michael J. Chinni, SMCAR-CCS-E) writes: > In a message from Michael Deutsch <deutsch@jplgodo.uucp> > dated 6 Apr 88 03:47:17 GMT he writes: > > exists. In case the file DOES NOT exist I want > > the program to function identically but the results > > should be flushed down the tube, i.e. nowhere, i.e. > I have a couple of suggestions. First, try writing to "/dev/null". > Second, a temporary file could be used ("mkstemp" in BSD or "tmpnam"/"tempnam" > and "tmpfile" in SysV). Last, a filename of personal choice could be created, > written to, and then deleted at the end of the program. Why not just open the file at the beginning, and use the file pointer returned to tell if you should write or not, i.e. if(fp != (FILE *) 0) fprintf(...); I usually encode things of this sort in a macro and it makes my life much easier. Also, if you don't have the file around in the first place, things will go much more quickly than writing to a temp file you're only going to delete, or writing to /dev/null. larry...
rbj@icst-cmr.arpa (Root Boy Jim) (04/26/88)
[access is ...] ... for setuid programs to determine whether the real user can access a file. (It's the wrong way to do even that, because of the resulting window, but that's another can of worms.) OK, now to address that window issue. As I understand it, the basic objection to access is a window of vulnerability between deciding if access to a file is okay, and actually doing something to that file, (for the purposes of this discussion, let's say open) someone could possibly substitute another file. I propose enclosing the whole mess between two stat's, and testing whether the vital statistics match. Then, you can assume it's the same file you asks about via access. der Mouse uucp: mouse@mcgill-vision.uucp arpa: mouse@larry.mcrcim.mcgill.edu (Root Boy) Jim Cottrell <rbj@icst-cmr.arpa> National Bureau of Standards Flamer's Hotline: (301) 975-5688 The opinions expressed are solely my own and do not reflect NBS policy or agreement Now, let's SEND OUT for QUICHE!!
mouse@larry.mcrcim.mcgill.edu (der Mouse) (04/26/88)
>> [access is ...] the wrong way to [determine whether the real user >> can access a file], because of the resulting window, but that's >> another can of worms. > OK, now to address that window issue. As I understand it, the basic > objection to access is a window of vulnerability between deciding if > access to a file is okay, and actually doing something to that file. Precisely. At least, that's the one I meant. > I propose enclosing the whole mess between two stat's, and testing > whether the vital statistics match. Then, you can assume it's the > same file you asks about via access. Well, you have to be very careful, and even then, I don't think it's possible to get it right. You can make the window much harder to hit, but I don't think it's possible to get rid of it entirely. After much arguing with myself, the closest I've come up with is fd = open(path) <--- this must succeed, of course access(path) <--- this must show "access permitted" stat(path) <--\ These two must produce fstat(fd) <--/ matching stat structures but this is vulnerable to a quick switch immediately before and after the access() call. Sprinkling extra calls (stat(), access(), etc) around doesn't help, because if the switches occur exactly before and after the access(), it is impossible to detect them. None of this helps any when you want to find out whether it is safe to create or remove a file. For any sequence of operations, switching symlinks immediately before (and after) an unlink() or open(...,O_CREAT,...) can beat it. Therefore, if a setuid program is to create or remove a file, it must be very sure that the real user cannot pull a switch on any directory on the path used to reach the file in question. Chdir() first (or create all your files in / :-) What's more, when creating, O_EXCL must be used. I shan't describe the problem in detail, because I'm sure far too few setuid programs actually do bother to use O_EXCL, and I don't want to be too blatant about giving directions on how to break into a system. What we need, it seems, is a way to say "I wish to restrict myself to the real user's access privileges" for a time, with the potential to revert back to the previous state. 4.3's setreuid() appears to be exactly this, though I seem to recall that if the real uid is 0, the process has superuser access even if the effective uid is not 0, which would mean that this technique is useless for setuid-root programs. It might be worth putting a flag into open() (O_REALUID maybe) to have it use the real UID when it does permission checks, just as a case of "make the common case easy". Open already takes flags, so it would be totally compatible. Security is such a mess. Why don't we all run GNU and leave this sort of security to the security freaks? Oh yes, that's right, GNU doesn't exist yet. Bother. der Mouse uucp: mouse@mcgill-vision.uucp arpa: mouse@larry.mcrcim.mcgill.edu
rbj@icst-cmr.arpa (Root Boy Jim) (04/29/88)
From: der Mouse <mouse@larry.mcrcim.mcgill.edu> Der Mouse und der Root Boy discussing access: I said... > I propose enclosing the whole mess between two stat's, and testing > whether the vital statistics match. Then, you can assume it's the > same file you asks about via access. To which he replied... Well, you have to be very careful, and even then, I don't think it's possible to get it right. You can make the window much harder to hit, but I don't think it's possible to get rid of it entirely. After much arguing with myself, the closest I've come up with is fd = open(path) <--- this must succeed, of course access(path) <--- this must show "access permitted" stat(path) <--\ These two must produce fstat(fd) <--/ matching stat structures but this is vulnerable to a quick switch immediately before and after the access() call. Sprinkling extra calls (stat(), access(), etc) around doesn't help, because if the switches occur exactly before and after the access(), it is impossible to detect them. My idea is more explicitly stat(path,&before) if (access(path,how) == 0) { /*OK*/ fd = open(path,mode); stat(path,&after); for (all relevant fields in struct stat) { if (before.field != after.field) { printf("fulling a fast one, eh?\n"); exit(-1); } } } /* everything OK */ Good things to check would be inode number and creation date. Neither can easily be faked, except thru acces to the raw device. I am assuming previous existence of the file access'ed. If it doesn't already exist, the job is a bit harder. Note also that the file should not be truncated on the open, in case a fast one *is* being pulled. Any problems with this approach? BTW, while we're talking windows, mktemp et al suffer as well. der Mouse uucp: mouse@mcgill-vision.uucp arpa: mouse@larry.mcrcim.mcgill.edu (Root Boy) Jim Cottrell <rbj@icst-cmr.arpa> National Bureau of Standards Flamer's Hotline: (301) 975-5688 The opinions expressed are solely my own and do not reflect NBS policy or agreement How many retured bricklayers from FLORIDA are out purchasing PENCIL SHARPENERS right NOW??
mouse@larry.mcrcim.mcgill.edu (der Mouse) (04/29/88)
>>> I propose enclosing the whole mess between two stat's, and testing >>> whether the vital statistics match. >> Well, you have to be very careful, and even then, I don't think it's >> possible to get it right. You can make the window much harder to >> hit, but I don't think it's possible to get rid of it entirely. > My idea is more explicitly > stat(path,&before) > if (access(path,how) == 0) { /*OK*/ > fd = open(path,mode); > stat(path,&after); > [compare after.xxx and before.xxx for appropriate xxx] > } > [later in letter] Any problems with this approach? Yes. Suppose we pull a switch immediately before and after the open(). You can't catch it, and can easily wind up opening the wrong file. Specifically: user does program does % touch myfile.blah % setuidpgm myfile.blah stat(path,&before) if (access(path,how) == 0) { /*OK*/ % mv myfile.blah myfile.save % ln -s /etc/passwd myfile.blah fd = open(path,mode); % rm -f myfile.blah % mv myfile.save myfile.blah stat(path,&after); [compare after.xxx and before.xxx for appropriate xxx] } (Of course, those wouldn't actually be typed commands; I'm just using the commands to indicate the operations being performed.) This is why I recommend doing fstat() on the file descriptor returned by open(), to ensure that the file you really opened is the one you were stat()ing. But that's vulnerable too; think about something similar to the above with the secure file in place at the beginning, replaced with an innocuous file for the access() to see. (You can see why I said the window is "much" harder to hit. The bad guy must time two operations exactly right instead of just one, and the interval between the two is very short.) > Good things to check would be inode number and creation date. Do any recent systems maintain a creation date? 4.[23]BSD doesn't. (st_ctime is the inode-change time, not the creation time.) > Neither can easily be faked, except thru acces to the raw device. If I wanted to patch a ctime field, I'd much rather change the clock and touch the file than meddle with the raw disk. > If [the file being open()ed] doesn't already exist, the job is a bit > harder. I claim it's impossible if the user has write access to any of the ancestors of the directory the file is to be created in. > BTW, while we're talking windows, mktemp et al suffer as well. Hence mkstemp(3). der Mouse uucp: mouse@mcgill-vision.uucp arpa: mouse@larry.mcrcim.mcgill.edu
rbj@icst-cmr.arpa (Root Boy Jim) (04/29/88)
OK, so expand the definion of `stat' to include `fstat' *and* `lstat'. Expanding the window to two windows *should* provide enuf security, altho I agree with your idea of a specific flag to open to say `use the real uid rather than the effective uid (maybe Chris can hack this in tonite :-). Anyone having permission to change the date or use the raw device is *already* root, and so won't have to resort to this trickery. And of course, Chris will want a seventh arg on select or a fourth on open :-) (Root Boy) Jim Cottrell <rbj@icst-cmr.arpa> National Bureau of Standards Flamer's Hotline: (301) 975-5688 The opinions expressed are solely my own and do not reflect NBS policy or agreement It's OKAY --- I'm an INTELLECTUAL, too.