[comp.bugs.sys5] AT&T system V fdopen mode checking

hae@mbf.UUCP (Hae Hirdler) (12/01/89)

The man page on the fdopen states that "the type of the stream must 
agree with the mode of the open file."  But, when a file is open()'ed
( fd= open (filename, oflag) ), and fdopen()'ed for a stream 
( fptr= fdopen (fd, mode) ), it allows this open file to be opened for 
any type of a stream regardless of the type of oflag already open()'ed. 
For example, fd= open(filename, O_RDONLY); fptr= fdopen(filename, "w")
will return a NON_NULL fptr value instead of NULL.  

The semantics of the man page on the fdopen seems to indicate that 
this should not be allowed. (return NULL)  

Is this a known bug?  or what?
      
	 - Hae Hirdler  
	  

gwyn@smoke.BRL.MIL (Doug Gwyn) (12/02/89)

In article <713@mbf.UUCP> hae@mbf.UUCP (Hae Hirdler) writes:
-The man page on the fdopen states that "the type of the stream must 
-agree with the mode of the open file."

I believe by "mode" they mean "file access permissions".

-For example, fd= open(filename, O_RDONLY); fptr= fdopen(filename, "w")
-will return a NON_NULL fptr value instead of NULL.  

O_RDONLY has nothing to do with the file.  It is just a parameter to open().

cpcahil@virtech.uucp (Conor P. Cahill) (12/02/89)

In article <11723@smoke.BRL.MIL>, gwyn@smoke.BRL.MIL (Doug Gwyn) writes:
> In article <713@mbf.UUCP> hae@mbf.UUCP (Hae Hirdler) writes:
> -The man page on the fdopen states that "the type of the stream must 
> -agree with the mode of the open file."
> 
> I believe by "mode" they mean "file access permissions".

Why would it have to do with the file permissions?  The only thing fdopen
does is associate a file pointer with a file descriptor.

Besides, if you open a file with O_RDONLY and then fdopen it with "w", 
the buffer flushes will fail because the "status flags" for the file 
descriptor do not allow write.  This is even the case when the access
permissions do permit write.

I think the problem is caused by the fact that older unixs did not
have an ability to obtain the current status flags for a file descriptor.
Therefore the fdopen() had no way to determine whether or not the 
fd mode and the fdopen mode matched.

Both System V and BSD (at least 4.3, not sure about prior) provide the 
F_GETFL functionality in fcntl() which can be used to determine the 
flags used to open the file (like O_RDONLY...).  fdopen() should be 
modified to check this and return NULL if appropriate.

> -For example, fd= open(filename, O_RDONLY); fptr= fdopen(filename, "w")
> -will return a NON_NULL fptr value instead of NULL.  
> 
> O_RDONLY has nothing to do with the file.  It is just a parameter to open().

It has everything to do with accessing data in the file via the file
descriptor.  Since fdopen uses the file descriptor (not the file name as
is displayed above) it will also have an effect on the correct usage
of the file pointer returned by fdopen().

As an example, the following code will return an error at either the
fprintf or the fclose() (usually the fclose since that is where the buffer
is flushed).

#include <stdio.h>
#include <fcntl.h>

main()
{
	int fd,status;
	FILE * fp;

	if( (fd=open("test",O_RDONLY)) == -1)
		exit(1);

	if( (fp=fdopen(fd,"w")) == NULL)
		 exit(2);

	printf("cnt = %d\n",             fprintf(fp,"this is a test\n"));

	printf("fclose returned %d\n",   fclose(fp));
	
	exit(0);
}
-- 
+-----------------------------------------------------------------------+
| Conor P. Cahill     uunet!virtech!cpcahil      	703-430-9247	!
| Virtual Technologies Inc.,    P. O. Box 876,   Sterling, VA 22170     |
+-----------------------------------------------------------------------+

peter@ficc.uu.net (Peter da Silva) (12/03/89)

Doug Gwyn isn't often wrong, but...

In article <11723@smoke.BRL.MIL> gwyn@brl.arpa (Doug Gwyn) writes:
> In article <713@mbf.UUCP> hae@mbf.UUCP (Hae Hirdler) writes:
> -The man page on the fdopen states that "the type of the stream must 
> -agree with the mode of the open file."

> I believe by "mode" they mean "file access permissions".

No, they mean the second argument to open(). But I don't believe it's
possible to determine what the mode of a file descriptor is by examining
it, so:

> -For example, fd= open(filename, O_RDONLY); fptr= fdopen(filename, "w")
> -will return a NON_NULL fptr value instead of NULL.  

Yes, but writes to the file may fail. There's no safe way of checking this
from fdopen. I suppose a write(fd, "", 0) will work as a check. I don't
know what this might do on some files (tape drives, for example).

I said may, not will, because if the file descriptor refers to a terminal
you can write to it even if it's opened O_RDONLY.

> O_RDONLY has nothing to do with the file.  It is just a parameter to open().

Yes, a parameter that determines the mode of the file descriptor. When you
try to write to a file opened O_RDONLY you will get an error EBADF.

The manual is correct, you should make the modes agree. The code doesn't
check, so you won't get an error, but don't do it anyway.
-- 
`-_-' Peter da Silva. +1 713 274 5180. <peter@ficc.uu.net>.
 'U`  Also <peter@ficc.lonestar.org> or <peter@sugar.lonestar.org>.
"The basic notion underlying USENET is the flame."
	-- Chuq Von Rospach, chuq@Apple.COM 

cpcahil@virtech.uucp (Conor P. Cahill) (12/03/89)

