Tell people when they've messed up with fcntl(FD_SETFD).
This is a subtle bug that even experts struggle with.
Test: treehugger
Change-Id: If9cf16a1c32c836f5688bb3374cfd21d55125b17
diff --git a/libc/bionic/fcntl.cpp b/libc/bionic/fcntl.cpp
index c508131..35af78b 100644
--- a/libc/bionic/fcntl.cpp
+++ b/libc/bionic/fcntl.cpp
@@ -30,6 +30,7 @@
#include <fcntl.h>
#include "private/bionic_fdtrack.h"
+#include "private/bionic_fortify.h"
#if defined(__LP64__)
@@ -44,6 +45,10 @@
void* arg = va_arg(args, void*);
va_end(args);
+ if (cmd == F_SETFD && (reinterpret_cast<uintptr_t>(arg) & ~FD_CLOEXEC) != 0) {
+ __fortify_fatal("fcntl(F_SETFD) passed non-FD_CLOEXEC flag: %p", arg);
+ }
+
int rc = __fcntl(fd, cmd, arg);
if (cmd == F_DUPFD) {
return FDTRACK_CREATE_NAME("F_DUPFD", rc);
diff --git a/tests/fcntl_test.cpp b/tests/fcntl_test.cpp
index d50a438..862f498 100644
--- a/tests/fcntl_test.cpp
+++ b/tests/fcntl_test.cpp
@@ -23,6 +23,7 @@
#include <sys/vfs.h>
#include <android-base/file.h>
+#include <android-base/silent_death_test.h>
#include <android-base/stringprintf.h>
// Glibc v2.19 doesn't include these in fcntl.h so host builds will fail without.
@@ -33,6 +34,8 @@
#include <linux/magic.h>
#endif
+using fcntl_DeathTest = SilentDeathTest;
+
TEST(fcntl, fcntl_smoke) {
int fd = open("/proc/version", O_RDONLY);
ASSERT_TRUE(fd != -1);
@@ -356,3 +359,7 @@
ASSERT_EQ(0, close(fd));
#endif
}
+
+TEST(fcntl_DeathTest, fcntl_F_SETFD) {
+ EXPECT_DEATH(fcntl(0, F_SETFD, O_NONBLOCK), "non-FD_CLOEXEC");
+}