On 1/23/2020 11:31 AM, Ken Brown wrote:
> Commit aa55d22c, "Cygwin: honor the O_PATH flag when opening a FIFO",
> fixed a hang but otherwise didn't accomplish the purpose of the O_PATH
> flag as stated in the Linux man page for open(2):
>
> Obtain a file descriptor that can be used for two purposes: to
> indicate a location in the filesystem tree and to perform
> operations that act purely at the file descriptor level. The
> file itself is not opened, and other file operations (e.g.,
> read(2), write(2), fchmod(2), fchown(2), fgetxattr(2),
> ioctl(2), mmap(2)) fail with the error EBADF.
>
> [The man page goes on to describe operations that *can* be
> performed: close(2), fchdir(2), fstat(2),....]
>
> Opening a file or directory with the O_PATH flag requires no
> permissions on the object itself (but does require execute
> permission on the directories in the path prefix).
>
> The first problem in the current implementation is that if open(2) is
> called on a FIFO, fhandler_base::device_access_denied is called and
> tries to open the FIFO with read access, which isn't supposed to be
> required. This is fixed by the first patch in this series.
>
> The second patch makes fhandler_fifo::open call fhandler_base::open_fs
> if O_PATH is set, so that we actually obtain a handle that can be used
> for the purposes stated above.
>
> The third page tweaks fhandler_fifo::fcntl and fhandler_fifo::dup so
> that they work with O_PATH.
>
> In a followup email I'll provide the program I used to test this
> implementation.
Test program attached.
$ gcc -o o_path_fifo_test o_path_fifo_test.c
$ ./o_path_fifo_test.exe
The following calls should fail with EBADF:
read: OK
write: OK
fchmod: OK
fchown: OK
ioctl: OK
fgetxattr: OK
mmap: OK
The following calls should succeed:
fstat: OK
fstatfs: OK
fcntl_dup: OK
fcntl_getfl: OK
fcntl_setfl: OK
fcntl_getfd: OK
fcntl_setfd: OK
close: OK
#define _GNU_SOURCE
#include <sys/stat.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <sys/vfs.h>
#include <sys/xattr.h>
#include <sys/mman.h>
#define FIFO_PATH "/tmp/myfifo"
int
main ()
{
struct stat s;
int fd;
if (mkfifo (FIFO_PATH, S_IRUSR | S_IWUSR | S_IWGRP) < 0
&& errno != EEXIST)
{
perror ("mkfifo");
exit (1);
}
fd = open (FIFO_PATH, O_PATH);
if (fd < 0)
{
perror ("open");
exit (1);
}
printf ("The following calls should fail with EBADF:\n");
errno = 0;
if (read (fd, NULL, 0) < 0 && errno == EBADF)
printf ("read: OK\n");
else
perror ("read");
errno = 0;
if (write (fd, NULL, 0) < 0 && errno == EBADF)
printf ("write: OK\n");
else
perror ("write");
errno = 0;
if (fchmod (fd, 0) < 0 && errno == EBADF)
printf ("fchmod: OK\n");
else
perror ("fchmod");
errno = 0;
if (fchown (fd, -1, -1) < 0 && errno == EBADF)
printf ("fchown: OK\n");
else
perror ("fchown");
errno = 0;
if (ioctl (fd, FIONBIO, NULL) < 0 && errno == EBADF)
printf ("ioctl: OK\n");
else
perror ("ioctl");
errno = 0;
if (fgetxattr (fd, "", NULL, 0) < 0 && errno == EBADF)
printf ("fgetxattr: OK\n");
else
perror ("fgetxattr");
errno = 0;
if (mmap (NULL, 1, 0, MAP_SHARED, fd, 0) == MAP_FAILED && errno == EBADF)
printf ("mmap: OK\n");
else
perror ("mmap");
printf ("\nThe following calls should succeed:\n");
if (fstat (fd, &s) < 0)
perror ("fstat");
else
printf ("fstat: OK\n");
struct statfs st;
if (fstatfs (fd, &st) < 0)
perror ("fstatfs");
else
printf ("fstatfs: OK\n");
if (fcntl (fd, F_DUPFD, 0) < 0)
perror ("fcntl_dup");
else
printf ("fcntl_dup: OK\n");
int flags = fcntl (fd, F_GETFL);
if (flags < 0)
perror ("fcntl_getfl");
else
printf ("fcntl_getfl: OK\n");
if (flags >= 0)
{
if (fcntl (fd, F_SETFL, flags) < 0)
perror ("fcntl_setfl");
else
printf ("fcntl_setfl: OK\n");
}
flags = fcntl (fd, F_GETFD);
if (flags < 0)
perror ("fcntl_getfd");
else
printf ("fcntl_getfd: OK\n");
if (flags >= 0)
{
if (fcntl (fd, F_SETFD, flags) < 0)
perror ("fcntl_setfd");
else
printf ("fcntl_setfd: OK\n");
}
if (close (fd) < 0)
perror ("close");
else
printf ("close: OK\n");
}