[PATCHv4 0/3] fs: add O_BENEATH flag to openat(2)

7 messages, 4 authors, 2015-08-14 · open the first message on its own page

[PATCHv4 0/3] fs: add O_BENEATH flag to openat(2)

From: David Drysdale <hidden>
Date: 2015-08-13 09:32:43

A couple of questions with this iteration:
 - Should we create a new errno (say ENOTBENEATH) for this policing, to
   make it easier to distinguish this case from other EPERM failures?
   (The FreeBSD implementation is considering this approach.)
 - Al, does the code look OK for (in particular) integrating with the
   shiny new re-worked fs/namei.c code?
Thanks.


This change adds a new O_BENEATH flag for openat(2) which restricts the
provided path, rejecting (with -EPERM) paths that are not beneath
the provided dfd.

This functionality was originally implemented as part of the internals
of the Capsicum security framework, which is available in FreeBSD 10.x
and which has previously had a Linux kernel port proposed [1].

However, as this behaviour is potentially useful as an independent feature,
this change exposes it via an openat(2) flag.  (This variant was not
originally exposed in FreeBSD, but is currently being proposed there
too [2].)

Various folks from Chrome[OS] have indicated an interest in having this
functionality -- when combined with a seccomp filter it allows a directory
to be more safely accessed by a sandboxed process.  Other folk have also
expressed an interest [3].


[1] https://lkml.org/lkml/2014/7/25/426
[2] https://reviews.freebsd.org/D2808
[3] https://groups.google.com/d/msg/capnproto/sKpzanYNZmQ/T9IbJIB-rqQJ

Changes since v3:
 - Merge up to v4.2-rc6
 - Reinstate local selftests (I'll send xfstest changes separately
   if and when this is merged)
 - Pull in common selftests makefile

Changes since v2:
 - Move tests into xfstests [Dave Chinner, with thanks for feedback
   on initial version]
 - Merge up to v4.0-rc3 & latest man-pages

Changes since v1:
 - Don't needlessly duplicate flags [Al Viro]
 - Use EPERM rather than EACCES as error code [Paolo Bonzini]
 - Disallow nd_jump_link for O_BENEATH [Al Viro/Andy Lutomirski]
 - Add test of a jumped symlink (/proc/self/root)

Changes since the version included in the Capsicum v2 patchset:
 - Add tests of normal symlinks
 - Fix man-page typo
 - Update patch to 3.17

Changes from v1 to v2 of Capsicum patchset:
 - renamed O_BENEATH_ONLY to O_BENEATH [Christoph Hellwig]


David Drysdale (2):
  fs: add O_BENEATH flag to openat(2)
  selftests: Add test of O_BENEATH & openat(2)

 arch/alpha/include/uapi/asm/fcntl.h       |   1 +
 arch/parisc/include/uapi/asm/fcntl.h      |   1 +
 arch/sparc/include/uapi/asm/fcntl.h       |   1 +
 fs/fcntl.c                                |   4 +-
 fs/namei.c                                |  12 +-
 fs/open.c                                 |   4 +-
 fs/proc/base.c                            |   4 +-
 fs/proc/namespaces.c                      |   8 +-
 include/linux/namei.h                     |   3 +-
 include/uapi/asm-generic/fcntl.h          |   4 +
 tools/testing/selftests/Makefile          |   1 +
 tools/testing/selftests/openat/.gitignore |   4 +
 tools/testing/selftests/openat/Makefile   |  29 ++++
 tools/testing/selftests/openat/openat.c   | 258 ++++++++++++++++++++++++++++++
 14 files changed, 326 insertions(+), 8 deletions(-)
 create mode 100644 tools/testing/selftests/openat/.gitignore
 create mode 100644 tools/testing/selftests/openat/Makefile
 create mode 100644 tools/testing/selftests/openat/openat.c

--
1.9.1

[PATCHv4 2/3] selftests: Add test of O_BENEATH & openat(2)

From: David Drysdale <hidden>
Date: 2015-08-13 09:32:45

Add simple tests of openat(2) variations, including examples that
check the new O_BENEATH flag.

Signed-off-by: David Drysdale <redacted>
---
 tools/testing/selftests/Makefile          |   1 +
 tools/testing/selftests/openat/.gitignore |   4 +
 tools/testing/selftests/openat/Makefile   |  29 ++++
 tools/testing/selftests/openat/openat.c   | 258 ++++++++++++++++++++++++++++++
 4 files changed, 292 insertions(+)
 create mode 100644 tools/testing/selftests/openat/.gitignore
 create mode 100644 tools/testing/selftests/openat/Makefile
 create mode 100644 tools/testing/selftests/openat/openat.c
diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile
index 24ae9e829e9a..606f8df5c8aa 100644
--- a/tools/testing/selftests/Makefile
+++ b/tools/testing/selftests/Makefile
@@ -11,6 +11,7 @@ TARGETS += memory-hotplug
 TARGETS += mount
 TARGETS += mqueue
 TARGETS += net
+TARGETS += openat
 TARGETS += powerpc
 TARGETS += ptrace
 TARGETS += seccomp
diff --git a/tools/testing/selftests/openat/.gitignore b/tools/testing/selftests/openat/.gitignore
new file mode 100644
index 000000000000..835b2dcd8678
--- /dev/null
+++ b/tools/testing/selftests/openat/.gitignore
@@ -0,0 +1,4 @@
+openat
+subdir
+topfile
+symlinkdown
\ No newline at end of file
diff --git a/tools/testing/selftests/openat/Makefile b/tools/testing/selftests/openat/Makefile
new file mode 100644
index 000000000000..73f80428b6a5
--- /dev/null
+++ b/tools/testing/selftests/openat/Makefile
@@ -0,0 +1,29 @@
+CFLAGS = -Wall
+BINARIES = openat
+DEPS = subdir topfile symlinkdown subdir/bottomfile subdir/symlinkup subdir/symlinkout subdir/symlinkin
+all: $(BINARIES) $(DEPS)
+
+subdir:
+	mkdir -p subdir
+topfile:
+	echo 0123456789 > $@
+subdir/bottomfile: | subdir
+	echo 0123456789 > $@
+subdir/symlinkup: | subdir
+	ln -s ../topfile $@
+subdir/symlinkout: | subdir
+	ln -s /etc/passwd $@
+subdir/symlinkin: | subdir
+	ln -s bottomfile $@
+symlinkdown:
+	ln -s subdir/bottomfile $@
+%: %.c
+	$(CC) $(CFLAGS) -o $@ $^
+
+TEST_PROGS := openat
+TEST_FILES := $(DEPS)
+
+include ../lib.mk
+
+clean:
+	rm -rf $(BINARIES) $(DEPS)
diff --git a/tools/testing/selftests/openat/openat.c b/tools/testing/selftests/openat/openat.c
new file mode 100644
index 000000000000..bc2c4b02a091
--- /dev/null
+++ b/tools/testing/selftests/openat/openat.c
@@ -0,0 +1,258 @@
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+
+#include <linux/fcntl.h>
+
+/* Bypass glibc */
+static int openat_(int dirfd, const char *pathname, int flags)
+{
+	return syscall(__NR_openat, dirfd, pathname, flags);
+}
+static int open_(const char *pathname, int flags)
+{
+	return syscall(__NR_open, pathname, flags);
+}
+
+static int openat_or_die(int dfd, const char *path, int flags)
+{
+	int fd = openat_(dfd, path, flags);
+
+	if (fd < 0) {
+		printf("Failed to openat(%d, '%s'); "
+			"check prerequisites are available\n", dfd, path);
+		exit(1);
+	}
+	return fd;
+}
+
+static int check_fd(int fd)
+{
+	int rc;
+	struct stat info;
+	char buffer[4];
+
+	if (fd < 0) {
+		printf("[FAIL]: openat() failed, rc=%d errno=%d (%s)\n",
+			fd, errno, strerror(errno));
+		return 1;
+	}
+	if (fstat(fd, &info) != 0) {
+		printf("[FAIL]: fstat() failed, rc=%d errno=%d (%s)\n",
+			fd, errno, strerror(errno));
+		return 1;
+	}
+	if (!S_ISDIR(info.st_mode)) {
+		errno = 0;
+		rc = read(fd, buffer, sizeof(buffer));
+		if (rc < 0) {
+			printf("[FAIL]: read() failed, rc=%d errno=%d (%s)\n",
+				rc, errno, strerror(errno));
+			return 1;
+		}
+	}
+	close(fd);
+	printf("[OK]\n");
+	return 0;
+}
+
+static int check_openat(int dfd, const char *path, int flags)
+{
+	int fd;
+
+	errno = 0;
+	printf("Check success of openat(%d, '%s', %x)... ",
+	       dfd, path?:"(null)", flags);
+	fd = openat_(dfd, path, flags);
+	return check_fd(fd);
+}
+
+static int check_open(const char *path, int flags)
+{
+	int fd;
+
+	errno = 0;
+	printf("Check success of open('%s', %x)... ", path?:"(null)", flags);
+	fd = open_(path, flags);
+	return check_fd(fd);
+}
+
+static int check_fail(int rc, int expected_errno, const char *errno_str)
+{
+	if (rc > 0) {
+		printf("[FAIL] (unexpected success from open operation)\n");
+		close(rc);
+		return 1;
+	}
+	if (errno != expected_errno) {
+		printf("[FAIL] (expected errno %d (%s) not %d (%s)\n",
+			expected_errno, strerror(expected_errno),
+			       errno, strerror(errno));
+		return 1;
+	}
+	printf("[OK]\n");
+	return 0;
+}
+
+#define check_openat_fail(dfd, path, flags, errno)	\
+	_check_openat_fail(dfd, path, flags, errno, #errno)
+static int _check_openat_fail(int dfd, const char *path, int flags,
+			      int expected_errno, const char *errno_str)
+{
+	int rc;
+
+	printf("Check failure of openat(%d, '%s', %x) with %s... ",
+		dfd, path?:"(null)", flags, errno_str);
+	errno = 0;
+	rc = openat_(dfd, path, flags);
+	return check_fail(rc, expected_errno, errno_str);
+}
+
+#define check_open_fail(path, flags, errno)	\
+	_check_open_fail(path, flags, errno, #errno)
+static int _check_open_fail(const char *path, int flags,
+			    int expected_errno, const char *errno_str)
+{
+	int rc;
+
+	printf("Check failure of open('%s', %x) with %s... ",
+	       path?:"(null)", flags, errno_str);
+	errno = 0;
+	rc = open_(path, flags);
+	return check_fail(rc, expected_errno, errno_str);
+}
+
+int check_proc(void)
+{
+	int root_dfd = openat_(AT_FDCWD, "/", O_RDONLY);
+	int proc_dfd = openat_(AT_FDCWD, "/proc/self", O_RDONLY);
+	int fail = 0;
+
+	if (proc_dfd < 0) {
+		printf("'/proc/self' unavailable (errno=%d '%s'), skipping\n",
+			errno, strerror(errno));
+		return 0;
+	}
+	fail += check_openat(proc_dfd, "root/etc/passwd", O_RDONLY);
+	fail += check_openat(root_dfd, "proc/self/root/etc/passwd", O_RDONLY);
+#ifdef O_BENEATH
+	fail += check_openat_fail(proc_dfd, "root/etc/passwd",
+				  O_RDONLY|O_BENEATH, EPERM);
+	fail += check_openat_fail(root_dfd, "proc/self/root/etc/passwd",
+				O_RDONLY|O_BENEATH, EPERM);
+#endif
+	return fail;
+}
+
+int main(int argc, char *argv[])
+{
+	int fail = 0;
+	int dot_dfd = openat_or_die(AT_FDCWD, ".", O_RDONLY);
+	int subdir_dfd = openat_or_die(AT_FDCWD, "subdir", O_RDONLY);
+	int file_fd = openat_or_die(AT_FDCWD, "topfile", O_RDONLY);
+
+	/* Sanity check normal behavior */
+	fail += check_open("topfile", O_RDONLY);
+	fail += check_open("subdir/bottomfile", O_RDONLY);
+	fail += check_openat(AT_FDCWD, "topfile", O_RDONLY);
+	fail += check_openat(AT_FDCWD, "subdir/bottomfile", O_RDONLY);
+
+	fail += check_openat(dot_dfd, "topfile", O_RDONLY);
+	fail += check_openat(dot_dfd, "subdir/bottomfile", O_RDONLY);
+	fail += check_openat(dot_dfd, "subdir/../topfile", O_RDONLY);
+	fail += check_open("subdir/../topfile", O_RDONLY);
+
+	fail += check_openat(subdir_dfd, "../topfile", O_RDONLY);
+	fail += check_openat(subdir_dfd, "bottomfile", O_RDONLY);
+	fail += check_openat(subdir_dfd, "../subdir/bottomfile", O_RDONLY);
+	fail += check_openat(subdir_dfd, "symlinkup", O_RDONLY);
+	fail += check_openat(subdir_dfd, "symlinkout", O_RDONLY);
+
+	fail += check_open("/etc/passwd", O_RDONLY);
+	fail += check_openat(AT_FDCWD, "/etc/passwd", O_RDONLY);
+	fail += check_openat(dot_dfd, "/etc/passwd", O_RDONLY);
+	fail += check_openat(subdir_dfd, "/etc/passwd", O_RDONLY);
+
+	fail += check_openat_fail(AT_FDCWD, "bogus", O_RDONLY, ENOENT);
+	fail += check_openat_fail(dot_dfd, "bogus", O_RDONLY, ENOENT);
+	fail += check_openat_fail(999, "bogus", O_RDONLY, EBADF);
+	fail += check_openat_fail(file_fd, "bogus", O_RDONLY, ENOTDIR);
+
+#ifdef O_BENEATH
+	/* Test out O_BENEATH */
+	fail += check_open("topfile", O_RDONLY|O_BENEATH);
+	fail += check_open("subdir/bottomfile", O_RDONLY|O_BENEATH);
+	fail += check_openat(AT_FDCWD, "topfile", O_RDONLY|O_BENEATH);
+	fail += check_openat(AT_FDCWD, "subdir/bottomfile",
+			     O_RDONLY|O_BENEATH);
+
+	fail += check_openat(dot_dfd, "topfile", O_RDONLY|O_BENEATH);
+	fail += check_openat(dot_dfd, "subdir/bottomfile",
+			     O_RDONLY|O_BENEATH);
+	fail += check_openat(dot_dfd, "subdir///bottomfile",
+			     O_RDONLY|O_BENEATH);
+	fail += check_openat(subdir_dfd, "bottomfile", O_RDONLY|O_BENEATH);
+	fail += check_openat(subdir_dfd, "./bottomfile", O_RDONLY|O_BENEATH);
+	fail += check_openat(subdir_dfd, ".", O_RDONLY|O_BENEATH);
+
+	/* Symlinks without .. or leading / are OK */
+	fail += check_open("symlinkdown", O_RDONLY|O_BENEATH);
+	fail += check_open("subdir/symlinkin", O_RDONLY|O_BENEATH);
+	fail += check_openat(dot_dfd, "symlinkdown", O_RDONLY|O_BENEATH);
+	fail += check_openat(dot_dfd, "subdir/symlinkin", O_RDONLY|O_BENEATH);
+	fail += check_openat(subdir_dfd, "symlinkin", O_RDONLY|O_BENEATH);
+	/* ... unless of course we specify O_NOFOLLOW */
+	fail += check_open_fail("symlinkdown",
+				O_RDONLY|O_BENEATH|O_NOFOLLOW, ELOOP);
+	fail += check_open_fail("subdir/symlinkin",
+				O_RDONLY|O_BENEATH|O_NOFOLLOW, ELOOP);
+	fail += check_openat_fail(dot_dfd, "symlinkdown",
+				  O_RDONLY|O_BENEATH|O_NOFOLLOW, ELOOP);
+	fail += check_openat_fail(dot_dfd, "subdir/symlinkin",
+				  O_RDONLY|O_BENEATH|O_NOFOLLOW, ELOOP);
+	fail += check_openat_fail(subdir_dfd, "symlinkin",
+				  O_RDONLY|O_BENEATH|O_NOFOLLOW, ELOOP);
+
+	/* Can't open paths with ".." in them */
+	fail += check_open_fail("subdir/../topfile",
+				O_RDONLY|O_BENEATH, EPERM);
+	fail += check_openat_fail(dot_dfd, "subdir/../topfile",
+				O_RDONLY|O_BENEATH, EPERM);
+	fail += check_openat_fail(subdir_dfd, "../topfile",
+				  O_RDONLY|O_BENEATH, EPERM);
+	fail += check_openat_fail(subdir_dfd, "../subdir/bottomfile",
+				O_RDONLY|O_BENEATH, EPERM);
+	fail += check_openat_fail(subdir_dfd, "..", O_RDONLY|O_BENEATH, EPERM);
+
+	/* Can't open paths starting with "/" */
+	fail += check_open_fail("/etc/passwd", O_RDONLY|O_BENEATH, EPERM);
+	fail += check_openat_fail(AT_FDCWD, "/etc/passwd",
+				  O_RDONLY|O_BENEATH, EPERM);
+	fail += check_openat_fail(dot_dfd, "/etc/passwd",
+				  O_RDONLY|O_BENEATH, EPERM);
+	fail += check_openat_fail(subdir_dfd, "/etc/passwd",
+				  O_RDONLY|O_BENEATH, EPERM);
+	/* Can't sneak around constraints with symlinks */
+	fail += check_openat_fail(subdir_dfd, "symlinkup",
+				  O_RDONLY|O_BENEATH, EPERM);
+	fail += check_openat_fail(subdir_dfd, "symlinkout",
+				  O_RDONLY|O_BENEATH, EPERM);
+	fail += check_openat_fail(subdir_dfd, "../symlinkdown",
+				  O_RDONLY|O_BENEATH, EPERM);
+	fail += check_openat_fail(dot_dfd, "subdir/symlinkup",
+				  O_RDONLY|O_BENEATH, EPERM);
+	fail += check_open_fail("subdir/symlinkup", O_RDONLY|O_BENEATH, EPERM);
+#else
+	printf("Skipping O_BENEATH tests due to missing #define\n");
+#endif
+	fail += check_proc();
+
+	if (fail > 0)
+		printf("%d tests failed\n", fail);
+	return fail;
+}
-- 
1.9.1

[PATCHv4 man-pages 3/3] open.2: describe O_BENEATH flag

From: David Drysdale <hidden>
Date: 2015-08-13 09:32:46

Signed-off-by: David Drysdale <redacted>
---
 man2/open.2 | 44 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 44 insertions(+)
diff --git a/man2/open.2 b/man2/open.2
index f49ab3042161..d09511f9ffb0 100644
--- a/man2/open.2
+++ b/man2/open.2
@@ -201,6 +201,43 @@ See
 for further details.
 See also BUGS, below.
 .TP
+.B O_BENEATH " (since Linux 4.??)"
+Ensure that the
+.I pathname
+is beneath the current working directory (for
+.BR open (2))
+or the
+.I dirfd
+(for
+.BR openat (2)).
+If the
+.I pathname
+is absolute or contains a path component of "..", the
+.BR open ()
+fails with the error
+.BR EPERM.
+This occurs even if ".." path component would not actually
+escape the original directory; for example, a
+.I pathname
+of "subdir/../filename" would be rejected.
+Path components that are symbolic links to absolute paths, or that are
+relative paths containing a ".." component, will also cause the
+.BR open ()
+operation to fail with the error
+.BR EPERM.
+
+This feature allows applications to be sure that the opened file is
+within the specified directory, regardless of the original source of the
+.I pathname
+argument.
+Some security-conscious programs may further ensure
+this by imposing a system call filter (with
+.BR seccomp (2))
+that requires this flag for all
+.BR open ()
+operations, so that the program cannot open files outside of
+specified directories even if subverted.
+.TP
 .BR O_CLOEXEC " (since Linux 2.6.23)"
 .\" NOTE! several other man pages refer to this text
 Enable the close-on-exec flag for the new file descriptor.
@@ -1015,6 +1052,13 @@ did not match the owner of the file and the caller was not privileged
 The operation was prevented by a file seal; see
 .BR fcntl (2).
 .TP
+.B EPERM
+The
+.B O_BENEATH
+flag was specified and the
+.I pathname
+was not beneath the relevant directory.
+.TP
 .B EROFS
 .I pathname
 refers to a file on a read-only filesystem and write access was
--
2.5.0.rc2.392.g76e840b

Re: [PATCHv4 man-pages 3/3] open.2: describe O_BENEATH flag

From: Andy Lutomirski <luto@amacapital.net>
Date: 2015-08-13 17:38:20

On Thu, Aug 13, 2015 at 2:32 AM, David Drysdale [off-list ref] wrote:
Signed-off-by: David Drysdale <redacted>
What's the behavior wrt fcntl(F_GETFL, etc)?

--Andy

Re: [PATCHv4 man-pages 3/3] open.2: describe O_BENEATH flag

From: Michael Kerrisk (man-pages) <hidden>
Date: 2015-08-14 05:33:17

On 13 August 2015 at 19:38, Andy Lutomirski [off-list ref] wrote:
On Thu, Aug 13, 2015 at 2:32 AM, David Drysdale [off-list ref] wrote:
quoted
Signed-off-by: David Drysdale <redacted>
What's the behavior wrt fcntl(F_GETFL, etc)?
I would presume that O_BENEATH is one of the so-called "file creation
flags". See this paragraph of the DESCRIPTION:

       In addition, zero or more file creation  flags  and  file  status
       flags  can be bitwise-or'd in flags.  The file creation flags are
       O_CLOEXEC, O_CREAT, O_DIRECTORY,  O_EXCL,  O_NOCTTY,  O_NOFOLLOW,
       O_TMPFILE,  O_TRUNC,  and  O_TTY_INIT.  The file status flags are
       all of the remaining flags listed below.  The distinction between
       these  two  groups  of flags is that the file status flags can be
       retrieved and (in some cases) modified; see fcntl(2) for details.

David, presuming this is correct (I can't see how O_BENEATH could be a
"file *status* flag"), your patch should also add O_BENEATH to the
list in that paragraph.

Cheers,

Michael



-- 
Michael Kerrisk
Linux man-pages maintainer; http://www.kernel.org/doc/man-pages/
Linux/UNIX System Programming Training: http://man7.org/training/

Re: [PATCHv4 man-pages 3/3] open.2: describe O_BENEATH flag

From: David Drysdale <hidden>
Date: 2015-08-14 09:29:08

On Fri, Aug 14, 2015 at 6:33 AM, Michael Kerrisk (man-pages)
[off-list ref] wrote:
On 13 August 2015 at 19:38, Andy Lutomirski [off-list ref] wrote:
quoted
On Thu, Aug 13, 2015 at 2:32 AM, David Drysdale [off-list ref] wrote:
quoted
Signed-off-by: David Drysdale <redacted>
What's the behavior wrt fcntl(F_GETFL, etc)?
I would presume that O_BENEATH is one of the so-called "file creation
flags". See this paragraph of the DESCRIPTION:

       In addition, zero or more file creation  flags  and  file  status
       flags  can be bitwise-or'd in flags.  The file creation flags are
       O_CLOEXEC, O_CREAT, O_DIRECTORY,  O_EXCL,  O_NOCTTY,  O_NOFOLLOW,
       O_TMPFILE,  O_TRUNC,  and  O_TTY_INIT.  The file status flags are
       all of the remaining flags listed below.  The distinction between
       these  two  groups  of flags is that the file status flags can be
       retrieved and (in some cases) modified; see fcntl(2) for details.

David, presuming this is correct (I can't see how O_BENEATH could be a
"file *status* flag"), your patch should also add O_BENEATH to the
list in that paragraph.
Yeah, O_BENEATH makes sense as a file creation flag; I'll add it
to that list -- thanks for spotting.
Cheers,

Michael



--
Michael Kerrisk
Linux man-pages maintainer; http://www.kernel.org/doc/man-pages/
Linux/UNIX System Programming Training: http://man7.org/training/

Re: [PATCHv4 man-pages 3/3] open.2: describe O_BENEATH flag

From: Andy Lutomirski <luto@amacapital.net>
Date: 2015-08-14 14:18:10

On Fri, Aug 14, 2015 at 2:29 AM, David Drysdale [off-list ref] wrote:
On Fri, Aug 14, 2015 at 6:33 AM, Michael Kerrisk (man-pages)
[off-list ref] wrote:
quoted
On 13 August 2015 at 19:38, Andy Lutomirski [off-list ref] wrote:
quoted
On Thu, Aug 13, 2015 at 2:32 AM, David Drysdale [off-list ref] wrote:
quoted
Signed-off-by: David Drysdale <redacted>
What's the behavior wrt fcntl(F_GETFL, etc)?
I would presume that O_BENEATH is one of the so-called "file creation
flags". See this paragraph of the DESCRIPTION:

       In addition, zero or more file creation  flags  and  file  status
       flags  can be bitwise-or'd in flags.  The file creation flags are
       O_CLOEXEC, O_CREAT, O_DIRECTORY,  O_EXCL,  O_NOCTTY,  O_NOFOLLOW,
       O_TMPFILE,  O_TRUNC,  and  O_TTY_INIT.  The file status flags are
       all of the remaining flags listed below.  The distinction between
       these  two  groups  of flags is that the file status flags can be
       retrieved and (in some cases) modified; see fcntl(2) for details.

David, presuming this is correct (I can't see how O_BENEATH could be a
"file *status* flag"), your patch should also add O_BENEATH to the
list in that paragraph.
Yeah, O_BENEATH makes sense as a file creation flag; I'll add it
to that list -- thanks for spotting.
Should there be a test that you can't clear O_BENEATH with F_SETFL?

--Andy
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help