In article <7190@ficc.uu.net>, peter@ficc.uu.net (Peter da Silva) writes:
> Doug Gwyn isn't often wrong, but...
> 
> In article <11723@smoke.BRL.MIL> gwyn@brl.arpa (Doug Gwyn) writes:
> > In article <713@mbf.UUCP> hae@mbf.UUCP (Hae Hirdler) writes:
> > -The man page on the fdopen states that "the type of the stream must 
> > -agree with the mode of the open file."
> 
> > I believe by "mode" they mean "file access permissions".
> 
> No, they mean the second argument to open(). But I don't believe it's
> possible to determine what the mode of a file descriptor is by examining
> it, so:

Yes it is.  fcntl(fd,F_GETFL) returns the status flags of an open file 
descriptor.

> > -For example, fd= open(filename, O_RDONLY); fptr= fdopen(filename, "w")
> > -will return a NON_NULL fptr value instead of NULL.  
> 
> Yes, but writes to the file may fail. There's no safe way of checking this
> from fdopen. I suppose a write(fd, "", 0) will work as a check. I don't
> know what this might do on some files (tape drives, for example).
> 
> I said may, not will, because if the file descriptor refers to a terminal
> you can write to it even if it's opened O_RDONLY.

This is not true on System V and I would expect it to not be true on any
unix system because the access mode for a file descriptor is checked before
any call to a device driver read/write routines.  

What you may be confusing it with is the ability to do a

		fdopen(0,"w");

to get another file pointer to stdin, but this file descriptor is really
opened for read and write, so the fdopen() for a subset of the capabilities
will succeed (and work).

> The manual is correct, you should make the modes agree. The code doesn't
> check, so you won't get an error, but don't do it anyway.

The code can, and should, check.  These capabilities have existed since 
System V.2 and at least 4.3BSD (not sure about prior BSD releases.


-- 
+-----------------------------------------------------------------------+
| Conor P. Cahill     uunet!virtech!cpcahil      	703-430-9247	!
| Virtual Technologies Inc.,    P. O. Box 876,   Sterling, VA 22170     |
+-----------------------------------------------------------------------+

gwyn@smoke.BRL.MIL (Doug Gwyn) (12/05/89)

In article <7190@ficc.uu.net> peter@ficc.uu.net (Peter da Silva) writes:
>Doug Gwyn isn't often wrong, but...

But I did make a mistake this time.  Sorry.
(That's what I get for posting when under the influence of a bad cold.)

guy@auspex.auspex.com (Guy Harris) (12/07/89)

>The man page on the fdopen states that "the type of the stream must 
>agree with the mode of the open file."  But, when a file is open()'ed
>( fd= open (filename, oflag) ), and fdopen()'ed for a stream 
>( fptr= fdopen (fd, mode) ), it allows this open file to be opened for 
>any type of a stream regardless of the type of oflag already open()'ed. 
>For example, fd= open(filename, O_RDONLY); fptr= fdopen(filename, "w")
>will return a NON_NULL fptr value instead of NULL.

A non-null but useless "fptr" value.  "Must" can either be read as
"'fdopen()' will reject your request if the type of the stream does not
agree with the mode of the open file" or "if the type of the stream does
not agree with the mode of the open file, the resulting stream won't be
usable."  It doesn't explicitly say that it does those checks, so an
implementation that doesn't perform them is valid.

Prior to the appearance of the "fcntl()" call in System III it would, in
fact, have been impossible to perform those checks without potential
risk to the file; the only way to find out if a file descriptor is open
for reading was to try and read it, and the only way to find out if a
file descriptor is open for writing was to try and write to it....

I suspect they either didn't even consider the possibility of adding
those checks once "fcntl" allowed you to see the file descriptor flags,
or they considered it unnecessary to do so, since presumably a
programmer is smart enough not to ask the system to make a standard I/O
stream open for writing out of a file descriptor open for reading.... 
(If the "fdopen()" is buried inside a routine that can be handed an
arbitrary file descriptor and/or an arbitrary open mode, the argument is
merely applied to calls to that routine rather than calls to
"fdopen()".)

>The semantics of the man page on the fdopen seems to indicate that 
>this should not be allowed. (return NULL)  

Nope.  It doesn't say so explicitly; it doesn't, in fact, indicate what
the possible failure modes of "f*open()" are.

hae@mbf.UUCP (Hae Hirdler) (12/07/89)

In article <1989Dec3.130758.27151@virtech.uucp>, cpcahil@virtech.uucp (Conor 
P. Cahill) writes:
>>In article <7190@ficc.uu.net>, peter@ficc.uu.net (Peter da Silva) writes:
>>...   
>>The manual is correct, you should make the modes agree. The code doesn't
>>check, so you won't get an error, but don't do it anyway.
>
>The code can, and should, check.  These capabilities have existed since 
>System V.2 and at least 4.3BSD (not sure about prior BSD releases.

I agree with both of the responses.

We could say that 'the manual is correct' in the sense that it plants a bomb
if the mode of fdopen() doesn't match with the oflag of the open()'ed file, 
and it will explore when fclose() or fflush() is called.  

But, I think that the man page is misleading in the sense that, if no 
error is received after fdopen(), it may let you assume that everything 
is ok so far.   This will only make a debugging harder.  I don't see what 
we are gaining here with this sneaky attack.  

To fully support the man page statement, I think the fdopen() code should 
be modified to include the error checking on the mode.  (Specially, now the 
tools are available - fcntl(fd, F_GETFL), as Conor P. Cahill points out.)  

	- hae hirdler