The flags passed to open(2) and openat(2) are not a simple bitset.
Instead, the bits in O_ACCMODE are effectively an enumeration, and the
other bits are or'ed onto that.
For example, a function that wraps open(2), taking a flag argument that it
passes through, that wants to verify that it was invoked with either
O_WRONLY or O_RDWR *cannot* just say
if ((flags & O_ACCMODE) & ~(O_WRONLY | O_RDWR))
return (EINVAL);
as that will accept O_RDONLY as well! The correct test is to mask off
O_ACCMODE and compare the results to the acceptable values:
if ((flags & O_ACCMODE) != O_WRONLY && (flags & O_ACCMODE) != O_RDWR)
return (EINVAL);
So, in anticipation of future changes, let's make interfaces that wrap
open() be more precise in the handling of flags for open(), testing
O_ACCMODE bits separately from others.
While here, document that shm_open() accept O_CLOEXEC and O_NOFOLLOW as
extensions to POSIX, and use O_CLOEXEC on the temporary fd in
posix_openpt()
ok?
Philip
Index: libc/db/db/db.c
===================================================================
RCS file: /cvs/src/lib/libc/db/db/db.c,v
retrieving revision 1.10
diff -u -p -r1.10 db.c
--- libc/db/db/db.c 5 Aug 2005 13:03:00 -0000 1.10
+++ libc/db/db/db.c 4 May 2015 04:48:11 -0000
@@ -48,9 +48,10 @@ dbopen(const char *fname, int flags, int
#define DB_FLAGS (DB_LOCK | DB_SHMEM | DB_TXN)
#define USE_OPEN_FLAGS
\
(O_CREAT | O_EXCL | O_EXLOCK | O_NOFOLLOW | O_NONBLOCK | \
- O_RDONLY | O_RDWR | O_SHLOCK | O_SYNC | O_TRUNC)
+ O_SHLOCK | O_SYNC | O_TRUNC)
- if ((flags & ~(USE_OPEN_FLAGS | DB_FLAGS)) == 0)
+ if (((flags & O_ACCMODE) == O_RDONLY || (flags & O_ACCMODE) == O_RDWR)
+ && (flags & ~(O_ACCMODE | USE_OPEN_FLAGS | DB_FLAGS)) == 0)
switch (type) {
case DB_BTREE:
return (__bt_open(fname, flags & USE_OPEN_FLAGS,
Index: libc/gen/shm_open.3
===================================================================
RCS file: /cvs/src/lib/libc/gen/shm_open.3,v
retrieving revision 1.4
diff -u -p -r1.4 shm_open.3
--- libc/gen/shm_open.3 8 Jul 2014 00:40:56 -0000 1.4
+++ libc/gen/shm_open.3 4 May 2015 04:48:11 -0000
@@ -45,7 +45,7 @@ and must include at least
or
.Dv O_RDWR
and may also include a combination of
-.Dv O_CREAT , O_EXCL ,
+.Dv O_CREAT , O_EXCL , O_CLOEXEC , O_NOFOLLOW ,
or
.Dv O_TRUNC .
This implementation forces the
@@ -81,6 +81,13 @@ and
.Fn shm_unlink
appear in
.St -p1003.1-2001 .
+Using
+.Dv O_CLOEXEC
+or
+.Dv O_NOFOLLOW
+with
+.Fn shm_open
+is an extension to that standard.
This implementation deviates from the standard by permitting less sharing.
.Pp
.Fn shm_mkstemp
Index: libc/gen/shm_open.c
===================================================================
RCS file: /cvs/src/lib/libc/gen/shm_open.c,v
retrieving revision 1.4
diff -u -p -r1.4 shm_open.c
--- libc/gen/shm_open.c 12 Nov 2013 06:09:48 -0000 1.4
+++ libc/gen/shm_open.c 4 May 2015 04:48:11 -0000
@@ -31,6 +31,9 @@
/* "/tmp/" + sha256 + ".shm" */
#define SHM_PATH_SIZE (5 + SHA256_DIGEST_STRING_LENGTH + 4)
+/* O_CLOEXEC and O_NOFOLLOW are extensions to POSIX */
+#define OK_FLAGS (O_CREAT | O_EXCL | O_TRUNC | O_CLOEXEC | O_NOFOLLOW)
+
static void
makeshmpath(const char *origpath, char *shmpath, size_t len)
{
@@ -47,8 +50,8 @@ shm_open(const char *path, int flags, mo
struct stat sb;
int fd;
- if (flags & ~(O_RDONLY | O_RDWR |
- O_CREAT | O_EXCL | O_TRUNC | O_CLOEXEC | O_NOFOLLOW)) {
+ if (((flags & O_ACCMODE) != O_RDONLY && (flags & O_ACCMODE) != O_RDWR)
+ || (flags & ~(O_ACCMODE | OK_FLAGS))) {
errno = EINVAL;
return -1;
}
Index: libc/stdlib/posix_pty.c
===================================================================
RCS file: /cvs/src/lib/libc/stdlib/posix_pty.c,v
retrieving revision 1.1
diff -u -p -r1.1 posix_pty.c
--- libc/stdlib/posix_pty.c 3 Dec 2012 20:08:33 -0000 1.1
+++ libc/stdlib/posix_pty.c 4 May 2015 04:48:11 -0000
@@ -35,13 +35,14 @@ posix_openpt(int oflag)
int fd, mfd = -1;
/* User must specify O_RDWR in oflag. */
- if (!(oflag & O_RDWR)) {
+ if ((oflag & O_ACCMODE) != O_RDWR ||
+ (oflag & ~(O_ACCMODE | O_NOCTTY)) != 0) {
errno = EINVAL;
return -1;
}
/* Get pty master and slave (this API only uses the master). */
- fd = open(PATH_PTMDEV, O_RDWR);
+ fd = open(PATH_PTMDEV, O_RDWR | O_CLOEXEC);
if (fd != -1) {
if (ioctl(fd, PTMGET, &ptm) != -1) {
close(ptm.sfd);
Index: libkvm/kvm.c
===================================================================
RCS file: /cvs/src/lib/libkvm/kvm.c,v
retrieving revision 1.54
diff -u -p -r1.54 kvm.c
--- libkvm/kvm.c 16 Jan 2015 16:48:51 -0000 1.54
+++ libkvm/kvm.c 4 May 2015 04:48:11 -0000
@@ -198,7 +198,8 @@ _kvm_open(kvm_t *kd, const char *uf, con
_kvm_err(kd, kd->program, "exec file name too long");
goto failed;
}
- if (flag & ~O_ACCMODE) {
+ if ((flag & ~O_ACCMODE) || (flag != O_RDONLY && flag != O_WRONLY &&
+ flag != O_RDWR)){
_kvm_err(kd, kd->program, "bad flags arg");
goto failed;
}