Bug 74242

Summary: Write to fifo with no reader fails in 6.0 current
Product: Base System Reporter: Derek Tattersall <dlt>
Component: kernAssignee: Robert Watson <rwatson>
Status: Closed FIXED    
Severity: Affects Only Me CC: eugen
Priority: Normal    
Version: Unspecified   
Hardware: Any   
OS: Any   

Description Derek Tattersall 2004-11-22 15:00:54 UTC
  Problem: Writing to a fifo before a reader is present results in the
write returning -1 with errno 45 "operation not supported".  This
behavior is new with a system cvsup'ed yesterday.

($?=0)dlt@lorne 1021 dlt% uname -a
FreeBSD lorne.arm.org 6.0-CURRENT FreeBSD 6.0-CURRENT #1: Sun Nov 21
12:00:32 EST 2004     root@lorne.arm.org:/usr/obj/usr/src/sys/LORNE
i386

The following two programs, speak.c (writer) and tick.c (reader)
demonstrate the problem.  If speak is started before tick, the write
always fails.  If tick is started before speak, everything works as
expected.  This code is slightly modified from code on Beej's Unix IPC
site.

speak.c --------------------------------------------------------------
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

#define FIFO_NAME "american_maid"

main()
{
  char s[300];
  int num, fd;

  /* don't forget to error check this stuff!! */
  /*mknod(FIFO_NAME, S_IFIFO | 0666, 0);*/
  mkfifo(FIFO_NAME, 0666);

  printf("waiting for readers...\n");
  fd = open(FIFO_NAME, O_WRONLY);
  printf("got a reader--type some stuff\n");

  while (gets(s), !feof(stdin)) {
    if ((num = write(fd, s, strlen(s))) == -1)
      perror("write");
    else
      printf("speak: wrote %d bytes\n", num);
  }
}
speak.c-------------------------------------------------------------
tick.c -------------------------------------------------------------
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

#define FIFO_NAME "american_maid"

main()
{
  char s[300];
  int num, fd;

  /* don't forget to error check this stuff!! */
  mknod(FIFO_NAME, S_IFIFO | 0666, 0);

  printf("waiting for writers...\n");
  fd = open(FIFO_NAME, O_RDONLY);
  printf("got a writer:\n");

  do {
    if ((num = read(fd, s, 300)) == -1)
      perror("read");
    else {
      s[num] = '\0';
      printf("tick: read %d bytes: \"%s\"\n", num, s);
    }
  } while (num > 0);
}
tick.c-------------------------------------------------------------

Note:  On a 5.3 RELEASE system it does not matter which program is
started first.  In fact, this code has worked on current up through
11/10/2004.

How-To-Repeat:  Using speak, compiled with "cc -o speak speak.c" and tick compiled with "cc -o tick tick.c", start speak in an xterm or console, then start tick in another xterm or console.  Type in the speak window, mash newline, observe error message in speak window or console.  Note that starting tick first then speak, and typing in the speak window shows no error.
Comment 1 Robert Watson freebsd_committer freebsd_triage 2004-11-22 21:55:41 UTC
Responsible Changed
From-To: freebsd-bugs->phk

Change ownership to Poul-Henning Kamp, who has recently had his hands in 
the fifo code.
Comment 2 Robert Watson freebsd_committer freebsd_triage 2005-09-13 11:49:02 UTC
Responsible Changed
From-To: phk->rwatson

Grab ownership of this PR since I've been fixing a number of bugs in the 
fifofs code.
Comment 3 Robert Watson freebsd_committer freebsd_triage 2005-09-13 12:10:48 UTC
State Changed
From-To: open->feedback

When I run the "tick" and "speak" programs as described, I get EBADF back 
from the read() call in "tick", as open() has failed, which results from 
mknod() failing with EPERM.  This somewhat obscure failure mode was due 
to a lack of error checking in the test programs, which didn't confirm 
that the fifo had been created or opened before attempting I/O on the 
returned descriptor.  If run sequentially, "tick" actually does work, 
since "speak" calls mkfifo(), which succeeds.  When the mknod() call in 
"tick" is replaced with mkfifo(), the tests appear to operate correctly 
on recent 7.x.  When I ran the test programs as provided on 4.x, they 
failed, but worked with the mkfifo change. 

There appears to be some disagreement about whether mknod(S_FIFO) should 
work for unprivileged users.  FreeBSD 4.x does not permit this.  FreeBSD 
6.x and 7.x do not permit this.  It could well be that FreeBSD 5.x does 
permit this.  POSIX indicates that privilege is required for non-S_FIFO, 
but appears to allow mknod(2) as an acceptable interface to create fifos 
as an unprivileged user.  It could be that we should broaden the scope 
of mknod(2) to require privilege only for non-fifo objects, in order to 
provide more portable support for fifos. 

Could you confirm that, in your environment, the source of the read() 
error is in fact that mknod() has failed (detected by checking for a 
return value of -1, and then printed using err(-1, "mknod")), and that 
if the fifo is created using mkfifo(), "tick" operates properly in your 
environment?  This would help us identify that there isn't another bug 
lurking here. 

FYI, it could be that FreeBSD 5.3 appeared to allow this by virtue of 
the fact that the order in which the provided programs are run is quite 
significant in how they operate: later runs of "tick" will work fine as 
the fifo has been created by a prior run of "speak", and then not been 
removed. 

Thanks, 

Robert Watson
Comment 4 Robert Watson freebsd_committer freebsd_triage 2005-09-15 21:21:32 UTC
State Changed
From-To: feedback->suspended

Place this PR into a suspended state.  We have established that the 
specific symptoms were the result of a software bug, but there is an 
open issue relating to whether we need to modify our mknod() system 
call to allow the unprivileged creation of fifos in order to conform 
to more recent POSIX revisions.  After some cogitation on the issue, 
we may want to re-open this PR as a feature request.
Comment 5 dfilter service freebsd_committer freebsd_triage 2008-06-22 22:51:49 UTC
rwatson     2008-06-22 21:51:32 UTC

  FreeBSD src repository

  Modified files:
    sys/kern             vfs_syscalls.c 
  Log:
  SVN rev 179936 on 2008-06-22 21:51:32Z by rwatson
  
  If S_IFIFO is passed to mknod(2), invoke kern_mkfifoat(9) to create a
  FIFO, as required by SUSv3.  No specific privilege check is performed
  in this case, as FIFOs may be created by unprivileged processes
  (subject to the normal file system name space restrictions that may be
  in place).
  
  Unlike the Apple implementation, we reject requests to create a FIFO
  using mknod(2) if there is a non-zero dev argument to the system call,
  which is permitted by the Open Group specification ("... undefined
  ...").  We might want to revise this if we find it causes
  compatibility problems for applications in practice.
  
  PR:             kern/74242, kern/68459
  Obtained from:  Apple, Inc.
  MFC after:      3 weeks
  
  Revision  Changes    Path
  1.454     +4 -0      src/sys/kern/vfs_syscalls.c
_______________________________________________
cvs-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/cvs-all
To unsubscribe, send any mail to "cvs-all-unsubscribe@freebsd.org"
Comment 6 Eugene Grosbein freebsd_committer freebsd_triage 2018-02-02 23:16:13 UTC
Seems to be fixed long time ago with r179936.